Toon Shading + Point Shadows #1

Merged
cosmonaut merged 9 commits from point_shadow into main 2020-10-19 22:17:48 +00:00
18 changed files with 284 additions and 28 deletions

2
Kav

@ -1 +1 @@
Subproject commit 66d4e5bf6e78949f6e5b2fc9eb1983d438047f0b Subproject commit cb0baf0bf0b2c8c830c239c1566ca7a2fcacced9

View File

@ -0,0 +1,15 @@
using Encompass;
using Microsoft.Xna.Framework;
namespace KavTest.Components
{
public struct AmbientLightComponent : IComponent
{
public Color Color { get; }
public AmbientLightComponent(Color color)
{
Color = color;
}
}
}

View File

@ -0,0 +1,15 @@
using Encompass;
using Microsoft.Xna.Framework;
namespace KavTest
{
public struct ContinuousRotationComponent : IComponent
{
public Quaternion Quaternion { get; }
public ContinuousRotationComponent(Vector3 axis, float angle)
{
Quaternion = Quaternion.CreateFromAxisAngle(axis, angle);
}
}
}

View File

@ -0,0 +1,15 @@
using Encompass;
using Microsoft.Xna.Framework.Graphics;
namespace KavTest.Components
{
public struct SkyboxComponent : IComponent
{
public TextureCube Skybox { get; }
public SkyboxComponent(TextureCube skybox)
{
Skybox = skybox;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 723 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 588 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 KiB

BIN
KavTest/Content/ToonShadeRuins.glb (Stored with Git LFS) Normal file

Binary file not shown.

BIN
KavTest/Content/bluetorus.glb (Stored with Git LFS) Normal file

Binary file not shown.

BIN
KavTest/Content/pinkcone.glb (Stored with Git LFS) Normal file

Binary file not shown.

BIN
KavTest/Content/redcylinder.glb (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -5,7 +5,7 @@ using Microsoft.Xna.Framework;
namespace KavTest.Engines namespace KavTest.Engines
{ {
[Reads(typeof(AngularVelocityComponent))] [Reads(typeof(AngularVelocityComponent), typeof(ContinuousRotationComponent))]
[Sends(typeof(LocalRotationMessage))] [Sends(typeof(LocalRotationMessage))]
public class AngularVelocityEngine : Engine public class AngularVelocityEngine : Engine
{ {
@ -18,6 +18,12 @@ namespace KavTest.Engines
SendMessage(new LocalRotationMessage(entity, Quaternion.CreateFromYawPitchRoll(angularVelocity.X, angularVelocity.Y, angularVelocity.Z))); SendMessage(new LocalRotationMessage(entity, Quaternion.CreateFromYawPitchRoll(angularVelocity.X, angularVelocity.Y, angularVelocity.Z)));
} }
foreach (var entity in ReadEntities<ContinuousRotationComponent>())
{
ref readonly var rotationComponent = ref GetComponent<ContinuousRotationComponent>(entity);
SendMessage(new LocalRotationMessage(entity, rotationComponent.Quaternion));
}
} }
} }
} }

View File

@ -13,6 +13,8 @@ namespace KavTest.Spawners
AddComponent(entity, new Transform3DComponent(new Transform3D(Vector3.Zero, message.Orientation))); AddComponent(entity, new Transform3DComponent(new Transform3D(Vector3.Zero, message.Orientation)));
AddComponent(entity, new DirectionalLightComponent(message.Color, message.Intensity)); AddComponent(entity, new DirectionalLightComponent(message.Color, message.Intensity));
var forward = Matrix.CreateFromQuaternion(message.Orientation).Forward;
AddComponent(entity, new ContinuousRotationComponent(forward, 0.01f));
} }
} }
} }

View File

