好的,我被困了。我一直试图将Nvidia WireFrame效果转换为vs,gs和ps HLSL文件,并在我的DirectX11.1应用程序中使用。转换看起来很简单。这是Nvida Sample
这是我对vs:
的看法cbuffer WorldViewProjectionType : register(b0)
{
matrix World;
matrix View;
matrix Projection;
};
struct VS_INPUT
{
float3 Pos : POSITION;
float3 Norm : NORMAL;
float2 Tex : TEXCOORD0;
};
struct GS_INPUT
{
float4 Pos : POSITION;
float4 PosV : TEXCOORD0;
};
GS_INPUT main(VS_INPUT input)
{
GS_INPUT output;
matrix WorldView = mul(World, View);
matrix WorldViewProjection = mul(WorldView, Projection);
output.Pos = mul(float4(input.Pos, 1), WorldViewProjection);
output.PosV = mul(float4(input.Pos, 1), WorldView);
return output;
}
gs:
float4 LightVector = float4(0, 0, 1, 0);
float4 FillColor = float4(0.0f, 0.125f, 0.3f, 1.0f);
struct GS_INPUT
{
float4 Pos : POSITION;
float4 PosV : TEXCOORD0;
};
struct PS_INPUT_WIRE
{
float4 Pos : SV_POSITION;
float4 Col : TEXCOORD0;
noperspective float3 Heights : TEXCOORD1;
};
// Compute the triangle face normal from 3 points
float3 faceNormal(in float3 posA, in float3 posB, in float3 posC)
{
return normalize(cross(normalize(posB - posA), normalize(posC - posA)));
}
// Compute the final color of a face depending on its facing of the light
float4 shadeFace(in float4 verA, in float4 verB, in float4 verC)
{
// Compute the triangle face normal in view frame
float3 normal = faceNormal(verA, verB, verC);
// Then the color of the face.
float shade = 0.5*abs(dot(normal, LightVector));
return float4(FillColor.xyz*shade, 1);
}
[maxvertexcount(3)]
void main(triangle GS_INPUT input[3], inout TriangleStream<PS_INPUT_WIRE> outStream)
{
PS_INPUT_WIRE output;
// Shade and colour face.
output.Col = shadeFace(input[0].PosV, input[1].PosV, input[2].PosV);
// Emit the 3 vertices
// The Height attribute is based on the constant
output.Pos = input[0].Pos;
output.Heights = float3(1, 0, 0);
outStream.Append(output);
output.Pos = input[1].Pos;
output.Heights = float3(0, 1, 0);
outStream.Append(output);
output.Pos = input[2].Pos;
output.Heights = float3(0, 0, 1);
outStream.Append(output);
outStream.RestartStrip();
}
和ps:
float4 WireColor = float4(1, 1, 1, 1);
float LineWidth = 0.15;
float PatternPeriod = 0.15;
float4 PatternColor = float4(1, 1, 0.5, 1);
struct PS_INPUT_WIRE
{
float4 Pos : SV_POSITION;
float4 Col : TEXCOORD0;
noperspective float3 Heights : TEXCOORD1;
};
float det(float2 a, float2 b)
{
return (a.x*b.y - a.y*b.x);
}
float4 main(PS_INPUT_WIRE input) : SV_Target
{
// Compute the shortest square distance between the fragment and the edges.
float3 eDists;
float3 vDists;
uint3 order = uint3(0, 1, 2);
float dist;
float3 ddxHeights = ddx(input.Heights);
float3 ddyHeights = ddy(input.Heights);
float3 invddHeights = 1.0 / sqrt(ddxHeights*ddxHeights + ddyHeights*ddyHeights);
eDists = input.Heights * invddHeights;
vDists = (1.0 - input.Heights) * invddHeights;
if (eDists[1] < eDists[0])
{
order.xy = order.yx;
}
if (eDists[2] < eDists[order.y])
{
order.yz = order.zy;
}
if (eDists[2] < eDists[order.x])
{
order.xy = order.yx;
}
// Now compute the coordinate of the fragment along each edges
float2 hDirs[3];
hDirs[0] = float2(ddxHeights[0], ddyHeights[0]) * invddHeights[0];
hDirs[1] = float2(ddxHeights[1], ddyHeights[1]) * invddHeights[1];
hDirs[2] = float2(ddxHeights[2], ddyHeights[2]) * invddHeights[2];
float2 hTans[3];
hTans[0] = float2(-hDirs[0].y, hDirs[0].x);
hTans[1] = float2(-hDirs[1].y, hDirs[1].x);
hTans[2] = float2(-hDirs[2].y, hDirs[2].x);
float2 ePoints[3];
ePoints[0] = input.Pos.xy - hDirs[0] * eDists[0];
ePoints[1] = input.Pos.xy - hDirs[1] * eDists[1];
ePoints[2] = input.Pos.xy - hDirs[2] * eDists[2];
float2 eCoords[3];
eCoords[0].x = det(hTans[1], ePoints[0] - ePoints[1]) / det(hTans[0], hTans[1]);
eCoords[0].y = det(hTans[2], ePoints[0] - ePoints[2]) / det(hTans[0], hTans[2]);
eCoords[1].x = det(hTans[2], ePoints[1] - ePoints[2]) / det(hTans[1], hTans[2]);
eCoords[1].y = det(hTans[0], ePoints[1] - ePoints[0]) / det(hTans[1], hTans[0]);
eCoords[2].x = det(hTans[0], ePoints[2] - ePoints[0]) / det(hTans[2], hTans[0]);
eCoords[2].y = det(hTans[1], ePoints[2] - ePoints[1]) / det(hTans[2], hTans[1]);
float2 edgeCoord;
// Current coordinate along closest edge in pixels
edgeCoord.x = abs(eCoords[order.x].x);
// Length of the closest edge in pixels
edgeCoord.y = abs(eCoords[order.x].y - eCoords[order.x].x);
dist = eDists[order.x];
// Standard wire color
float4 color = WireColor;
float realLineWidth = 0.5*LineWidth;
// if on the diagonal edge apply pattern
if (2 == order.x)
{
if (dist > LineWidth + 1) discard;
float patternPos = (abs(edgeCoord.x - 0.5 * edgeCoord.y)) % (PatternPeriod * 2 * LineWidth) - PatternPeriod * LineWidth;
dist = sqrt(patternPos*patternPos + dist*dist);
color = PatternColor;
realLineWidth = LineWidth;
// Filling the corners near the vertices with the WireColor
if (eDists[order.y] < (0.5*LineWidth + 1))
{
dist = eDists[order.y];
color = WireColor;
realLineWidth = 0.5*LineWidth;
}
}
// Cull fragments too far from the edge.
else if (dist > 0.5*LineWidth + 1) discard;
// Map the computed distance to the [0,2] range on the border of the line.
dist = clamp((dist - (realLineWidth - 1)), 0, 2);
// Alpha is computed from the function exp2(-2(x)^2).
dist *= dist;
float alpha = exp2(-2 * dist);
color.a *= alpha;
return color;
}
几乎是该实现的直接副本。在vs2013中,我将HLSL编译器设置为5.0版,并输出包含字节码等的Header文件。
在我的应用程序中,我定义了一个新类{SolidWireFrame.cpp},它使用头文件中的字节码创建vs,gs和ps。
这些构建vs,gs和ps着色器,没有任何我知道的异常/错误。
该效果还设置了DepthStencilState,RasterizerState和BlendStates。所以我在SolidWireFrame类中创建了方法来复制这些状态。
bool SolidWireFrame::InitializeBlendState(ID3D11Device* device)
{
D3D11_BLEND_DESC blendStateDescription;
// Clear the blend state description.
ZeroMemory(&blendStateDescription, sizeof(D3D11_BLEND_DESC));
blendStateDescription.RenderTarget[0].BlendEnable = TRUE;
blendStateDescription.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
blendStateDescription.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
blendStateDescription.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_SRC_ALPHA;
blendStateDescription.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_DEST_ALPHA;
blendStateDescription.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
blendStateDescription.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
// Create the blend state using the description.
HRESULT result = device->CreateBlendState(&blendStateDescription, &m_pBlendingState);
if (FAILED(result))
{
return false;
}
return true;
}
bool SolidWireFrame::InitializeDepthStencilState(ID3D11Device* device)
{
D3D11_DEPTH_STENCIL_DESC depthStencilDesc;
// Initialize the description of the stencil state.
ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
// Set up the description of the stencil state.
depthStencilDesc.DepthEnable = TRUE;
depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
depthStencilDesc.StencilEnable = FALSE;
depthStencilDesc.StencilReadMask = 255;
depthStencilDesc.StencilWriteMask = 255;
depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// Create the depth stencil state.
HRESULT result = device->CreateDepthStencilState(&depthStencilDesc, &m_pdepthLessEqualStencilState);
if (FAILED(result))
{
return false;
}
return true;
}
bool SolidWireFrame::InitializeRaterizerState(ID3D11Device* device)
{
D3D11_RASTERIZER_DESC rasterizerDescription;
ZeroMemory(&rasterizerDescription, sizeof(D3D11_RASTERIZER_DESC));
rasterizerDescription.FillMode = D3D11_FILL_SOLID;
rasterizerDescription.CullMode = D3D11_CULL_NONE;
rasterizerDescription.DepthBias = FALSE;
rasterizerDescription.MultisampleEnable = TRUE;
rasterizerDescription.FrontCounterClockwise = FALSE;
rasterizerDescription.DepthBiasClamp = 0.000000000;
rasterizerDescription.SlopeScaledDepthBias = 0.000000000;
rasterizerDescription.DepthClipEnable = TRUE;
rasterizerDescription.ScissorEnable = FALSE;
rasterizerDescription.AntialiasedLineEnable = FALSE;
HRESULT hr = device->CreateRasterizerState(&rasterizerDescription, &m_pfillRasterizerState);
if (FAILED(hr))
return false;
return true;
}
现在在我的渲染循环中,我只需调用solidWireFrame-&gt; ApplySolidWirePatter(devicecontext),它可以有效地设置InputLayout,三个状态以及vs,gs和ps。
void SolidWireFrame::ApplySolidWirePattern(ID3D11DeviceContext* deviceContext)
{
deviceContext->IASetInputLayout(m_vertexLayout);
SetDepthStencilState(deviceContext, m_pdepthLessEqualStencilState);
SetRasterizerState(deviceContext, m_pfillRasterizerState);
SetBlendState(deviceContext, m_pBlendingState);
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->GSSetShader(m_geometrySolidWireShader, NULL, 0);
deviceContext->PSSetShader(m_pixelSolidWireShader, NULL, 0);
}
但我看到的只是一个清除屏幕。什么可能是错的?
请帮忙。
哦,如果没有设置线框,渲染工作。
答案 0 :(得分:0)
似乎我的代码中有一个小错误。当我用纹理渲染时,我正在使用不同的vs,ps。因此,当我转向线框vs,gs和ps时,我无法更新vs Constantbuffers,其中包含世界,视图,投影。
所以现在我有线框,虽然我猜我的绕组是不正确的,因为它隐藏了不正确的边缘。但我会解决这个问题。
void SolidWireFrame::ApplySolidWirePattern(ID3D11DeviceContext* deviceContext, ID3D11Buffer* worldViewProjectionType)
{
deviceContext->IASetInputLayout(m_vertexLayout);
deviceContext->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
SetDepthStencilState(deviceContext, m_pdepthLessEqualStencilState);
SetRasterizerState(deviceContext, m_pfillRasterizerState);
SetBlendState(deviceContext, m_pBlendingState);
deviceContext->VSSetShader(m_vertexShader, NULL, 0);
deviceContext->VSSetConstantBuffers(0, 1, &worldViewProjectionType);
deviceContext->GSSetShader(m_geometrySolidWireShader, NULL, 0);
deviceContext->PSSetShader(m_pixelSolidWireShader, NULL, 0);
}