How to use instancing and world translation together? - c++

I'm trying to optimize my application, so I've started to use instancing to save myself from multiple draw calls for the same object.
But what I'm not being able to understand is how do I position each instanced object on the right position, I've been learning from Rastertek tutorials and this is their shader code:
struct VertexInputType
{
float4 position : POSITION;
float2 tex : TEXCOORD0;
float3 instancePosition : TEXCOORD1;
};
struct PixelInputType
{
float4 position : SV_POSITION;
float2 tex : TEXCOORD0;
};
////////////////////////////////////////////////////////////////////////////////
// Vertex Shader
////////////////////////////////////////////////////////////////////////////////
PixelInputType TextureVertexShader(VertexInputType input)
{
PixelInputType output;
// Change the position vector to be 4 units for proper matrix calculations.
input.position.w = 1.0f;
// Update the position of the vertices based on the data for this particular instance.
input.position.x += input.instancePosition.x;
input.position.y += input.instancePosition.y;
input.position.z += input.instancePosition.z;
// Calculate the position of the vertex against the world, view, and projection matrices.
output.position = mul(input.position, worldMatrix);
output.position = mul(output.position, viewMatrix);
output.position = mul(output.position, projectionMatrix);
// Store the texture coordinates for the pixel shader.
output.tex = input.tex;
return output;
}
I've been using XMMatrixTranslation from DirectXMath.h on my world matrix to put each object on place, but now looks like the instanced objects have to get their coordinates directly on the shader and as I'm aware of this will be done for each vertex on each instance.
This really got me confused, what's the purpose of the world matrix if every instance of the object is already going to be placed in the world by instancePosition? If there's a way to keep using my world matrix to translate each instance of the same object to the world it would be many times better for me, but I don't know if it is possible, if anyone knows anything which could help me on this it would be great.

Related

D3D11 Multiple Vertex Buffer 2D Depth sorting with depth buffer

I am trying to create some 2D UI drawing in D3D11. I am trying to get the draw calls down as much as possible to improve performance. Previously, I batched up as many textures as possible to send to one draw call, they were accessed with an else if. Well it turned out that sending many textures, especially large ones, to a single shader destroyed performance in some scenarios which is exactly the opposite of what I was trying to achieve.
The goal is to render things back to front from 2 VBOs. So now, I am trying split some things up into a few vertex buffers. I have one vertex buffer that contains non textured vertices, and one that contains different textures. This is because I send one texture to the shader at a time, and want to keep the amount of texture swapping between vertices being drawn at a minimum. The problem I am encountering is that the depth sorting does not work as I want it to. I render the textured vertex buffer first, then the non textured one. When I try to render textures over something rendered in the non textured vertex buffer, it simply doesn't work. There may be some other strange effects that I cant quite explain.
Maybe this is something with my alpha blending? It seems to me that the Z value I write has no effect on the output. Here is the relevant code:
desc->AlphaToCoverageEnable = false;
desc->RenderTarget[0].BlendEnable = true;
desc->RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
desc->RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
desc->RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
desc->RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_DEST_ALPHA;
desc->RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ONE;
desc->RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc->RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
d3d->device->CreateBlendState(desc.get(), &d3d->blend_state);
I also tried Depth -= 1.0f and keeping the depth between 0.0 and 1.0 here to no effect
void put(float x, float y, float u, float v) {
CurrentVBO->put({ {x,y, Depth }, current_color, {u,v}, Scale });
Depth += 1.0f;
}
vertex shader
cbuffer vertex_buffer : register(b0) {
float4x4 projection_matrix;
float render_time;
};
struct VS_INPUT {
float3 pos : POSITION;
float4 color : COLOR;
float2 uv : TEXCOORD;
float scale : SCALE;
};
struct PS_INPUT {
float4 pos : SV_Position;
float4 color : COLOR;
float2 uv : TEXCOORD;
uint tex_id : TEXID;
};
PS_INPUT main(VS_INPUT input) {
PS_INPUT output;
output.pos = mul(projection_matrix, float4(input.pos.xy * input.scale, input.pos.z, 1.0f));
output.color = input.color;
output.uv = input.uv;
return output;
}
desc->DepthEnable = true;
desc->DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc->DepthFunc = D3D11_COMPARISON_LESS;
desc->StencilEnable = false;
desc->FrontFace.StencilFailOp = desc->FrontFace.StencilDepthFailOp = desc->FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc->FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc->BackFace = desc->FrontFace;
d3d->device->CreateDepthStencilState(desc.get(), &d3d->depth_stencil_2d);
After some more reading, I may need to do some more work to make this work properly.
Since the problems of blending and ordering transparent objects with depth. I went with my original plan, but only allow a few textures to be passed to one shader. I also removed the high resolution textures as I think they were causing bandwidth problems in general, as the GPU is already being heavily strained in my case.

