implement different kinds of billboarding

instancing
cosmonaut 2020-12-04 18:51:59 -08:00
parent 665ff6dd44
commit ae445d94d3
4 changed files with 71 additions and 19 deletions

View File

@ -16,8 +16,15 @@ namespace Kav
public float NearPlane { get; } public float NearPlane { get; }
public float FarPlane { get; } public float FarPlane { get; }
public PerspectiveCamera(Vector3 position, Vector3 forward, Vector3 up, float fieldOfView, float aspectRatio, float nearPlane, float farPlane) public PerspectiveCamera(
{ Vector3 position,
Vector3 forward,
Vector3 up,
float fieldOfView,
float aspectRatio,
float nearPlane,
float farPlane
) {
Position = position; Position = position;
Forward = forward; Forward = forward;
Up = up; Up = up;

View File

@ -0,0 +1,9 @@
namespace Kav
{
public enum SpriteBillboardConstraint
{
None,
Horizontal,
Full
}
}

View File

@ -10,30 +10,48 @@ namespace Kav
public Vector2 Origin { get; } public Vector2 Origin { get; }
public float Rotation { get; } public float Rotation { get; }
public Vector2 Scale { get; } public Vector2 Scale { get; }
public SpriteBillboardConstraint BillboardConstraint { get; }
public Matrix TransformMatrix { get; }
public Sprite( public Sprite(
Texture2D texture, Texture2D texture,
Vector3 position, Vector3 position,
Vector2 origin, Vector2 origin,
float rotation, float rotation,
Vector2 scale Vector2 scale,
SpriteBillboardConstraint billboardConstraint = SpriteBillboardConstraint.None
) { ) {
Texture = texture; Texture = texture;
Position = position; Position = position;
Origin = origin; Origin = origin;
Rotation = rotation; Rotation = rotation;
Scale = scale; Scale = scale;
BillboardConstraint = billboardConstraint;
TransformMatrix = ConstructTransformMatrix(Position, Scale);
} }
public Sprite( public Sprite(
Texture2D texture, Texture2D texture,
Vector3 position Vector3 position,
SpriteBillboardConstraint billboardConstraint = SpriteBillboardConstraint.None
) { ) {
Texture = texture; Texture = texture;
Position = position; Position = position;
Origin = Vector2.Zero; Origin = Vector2.Zero;
Rotation = 0f; Rotation = 0;
Scale = Vector2.One; Scale = Vector2.One;
BillboardConstraint = billboardConstraint;
TransformMatrix = ConstructTransformMatrix(Position, Scale);
}
private static Matrix ConstructTransformMatrix(
Vector3 position,
Vector2 scale
) {
return
Matrix.CreateTranslation(position) *
Matrix.CreateScale(scale.X, scale.Y, 1);
} }
} }
} }

View File

@ -254,35 +254,53 @@ namespace Kav
DepthRender(camera, modelTransforms); DepthRender(camera, modelTransforms);
GraphicsDevice.Clear(ClearOptions.Target, new Color(0, 0, 0, 0), 1f, 0); GraphicsDevice.Clear(ClearOptions.Target, new Color(0, 0, 0, 0), 1f, 0);
Matrix invertY = Matrix.CreateScale(1, -1, 1); BasicEffect.View = camera.View;
BasicEffect.World = invertY;
BasicEffect.View = Matrix.Identity;
BasicEffect.Projection = camera.Projection; BasicEffect.Projection = camera.Projection;
BasicEffect.TextureEnabled = true; BasicEffect.TextureEnabled = true;
BasicEffect.VertexColorEnabled = true; BasicEffect.VertexColorEnabled = true;
SpriteBatch.Begin(0, null, null, DepthStencilState.DepthRead, RasterizerState.CullNone, BasicEffect);
foreach (var sprite in sprites) foreach (var sprite in sprites)
{ {
// transform view space on CPU so we don't have to break the batch if (sprite.BillboardConstraint == SpriteBillboardConstraint.None)
Vector3 viewSpacePosition = Vector3.Transform(sprite.Position, camera.View * invertY); {
BasicEffect.World = sprite.TransformMatrix;
}
else if (sprite.BillboardConstraint == SpriteBillboardConstraint.Horizontal)
{
BasicEffect.World = Matrix.CreateConstrainedBillboard(
sprite.Position,
camera.Position,
Vector3.Up,
camera.Forward,
camera.Position - sprite.Position
);
}
else
{
BasicEffect.World = Matrix.CreateConstrainedBillboard(
sprite.Position,
camera.Position,
Vector3.Up,
null,
null
);
}
SpriteBatch.Begin(0, null, null, DepthStencilState.DepthRead, RasterizerState.CullNone, BasicEffect);
SpriteBatch.Draw( SpriteBatch.Draw(
sprite.Texture, sprite.Texture,
new Vector2(viewSpacePosition.X, viewSpacePosition.Y), Vector2.Zero,
null, null,
Color.White, Color.White,
0, sprite.Rotation,
sprite.Origin, sprite.Origin,
sprite.Scale / new Vector2(sprite.Texture.Width, sprite.Texture.Height), sprite.Scale / new Vector2(sprite.Texture.Width, -sprite.Texture.Height),
0, 0,
viewSpacePosition.Z 0
); );
SpriteBatch.End();
} }
SpriteBatch.End();
GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.Clear(new Color(0, 0, 0, 0)); GraphicsDevice.Clear(new Color(0, 0, 0, 0));