major API refactor

instancing
cosmonaut 2020-12-07 20:10:27 -08:00
parent fe222e266f
commit 84601379b5
5 changed files with 282 additions and 260 deletions

View File

@ -0,0 +1,9 @@
using Microsoft.Xna.Framework;
namespace Kav
{
public interface IHasWorldMatrix
{
Matrix World { get; set; }
}
}

View File

@ -3,28 +3,28 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav
{
public class LinearDepthEffect : Effect
public class LinearDepthEffect : Effect, IHasWorldMatrix
{
EffectParameter modelParam;
EffectParameter modelViewProjectionParam;
EffectParameter worldParam;
EffectParameter worldViewProjectionParam;
EffectParameter lightPositionParam;
EffectParameter farPlaneParam;
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
Matrix model;
Matrix world;
Matrix view;
Matrix projection;
public Vector3 LightPosition { get; set; }
public float FarPlane { get; set; }
public Matrix Model
public Matrix World
{
get { return model; }
get { return world; }
set
{
model = value;
world = value;
dirtyFlags |= EffectDirtyFlags.World;
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
}
@ -60,16 +60,16 @@ namespace Kav
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
{
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection);
Matrix.Multiply(ref model, ref viewProjection, out Matrix worldViewProj);
Matrix.Multiply(ref world, ref viewProjection, out Matrix worldViewProj);
modelViewProjectionParam.SetValue(worldViewProj);
worldViewProjectionParam.SetValue(worldViewProj);
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
}
if ((dirtyFlags & EffectDirtyFlags.World) != 0)
{
modelParam.SetValue(model);
worldParam.SetValue(world);
dirtyFlags &= ~EffectDirtyFlags.World;
}
@ -80,8 +80,8 @@ namespace Kav
private void CacheEffectParameters()
{
modelParam = Parameters["Model"];
modelViewProjectionParam = Parameters["ModelViewProjection"];
worldParam = Parameters["Model"];
worldViewProjectionParam = Parameters["ModelViewProjection"];
lightPositionParam = Parameters["LightPosition"];
farPlaneParam = Parameters["FarPlane"];

View File

@ -3,23 +3,26 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav
{
public class SimpleDepthEffect : Effect
public class SimpleDepthEffect : Effect, IHasWorldMatrix
{
EffectParameter modelViewProjectionParam;
EffectParameter worldParam;
EffectParameter viewProjectionParam;
EffectParameter vertexShaderIndexParam;
Matrix model;
Matrix world;
Matrix view;
Matrix projection;
bool hardwareInstancingEnabled = false;
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
public Matrix Model
public Matrix World
{
get { return model; }
get { return world; }
set
{
model = value;
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
world = value;
dirtyFlags |= EffectDirtyFlags.World;
}
}
@ -29,7 +32,7 @@ namespace Kav
set
{
view = value;
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
dirtyFlags |= EffectDirtyFlags.ViewProj;
}
}
@ -39,7 +42,20 @@ namespace Kav
set
{
projection = value;
dirtyFlags |= EffectDirtyFlags.WorldViewProj;
dirtyFlags |= EffectDirtyFlags.ViewProj;
}
}
public bool HardwareInstancingEnabled
{
get { return hardwareInstancingEnabled; }
set
{
if (value != hardwareInstancingEnabled)
{
hardwareInstancingEnabled = value;
dirtyFlags |= EffectDirtyFlags.VertexShaderIndex;
}
}
}
@ -50,20 +66,39 @@ namespace Kav
protected override void OnApply()
{
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
if ((dirtyFlags & EffectDirtyFlags.World) != 0)
{
worldParam.SetValue(world);
dirtyFlags &= ~EffectDirtyFlags.World;
}
if ((dirtyFlags & EffectDirtyFlags.ViewProj) != 0)
{
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection);
Matrix.Multiply(ref model, ref viewProjection, out Matrix worldViewProj);
viewProjectionParam.SetValue(viewProjection);
modelViewProjectionParam.SetValue(worldViewProj);
dirtyFlags &= ~EffectDirtyFlags.ViewProj;
}
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
if ((dirtyFlags & EffectDirtyFlags.VertexShaderIndex) != 0)
{
int vertexShaderIndex = 0;
if (hardwareInstancingEnabled)
{
vertexShaderIndex = 1;
}
vertexShaderIndexParam.SetValue(vertexShaderIndex);
}
}
private void CacheEffectParameters()
{
modelViewProjectionParam = Parameters["ModelViewProjection"];
worldParam = Parameters["World"];
viewProjectionParam = Parameters["ViewProjection"];
vertexShaderIndexParam = Parameters["VertexShaderIndex"];
}
}
}

