c++ - Normals are not transfered to DirectX 11 shader correctly - random, time-dependent values? -
today trying add normal maps directx 11 application.
something went wrong. i've decided output normals' information instead of color on scene objects "see" lies problem. surprised me normals' values changes fast (the colors blinking each frame). , i'm sure don't manipulate values during program execution (the position of vertices stays stable, normals not).
here 2 screens frames @ t1
, t2
:
my vertex structure:
struct myvertex{//vertex structure myvertex() : weightcount(0), normal(0,0,0){ //texturecoordinates.x = 1; //texturecoordinates.y = 1; } myvertex(float x, float y, float z, float u, float v, float nx, float ny, float nz) : position(x, y, z), texturecoordinates(u, v), normal(0,0,0), weightcount(0){ } directx::xmfloat3 position; directx::xmfloat2 texturecoordinates; directx::xmfloat3 normal = directx::xmfloat3(1.0f, 0.0f, 0.0f); //will not sent shader (and used skinned models) int startweightindex; int weightcount; //=0 means it's not skinned vertex };
the corresponding vertex layout:
layout[0] = { "position", 0, dxgi_format_r32g32b32_float, 0, 0, d3d11_input_per_vertex_data, 0 }; layout[1] = { "texcoord", 0, dxgi_format_r32g32_float, 0, 12, d3d11_input_per_vertex_data, 0 }; layout[2] = { "normal", 0, dxgi_format_r32g32b32_float, 0, 20, d3d11_input_per_vertex_data, 0 };
vertex buffer:
d3d11_buffer_desc bd; zeromemory(&bd, sizeof(bd)); bd.usage = d3d11_usage_default; //d3d11_usage_dynamic bd.bytewidth = sizeof(myvertex) * structure->getverticescount(); bd.bindflags = d3d11_bind_vertex_buffer; bd.cpuaccessflags = 0; d3d11_subresource_data initdata; zeromemory(&initdata, sizeof(initdata)); initdata.psysmem = structure->vertices; if(device->createbuffer(&bd, &initdata, &buffers->vertexbuffer) != s_ok){ return false; }
and shader output normals "as color" (of course, if set output.normal
float3(1,1,1)
, objects stays white):
struct light { float3 diffuse; float3 position; float3 direction; }; cbuffer cbperobject : register(b0) { float4x4 wvp; float4x4 world; float4 difcolor; bool hastexture; bool hasnormmap; }; cbuffer cbperframe : register(b1) { light light; }; texture2d objtexture; texture2d objnormmap; samplerstate objsamplerstate; texturecube skymap; struct vs_input { float4 position : position; float2 tex : texcoord; float3 normal : normal; }; struct vs_output { float4 pos : sv_position; float4 worldpos : position; float3 normal : normal; float2 texcoord : texcoord; float3 tangent : tangent; }; vs_output vs(vs_input input) { vs_output output; //input.position.w = 1.0f; output.pos = mul(input.position, wvp); output.worldpos = mul(input.position, world); output.normal = input.normal; output.tangent = mul(input.tangent, world); output.texcoord = input.tex; return output; } float4 ps(vs_output input) : sv_target { return float4(input.normal, 1.0); } //-------------------------------------------------------------------------------------- // techniques //-------------------------------------------------------------------------------------- technique10 render { pass p0 { setvertexshader( compileshader( vs_4_0, vs() ) ); setpixelshader( compileshader( ps_4_0, ps() ) ); setblendstate( srcalphablendingadd, float4( 0.0f, 0.0f, 0.0f, 0.0f ), 0xffffffff ); } }
where have made mistake? maybe there other places in code can cause strange behavior (some locking, buffers, dunno...)?
edit:
as 413x suggested, i've run directx diagnostic:
what strange on small preview, screen looks same in program. when investigate frame (screenshot), got different colors:
also, here's strange - pick blue pixel , it's says it's black (on right):
edit 2:
as catflier requested post additional code.
the rendering , buffers binding:
//set object world matrix directx::xmmatrix objectworldmatrix = directx::xmmatrixidentity(); directx::xmmatrix rotationmatrix = directx::xmmatrixrotationquaternion( directx::xmvectorset(object->getorientation().getx(), object->getorientation().gety(), object->getorientation().getz(), object->getorientation().getw()) ); irectx::xmmatrix scalematrix = ( object->usesscalematrix() ? directx::xmmatrixscaling(object->gethalfsize().getx(), object->gethalfsize().gety(), object->gethalfsize().getz()) : directx::xmmatrixscaling(1.0f, 1.0f, 1.0f) ); directx::xmmatrix translationmatrix = directx::xmmatrixtranslation(object->getposition().getx(), object->getposition().gety(), object->getposition().getz()); objectworldmatrix = scalematrix * rotationmatrix * translationmatrix; uint stride = sizeof(myvertex); uint offset = 0; context->iasetvertexbuffers(0, 1, &buffers->vertexbuffer, &stride, &offset); //set vertex buffer context->iasetindexbuffer(buffers->indexbuffer, dxgi_format_r16_uint, 0); //set index buffer //set constants per object constantbufferstructure constantsperobject; //set matrices directx::xmfloat4x4 view = mycamera->getview(); directx::xmmatrix camview = xmloadfloat4x4(&view); directx::xmfloat4x4 projection = mycamera->getprojection(); directx::xmmatrix camprojection = xmloadfloat4x4(&projection); directx::xmmatrix worldviewprojectionmatrix = objectworldmatrix * camview * camprojection; constantsperobject.worldviewprojection = xmmatrixtranspose(worldviewprojectionmatrix); constantsperobject.world = xmmatrixtranspose(objectworldmatrix); //draw objects's non-transparent subsets for(int i=0; i<structure->subsets.size(); i++){ setcolorsandtextures(structure->subsets[i], constantsperobject, context); //custom method insert data constantsperobject variable //bind constants per object constant buffer , send vertex , pixel shaders context->updatesubresource(constantbuffer, 0, null, &constantsperobject, 0, 0); context->vssetconstantbuffers(0, 1, &constantbuffer); context->pssetconstantbuffers(0, 1, &constantbuffer); context->rssetstate(rsculldefault); int start = structure->subsets[i]->getvertexindexstart(); int count = structure->subsets[i]->getvertexindexammount(); context->drawindexed(count, start, 0); }
the rasterizer:
void rendererdx::initcull(id3d11device * device){ d3d11_rasterizer_desc cmdesc; zeromemory(&cmdesc, sizeof(d3d11_rasterizer_desc)); cmdesc.fillmode = d3d11_fill_solid; cmdesc.cullmode = d3d11_cull_back; #ifdef graphic_left_handed cmdesc.frontcounterclockwise = true; #else cmdesc.frontcounterclockwise = false; #endif cmdesc.cullmode = d3d11_cull_none; //cmdesc.fillmode = d3d11_fill_wireframe; hresult hr = device->createrasterizerstate(&cmdesc, &rsculldefault); }
edit 3:
the debugger output (there mismatches in semantics?):
d3d11 error: id3d11devicecontext::drawindexed: input assembler - vertex shader linkage error: signatures between stages incompatible. input stage requires semantic/index (normal,0) input, not provided output stage. [ execution error #342: device_shader_linkage_semanticname_not_found]
d3d11 error: id3d11devicecontext::drawindexed: input assembler - vertex shader linkage error: signatures between stages incompatible. semantic 'texcoord' defined mismatched hardware registers between output stage , input stage. [ execution error #343: device_shader_linkage_registerindex]
d3d11 error: id3d11devicecontext::drawindexed: input assembler - vertex shader linkage error: signatures between stages incompatible. semantic 'texcoord' in each signature have different min precision levels, when must bet identical. [ execution error #3146050: device_shader_linkage_minprecision]
i pretty sure bytes missaligned. float 4 bytes me thinks , float4 16 bytes. , wants 16 byte aligned. observe:
layout[0] = { "position", 0, dxgi_format_r32g32b32_float, 0, 0, d3d11_input_per_vertex_data, 0 }; layout[1] = { "texcoord", 0, dxgi_format_r32g32_float, 0, 12, d3d11_input_per_vertex_data, 0 }; layout[2] = { "normal", 0, dxgi_format_r32g32b32_float, 0, 20, d3d11_input_per_vertex_data, 0 };
the value; 0,12,20. (alignedbyteoffset) value starts. mean; position starts @ 0. texcoord starts @ end of float3, gives wrong results. because inside shader:
struct vs_input { float4 position : position; float2 tex : texcoord; float3 normal : normal; };
and normal @ float3+float2. generally, want align things more consistantly. maybe "padding" fill spaces keep variables @ 16 bytes aligned.
but keep more simple you. want switch statement to:
layout[0] = { "position", 0, dxgi_format_r32g32b32_float, 0, 0, d3d11_input_per_vertex_data, 0 }; layout[1] = { "texcoord", 0, dxgi_format_r32g32_float, 0, d3d11_append_aligned_element, d3d11_input_per_vertex_data, 0 }; layout[2] = { "normal", 0, dxgi_format_r32g32b32_float, 0, d3d11_append_aligned_element, d3d11_input_per_vertex_data, 0 };
what happens now? well, thing aligns automagically, can less optimal. 1 thing shaders, try keep 16 byte aligned.
Comments
Post a Comment