@ -23,8 +23,8 @@ namespace KavTest
public KavTestGame() public KavTestGame()
{ {
graphics = new GraphicsDeviceManager(this); graphics = new GraphicsDeviceManager(this);
graphics.PreferredBackBufferWidth = 1280; graphics.PreferredBackBufferWidth = 1600;
graphics.PreferredBackBufferHeight = 720; graphics.PreferredBackBufferHeight = 900;
graphics.PreferMultiSampling = false; graphics.PreferMultiSampling = false;
Content.RootDirectory = "Content"; Content.RootDirectory = "Content";
@ -50,8 +50,17 @@ namespace KavTest
var rustyBallModel = Kav.ModelLoader.Load( var rustyBallModel = Kav.ModelLoader.Load(
GraphicsDevice, GraphicsDevice,
Smuggler.Importer.ImportGLB(GraphicsDevice, File.OpenRead("Content/rustysphere.glb")) Smuggler.Importer.ImportGLB(
GraphicsDevice,
File.OpenRead("Content/rustysphere.glb")
)
); );
rustyBallModel.DisableNormalMaps();
rustyBallModel.DisableAlbedoMaps();
rustyBallModel.DisableMetallicRoughnessMaps();
rustyBallModel.Albedo = Color.DeepSkyBlue;
rustyBallModel.Metallic = 0.5f;
rustyBallModel.Roughness = 0.284f;
var lightBulbModel = Kav.ModelLoader.Load( var lightBulbModel = Kav.ModelLoader.Load(
GraphicsDevice, GraphicsDevice,
@ -62,12 +71,104 @@ namespace KavTest
GraphicsDevice, GraphicsDevice,
Smuggler.Importer.ImportGLB(GraphicsDevice, File.OpenRead("Content/floor.glb")) Smuggler.Importer.ImportGLB(GraphicsDevice, File.OpenRead("Content/floor.glb"))
); );
floorModel.Metallic = 0f;
floorModel.Roughness = 0f;
var avocadoModel = Kav.ModelLoader.Load( var avocadoModel = Kav.ModelLoader.Load(
GraphicsDevice, GraphicsDevice,
Smuggler.Importer.ImportGLB(GraphicsDevice, File.OpenRead("Content/avocado.glb")) Smuggler.Importer.ImportGLB(GraphicsDevice, File.OpenRead("Content/avocado.glb"))
); );
var redCylinderModel = Kav.ModelLoader.Load(
GraphicsDevice,
Smuggler.Importer.ImportGLB(
GraphicsDevice,
File.OpenRead("Content/redcylinder.glb")
)
);
var pinkConeModel = Kav.ModelLoader.Load(
GraphicsDevice,
Smuggler.Importer.ImportGLB(
GraphicsDevice,
File.OpenRead("Content/pinkcone.glb")
)
);
var blueTorusModel = Kav.ModelLoader.Load(
GraphicsDevice,
Smuggler.Importer.ImportGLB(
GraphicsDevice,
File.OpenRead("Content/bluetorus.glb")
)
);
var cubeModel = Kav.ModelLoader.Load(
GraphicsDevice,
Smuggler.Importer.ImportGLB(
GraphicsDevice,
File.OpenRead("Content/cube.glb")
)
);
var toonShadeRuinsModel = Kav.ModelLoader.Load(
GraphicsDevice,
Smuggler.Importer.ImportGLB(
GraphicsDevice,
File.OpenRead("Content/ToonShadeRuins.glb")
)
);
Texture2D.TextureDataFromStreamEXT(
File.OpenRead("Content/Skybox/front.jpg"),
out var skyboxSize,
out _,
out byte[] frontPixels
);
Texture2D.TextureDataFromStreamEXT(
File.OpenRead("Content/Skybox/back.jpg"),
out _,
out _,
out byte[] backPixels
);
Texture2D.TextureDataFromStreamEXT(
File.OpenRead("Content/Skybox/right.jpg"),
out _,
out _,
out byte[] rightPixels
);
Texture2D.TextureDataFromStreamEXT(
File.OpenRead("Content/Skybox/left.jpg"),
out _,
out _,
out byte[] leftPixels
);
Texture2D.TextureDataFromStreamEXT(
File.OpenRead("Content/Skybox/top.jpg"),
out _,
out _,
out byte[] topPixels
);
Texture2D.TextureDataFromStreamEXT(
File.OpenRead("Content/Skybox/bottom.jpg"),
out _,
out _,
out byte[] bottomPixels
);
var skybox = new TextureCube(GraphicsDevice, skyboxSize, false, SurfaceFormat.Color);
skybox.SetData(CubeMapFace.PositiveZ, frontPixels);
skybox.SetData(CubeMapFace.NegativeZ, backPixels);
skybox.SetData(CubeMapFace.PositiveX, rightPixels);
skybox.SetData(CubeMapFace.NegativeX, leftPixels);
skybox.SetData(CubeMapFace.PositiveY, topPixels);
skybox.SetData(CubeMapFace.NegativeY, bottomPixels);
WorldBuilder.AddEngine(new InputEngine(this)); WorldBuilder.AddEngine(new InputEngine(this));
WorldBuilder.AddEngine(new AngularVelocityEngine()); WorldBuilder.AddEngine(new AngularVelocityEngine());
WorldBuilder.AddEngine(new MoveAlongCurve3DEngine()); WorldBuilder.AddEngine(new MoveAlongCurve3DEngine());
@ -94,35 +195,97 @@ namespace KavTest
// new Vector3(-1, 1, 1) // new Vector3(-1, 1, 1)
// )); // ));
// WorldBuilder.SendMessage(new StaticModelSpawnMessage(
// new Transform3D(new Vector3(0, 1, 0), Quaternion.Identity, new Vector3(1f, 1f, 1f)),
// rustyBallModel
// ));
WorldBuilder.SendMessage(new StaticModelSpawnMessage( WorldBuilder.SendMessage(new StaticModelSpawnMessage(
new Transform3D(new Vector3(0, -3, 0), Quaternion.Identity, new Vector3(10f, 1f, 10f)), new Transform3D(new Vector3(0, -3, 0), Quaternion.Identity, new Vector3(10f, 1f, 10f)),
floorModel floorModel
)); ));
var entity = WorldBuilder.CreateEntity(); WorldBuilder.SendMessage(new StaticModelSpawnMessage(
WorldBuilder.SetComponent(entity, new Transform3DComponent(
new Transform3D( new Transform3D(
new Vector3(0, 1, 0), new Vector3(0, 1, 0),
Quaternion.CreateFromAxisAngle(Vector3.Right, -Microsoft.Xna.Framework.MathHelper.PiOver2), Quaternion.CreateFromAxisAngle(
new Vector3(30, 30, 30)) Vector3.Right,
-Microsoft.Xna.Framework.MathHelper.PiOver2
),
new Vector3(1f, 1f, 1f)
),
redCylinderModel
));
WorldBuilder.SendMessage(new StaticModelSpawnMessage(
new Transform3D(
new Vector3(-3, 1, 0),
Quaternion.CreateFromAxisAngle(
Vector3.Right,
-Microsoft.Xna.Framework.MathHelper.PiOver2
),
new Vector3(1f, 1f, 1f)
),
blueTorusModel
));
WorldBuilder.SendMessage(new StaticModelSpawnMessage(
new Transform3D(
new Vector3(3, 1, 0),
Quaternion.CreateFromAxisAngle(
Vector3.Right,
-Microsoft.Xna.Framework.MathHelper.PiOver2
),
new Vector3(1f, 1f, 1f)
),
cubeModel
));
// WorldBuilder.SendMessage(new StaticModelSpawnMessage(
// Transform3D.Identity,
// toonShadeRuinsModel
// ));
var lightEntity = WorldBuilder.CreateEntity();
WorldBuilder.SetComponent(
lightEntity,
new Transform3DComponent(
new Transform3D(
new Vector3(0, 3, 3),
Quaternion.Identity,
new Vector3(0.1f, 0.1f, 0.1f)
)
) )
); );
WorldBuilder.SetComponent(entity, new ModelComponent(avocadoModel)); WorldBuilder.SetComponent(
lightEntity,
new PointLightComponent(Color.Blue, 1000f)
);
WorldBuilder.SetComponent(
lightEntity,
new ModelComponent(cubeModel)
);
for (var i = 0; i < 1; i++) // for (var i = 0; i < 1; i++)
{ // {
var start = RandomHelper.RandomVector3(-5, 5); // var start = RandomHelper.RandomVector3(2, 5);
WorldBuilder.SendMessage(new LightBulbSpawnMessage( // WorldBuilder.SendMessage(new LightBulbSpawnMessage(
new Transform3D(start.ToXNAVector(), Quaternion.Identity, new Vector3(0.1f, 0.1f, 0.1f)), // new Transform3D(start.ToXNAVector(), Quaternion.Identity, new Vector3(0.1f, 0.1f, 0.1f)),
RandomHelper.RandomColor(), // RandomHelper.RandomColor(),
1f, // 5f,
RandomHelper.RandomLoop(start, -15, 15, 3, 10) // RandomHelper.RandomLoop(start, 2, 5, 3, 10)
// ));
// }
var ambientLightEntity = WorldBuilder.CreateEntity();
WorldBuilder.SetComponent(ambientLightEntity, new AmbientLightComponent(
new Color(0.4f, 0.4f, 0.4f)
)); ));
}
WorldBuilder.SendMessage(new DirectionalLightSpawnMessage( WorldBuilder.SendMessage(new DirectionalLightSpawnMessage(
//Quaternion.CreateFromAxisAngle(Vector3.Right, Microsoft.Xna.Framework.MathHelper.Pi / 3f),
Quaternion.CreateFromAxisAngle(Vector3.Right, Microsoft.Xna.Framework.MathHelper.PiOver4), Quaternion.CreateFromAxisAngle(Vector3.Right, Microsoft.Xna.Framework.MathHelper.PiOver4),
Color.LightGoldenrodYellow, Color.LightGoldenrodYellow,
0.7f 0.7f
@ -155,6 +318,11 @@ namespace KavTest
100f 100f
)); ));
var skyboxEntity = WorldBuilder.CreateEntity();
WorldBuilder.SetComponent(skyboxEntity, new SkyboxComponent(
skybox
));
World = WorldBuilder.Build(); World = WorldBuilder.Build();
} }

