DirectX从效果转换为HLSL vs,gs和ps

时间:2015-11-03 22:18:49

标签: directx-11

好的,我被困了。我一直试图将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);
}

但我看到的只是一个清除屏幕。什么可能是错的?

请帮忙。

哦,如果没有设置线框,渲染工作。

Normal No WireFrame

1 个答案:

答案 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);
}