DX11着色器仅绑定未使用常量缓冲区时正常执行问题求助
DX11着色器常量缓冲区异常问题
只有将像素着色器中寄存器b1的常量缓冲区设置为指定的ConstantBuffer结构体时,着色器才能正常工作。排查8小时后发现,ConstantBuffer中的time变量数据似乎混入了CameraBuffer的变量中。已使用__declspec(align(16))处理内存对齐,且自认为数据填充正确,但问题依旧。
C++代码实现
// A buffer for lighting __declspec(align(16)) struct CameraBuffer { Vec3f position{}; Vec3f direction{}; Vec2f pad{}; }; // The buffer required for proper results, even though it shouldn't be required. __declspec(align(16)) struct ConstantBuffer { float time; float period; float amplitude; }; // Method for drawing a sphere void DXGLApp::drawMaterialSphere(Vec3f position, dxgl::SP_DXGLMaterial material) { // transform data dxgl::buffer::TransformBuffer tbuff1{}; tbuff1.world.setIdentity(); tbuff1.world.setTranslation(position); tbuff1.view = m_camera->view(); tbuff1.proj = m_camera->proj(); m_cbLandscape->update(&tbuff1); // setting vertex data render()->stageInput()->setInputLayout(m_layout); render()->stageInput()->setVertexBuffers(1, &m_mesh1->getVertexBuffer()); render()->stageInput()->setIndexBuffer(m_mesh1->getIndexBuffer()); // setting shaders render()->stageShader()->VS_setShader(m_vs); render()->stageShader()->PS_setShader(m_ps); // setting cbuffers render()->stageShader()->VS_setCBuffer(0, 1, m_cbLandscape->get()); render()->stageShader()->PS_setCBuffer(0, 1, m_cbCamera->get()); // This cbuffer, 'm_cbPostProcess' is not used in the currently bound shader, // yet the results produced without it are incorrect. render()->stageShader()->PS_setCBuffer(1, 1, m_cbPostProcess->get()); // sets texture slots render()->stageShader()->PS_setMaterial(0, 6, material); // draw render()->stageInput()->drawIndexedTriangleList(m_mesh1->getIndices().size(), 0, 0); // unbind //render()->stageShader()->VS_setShader(0); //render()->stageShader()->PS_setShader(0); //render()->stageShader()->VS_setCBuffer(0, 0, 0); //render()->stageShader()->PS_setCBuffer(0, 0, 0); } void update(long double delta) { // updating m_cbCamera dxgl::buffer::CameraBuffer camBuff{}; camBuff.position = m_camera->world().getTranslation(); camBuff.direction = m_camera->world().getZDirection(); m_cbCamera->update(&camBuff); // updating m_cbPostProcess ConstantBuffer dvbuff{}; dvbuff.time = t / 4.0f; dvbuff.period = 0;// 8.0f; dvbuff.amplitude = 0;// 0.0125f; m_cbPostProcess->update(&dvbuff); }
着色器代码实现
顶点着色器
struct VS_Input { float4 position: POSITION; float2 texcoord: TEXCOORD; float3 normal: NORMAL; float3 tangent: TANGENT; }; struct PS_Input { float4 position: SV_POSITION; float2 texcoord: TEXCOORD; float3 normal: NORMAL; float3 tangent: TANGENT; float3 pixelPosition: POSITION; }; cbuffer transform: register(b0) { row_major float4x4 world; row_major float4x4 view; row_major float4x4 proj; }; PS_Input main(VS_Input input) { PS_Input output = (PS_Input)0; output.position = mul(input.position, world); output.position = mul(output.position, view); output.position = mul(output.position, proj); output.pixelPosition = mul(input.position, world); output.texcoord = input.texcoord; output.normal = mul(input.normal, world); output.tangent = mul(input.tangent, world); return output; }
像素着色器
struct PS_Input { float4 position: SV_POSITION; float2 texcoord: TEXCOORD; float3 normal: NORMAL; float3 tangent: TANGENT; float3 pixelPosition: POSITION; }; cbuffer camera: register(b0) { float4 cameraPosition; float4 cameraDirection; } float PI = 3.14159265359f; SamplerState textureSampler: register(s0); Texture2D tex_normalMap: register(t0); Texture2D tex_heightMap: register(t1); Texture2D tex_albedoMap: register(t2); Texture2D tex_metallicMap: register(t3); Texture2D tex_roughnessMap: register(t4); Texture2D tex_aoMap: register(t5); float3 calculateNormals(PS_Input input) { float3 normal = normalize(input.normal); float3 tangent = normalize(input.tangent); tangent = normalize(input.tangent - dot(input.tangent, input.normal) * input.normal); float3 bitangent = normalize(cross(normal, tangent)); const float3x3 TBN = float3x3(tangent, bitangent, normal); float3 normalSample = tex_normalMap.Sample(textureSampler, input.texcoord).rgb; normalSample.x = 2.0f * normalSample.r - 1.0f; normalSample.y = -2.0f * normalSample.g + 1.0f; normalSample.z = normalSample.b; normal = mul(normalSample, TBN); return normal; } float3 fresnelSchlick(float cosTheta, float3 F0) { if (cosTheta > 1.0f) { cosTheta = 1.0f; } float p = pow(1.0f - cosTheta, 5.0f); return F0 + (1.0f - F0) * p; } float DistributionGGX(float3 N, float3 H, float roughness) { float a = roughness * roughness; float a2 = a * a; float NdotH = max(dot(N, H), 0.0f); float NdotH2 = NdotH * NdotH; float num = a2; float denom = (NdotH2 * (a2 - 1.0f) + 1.0f); denom = PI * denom * denom; return num / denom; } float GeometrySchlickGGX(float NdotV, float roughness) { float r = (roughness + 1.0f); float k = (r * r) / 8.0f; float num = NdotV; float denom = NdotV * (1.0f - k) + k; return num / denom; } float GeometrySmith(float3 N, float3 V, float3 L, float roughness) { float NdotV = max(dot(N, V), 0.0f); float NdotL = max(dot(N, L), 0.0f); float ggx2 = GeometrySchlickGGX(NdotV, roughness); float ggx1 = GeometrySchlickGGX(NdotL, roughness); return ggx1 * ggx2; } float3 getPBRLighting(PS_Input input) { float3 color = float3(0.0f, 0.0f, 0.0f); float3 albedoSample = pow(tex_albedoMap.Sample(textureSampler, input.texcoord).rgb, 2.2333f); float metallicSample = tex_metallicMap.Sample(textureSampler, input.texcoord).r; float roughnessSample = tex_roughnessMap.Sample(textureSampler, input.texcoord).r; float aoSample = tex_aoMap.Sample(textureSampler, input.texcoord).r; float3 N = normalize(input.normal); float3 V = normalize(cameraPosition - input.pixelPosition); float3 F0 = float3(0.04f, 0.04f, 0.04f); F0 = lerp(F0, albedoSample, metallicSample); float3 lightPositions[6] = { float3(-12.0f, 0.0f, -3.0f), float3( -6.0f, 0.0f, -3.0f), float3( 0.0f, 0.0f, -3.0f), float3( 6.0f, 0.0f, -3.0f), float3( 12.0f, 0.0f, -3.0f), float3( 18.0f, 0.0f, -3.0f), }; float3 lightColor = float3(1.0f, 1.0f, 1.0f); // reflectance equation float3 Lo = float3(0.0f, 0.0f, 0.0f); for (int i = 0; i < 6; i++) { // calculate per-light radiance float3 L = normalize(lightPositions[i] - input.pixelPosition); float3 H = normalize(V + L); float distance = length(lightPositions[i] - input.pixelPosition); float attenuation = 1.0f / (distance * distance); float3 radiance = lightColor * attenuation; // cook-torrance brdf float NDF = DistributionGGX(N, H, roughnessSample); float G = GeometrySmith(N, V, L, roughnessSample); float3 F = fresnelSchlick(max(dot(H, V), 0.0f), F0); float3 kS = F; float3 kD = float3(1.0f, 1.0f, 1.0f) - kS; kD *= 1.0f - metallicSample; float3 numerator = NDF * G * F; float denominator = 4.0f * max(dot(N, V), 0.0f) * max(dot(N, L), 0.0f) + 0.0001f; float3 specular = numerator / denominator; // add to outgoing radiance Lo float NdotL = max(dot(N, L), 0.0f); Lo += (kD * albedoSample / PI + specular) * radiance * NdotL; } float3 ambient = float3(0.01f, 0.01f, 0.01f) * albedoSample * aoSample; color = ambient + Lo; return color; } float4 main(PS_Input input) : SV_TARGET { input.normal = calculateNormals(input); float3 color = getPBRLighting(input); // HDR tone mapping and gamma correction float exposure = 10.0f; float gamma = 1.0f; float3 toneMap = float3(1.0f, 1.0f, 1.0f) - exp((-color) * exposure); float3 toneMappedColor = pow(toneMap, float3(gamma, gamma, gamma)); return float4(toneMappedColor, 1.0f); }
渲染现象
- 绑定
m_cbPostProcess时,渲染结果正常,PBR光照表现符合预期; - 注释掉
m_cbPostProcess时,渲染结果异常,光照计算出现明显错误。
所有代码均可正常编译,但始终无法定位常量缓冲区工作异常的根本原因,恳请提供帮助或建议。
内容的提问来源于stack exchange,提问作者Christian Waldmann
相关产品推荐
相关产品推荐

