zoukankan      html  css  js  c++  java
  • DX10 Shadow Volumn Sample Code的Bug修正

    在DX10 Shadow Volumn Sample中的DetectAndProcessSilhouette这个函数意思是说边缘检测,但实际啥都没做,只是沿伸了顶点生成shadow vloumn。为了证明存在的BUG,换了个简单的模型来看一下shadow volumn的样子:

    在这幅图中,很明显,反向面的顶点也做了不必要的沿伸。

    下图是修正过的效果图:

    明显shadow volumn 要更干净些了,而且结果完全正确。

    再换回到原先的模型看一下效果。

    以下两幅图是原来的代码结果:

    以下是修正的结果:

    可以看出,结果是没问题的。

    下面分析代码是如何修改,修改过的代码段如下:

    //
    // Helper to detect a silhouette edge and extrude a volume from it
    //
    void DetectAndProcessSilhouette( float3 N,         // Un-normalized triangle normal
                                     GSShadowIn v1,    // Shared vertex
                                     GSShadowIn v2,    // Shared vertex
                                     GSShadowIn vAdj,  // Adjacent triangle vertex
                                     inout TriangleStream<PSShadowIn> ShadowTriangleStream // triangle stream
                                     )
    {    
        float3 NAdj = cross( v2.pos - vAdj.pos, v1.pos - vAdj.pos );
        
        float3 AdjDir = normalize(g_vLightPos - vAdj.pos);
        if(dot(AdjDir, NAdj) < 0.0f) 
        {
            float3 outpos[4];
            float3 extrude1 = normalize(v1.pos - g_vLightPos);
            float3 extrude2 = normalize(v2.pos - g_vLightPos);
            
            outpos[0] = v1.pos + g_fExtrudeBias*extrude1;
            outpos[1] = v1.pos + g_fExtrudeAmt*extrude1;
            outpos[2] = v2.pos + g_fExtrudeBias*extrude2;
            outpos[3] = v2.pos + g_fExtrudeAmt*extrude2;
            
            // Extrude silhouette to create two new triangles
            PSShadowIn Out;
            for(int v=0; v<4; v++)
            {
                Out.pos = mul( float4(outpos[v],1), g_mViewProj );
                ShadowTriangleStream.Append( Out );
            }
            ShadowTriangleStream.RestartStrip();
        }
    }

    这段代码添加了个条件:

        float3 AdjDir = normalize(g_vLightPos - vAdj.pos);
        if(dot(AdjDir, NAdj) < 0.0f) 
        {}
    原理是这样的,如果一个三角形有任意两个顶点的法线分别和入射光线的的点乘结果符号不相同,则这个三角形一定和边缘相交。
    下面是原理图,其中
    dot(v1,n1)>0, dot(v2,n2)<0
     

    图片来源于ShaderX3,在章节1.5中也有这个方法的介绍。

    在进入DetectAndProcessSilhouette之前,先执行的是这段代码:

    //
    // GS for generating shadow volumes
    //
    //triangleadj assumes that every other vertex is an adjacent vertex
    [maxvertexcount(18)]
    void GSShadowmain( triangleadj GSShadowIn In[6], inout TriangleStream<PSShadowIn> ShadowTriangleStream )
    {
        // Compute un-normalized triangle normal
        float3 N = cross( In[2].pos - In[0].pos, In[4].pos - In[0].pos );
        
        // Compute direction from this triangle to the light
        float3 lightDir = g_vLightPos - In[0].pos;
        
        //if we're facing the light
        if( dot(N, lightDir) > 0.0f )
        {
            // For each edge of the triangle, determine if it is a silhouette edge
            DetectAndProcessSilhouette( lightDir, In[0], In[2], In[1], ShadowTriangleStream );
            DetectAndProcessSilhouette( lightDir, In[2], In[4], In[3], ShadowTriangleStream );
            DetectAndProcessSilhouette( lightDir, In[4], In[0], In[5], ShadowTriangleStream );
            
            //near cap using g_fExtrudeBias
            PSShadowIn Out;
            for(int v=0; v<6; v+=2)
            {
                float3 extrude = normalize(In[v].pos - g_vLightPos);
                
                float3 pos = In[v].pos + g_fExtrudeBias*extrude;
                Out.pos = mul( float4(pos,1), g_mViewProj );
                ShadowTriangleStream.Append( Out );
            }
            ShadowTriangleStream.RestartStrip();
            
            //far cap (reverse the order - back face) using g_fExtrudeAmt
            for(int v=4; v>=0; v-=2)
            {
                float3 extrude = normalize(In[v].pos - g_vLightPos);
            
                float3 pos = In[v].pos + g_fExtrudeAmt*extrude;
                Out.pos = mul( float4(pos,1), g_mViewProj );
                ShadowTriangleStream.Append( Out );
            }
            ShadowTriangleStream.RestartStrip();
        }
    }

    其中,由这个条件所知if( dot(N, lightDir) > 0.0f ),我们一开始取的是正向面,这也是为什么之后要取if(dot(AdjDir, NAdj) < 0.0f)的原因了。triangleadj的顶点结构如下:

    References:
    [1] ShaderX3 Chaper 1.5

    [2] http://msdn.microsoft.com/en-us/library/windows/desktop/bb509609(v=vs.85).aspx

  • 相关阅读:
    SuiteScript > Script Queue Monitor (Beta)
    Mac > MacBook Pro的移动硬盘方案
    财务报表 > 现金流表的直接法,间接法,Cash Flow from Operating Activites
    税收基础知识 > 三税(营业税, 增值税, 所得税) + 关税
    Netsuite > Hierarchy of transactions in Inventory cost calculation
    Javascript > Eclipse > problems encountered during text search
    Javascript > Eclipse > 自动代码规范化
    嵌入式Linux > 简易安装思路,步骤记录
    Netsuite > Employee Record Name维护规则
    POSTMAN as debugger for integration APPs
  • 原文地址:https://www.cnblogs.com/RobinG/p/2540196.html
Copyright © 2011-2022 走看看