billboarding implementation

main
cosmonaut 2020-12-04 15:40:27 -08:00
parent 1c679b8323
commit f08c89e327
11 changed files with 224 additions and 24 deletions

8
.vscode/launch.json vendored
View File

@ -17,13 +17,13 @@
"type": "mono",
"request": "launch",
"preLaunchTask": "Build: Mono Debug",
"program": "${workspaceFolder}/KavTest/bin/Debug/net48/KavTest.exe",
"program": "${workspaceFolder}/KavTest/bin/x64/Debug/net48/KavTest.exe",
"args": [],
"env": {
"LD_LIBRARY_PATH": "${workspaceFolder}/KavTest/bin/Debug/net48/lib64",
"DYLD_LIBRARY_PATH": "${workspaceFolder}/KavTest/bin/Debug/net48/osx"
"LD_LIBRARY_PATH": "./lib64",
"DYLD_LIBRARY_PATH": "./osx"
},
"cwd": "${workspaceFolder}",
"cwd": "${workspaceFolder}/KavTest/bin/x64/Debug/net48",
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen"
},

7
.vscode/tasks.json vendored
View File

@ -46,7 +46,7 @@
"LD_LIBRARY_PATH": "./lib64",
"DYLD_LIBRARY_PATH": "./osx"
},
"cwd": "${workspaceFolder}/KavTest/bin/Release/net48"
"cwd": "${workspaceFolder}/KavTest/bin/x64/Release/net48"
},
"type": "process",
"group": {
@ -93,9 +93,10 @@
"options": {
"env": {
"LD_LIBRARY_PATH": "./lib64",
"DYLD_LIBRARY_PATH": "./osx"
"DYLD_LIBRARY_PATH": "./osx",
"FNA3D_FORCE_DRIVER": "Vulkan"
},
"cwd": "${workspaceFolder}/KavTest/bin/Debug/net48"
"cwd": "${workspaceFolder}/KavTest/bin/x64/Debug/net48"
},
"type": "process",
"group": {

2
Kav

@ -1 +1 @@
Subproject commit d83aacd57f692c9732987fe755cc860fee3c5456
Subproject commit acaafdcdcd3d1e8c7262879d70e0cf5c7c1f4c78

View File

@ -0,0 +1,19 @@
using Encompass;
using Microsoft.Xna.Framework;
namespace KavTest.Components
{
public struct SpotLightComponent : IComponent
{
public Color Color { get; }
public float Intensity { get; }
public float Angle { get; }
public SpotLightComponent(Color color, float intensity, float angleInRadians)
{
Color = color;
Intensity = intensity;
Angle = angleInRadians;
}
}
}

View File

@ -0,0 +1,18 @@
using Encompass;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace KavTest
{
public struct SpriteComponent : IComponent
{
public Texture2D Texture { get; }
public Vector2 Origin { get; }
public SpriteComponent(Texture2D texture, Vector2 origin)
{
Texture = texture;
Origin = origin;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,25 @@
using Encompass;
using KavTest.Components;
using KavTest.Messages;
using Microsoft.Xna.Framework;
namespace KavTest.Spawners
{
public class BillboardSpriteSpawner : Spawner<BillboardSpriteSpawnMessage>
{
protected override void Spawn(in BillboardSpriteSpawnMessage message)
{
var entity = CreateEntity();
var transform = new Transform3D(
message.Position,
Quaternion.Identity,
new Vector3(message.Scale, 1)
);
AddComponent(entity, new Transform3DComponent(transform));
AddComponent(entity, new SpriteComponent(message.Texture, message.Origin));
AddComponent(entity, new AngularVelocityComponent(new Vector3(2f, 0, 0)));
}
}
}

View File

@ -0,0 +1,32 @@
using Microsoft.Xna.Framework;
namespace KavTest.Extensions
{
public static class QuaternionExtensions
{
public static Vector3 EulerAngles(this Quaternion q)
{
Vector3 angles;
double sinr_cosp = 2 * (q.W * q.X + q.Y * q.Z);
double cosr_cosp = 1 - 2 * (q.X * q.X + q.Y * q.Y);
angles.X = (float) System.Math.Atan2(sinr_cosp, cosr_cosp);
double sinp = 2 * (q.W * q.Y - q.Z * q.X);
if (System.Math.Abs(sinp) >= 1)
{
angles.Y = (float) System.Math.PI / 2 * System.Math.Sign(sinp);
}
else
{
angles.Y = (float) System.Math.Asin(sinp);
}
double siny_cosp = 2 * (q.W * q.Z + q.X * q.Y);
double cosy_cosp = 1 - 2 * (q.Y * q.Y + q.Z * q.Z);
angles.Z = (float) System.Math.Atan2(siny_cosp, cosy_cosp);
return angles;
}
}
}

View File

@ -30,7 +30,7 @@ namespace KavTest
Window.AllowUserResizing = true;
IsMouseVisible = true;
Microsoft.Xna.Framework.Input.Mouse.IsRelativeMouseModeEXT = true;
}
@ -51,7 +51,7 @@ namespace KavTest
var rustyBallModel = Kav.ModelLoader.Load(
GraphicsDevice,
Smuggler.Importer.ImportGLB(
GraphicsDevice,
GraphicsDevice,
File.OpenRead("Content/rustysphere.glb")
)
);
@ -169,6 +169,8 @@ namespace KavTest
skybox.SetData(CubeMapFace.PositiveY, topPixels);
skybox.SetData(CubeMapFace.NegativeY, bottomPixels);
var mushroomGuyTexture = Texture2D.FromStream(GraphicsDevice, new FileStream("Content/Sprites/mushroomguy.png", FileMode.Open));
WorldBuilder.AddEngine(new InputEngine(this));
WorldBuilder.AddEngine(new AngularVelocityEngine());
WorldBuilder.AddEngine(new MoveAlongCurve3DEngine());
@ -178,6 +180,7 @@ namespace KavTest
WorldBuilder.AddEngine(new LightBulbSpawner(lightBulbModel));
WorldBuilder.AddEngine(new StaticModelSpawner());
WorldBuilder.AddEngine(new DirectionalLightSpawner());
WorldBuilder.AddEngine(new BillboardSpriteSpawner());
WorldBuilder.AddGeneralRenderer(new SceneRenderer(GraphicsDevice), 0);
// WorldBuilder.SendMessage(new RustyBallSpawnMessage(
@ -207,11 +210,11 @@ namespace KavTest
WorldBuilder.SendMessage(new StaticModelSpawnMessage(
new Transform3D(
new Vector3(0, 1, 0),
new Vector3(0, 1, 0),
Quaternion.CreateFromAxisAngle(
Vector3.Right,
Vector3.Right,
-Microsoft.Xna.Framework.MathHelper.PiOver2
),
),
new Vector3(1f, 1f, 1f)
),
redCylinderModel
@ -219,11 +222,11 @@ namespace KavTest
WorldBuilder.SendMessage(new StaticModelSpawnMessage(
new Transform3D(
new Vector3(-3, 1, 0),
new Vector3(-3, 1, 0),
Quaternion.CreateFromAxisAngle(
Vector3.Right,
Vector3.Right,
-Microsoft.Xna.Framework.MathHelper.PiOver2
),
),
new Vector3(1f, 1f, 1f)
),
blueTorusModel
@ -231,16 +234,24 @@ namespace KavTest
WorldBuilder.SendMessage(new StaticModelSpawnMessage(
new Transform3D(
new Vector3(3, 1, 0),
new Vector3(3, 1, 0),
Quaternion.CreateFromAxisAngle(
Vector3.Right,
Vector3.Right,
-Microsoft.Xna.Framework.MathHelper.PiOver2
),
),
new Vector3(1f, 1f, 1f)
),
cubeModel
));
WorldBuilder.SendMessage(new BillboardSpriteSpawnMessage(
mushroomGuyTexture,
new Vector3(3, 1, 10),
Vector2.Zero,
0,
Vector2.One
));
// WorldBuilder.SendMessage(new StaticModelSpawnMessage(
// Transform3D.Identity,
// toonShadeRuinsModel
@ -251,8 +262,8 @@ namespace KavTest
// lightEntity,
// new Transform3DComponent(
// new Transform3D(
// new Vector3(0, 3, 3),
// Quaternion.Identity,
// new Vector3(0, 3, 3),
// Quaternion.Identity,
// new Vector3(0.1f, 0.1f, 0.1f)
// )
// )

View File

@ -0,0 +1,28 @@
using Encompass;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace KavTest.Messages
{
public struct BillboardSpriteSpawnMessage : IMessage
{
public Texture2D Texture { get; }
public Vector3 Position { get; }
public Vector2 Origin { get; }
public float Rotation { get; }
public Vector2 Scale { get; }
public BillboardSpriteSpawnMessage(
Texture2D texture,
Vector3 position,
float rotation,
Vector2 scale
) {
Texture = texture;
Origin = new Vector2(texture.Width / 2, texture.Height / 2);
Position = position;
Rotation = rotation;
Scale = scale;
}
}
}

View File

@ -11,7 +11,12 @@ namespace KavTest.Renderers
{
public class SceneRenderer : GeneralRenderer
{
private GraphicsDevice GraphicsDevice { get; }
private SpriteBatch SpriteBatch { get; }
private Kav.Renderer Renderer { get; }
private RenderTarget2D DeferredTarget { get; }
private RenderTarget2D BillboardTarget { get; }
private IEnumerable<(Kav.Model, Matrix)> ModelTransforms
{
@ -86,15 +91,62 @@ namespace KavTest.Renderers
);
}
private IEnumerable<Sprite> Sprites()
{
foreach (var entity in ReadEntitiesAsEnumerable<SpriteComponent>())
{
var transformComponent = GetComponent<Transform3DComponent>(entity);
var spriteComponent = GetComponent<SpriteComponent>(entity);
var angles = transformComponent.Transform.Orientation.EulerAngles();
yield return new Sprite(
spriteComponent.Texture,
transformComponent.Transform.Position,
spriteComponent.Origin,
angles.X,
new Vector2(
transformComponent.Transform.Scale.X,
transformComponent.Transform.Scale.Y
)
);
}
}
public SceneRenderer(GraphicsDevice graphicsDevice)
{
Renderer = new Kav.Renderer(
graphicsDevice,
graphicsDevice.PresentationParameters.BackBufferWidth,
graphicsDevice,
graphicsDevice.PresentationParameters.BackBufferWidth,
graphicsDevice.PresentationParameters.BackBufferHeight,
4,
4096
);
DeferredTarget = new RenderTarget2D(
graphicsDevice,
graphicsDevice.PresentationParameters.BackBufferWidth,
graphicsDevice.PresentationParameters.BackBufferHeight,
false,
SurfaceFormat.Color,
DepthFormat.Depth24Stencil8,
0,
RenderTargetUsage.PreserveContents
);
BillboardTarget = new RenderTarget2D(
graphicsDevice,
graphicsDevice.PresentationParameters.BackBufferWidth,
graphicsDevice.PresentationParameters.BackBufferHeight,
false,
SurfaceFormat.Color,
DepthFormat.Depth24Stencil8,
0,
RenderTargetUsage.PreserveContents
);
GraphicsDevice = graphicsDevice;
SpriteBatch = new SpriteBatch(GraphicsDevice);
}
public override void Render()
@ -140,6 +192,7 @@ namespace KavTest.Renderers
// );
Renderer.DeferredToonRender(
DeferredTarget,
camera,
ModelTransforms,
AmbientLight,
@ -148,6 +201,19 @@ namespace KavTest.Renderers
ReadComponent<SkyboxComponent>().Skybox
);
Renderer.BillboardSpriteRender(
BillboardTarget,
camera,
ModelTransforms,
Sprites()
);
GraphicsDevice.SetRenderTarget(null);
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null);
SpriteBatch.Draw(DeferredTarget, Vector2.Zero, Color.White);
SpriteBatch.Draw(BillboardTarget, Vector2.Zero, Color.White);
SpriteBatch.End();
// foreach (var directionalLight in DirectionalLights)
// {
// Renderer.DepthRender(