View File

@ -220,48 +220,145 @@ namespace Kav
}
}
public void DepthRender(
RenderTarget2D renderTarget,
// Renders a series of drawable-transform pairs using an effect that has a World matrix.
// Effect must be pre-configured!!
public static void CullAndRenderIndexed<T, U>(
GraphicsDevice graphicsDevice,
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms
) {
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
IEnumerable<(T, Matrix)> drawableTransformPairs,
U effect
) where T : IIndexDrawable, ICullable where U : Effect, IHasWorldMatrix
{
var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms))
foreach (var (drawable, transform) in FrustumCull(boundingFrustum, drawableTransformPairs))
{
foreach (var modelMesh in model.Meshes)
{
foreach (var meshPart in modelMesh.MeshParts)
{
SimpleDepthEffect.World = transform;
SimpleDepthEffect.View = camera.View;
SimpleDepthEffect.Projection = camera.Projection;
effect.World = transform;
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
GraphicsDevice.Indices = meshPart.IndexBuffer;
foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
meshPart.VertexBuffer.VertexCount,
0,
meshPart.Triangles.Length
);
}
}
}
RenderIndexed(
graphicsDevice,
drawable,
effect
);
}
}
public void SkyboxRender(
public static void RenderIndexed<T, U>(
GraphicsDevice graphicsDevice,
T drawable,
U effect
) where T : IIndexDrawable where U : Effect
{
graphicsDevice.SetVertexBuffer(drawable.VertexBuffer);
graphicsDevice.Indices = drawable.IndexBuffer;
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
graphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
drawable.VertexBuffer.VertexCount,
0,
drawable.IndexBuffer.IndexCount / 3
);
}
}
public static int FillAndSetBuffersForInstancing<T, V>(
GraphicsDevice graphicsDevice,
PerspectiveCamera camera,
T drawable,
IEnumerable<Matrix> transforms,
V[] vertexData,
DynamicVertexBuffer dynamicVertexBuffer
) where T : ICullable, IIndexDrawable where V : struct, IVertexType, IHasWorldMatrix
{
var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
int numInstances = 0;
foreach (var transform in FrustumCull(boundingFrustum, drawable, transforms))
{
vertexData[numInstances].World = transform;
numInstances += 1;
}
if (numInstances == 0) { return 0; }
dynamicVertexBuffer.SetData(
vertexData,
0,
numInstances,
SetDataOptions.Discard
);
graphicsDevice.SetVertexBuffers(
drawable.VertexBuffer,
new VertexBufferBinding(dynamicVertexBuffer, 0, 1)
);
graphicsDevice.Indices = drawable.IndexBuffer;
return numInstances;
}
public static void RenderInstanced<T, U>(
GraphicsDevice graphicsDevice,
T drawable,
U effect,
int numInstances
) where T : ICullable, IIndexDrawable where U : Effect
{
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
graphicsDevice.DrawInstancedPrimitives(
PrimitiveType.TriangleList,
0,
0,
drawable.VertexBuffer.VertexCount,
0,
drawable.IndexBuffer.IndexCount / 3,
numInstances
);
}
}
// TODO: can probably make this static somehow
public void RenderFullscreenEffect(
Effect effect
) {
foreach (var pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}
}
public void RenderDepth<T>(
RenderTarget2D renderTarget,
PerspectiveCamera camera,
IEnumerable<(T, Matrix)> drawableTransforms
) where T : ICullable, IIndexDrawable
{
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
SimpleDepthEffect.View = camera.View;
SimpleDepthEffect.Projection = camera.Projection;
CullAndRenderIndexed(
GraphicsDevice,
camera,
drawableTransforms,
SimpleDepthEffect
);
}
public void RenderSkybox(
RenderTarget2D renderTarget,
PerspectiveCamera camera,
TextureCube skybox
@ -274,41 +371,29 @@ namespace Kav
var view = camera.View;
view.Translation = Vector3.Zero;
SkyboxEffect.View = view;
SkyboxEffect.View = view;
SkyboxEffect.Projection = camera.Projection;
GraphicsDevice.SetVertexBuffer(UnitCube.Meshes[0].MeshParts[0].VertexBuffer);
GraphicsDevice.Indices = UnitCube.Meshes[0].MeshParts[0].IndexBuffer;
RenderIndexed(
GraphicsDevice,
UnitCube.Meshes[0].MeshParts[0],
SkyboxEffect
);
foreach (var pass in SkyboxEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
UnitCube.Meshes[0].MeshParts[0].VertexBuffer.VertexCount,
0,
UnitCube.Meshes[0].MeshParts[0].Triangles.Length
);
}
GraphicsDevice.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace;
}
/// <summary>
/// GBuffer binding must have 4 render targets.
/// </summary>
public void InstancedGBufferRender<T>(
public void RenderGBufferInstanced<T>(
RenderTargetBinding[] gBuffer,
RenderTarget2D depthBuffer,
PerspectiveCamera camera,
T drawable,
IEnumerable<Matrix> transforms
) where T : ICullable, IIndexDrawable, IGBufferDrawable {
int numInstances = 0;
GraphicsDevice.SetRenderTargets(gBuffer);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque;
@ -326,132 +411,67 @@ namespace Kav
Deferred_GBufferEffect.View = camera.View;
Deferred_GBufferEffect.Projection = camera.Projection;
var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
foreach (var transform in FrustumCull(boundingFrustum, drawable, transforms))
{
GBufferInstanceVertices[numInstances].World = transform;
numInstances += 1;
}
if (numInstances == 0) { return; }
GBufferInstanceVertexBuffer.SetData(
var numInstances = FillAndSetBuffersForInstancing(
GraphicsDevice,
camera,
drawable,
transforms,
GBufferInstanceVertices,
0,
numInstances,
SetDataOptions.Discard
GBufferInstanceVertexBuffer
);
GraphicsDevice.SetVertexBuffers(
drawable.VertexBuffer,
new VertexBufferBinding(GBufferInstanceVertexBuffer, 0, 1)
RenderInstanced(
GraphicsDevice,
drawable,
Deferred_GBufferEffect,
numInstances
);
GraphicsDevice.Indices = drawable.IndexBuffer;
foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawInstancedPrimitives(
PrimitiveType.TriangleList,
0,
0,
drawable.VertexBuffer.VertexCount,
0,
drawable.IndexBuffer.IndexCount / 3,
numInstances
);
}
// re-render to get depth
GraphicsDevice.SetRenderTarget(depthBuffer);
foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawInstancedPrimitives(
PrimitiveType.TriangleList,
0,
0,
drawable.VertexBuffer.VertexCount,
0,
drawable.IndexBuffer.IndexCount / 3,
numInstances
);
}
//SimpleDepthEffect.HardwareInstancingEnabled = true;
//SimpleDepthEffect.View = camera.View;
//SimpleDepthEffect.Projection = camera.Projection;
//foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes)
//{
// pass.Apply();
// GraphicsDevice.DrawInstancedPrimitives(
// PrimitiveType.TriangleList,
// 0,
// 0,
// drawable.VertexBuffer.VertexCount,
// 0,
// drawable.IndexBuffer.IndexCount / 3,
// numInstances
// );
//}
RenderInstanced(
GraphicsDevice,
drawable,
Deferred_GBufferEffect,
numInstances
);
}
public void GBufferRender(
public void RenderGBufferIndexed<T>(
RenderTargetBinding[] gBuffer,
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms
) {
IEnumerable<(T, Matrix)> drawableTransforms
) where T : ICullable, IIndexDrawable, IGBufferDrawable {
GraphicsDevice.SetRenderTargets(gBuffer);
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque;
Deferred_GBufferEffect.HardwareInstancingEnabled = false;
Deferred_GBufferEffect.View = camera.View;
Deferred_GBufferEffect.Projection = camera.Projection;
var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection);
foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms))
foreach (var (drawable, transform) in FrustumCull(boundingFrustum, drawableTransforms))
{
foreach (var modelMesh in model.Meshes)
{
foreach (var meshPart in modelMesh.MeshParts)
{
Deferred_GBufferEffect.World = transform;
Deferred_GBufferEffect.View = camera.View;
Deferred_GBufferEffect.Projection = camera.Projection;
Deferred_GBufferEffect.World = transform;
Deferred_GBufferEffect.HardwareInstancingEnabled = false;
Deferred_GBufferEffect.HardwareInstancingEnabled = false;
Deferred_GBufferEffect.Albedo = meshPart.Albedo;
Deferred_GBufferEffect.Metallic = meshPart.Metallic;
Deferred_GBufferEffect.Roughness = meshPart.Roughness;
Deferred_GBufferEffect.Albedo = drawable.Albedo;
Deferred_GBufferEffect.Metallic = drawable.Metallic;
Deferred_GBufferEffect.Roughness = drawable.Roughness;
Deferred_GBufferEffect.AlbedoTexture = meshPart.AlbedoTexture;
Deferred_GBufferEffect.NormalTexture = meshPart.NormalTexture;
Deferred_GBufferEffect.MetallicRoughnessTexture = meshPart.MetallicRoughnessTexture;
Deferred_GBufferEffect.AlbedoTexture = drawable.AlbedoTexture;
Deferred_GBufferEffect.NormalTexture = drawable.NormalTexture;
Deferred_GBufferEffect.MetallicRoughnessTexture = drawable.MetallicRoughnessTexture;
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
GraphicsDevice.Indices = meshPart.IndexBuffer;
foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
meshPart.VertexBuffer.VertexCount,
0,
meshPart.Triangles.Length
);
}
}
}
RenderIndexed(GraphicsDevice, drawable, Deferred_GBufferEffect);
}
}
public void AmbientLightRender(
public void RenderAmbientLight(
RenderTarget2D renderTarget,
Texture2D gPosition,
Texture2D gAlbedo,
@ -465,25 +485,20 @@ namespace Kav
DeferredAmbientLightEffect.GAlbedo = gAlbedo;
DeferredAmbientLightEffect.AmbientColor = ambientLight.Color.ToVector3();
foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}
RenderFullscreenEffect(DeferredAmbientLightEffect);
}
public void PointLightRender(
public void RenderPointLight<T>(
RenderTarget2D renderTarget,
Texture2D gPosition,
Texture2D gAlbedo,
Texture2D gNormal,
Texture2D gMetallicRoughness,
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
IEnumerable<(T, Matrix)> modelTransforms,
PointLight pointLight
) {
RenderPointShadows(camera, modelTransforms, pointLight);
) where T : ICullable, IIndexDrawable {
RenderPointShadows(PointShadowCubeMap, camera, modelTransforms, pointLight);
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
@ -503,26 +518,21 @@ namespace Kav
DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value
foreach (var pass in DeferredPointLightEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}
RenderFullscreenEffect(DeferredPointLightEffect);
}
public void DirectionalLightRender(
public void RenderDirectionalLight<T>(
RenderTarget2D renderTarget,
Texture2D gPosition,
Texture2D gAlbedo,
Texture2D gNormal,
Texture2D gMetallicRoughness,
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
IEnumerable<(T, Matrix)> modelTransforms,
DirectionalLight directionalLight,
int numShadowCascades
) {
RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect);
) where T : ICullable, IIndexDrawable {
//RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect);
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
@ -554,27 +564,22 @@ namespace Kav
DeferredDirectionalLightEffect.ViewMatrix = camera.View;
DeferredDirectionalLightEffect.EyePosition = camera.Position;
foreach (EffectPass pass in DeferredDirectionalLightEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}
RenderFullscreenEffect(DeferredDirectionalLightEffect);
}
public void DirectionalLightToonRender(
public void RenderDirectionalLightToon<T>(
RenderTarget2D renderTarget,
Texture2D gPosition,
Texture2D gAlbedo,
Texture2D gNormal,
Texture2D gMetallicRoughness,
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
IEnumerable<(T, Matrix)> modelTransforms,
DirectionalLight directionalLight,
int numShadowCascades,
bool ditheredShadows
) {
RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect);
) where T : ICullable, IIndexDrawable {
//RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect);
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
@ -609,20 +614,15 @@ namespace Kav
Deferred_ToonEffect.ViewMatrix = camera.View;
foreach (EffectPass pass in Deferred_ToonEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}
RenderFullscreenEffect(Deferred_ToonEffect);
}
private void RenderDirectionalShadows(
private void RenderDirectionalShadows<T>(
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight,
ShadowCascadeEffect effect
) {
) where T : ICullable, IIndexDrawable {
// render the individual shadow cascades
var previousFarPlane = camera.NearPlane;
for (var i = 0; i < NumShadowCascades; i++)
@ -739,26 +739,18 @@ namespace Kav
}
}
private void RenderPointShadows(
private void RenderPointShadows<T>(
RenderTargetCube pointShadowCubeMap,
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
IEnumerable<(T, Matrix)> modelTransforms,
PointLight pointLight
) {
) where T : ICullable, IIndexDrawable {
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque;
LinearDepthEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.PiOver2,
1,
0.1f,
25f // FIXME: magic value
);
LinearDepthEffect.FarPlane = 25f;
LinearDepthEffect.LightPosition = pointLight.Position;
foreach (CubeMapFace face in Enum.GetValues(typeof(CubeMapFace)))
{
GraphicsDevice.SetRenderTarget(PointShadowCubeMap, face);
GraphicsDevice.SetRenderTarget(pointShadowCubeMap, face);
Vector3 targetDirection;
Vector3 targetUpDirection;
@ -805,36 +797,22 @@ namespace Kav
pointLight.Position + targetDirection,
targetUpDirection
);
LinearDepthEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.PiOver2,
1,
0.1f,
25f // FIXME: magic value
);
LinearDepthEffect.FarPlane = 25f;
var boundingFrustum = new BoundingFrustum(LinearDepthEffect.View * LinearDepthEffect.Projection);
LinearDepthEffect.LightPosition = pointLight.Position;
foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms))
{
foreach (var modelMesh in model.Meshes)
{
foreach (var meshPart in modelMesh.MeshParts)
{
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer);
GraphicsDevice.Indices = meshPart.IndexBuffer;
LinearDepthEffect.Model = transform;
foreach (var pass in LinearDepthEffect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
meshPart.VertexBuffer.VertexCount,
0,
meshPart.Triangles.Length
);
}
}
}
}
CullAndRenderIndexed(
GraphicsDevice,
camera,
modelTransforms,
LinearDepthEffect
);
}
}

View File

@ -5,7 +5,7 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct GBufferInstanceVertex : IVertexType
public struct GBufferInstanceVertex : IVertexType, IHasWorldMatrix
{
VertexDeclaration IVertexType.VertexDeclaration
{