SharpDX D3D11 VertexElement Format Mismatch?

I have a shader that no longer draws correctly. It was working in XNA, but had to be rewritten for DX11 and SharpDX and now uses shader model 5. There are no exceptions and the shader effect compiles fine, no debug-layer messages from the device except for an unrelated(?) default sampler-state complaint. It is a normal, fullscreen quad doing the simplest texture blit. (Using a random noise texture for testing)
I am feeding the vertex shader a VertexPositionTexutre, a SharpDX object which contains:
[VertexElement("SV_Position")]
public Vector3 Position;
[VertexElement("TEXCOORD0")]
public Vector2 TextureCoordinate;
I suspect there is a mismatch between signatures. VertexPositionTexture has a Vector3 position component defined for "SV_Position".
D3D11 defines "SV_Position" as a float4. It is a System-Value constant with a concrete native type. I fear the shader is eating an extra float beyond the end of the float3 of Vector3. This would also explain why my UVs are broken on several vertices.
This is my vertex shader:
struct V2P
{
float4 vPosition : SV_Position;
float2 vTexcoord : TEXCOORD0;
};
V2P VSCopy(float4 InPos : SV_Position,
float2 InTex : TEXCOORD0)
{
V2P Out = (V2P)0;
// transform the position to the screen
Out.vPosition = float4(InPos);
Out.vTexcoord = InTex;
return Out;
}
I have tried to change the input of VSCopy() from float4 to float3 with no change in result. Short of recompiling SharpDX VertexPositionTexture, I don't see how to fix this, yet SharpDX fully supports DirectX11 so I must be doing something incorrectly.
I am defining my vertices and setting them as follows:
//using SharpDX.Toolkit.Graphics
[...]//In the initialization
verts = new VertexPositionTexture[]
{
new VertexPositionTexture(
new Vector3(1.0f,-1.0f,0),
new Vector2(1,1)),
new VertexPositionTexture(
new Vector3(-1.0f,-1.0f,0),
new Vector2(0,1)),
new VertexPositionTexture(
new Vector3(-1.0f,1.0f,0),
new Vector2(0,0)),
new VertexPositionTexture(
new Vector3(1.0f,1.0f,0),
new Vector2(1,0))
}
//vb is a Buffer<VertexPositionTexture>
short[] indeces = new short[] { 0, 1, 2, 2, 3, 0 };
vb = SharpDX.Toolkit.Graphics.Buffer.Vertex.New(Game.Instance.GraphicsDevice, verts, SharpDX.Direct3D11.ResourceUsage.Dynamic);
ib = SharpDX.Toolkit.Graphics.Buffer.Index.New(Game.Instance.GraphicsDevice, indeces, dx11.ResourceUsage.Dynamic);
[...] //In the Render method, called every frame to draw the quad
Game.Instance.GraphicsDevice.SetVertexBuffer<VertexPositionTexture>(vb, 0);
Game.Instance.GraphicsDevice.SetIndexBuffer(ib, false);
Game.Instance.GraphicsDevice.DrawIndexed(PrimitiveType.TriangleList, 6);
SharpDX.Tookit provides a method for specifying the InputLayout to the vertex shader. I had missed this method and was incorrectly trying to set the vertex input layout via the property:
SharpDX.Direct3D11.ImmediateContext.InputAssembler.InputLayout
You must set the input layout via the SharpDX.Toolkit.Graphics.GraphicsDevice.SetVertexInputLayout(); method.

Strange rendering with Direct3D10