View File

@ -19,6 +19,7 @@ namespace KavTest.Renderers
{ {
foreach (var entity in ReadEntitiesAsEnumerable<ModelComponent>()) foreach (var entity in ReadEntitiesAsEnumerable<ModelComponent>())
{ {
/* FIXME: this transformation should definitely not go here */
var transformComponent = GetComponent<Transform3DComponent>(entity); var transformComponent = GetComponent<Transform3DComponent>(entity);
var modelComponent = GetComponent<ModelComponent>(entity); var modelComponent = GetComponent<ModelComponent>(entity);
if (HasComponent<OverrideAlbedoComponent>(entity)) if (HasComponent<OverrideAlbedoComponent>(entity))
@ -29,11 +30,8 @@ namespace KavTest.Renderers
{ {
foreach (var meshPart in mesh.MeshParts) foreach (var meshPart in mesh.MeshParts)
{ {
if (meshPart.Effect is DeferredPBR_GBufferEffect gBufferEffect) meshPart.DisableAlbedoMap = true;
{ meshPart.Albedo = overrideAlbedoComponent.Color;
gBufferEffect.AlbedoTexture = null;
gBufferEffect.Albedo = overrideAlbedoComponent.Color;
}
} }
} }
} }
@ -42,6 +40,21 @@ namespace KavTest.Renderers
} }
} }
private AmbientLight AmbientLight
{
get
{
if (SomeComponent<AmbientLightComponent>())
{
return new AmbientLight(ReadComponent<AmbientLightComponent>().Color);
}
else
{
return new AmbientLight(Color.Black);
}
}
}
private IEnumerable<PointLight> PointLights private IEnumerable<PointLight> PointLights
{ {
get get
@ -118,11 +131,21 @@ namespace KavTest.Renderers
// ); // );
// } // }
Renderer.DeferredRender( // Renderer.DeferredRender(
// camera,
// ModelTransforms,
// AmbientLight,
// PointLights,
// DirectionalLight()
// );
Renderer.DeferredToonRender(
camera, camera,
ModelTransforms, ModelTransforms,
AmbientLight,
PointLights, PointLights,
DirectionalLight() DirectionalLight(),
ReadComponent<SkyboxComponent>().Skybox
); );
// foreach (var directionalLight in DirectionalLights) // foreach (var directionalLight in DirectionalLights)