하드웨어 인스 턴싱을 시도하고 있지만 이상한 성능 문제가 발생했습니다. 평균 프레임 속도는 약 45이지만 매우 고르지 않습니다.
- 창
- SynchronizeWithVerticalRetrace = 거짓
- IsFixedTimeStep = false
- PresentationInterval = PresentInterval.Immediate
아래 이미지는 측정 된 타이밍을 표시합니다 ( Stopwatch
). 최상위 그래프는 Draw
분석법에 소요 된 시간 이고 하단 그래프는 종료 시점부터 Draw
시작 시점까지의 시간입니다.Update
스파이크는 거의 정확히 1 초 간격이며 항상 일반적인 시간의 2, 3, 4 또는 5 배입니다. 스파이크 직후의 프레임은 시간이 전혀 걸리지 않습니다. 가비지 수집기가 아닌지 확인했습니다.
현재 12 개의 삼각형과 36 개의 정점으로 구성된 메쉬를 삼각형 목록으로 인스턴스화하고 있습니다 (최적의 것은 아니지만 테스트 용입니다). 인스턴스화 드로우 콜을 250 인스턴스의 작은 부분으로 일괄 처리하면 문제가 완화되지만 CPU 사용량이 크게 증가합니다. 위의 실행은 그리기 호출 당 10000 인스턴스이며 CPU에서 훨씬 쉽습니다.
게임을 전체 화면으로 실행하면 하단 그래프가 거의 존재하지 않지만 방법에서 동일한 문제가 발생합니다 Draw
.
여기 PIX 내부의 실행이 있습니다 . 렌더링이없는 일부 프레임의 경우 ...
어떤 생각,이 원인은 무엇입니까?
편집 : 요청에 따라 렌더링 코드의 관련 부분
A CubeBuffer
가 만들어지고 초기화 된 다음 큐브로 채워집니다. 큐브의 양이 특정 한계를 초과하면 새 큐브 등 CubeBuffer
이 만들어집니다. 각 버퍼는 한 번의 호출로 모든 인스턴스를 그립니다.
한 번만 필요한 정보는 static
(정점, 인덱스 버퍼 및 정점 선언입니다. 지금까지 아무런 차이는 없습니다). 텍스처는 512x512입니다
무승부()
device.Clear(Color.DarkSlateGray);
device.RasterizerState = new RasterizerState() { };
device.BlendState = new BlendState { };
device.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };
//samplerState=new SamplerState() { AddressU = TextureAddressMode.Mirror, AddressV = TextureAddressMode.Mirror, Filter = TextureFilter.Linear };
device.SamplerStates[0] = samplerState
effect.CurrentTechnique = effect.Techniques["InstancingTexColorLight"];
effect.Parameters["xView"].SetValue(cam.viewMatrix);
effect.Parameters["xProjection"].SetValue(projectionMatrix);
effect.Parameters["xWorld"].SetValue(worldMatrix);
effect.Parameters["cubeTexture"].SetValue(texAtlas);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
pass.Apply();
foreach (var buf in CubeBuffers)
buf.Draw();
base.Draw(gameTime);
큐브 버퍼
[StructLayout(LayoutKind.Sequential)]
struct InstanceInfoOpt9
{
public Matrix World;
public Vector2 Texture;
public Vector4 Light;
};
static VertexBuffer geometryBuffer = null;
static IndexBuffer geometryIndexBuffer = null;
static VertexDeclaration instanceVertexDeclaration = null;
VertexBuffer instanceBuffer = null;
InstanceInfoOpt9[] Buffer = new InstanceInfoOpt9[MaxCubeCount];
Int32 bufferCount=0
Init()
{
if (geometryBuffer == null)
{
geometryBuffer = new VertexBuffer(Device, typeof (VertexPositionTexture), 36, BufferUsage.WriteOnly);
geometryIndexBuffer = new IndexBuffer(Device, typeof (Int32), 36, BufferUsage.WriteOnly);
vertices = new[]{...}
geometryBuffer.SetData(vertices);
indices = new[]{...}
geometryIndexBuffer.SetData(indices);
var instanceStreamElements = new VertexElement[6];
instanceStreamElements[0] = new VertexElement(sizeof (float)*0, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 1);
instanceStreamElements[1] = new VertexElement(sizeof (float)*4, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 2);
instanceStreamElements[2] = new VertexElement(sizeof (float)*8, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 3);
instanceStreamElements[3] = new VertexElement(sizeof (float)*12, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 4);
instanceStreamElements[4] = new VertexElement(sizeof (float)*16, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 5);
instanceStreamElements[5] = new VertexElement(sizeof (float)*18, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 6);
instanceVertexDeclaration = new VertexDeclaration(instanceStreamElements);
}
instanceBuffer = new VertexBuffer(Device, instanceVertexDeclaration, MaxCubeCount, BufferUsage.WriteOnly);
instanceBuffer.SetData(Buffer);
bindings = new[]
{
new VertexBufferBinding(geometryBuffer),
new VertexBufferBinding(instanceBuffer, 0, 1),
};
}
AddRandomCube(Vector3 pos)
{
if(cubes.Count >= MaxCubeCount)
return null;
Vector2 tex = new Vector2(rnd.Next(0, 16), rnd.Next(0, 16))
Vector4 l= new Vector4((float)rnd.Next(), (float)rnd.Next(), (float)rnd.Next(), (float)rnd.Next());
var cube = new InstanceInfoOpt9(Matrix.CreateTranslation(pos),tex, l);
Buffer[bufferCount++] = cube;
return cube;
}
Draw()
{
Device.Indices = geometryIndexBuffer;
Device.SetVertexBuffers(bindings);
Device.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 36, 0, 12, bufferCount);
}
셰이더
float4x4 xView;
float4x4 xProjection;
float4x4 xWorld;
texture cubeTexture;
sampler TexColorLightSampler = sampler_state
{
texture = <cubeTexture>;
mipfilter = LINEAR;
minfilter = LINEAR;
magfilter = LINEAR;
};
struct InstancingVSTexColorLightInput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
};
struct InstancingVSTexColorLightOutput
{
float4 Position : POSITION0;
float2 TexCoord : TEXCOORD0;
float4 Light : TEXCOORD1;
};
InstancingVSTexColorLightOutput InstancingVSTexColorLight(InstancingVSTexColorLightInput input, float4x4 instanceTransform : TEXCOORD1, float2 instanceTex : TEXCOORD5, float4 instanceLight : TEXCOORD6)
{
float4x4 preViewProjection = mul (xView, xProjection);
float4x4 preWorldViewProjection = mul (xWorld, preViewProjection);
InstancingVSTexColorLightOutput output;
float4 pos = input.Position;
pos = mul(pos, transpose(instanceTransform));
pos = mul(pos, preWorldViewProjection);
output.Position = pos;
output.Light = instanceLight;
output.TexCoord = float2((input.TexCoord.x / 16.0f) + (1.0f / 16.0f * instanceTex.x),
(input.TexCoord.y / 16.0f) + (1.0f / 16.0f * instanceTex.y));
return output;
}
float4 InstancingPSTexColorLight(InstancingVSTexColorLightOutput input) : COLOR0
{
float4 color = tex2D(TexColorLightSampler, input.TexCoord);
color.r = color.r * input.Light.r;
color.g = color.g * input.Light.g;
color.b = color.b * input.Light.b;
color.a = color.a * input.Light.a;
return color;
}
technique InstancingTexColorLight
{
pass Pass0
{
VertexShader = compile vs_3_0 InstancingVSTexColorLight();
PixelShader = compile ps_3_0 InstancingPSTexColorLight();
}
}