I'm writing an application which renders graphics on the screen. The application can switch between Direct3D9 and Direct3D10 graphics modules (I wrote DLLs that wrap both D3D9 and D3D10). When trying to render a test mesh (a torus which comes as a stock mesh in D3DX9 and in DXUT library you can find in DirectX10 samples), Direct3D10 module behaves rather weird. Here's what I get.
D3D9:
D3D10:
The view, projection and world matrices are the same for both cases. The only thing that differs is the device initialization code, and the HLSL effect files (for simplicity I only apply ambient colors and don't use advanced lighting, texturing etc). Can this be because of wrong device initialization or because of bad shaders? I would appreciate any hint. I can post any code piece by request.
A guy on Game Dev StackExchange suggested that it is probably because of transposed Projection matrix. I've tried replacing the order the matrices are multiplied in shader file, I've tried almost every permutation I could get, but no right output on the screen.
Thanks in advance.
EDIT: Here's the .fx file. You can ignore PS, there's nothing interesting happening in there.
//Basic ambient light shader with no textures
matrix World;
matrix View;
matrix Projection;
float4 AmbientColor : AMBIENT = float4(1.0, 1.0, 1.0, 1.0);
float AmbientIntensity = 1.0;
struct VS_OUTPUT
{
float4 Position : SV_POSITION; // vertex position
float4 Color : COLOR0; // vertex color
};
RasterizerState rsWireframe { FillMode = WireFrame; };
VS_OUTPUT RenderSceneVS( float4 vPos : POSITION)
{
VS_OUTPUT output;
matrix WorldProjView = mul(World, mul(View, Projection));
vPos = mul(vPos, WorldProjView);
output.Position = vPos;
output.Color.rgb = AmbientColor * AmbientIntensity;
output.Color.a = AmbientColor.a;
return output;
}
struct PS_OUTPUT
{
float4 RGBColor : SV_Target; // Pixel color
};
PS_OUTPUT RenderScenePS( VS_OUTPUT In )
{
PS_OUTPUT output;
output.RGBColor = In.Color;
return output;
}
technique10 Ambient
{
pass P0
{
SetRasterizerState( rsWireframe );
SetVertexShader( CompileShader( vs_4_0, RenderSceneVS( ) ) );
SetGeometryShader( NULL );
SetPixelShader( CompileShader( ps_4_0, RenderScenePS( ) ) );
}
}
Make sure that your vPos.w = 1.0f.
If this is not the case, matrix multiplication will go wild and create strange results.
Not sure what causes the problem but you can check the following:
make sure constant buffers with tranformation matrices are "initialized with something", not some garbage data
if you use normal/tangent in your vertex buffer also make sure you don't put some garbage data in there (per vertex) but it would rather cause problem with texturing
make sure your vertex layout description matches the input in vertexshader (.hlsl), sometimes even if it doesn't match it will just compile and run but showing some unexpected mesh.
I have no idea how is it in DX9 but maybe there is also something with coordinates, multiplying z in vertex buffer on in some transformation matrix by -1 might help
Edit: It might be also good idea to just put some simple mesh into the buffer, cube for example (a triangle even) and check if it's drawning properly.
You need to transpose your matrices before setting them as shader constants. If you are using xnamath use the XMMatrixTranspose() function on each of the world, view and projection matrices before setting them into your constant buffer.

how do i create 3d bounding box? (Direct 3d 11, HLSL)

I am using direct 3d for the first time and i am looking for a way to represent bounding boxes (rectangles/cylinders/spheres). How do i outline the bounding box? Is this a shader, or do i use somthing else to create an outlined shape?
chasester
The simplest way is to use a line list to create a unit wireframe bounding volume.
using a transform matrix, you can scale, translate or rotate the volume around any object in your 3D world.
accomplishing this requires 3 main parts:
A constant VB and IB with the linelist verts set up (remember it needs to be centered around the origin, and have a unit length of 1), plus a VB for per-instance data.
An input layout that takes in a transform matrix as a per instance member.
A vertex shader that applies the transform matrix to each vertex of the cube. (the pixel shader need only output the color as is supplied).
(It should be noted that the same principle applies to spheres, hulls etc. as well)
The shaders I use look like this:
struct WIRE_VS_INPUT
{
float3 Position : POSITION;
float4 Color : COLOR0;
float3 Transform : TRANSFORM;
float3 Size : SIZE;
};
struct WIRE_VS_OUTPUT
{
float4 Position : SV_POSITION;
float4 Color : COLOR0;
};
WIRE_VS_OUTPUT WireBoxVS( WIRE_VS_INPUT Input )
{
WIRE_VS_OUTPUT Output;
Output.Position = mul(float4((Input.Position * Input.Size) + Input.Transform,1),g_mWorldViewProjection);
Output.Color = Input.Color;
return Output;
}
float4 WireBoxPS( WIRE_VS_OUTPUT Input ) : SV_TARGET
{
return Input.Color;
}
The cube VB & IB setup:
const DirectX::XMFLOAT3 kWireCube[] =
{
DirectX::XMFLOAT3(-1,-1,-1),
DirectX::XMFLOAT3(1,-1,-1),
DirectX::XMFLOAT3(1,1,-1),
DirectX::XMFLOAT3(-1,1,-1),
DirectX::XMFLOAT3(-1,-1,1),
DirectX::XMFLOAT3(1,-1,1),
DirectX::XMFLOAT3(1,1,1),
DirectX::XMFLOAT3(-1,1,1)
};
const WORD kWireCubeIndices[] =
{
0,1,
1,2,
2,3,
3,0,
4,5,
5,6,
6,7,
7,4,
0,4,
1,5,
2,6,
3,7
};

HLSL and DX Skybox Issues (creates seams)

I'm (re)learning DirectX and have moved into HLSL coding. Prior to using my custom .fx file I created a skybox for a game with a vertex buffer of quads. Everything worked fine...texture mapped and wrapped beautifully. However now that I have HLSL setup to manage the vertices there are distinctive seams where the quads meet. The textures all line up properly I just cant get rid of this damn seam!
I tend to think the problem is with the texCube...or rather all the texturing information here. I'm texturing the quads in DX...it may just be that I still don't quite get the link between the two..not sure. Anyway thanks for the help in advance!
Heres the .fx file:
float4x4 World;
float4x4 View;
float4x4 Projection;
float3 CameraPosition;
Texture SkyBoxTexture;
samplerCUBE SkyBoxSampler = sampler_state
{
texture = <SkyBoxTexture>;
minfilter = ANISOTROPIC;
mipfilter = LINEAR;
AddressU = Wrap;
AddressV = Wrap;
AddressW = Wrap;
};
struct VertexShaderInput
{
float4 Position : POSITION0;
};
struct VertexShaderOutput
{
float4 Position : POSITION0;
float3 TextureCoordinate : TEXCOORD0;
};
VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
VertexShaderOutput output;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
float4 VertexPosition = mul(input.Position, World);
output.TextureCoordinate = VertexPosition - CameraPosition;
return output;
}
float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
return texCUBE(SkyBoxSampler, normalize(input.TextureCoordinate));
}
technique Skybox
{
pass Pass1
{
VertexShader = compile vs_2_0 VertexShaderFunction();
PixelShader = compile ps_2_0 PixelShaderFunction();
}
}
To avoid seams you need to draw your skybox in a single DrawIndexedPrimitive call, preferably using triangle strip. DON'T draw each face as separate primitive transformed with individual matrix or something like that - you WILL get seams. If you for some unexplainable reason don't want to use single DrawIndexedPrimitive call for skybox parts, then you must ensure that all faces are drawn using same matrix (same world + view + projection matrix used in every call) and same coordinate values for corner vertices - i.e. "top" face should use exactly same vectors (position) for corners that are used by "side" faces.
Another thing is that you should either store skybox as
cubemap (looks like that's what you're doing) - make just 8 vertices for skybox, draw them as indexed primitive.
Or an unwrapped "atlas" texture that has unused areas filled. with border color.
Or - if you're fine with shaders, you could "raytrace" skybox using shader.
You need to clamp the texture coordinates with setsampler state to get rid of the seam. This toymaker page explains this. Toymaker is a great site for learning Direct3D you should check out the tutorials if you have any more trouble.
You may like to draw a skybox using only one quad. Everything you need is an inverse of World*View*Proj matrix, that is (World*View*Proj)^(-1).
The vertices of the quad should be: (1, 1, 1, 1), (1, -1, 1, 1), (-1, 1, 1, 1), (-1, -1, 1, 1).
Then you compute texture coordinates in VS:
float4 pos = mul(vPos, WorldViewProjMatrixInv);
float3 tex_coord = pos.xyz / pos.w;
And finally you sample the texture in PS:
float4 color = texCUBE(sampler, tex_coord);
No worry about any seams! :)