• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天行健 君子當自強而不息

            頂點著色器入門(4)

            新建網頁 1

            17.5.3輪廓勾勒

            要完成卡通效果,我們還需要勾勒(outline)輪廓邊(silhouette edge),這比卡通著色稍微復雜一點。

             

            17.5.3.1 邊的表示法

            我們將一個網格的一條邊表示為一個四元組(構建自2個三角形)——參見圖17.5

            我們選擇四元組有兩個原因:我們可以通過調整四元組的尺寸容易地改變邊的厚度,并且我們可以渲染退化的四元組來隱藏某些邊,也即非輪廓邊。在Direct3D中,我們從兩個三角形來構建一個四元組。退化四元組(degenerate quad)是從兩個退化三角形構建而來的四元組。退化三角形(degenerate triangle)是一個面積為零的三角形,或者換句話說,是一個三點位于一線上的三角形。如果我們傳入一個退化三角形到渲染管線,則該三角形顯示為空。這是很有用的,因為如果我們希望隱藏特定三角形,我們可以簡單的退化它而不需要實際的從三角形列表(頂點緩沖)移除它。回想一下,我們只需要顯示輪廓邊——而不是網格的每一條邊。

            當我們首先創建一條邊的時候,我們指定其四個頂點,并使其退化,這意味著邊將會被隱藏(渲染時不顯示)。

            注意圖17.6中的兩個頂點v0v1,我們設置其頂點法線向量為零向量。然后當我們將邊的頂點送入頂點著色器的時候,頂點著色器將會檢測頂點是否位于輪廓邊上;如果是,則頂點著色器將沿頂點法線的方向偏移頂點位置的標量。觀察法線向量為零的頂點,它不會被偏移。

            因此,我們最終以一個非退化四元組(non-degenerate quad)來表示輪廓邊,如圖17.7所示。

             

            備注:如果我們沒有設置頂點v0v1的頂點法線為零向量,那么那些頂點就同樣會被偏移。但是如果偏移描述輪廓邊的所有四個頂點,那么我們僅是平移了該退化四元組。通過保持頂點v0v1固定并僅僅偏移頂點v2v3,我們重新生成了四元組。

             

             

            17.5.3.2 輪廓邊測試

            若兩個三角面face0face1在視圖方向上與兩個不同方向的面共享同一條邊,則該邊為輪廓邊。也就是說,如果一個面是前面(front facing)而另一個面是后面(back facing),那么這條邊就是一條輪廓邊。圖17.8給出了一個輪廓邊和一個非輪廓邊的例子。

             

            接下來,為了檢測一個頂點是否在輪廓邊上,我們必須以每個頂點為基礎了解face0 face1的法線向量。我們的邊的頂點數據結構反映如下:

                              
                    

            struct         VS_INPUT

                    

            {

                    

                         vector position    : POSITION;

                    

                         vector normal      : NORMAL0;

                    

                         vector faceNormal1 : NORMAL1;

                    

                         vector faceNormal2 : NORMAL2;

                    

            };

            前兩個分量很直接,但讓我們看看兩個額外的法線向量,它們是faceNormal1faceNormal2。這些向量描述了兩個三角面的面法線,共享邊的頂點位于這兩個面的共享邊上,這兩個面是face0face1

            實際檢測頂點是否在共享邊上的數學原理如下。假設我們在視圖空間中,令v為一原點指向檢測頂點的向量——圖17.8,令n0face0的面法線且n1face0的面法線,若下面的不等式為真,則頂點位于輪廓邊上:

            1)(v·n0)(v·n1)<0

            若兩點積符號相異,則不等式為真,使得不等式左邊為負。回想一下點積的性質:兩個點積的符號相異,這意味著一個三角面是前面而另一個是后面。

            現在,考慮一條邊只有一個三角形共享它的情況,如圖17.9,其法線將會被存儲在faceNormal1中。

             

            我們定義這種邊總為輪廓邊。要確保頂點著色器將這種邊作為輪廓邊處理,我們要讓faceNormal2 = -faceNormal1。因此,反向的面法線和不等式(1)為真,表示該邊為一輪廓邊。

             

             

            17.5.3.3 邊的生成

            生成網格的邊是微不足道的;我們簡單的遍歷網格的每個三角面并為三角面上每條邊計算一個四元組(退化的,如圖17.6所示)。注意:每個三角形有三條邊。

            對于每條邊上的頂點,我們同樣需要知道共享邊的兩個三角面。一個面是邊所在的三角形。例如,如果要計算第1個面的一條邊,那么第1個面共享該邊。共享該邊的另一個面可以使用網格的鄰接信息找到。

             

             

            輪廓邊的實現代碼:

             

            OutlineEdges.h:

                 /***************************************************************************************
                  Generates the outline geometry of a mesh and renders it.  
                  Note that we assume mesh vertex formats as described in sMeshVertex.
                 ***************************************************************************************/

                
                #ifndef OUTLINE_EDGES_H
                
            #define OUTLINE_EDGES_H
                
                #include "d3dUtility.h"
                
                
            struct sEdgeVertex
                {
                    D3DXVECTOR3 position;
                    D3DXVECTOR3 normal;
                    D3DXVECTOR3 face_normal_1;
                    D3DXVECTOR3 face_normal_2;
                };
                
                
            struct sMeshVertex
                {
                    D3DXVECTOR3 position;
                    D3DXVECTOR3 normal;
                };
                
                
            const DWORD MESH_VERTEX_FVF = D3DFVF_XYZ | D3DFVF_NORMAL;
                
                
                ////////////////////////////////////////////////////////////////////////////////////
                

                
            class cOutlineEdges
                {
                
            private:
                    IDirect3DDevice9*                m_device;
                    IDirect3DVertexBuffer9*            m_vertex_buffer;
                    IDirect3DIndexBuffer9*            m_index_buffer;
                    IDirect3DVertexDeclaration9*    m_vertex_decl;
                
                    UINT    m_num_verts;
                    UINT    m_num_faces;
                
                
            public:
                    cOutlineEdges(IDirect3DDevice9* device, ID3DXMesh* mesh, ID3DXBuffer* adj_buffer);
                    ~cOutlineEdges();
                
                    
            void render();
                
                
            private:
                    
            bool create_vertex_declaration();
                
                    
            void get_face_normal(ID3DXMesh* mesh, DWORD face_index, D3DXVECTOR3* face_normal);
                
                    
            void get_adj_faces_normal(
                        ID3DXMesh*        mesh,
                        ID3DXBuffer*    adj_buffer,
                        DWORD            current_face_index,
                        D3DXVECTOR3*    current_face_normal,
                        D3DXVECTOR3        adj_face_normals[3]);
                
                    
            void generate_edge_vertices(ID3DXMesh* mesh, ID3DXBuffer* adj_buffer);
                    
            void generate_edge_indices(ID3DXMesh* mesh);
                };
                
                
            #endif

            OutlineEdges.cpp:
                 /***************************************************************************************
                  Generates the outline geometry of a mesh and renders it.  
                  Note that we assume mesh vertex formats as described in sMeshVertex.
                 ***************************************************************************************/

                
                #include "OutlineEdges.h"
                
                cOutlineEdges::cOutlineEdges(IDirect3DDevice9* device, ID3DXMesh* mesh, ID3DXBuffer* adj_buffer)
                {
                    m_device = device;
                
                    m_vertex_buffer = NULL;
                    m_index_buffer  = NULL;
                    m_vertex_decl    = NULL;
                
                    m_num_verts = 0;
                    m_num_faces = 0;
                
                    generate_edge_vertices(mesh, adj_buffer);
                    generate_edge_indices(mesh);
                
                    create_vertex_declaration();
                }    
                
                cOutlineEdges::~cOutlineEdges()
                {
                    safe_release<IDirect3DVertexBuffer9*>(m_vertex_buffer);
                    safe_release<IDirect3DIndexBuffer9*>(m_index_buffer);
                    safe_release<IDirect3DVertexDeclaration9*>(m_vertex_decl);
                }
                
                
                //////////////////////////////////////////////////////////////////////////////////////////////////
                

                
            bool cOutlineEdges::create_vertex_declaration()
                {
                    
            // typedef struct _D3DVERTEXELEMENT9
                    // {
                    //     WORD    Stream;     // Stream index
                    //     WORD    Offset;     // Offset in the stream in bytes
                    //     BYTE    Type;       // Data type
                    //     BYTE    Method;     // Processing method
                    //     BYTE    Usage;      // Semantics
                    //     BYTE    UsageIndex; // Semantic index
                    // } D3DVERTEXELEMENT9, *LPD3DVERTEXELEMENT9;
                

                    D3DVERTEXELEMENT9 decl[] =
                    {
                        {0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
                        {0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
                        {0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   1},
                        {0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   2},
                
                        D3DDECL_END()
                    };
                
                    HRESULT hr = m_device->CreateVertexDeclaration(decl, &m_vertex_decl);
                
                    
            if(FAILED(hr))
                    {
                        MessageBox(NULL, "CreateVertexDeclaration() - FAILED", "ERROR", MB_OK);
                        
            return false;
                    }
                
                    
            return true;
                }
                
                
                //////////////////////////////////////////////////////////////////////////////////////////////////
                

                
            void cOutlineEdges::get_face_normal(ID3DXMesh* mesh, DWORD face_index, D3DXVECTOR3* face_normal)
                {
                    sMeshVertex* vertices;
                    mesh->LockVertexBuffer(0, (
            void**)&vertices);
                
                    WORD* indices;
                    mesh->LockIndexBuffer(0, (
            void**)&indices);
                
                    
            // get the triangle's indices
                
                    WORD vert_index_0 = indices[face_index * 3];
                    WORD vert_index_1 = indices[face_index * 3 + 1];
                    WORD vert_index_2 = indices[face_index * 3 + 2];
                
                    
            // now extract the triangles vertices position
                
                    D3DXVECTOR3 v0 = vertices[vert_index_0].position;
                    D3DXVECTOR3 v1 = vertices[vert_index_1].position;
                    D3DXVECTOR3 v2 = vertices[vert_index_2].position;
                
                    
            // compute face normal
                

                    D3DXVECTOR3 edge0 = v1 - v0;
                    D3DXVECTOR3 edge1 = v2 - v0;
                
                    D3DXVec3Cross(face_normal, &edge0, &edge1);
                    D3DXVec3Normalize(face_normal, face_normal);
                
                    mesh->UnlockVertexBuffer();
                    mesh->UnlockIndexBuffer();
                }
                
                
            void cOutlineEdges::get_adj_faces_normal(ID3DXMesh*        mesh, 
                                                         ID3DXBuffer*    adj_buffer, 
                                                         DWORD            current_face_index, 
                                                         D3DXVECTOR3*    current_face_normal, 
                                                         D3DXVECTOR3    adj_face_normals[3])
                {
                    sMeshVertex* vertices;
                    mesh->LockVertexBuffer(0, (
            void**)&vertices);
                
                    WORD* indices;
                    mesh->LockIndexBuffer(0, (
            void**)&indices);
                
                    get_face_normal(mesh, current_face_index, current_face_normal);
                
                    DWORD* adj = (DWORD*) adj_buffer->GetBufferPointer();
                
                    
            // get adjacent face indices
                
                    DWORD adj_face_index_0 = adj[current_face_index * 3];
                    DWORD adj_face_index_1 = adj[current_face_index * 3 + 1];
                    DWORD adj_face_index_2 = adj[current_face_index * 3 + 2];
                
                    
            // Get adjacent face normals, if there is no adjacent face, then set the adjacent face normal 
                    // to the opposite of the "current_face_normal".  Recall we do this because edges that don't 
                    // have an adjacent triangle are automatically considered outline edges. And in order to 
                    // make that happen, we need the current face normal and adjacent face normal to point in the 
                    // opposite direction.  Also, recall that an entry in the adjacency buffer equal to -1 denotes 
                    // that the edge doesn't have an adjacent triangle.
                

                    D3DXVECTOR3 adj_face_normal_0, adj_face_normal_1, adj_face_normal_2;
                
                    
            if(adj_face_index_0 != USHRT_MAX)    // is there an adjacent triangle?
                
                {
                        WORD adj_vert_index_0 = indices[adj_face_index_0 * 3];
                        WORD adj_vert_index_1 = indices[adj_face_index_0 * 3 + 1];
                        WORD adj_vert_index_2 = indices[adj_face_index_0 * 3 + 2];
                
                        D3DXVECTOR3 v0 = vertices[adj_vert_index_0].position;
                        D3DXVECTOR3 v1 = vertices[adj_vert_index_1].position;
                        D3DXVECTOR3 v2 = vertices[adj_vert_index_2].position;
                
                        D3DXVECTOR3 edge0 = v1 - v0;
                        D3DXVECTOR3 edge1 = v2 - v0;
                
                        D3DXVec3Cross(&adj_face_normal_0, &edge0, &edge1);
                        D3DXVec3Normalize(&adj_face_normal_0, &adj_face_normal_0);
                    }
                    
            else
                    {
                        adj_face_normal_0 = -(*current_face_normal);
                    }
                
                    
            if( adj_face_index_1 != USHRT_MAX ) // is there an adjacent triangle?
                
                {
                        WORD adj_vert_index_0 = indices[adj_face_index_1 * 3];
                        WORD adj_vert_index_1 = indices[adj_face_index_1 * 3 + 1];
                        WORD adj_vert_index_2 = indices[adj_face_index_1 * 3 + 2];
                
                        D3DXVECTOR3 v0 = vertices[adj_vert_index_0].position;
                        D3DXVECTOR3 v1 = vertices[adj_vert_index_1].position;
                        D3DXVECTOR3 v2 = vertices[adj_vert_index_2].position;
                
                        D3DXVECTOR3 edge0 = v1 - v0;
                        D3DXVECTOR3 edge1 = v2 - v0;
                
                        D3DXVec3Cross(&adj_face_normal_1, &edge0, &edge1);
                        D3DXVec3Normalize(&adj_face_normal_1, &adj_face_normal_1);
                    }
                    
            else
                    {
                        adj_face_normal_1 = -(*current_face_normal);
                    }
                    
                    
            if( adj_face_index_2 != USHRT_MAX ) // is there an adjacent triangle?
                
                {
                        WORD adj_vert_index_0 = indices[adj_face_index_2 * 3];
                        WORD adj_vert_index_1 = indices[adj_face_index_2 * 3 + 1];
                        WORD adj_vert_index_2 = indices[adj_face_index_2 * 3 + 2];
                
                        D3DXVECTOR3 v0 = vertices[adj_vert_index_0].position;
                        D3DXVECTOR3 v1 = vertices[adj_vert_index_1].position;
                        D3DXVECTOR3 v2 = vertices[adj_vert_index_2].position;
                
                        D3DXVECTOR3 edge0 = v1 - v0;
                        D3DXVECTOR3 edge1 = v2 - v0;
                
                        D3DXVec3Cross(&adj_face_normal_2, &edge0, &edge1);
                        D3DXVec3Normalize(&adj_face_normal_2, &adj_face_normal_2);
                    }
                    
            else
                    {
                        adj_face_normal_2 = -(*current_face_normal);
                    }
                
                    
            // save adjacent face normals
                
                    adj_face_normals[0] = adj_face_normal_0;
                    adj_face_normals[1] = adj_face_normal_1;
                    adj_face_normals[2] = adj_face_normal_2;
                
                    mesh->UnlockVertexBuffer();
                    mesh->UnlockIndexBuffer();
                }
                
                
                //////////////////////////////////////////////////////////////////////////////////////////////////
                

                
            void cOutlineEdges::generate_edge_vertices(ID3DXMesh* mesh, ID3DXBuffer* adj_buffer)
                {
                    
            // 3 edges per face and 4 vertices per edge
                
                    m_num_verts = mesh->GetNumFaces() * 3 * 4;
                
                    m_device->CreateVertexBuffer(
                        m_num_verts * 
            sizeof(sEdgeVertex),
                        D3DUSAGE_WRITEONLY,
                        0,    
            // using vertex declaration
                
                    D3DPOOL_MANAGED,
                        &m_vertex_buffer,
                        NULL);
                
                    sMeshVertex* vertices;
                    mesh->LockVertexBuffer(0, (
            void**) &vertices);
                
                    WORD* indices;
                    mesh->LockIndexBuffer(0, (
            void**) &indices);
                
                    sEdgeVertex* edge_vertices;
                    m_vertex_buffer->Lock(0, 0, (
            void**) &edge_vertices, 0);
                
                    
            for(unsigned int i = 0; i < mesh->GetNumFaces(); i++)
                    {
                        D3DXVECTOR3 current_face_normal;
                        D3DXVECTOR3 adj_face_normals[3];
                
                        get_adj_faces_normal(mesh, adj_buffer, i, &current_face_normal, adj_face_normals);
                
                        
            // get the indices for this face
                
                        WORD vert_index_0 = indices[i * 3];
                        WORD vert_index_1 = indices[i * 3 + 1];
                        WORD vert_index_2 = indices[i * 3 + 2];
                
                        
            // get the vertices for this face
                
                        sMeshVertex v0 = vertices[vert_index_0];
                        sMeshVertex v1 = vertices[vert_index_1];
                        sMeshVertex v2 = vertices[vert_index_2];
                
                        
            // A        B
                        // *--------*
                        // |  edge  |
                        // *--------*
                        // C        D
                        //
                        // Note, C and D are duplicates of A and B respectively, such that the quad is degenerate.  
                        // The vertex shader will un-degenerate the quad if it is a outline edge.
                
                        // compute edge0 v0->v1, note adjacent face normal is adj_face_normals[0]
                

                        sEdgeVertex A0, B0, C0, D0;
                
                        A0.position         = v0.position;
                        A0.normal         = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
                        A0.face_normal_1 = current_face_normal;
                        A0.face_normal_2 = adj_face_normals[0];
                
                        B0.position         = v1.position;
                        B0.normal         = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
                        B0.face_normal_1 = current_face_normal;
                        B0.face_normal_2 = adj_face_normals[0];
                
                        C0 = A0;
                        C0.normal = v0.normal;
                
                        D0 = B0;
                        D0.normal = v1.normal;
                
                        *edge_vertices = A0; edge_vertices++;
                        *edge_vertices = B0; edge_vertices++;
                        *edge_vertices = C0; edge_vertices++;
                        *edge_vertices = D0; edge_vertices++;
                
                        
            // compute edge0 v1->v2, note adjacent face normal is adj_face_normals[1]
                

                        sEdgeVertex A1, B1, C1, D1;
                
                        A1.position      = v1.position;
                        A1.normal         = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
                        A1.face_normal_1 = current_face_normal;
                        A1.face_normal_2 = adj_face_normals[1];
                
                        B1.position      = v2.position;
                        B1.normal        = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
                        B1.face_normal_1 = current_face_normal;
                        B1.face_normal_2 = adj_face_normals[1];
                
                        C1 = A1;
                        C1.normal = v1.normal;
                        
                        D1 = B1;
                        D1.normal = v2.normal;
                
                        *edge_vertices = A1; ++edge_vertices;
                        *edge_vertices = B1; ++edge_vertices;
                        *edge_vertices = C1; ++edge_vertices;
                        *edge_vertices = D1; ++edge_vertices;    
                
                        
            // compute edge0 v0->v2, note adjacent face normal is adj_face_normals[2]
                

                        sEdgeVertex A2, B2, C2, D2;
                
                        A2.position      = v0.position;
                        A2.normal        = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
                        A2.face_normal_1 = current_face_normal;
                        A2.face_normal_2 = adj_face_normals[2];
                
                        B2.position      = v2.position;
                        B2.normal        = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
                        B2.face_normal_1 = current_face_normal;
                        B2.face_normal_2 = adj_face_normals[2];
                
                        C2 = A2;
                        C2.normal = v0.normal;
                        
                        D2 = B2;
                        D2.normal = v2.normal;
                
                        *edge_vertices = A2; ++edge_vertices;
                        *edge_vertices = B2; ++edge_vertices;
                        *edge_vertices = C2; ++edge_vertices;
                        *edge_vertices = D2; ++edge_vertices;    
                    }
                
                    m_vertex_buffer->Unlock();
                
                    mesh->UnlockVertexBuffer();
                    mesh->UnlockIndexBuffer();
                }
                
                
            void cOutlineEdges::generate_edge_indices(ID3DXMesh* mesh)
                {
                    DWORD num_edges = mesh->GetNumFaces() * 3;
                    m_num_faces        = num_edges * 2;
                
                    m_device->CreateIndexBuffer(
                        num_edges * 6 * 
            sizeof(WORD),    // 2 triangles per edge
                
                        D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_index_buffer, NULL);
                
                    WORD* indices;
                    m_index_buffer->Lock(0, 0, (
            void**)&indices, 0);
                
                    
            // 0        1
                    // *--------*
                    // |  edge  |
                    // *--------*
                    // 2        3
                

                    
            for(WORD i = 0; i < num_edges; i++)
                    {
                        
            // Six indices to define the triangles of the edge, so every edge we skip six entries in the index buffer.  
                        // Four vertices to define the edge, so every edge we skip four entries in the vertex buffer.
                
                        indices[i * 6]     = i * 4 + 0;
                        indices[i * 6 + 1] = i * 4 + 1;
                        indices[i * 6 + 2] = i * 4 + 2;
                        indices[i * 6 + 3] = i * 4 + 1;
                        indices[i * 6 + 4] = i * 4 + 3;
                        indices[i * 6 + 5] = i * 4 + 2;
                    }
                
                    m_index_buffer->Unlock();
                }
                
                
                //////////////////////////////////////////////////////////////////////////////////////////////////
                

                
            void cOutlineEdges::render()
                {
                    m_device->SetVertexDeclaration(m_vertex_decl);
                    m_device->SetStreamSource(0, m_vertex_buffer, 0, 
            sizeof(sEdgeVertex));
                    m_device->SetIndices(m_index_buffer);
                
                    m_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, m_num_verts, 0, m_num_faces);
                }

            17.5.4 輪廓邊頂點著色器代碼

            我們現在呈現渲染輪廓邊的頂點著色器代碼。這個著色器的主要任務就是確定傳入的頂點是否在輪廓邊上。如果是,頂點著色器就以一定的值,沿頂點法線的方向偏移頂點。

                /*************************************************************************************
                  Vertex shader that draws the outline edges of a mesh.
                 *************************************************************************************/

                
                matrix g_world_view;
                matrix g_proj;
                
                
            static vector BLACK = {0.0f, 0.0f, 0.0f, 0.0f};
                
                
            struct sVertexInput
                {
                    vector position            : POSITION;
                    vector normal            : NORMAL0;
                    vector face_normal_1    : NORMAL1;
                    vector face_normal_2    : NORMAL2;
                };
                
                
            struct sVertexOutput
                {
                    vector position : POSITION;
                    vector diffuse  : COLOR;
                };
                
                
                ////////////////////////////////////////////////////////////////////////////////////////////////////
                

                sVertexOutput main(sVertexInput input)
                {
                    sVertexOutput output = (sVertexOutput) 0;
                
                    
            // transform position to view space
                
                    input.position = mul(input.position, g_world_view);
                
                    
            // Compute a vector in the direction of the vertex from the eye. 
                    // Recall the eye is at the origin in view space - eye is just camera position.
                
                    vector eye_to_vertex = input.position;
                
                    
            // Transform normals to view space.  
                    // !! Important, set w components to zero since we're transforming vectors.
                    // Assume there are no scalings in the world matrix as well.
                

                    input.normal.w          = 0.0f;
                    input.face_normal_1.w = 0.0f;
                    input.face_normal_2.w = 0.0f;
                
                    input.normal        = mul(input.normal,           g_world_view);
                    input.face_normal_1 = mul(input.face_normal_1, g_world_view);
                    input.face_normal_2 = mul(input.face_normal_2, g_world_view);
                
                    
            // compute the cosine of the angles between the eye_to_vertex vector and the face normals
                
                float dot0 = dot(eye_to_vertex, input.face_normal_1);
                    
            float dot1 = dot(eye_to_vertex, input.face_normal_2);
                
                    
            // If cosines are different signs (positive/negative) than we are on a outline edge.  
                    // Do the signs differ?
                
                if((dot0 * dot1) < 0.0f)
                    {
                        
            // Yes, then this vertex is on a outline edge, offset the vertex position by some scalar 
                        // in the direction of the vertex normal, which scalar value designate outline's tickness.
                
                        input.position += 0.1f * input.normal;
                    }
                
                    
            // transform to homogeneous clip space
                
                    output.position = mul(input.position, g_proj);
                
                    output.diffuse = BLACK;    
            // set outline color
                

                    
            return output;
                }

            執行程序:
                        /**************************************************************************************************
                  Demonstrates cartoon rendering with outline edges using a vertex shader.  
                  Note that you will have to switch to the REF device to view this sample if your 
                  graphics card does not support vertex shaders.  
                  Or you can use software vertex processing: D3DCREATE_SOFTWARE_VERTEXPROCESSING.  
                 **************************************************************************************************/

                
                #include "d3dUtility.h"
                #include "OutlineEdges.h"
                
                #pragma warning(disable : 4100)
                
                
            #define MESH_TEAPOT        0
                
            #define MESH_SPHERE        1
                
            #define MESH_TORUS        2
                
            #define MESH_CYLINDER    3
                
            #define NUM_MESH        4
                
                
            const int WIDTH  = 640;
                
            const int HEIGHT = 480;
                
                IDirect3DDevice9*        g_device;
                IDirect3DVertexShader9* g_vertex_shader;
                ID3DXConstantTable*        g_constant_table;
                IDirect3DTexture9*        g_shade_texture;
                
                ID3DXMesh*                g_meshes[NUM_MESH];
                D3DXMATRIX                g_world_matrices[NUM_MESH];
                D3DXVECTOR4                g_mesh_colors[NUM_MESH];
                
                D3DXMATRIX                g_proj_matrix;
                
                D3DXHANDLE                g_world_view_handle;
                D3DXHANDLE                g_world_view_proj_handle;
                D3DXHANDLE                g_color_handle;
                D3DXHANDLE                g_dir_to_light_handle;
                
                cOutlineEdges*            g_mesh_outlines[NUM_MESH];
                IDirect3DVertexShader9*    g_outline_shader;
                ID3DXConstantTable*        g_outline_constant_table;
                
                D3DXHANDLE                g_outline_world_view_handle;
                D3DXHANDLE                g_outline_proj_handle;
                
                
                ////////////////////////////////////////////////////////////////////////////////////////////////////
                

                
            bool setup()
                {    
                    
            // create geometry and compute corresponding world matrix and color for each mesh
                

                    ID3DXBuffer* adj_buffer[NUM_MESH];
                
                    D3DXCreateTeapot(g_device, &g_meshes[MESH_TEAPOT], &adj_buffer[MESH_TEAPOT]);
                    D3DXCreateSphere(g_device, 1.0f, 20, 20, &g_meshes[MESH_SPHERE], &adj_buffer[MESH_SPHERE]);
                    D3DXCreateTorus(g_device, 0.5f, 1.0f, 20, 20, &g_meshes[MESH_TORUS], &adj_buffer[MESH_TORUS]);
                    D3DXCreateCylinder(g_device, 0.5f, 0.5f, 2.0f, 20, 20, &g_meshes[MESH_CYLINDER], &adj_buffer[MESH_CYLINDER]);
                
                    D3DXMatrixTranslation(&g_world_matrices[MESH_TEAPOT],   0.0f,   2.0f, 0.0f);
                    D3DXMatrixTranslation(&g_world_matrices[MESH_SPHERE],   0.0f,  -2.0f, 0.0f);
                    D3DXMatrixTranslation(&g_world_matrices[MESH_TORUS],    -3.0f,  0.0f, 0.0f);
                    D3DXMatrixTranslation(&g_world_matrices[MESH_CYLINDER],  3.0f,  0.0f, 0.0f);
                
                    g_mesh_colors[MESH_TEAPOT]   = D3DXVECTOR4(1.0f, 0.0f, 0.0f, 1.0f);
                    g_mesh_colors[MESH_SPHERE]   = D3DXVECTOR4(0.0f, 1.0f, 0.0f, 1.0f);
                    g_mesh_colors[MESH_TORUS]    = D3DXVECTOR4(0.0f, 0.0f, 1.0f, 1.0f);
                    g_mesh_colors[MESH_CYLINDER] = D3DXVECTOR4(1.0f, 1.0f, 0.0f, 1.0f);
                
                    
            // allocate mesh outlines
                
                    g_mesh_outlines[MESH_TEAPOT]   = new cOutlineEdges(g_device, g_meshes[MESH_TEAPOT],   adj_buffer[MESH_TEAPOT]);
                    g_mesh_outlines[MESH_SPHERE]   = 
            new cOutlineEdges(g_device, g_meshes[MESH_SPHERE],   adj_buffer[MESH_SPHERE]);
                    g_mesh_outlines[MESH_TORUS]       = 
            new cOutlineEdges(g_device, g_meshes[MESH_TORUS],    adj_buffer[MESH_TORUS]);
                    g_mesh_outlines[MESH_CYLINDER] = 
            new cOutlineEdges(g_device, g_meshes[MESH_CYLINDER], adj_buffer[MESH_CYLINDER]);
                
                    safe_release<ID3DXBuffer*>(adj_buffer[MESH_TEAPOT]);
                    safe_release<ID3DXBuffer*>(adj_buffer[MESH_SPHERE]);
                    safe_release<ID3DXBuffer*>(adj_buffer[MESH_TORUS]);
                    safe_release<ID3DXBuffer*>(adj_buffer[MESH_CYLINDER]);
                
                    
            // compile cartoon shader
                

                    ID3DXBuffer*    shader_buffer;
                    ID3DXBuffer*    error_buffer;
                
                    HRESULT hr = D3DXCompileShaderFromFile("ToonShader.cxx", NULL, NULL, "main", "vs_1_1",
                                                           D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
                                                           &shader_buffer, &error_buffer, &g_constant_table);
                
                    
            // output any error messages
                
                if(error_buffer)
                    {
                        MessageBox(NULL, (
            char*)error_buffer->GetBufferPointer(), "ERROR", MB_OK);
                        safe_release<ID3DXBuffer*>(error_buffer);
                    }
                
                    
            if(FAILED(hr))
                    {
                        MessageBox(NULL, "D3DXCreateEffectFromFile() - FAILED", "ERROR", MB_OK);
                        
            return false;
                    }
                
                    hr = g_device->CreateVertexShader((DWORD*) shader_buffer->GetBufferPointer(), &g_vertex_shader);
                
                    
            if(FAILED(hr))
                    {
                        MessageBox(NULL, "CreateVertexShader - FAILED", "ERROR", MB_OK);
                        
            return false;
                    }
                
                    safe_release<ID3DXBuffer*>(shader_buffer);
                
                    
            // compile outline shader
                

                    ID3DXBuffer* outline_shader_buffer;
                    ID3DXBuffer* outline_error_buffer;
                
                    hr = D3DXCompileShaderFromFile("OutlineShader.cxx", NULL, NULL, "main", "vs_1_1",
                                D3DXSHADER_DEBUG, &outline_shader_buffer, &outline_error_buffer, &g_outline_constant_table);
                
                    
            // output any error messages
                
                if(outline_error_buffer)
                    {
                        MessageBox(NULL, (
            char*) outline_error_buffer->GetBufferPointer(), "ERROR", MB_OK);
                        safe_release<ID3DXBuffer*>(outline_error_buffer);
                    }
                
                    
            if(FAILED(hr))
                    {
                        MessageBox(NULL, "D3DXCompileShaderFromFile() - FAILED", "ERROR", MB_OK);
                        
            return false;
                    }
                
                    hr = g_device->CreateVertexShader((DWORD*) outline_shader_buffer->GetBufferPointer(), &g_outline_shader);
                
                    
            if(FAILED(hr))
                    {
                        MessageBox(NULL, "CreateVertexShader - FAILED", "ERROR", MB_OK);
                        
            return false;
                    }
                
                    safe_release<ID3DXBuffer*>(outline_shader_buffer);
                
                    
            // load textures
                
                    D3DXCreateTextureFromFile(g_device, "toonshade.bmp", &g_shade_texture);
                
                    g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
                    g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
                    g_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);        
            // disable mipmap
                
                    // get handles
                
                    g_world_view_handle            = g_constant_table->GetConstantByName(NULL, "g_world_view");
                    g_world_view_proj_handle    = g_constant_table->GetConstantByName(NULL, "g_world_view_proj");
                    g_color_handle                = g_constant_table->GetConstantByName(NULL, "g_color");        
                    g_dir_to_light_handle        = g_constant_table->GetConstantByName(NULL, "g_dir_to_light");
                
                    g_outline_world_view_handle = g_outline_constant_table->GetConstantByName(NULL, "g_world_view");
                    g_outline_proj_handle        = g_outline_constant_table->GetConstantByName(NULL, "g_proj");
                
                    
            // set shader constants
                

                    D3DXVECTOR4 dir_to_light(-0.57f, 0.57f, -0.57f, 0.0f);
                    g_constant_table->SetVector(g_device, g_dir_to_light_handle, &dir_to_light);
                
                    g_constant_table->SetDefaults(g_device);
                    g_outline_constant_table->SetDefaults(g_device);
                
                    
            // set the projection matrix
                
                    D3DXMatrixPerspectiveFovLH(&g_proj_matrix, D3DX_PI/4.0f, (float)WIDTH/HEIGHT, 1.0f, 1000.0f);
                    
                    
            //g_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
                
                
                    
            return true;
                }
                
                
                ///////////////////////////////////////////////////////////////////////////////////////////////////////
                

                
            void cleanup()
                {    
                    
            for(int i = 0; i < NUM_MESH; i++)
                    {
                        safe_release<ID3DXMesh*>(g_meshes[i]);
                        safe_delete<cOutlineEdges*>(g_mesh_outlines[i]);
                    }
                
                    safe_release<IDirect3DTexture9*>(g_shade_texture);
                    safe_release<IDirect3DVertexShader9*>(g_vertex_shader);
                    safe_release<ID3DXConstantTable*>(g_constant_table);    
                    safe_release<IDirect3DVertexShader9*>(g_outline_shader);
                    safe_release<ID3DXConstantTable*>(g_outline_constant_table);
                }
                
                
                ///////////////////////////////////////////////////////////////////////////////////////////////////////
                

                
            bool display(float time_delta)
                {    
                    
            static float angle  = (3.0f * D3DX_PI) / 2.0f;
                    
            static float height = 5.0f;
                
                    
            if(GetAsyncKeyState(VK_LEFT) & 0x8000f)
                        angle -= 0.5f * time_delta;
                
                    
            if(GetAsyncKeyState(VK_RIGHT) & 0x8000f)
                        angle += 0.5f * time_delta;
                
                    
            if(GetAsyncKeyState(VK_UP) & 0x8000f)
                        height += 5.0f * time_delta;
                
                    
            if(GetAsyncKeyState(VK_DOWN) & 0x8000f)
                        height -= 5.0f * time_delta;
                
                    D3DXVECTOR3 position(cosf(angle) * 7.0f, height, sinf(angle) * 7.0f);
                    D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
                    D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
                
                    D3DXMATRIX view_matrix;
                    D3DXMatrixLookAtLH(&view_matrix, &position, &target, &up);    
                    
                    
            // render now
                

                    g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xFFFFFFFF, 1.0f, 0);
                
                    g_device->BeginScene();
                
                    
            // draw cartoon
                

                    g_device->SetVertexShader(g_vertex_shader);
                    g_device->SetTexture(0, g_shade_texture);
                
                    D3DXMATRIX world_view, world_view_proj;
                
                    
            for(int i = 0; i < NUM_MESH; i++)
                    {
                        world_view        = g_world_matrices[i] * view_matrix;
                        world_view_proj = g_world_matrices[i] * view_matrix * g_proj_matrix;
                
                        g_constant_table->SetMatrix(g_device, g_world_view_handle,        &world_view);
                        g_constant_table->SetMatrix(g_device, g_world_view_proj_handle, &world_view_proj);
                
                        g_constant_table->SetVector(g_device, g_color_handle,            &g_mesh_colors[i]);
                
                        g_meshes[i]->DrawSubset(0);
                    }    
                
                    
            // draw outlines
                

                    g_device->SetVertexShader(g_outline_shader);
                    g_device->SetTexture(0, NULL);
                
                    
            // !! Important, do not cull back faces.
                
                    g_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
                
                    
            for(int i = 0; i < NUM_MESH; i++)
                    {
                        world_view = g_world_matrices[i] * view_matrix;
                
                        g_outline_constant_table->SetMatrix(g_device, g_outline_world_view_handle, &world_view);
                        g_outline_constant_table->SetMatrix(g_device, g_outline_proj_handle,       &g_proj_matrix);
                
                        g_mesh_outlines[i]->render();
                    }
                
                    
            // restore to cull back faces with counterclockwise vertices
                
                    g_device->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
                    
                    g_device->EndScene();
                
                    g_device->Present(NULL, NULL, NULL, NULL);
                
                    
            return true;
                }
                
                
                ///////////////////////////////////////////////////////////////////////////////////////////////////////
                

                LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM word_param, LPARAM long_param)
                {
                    
            switch(msg)
                    {
                    
            case WM_DESTROY:
                        PostQuitMessage(0);
                        
            break;
                
                    
            case WM_KEYDOWN:
                        
            if(word_param == VK_ESCAPE)
                            DestroyWindow(hwnd);
                
                        
            break;
                    }
                
                    
            return DefWindowProc(hwnd, msg, word_param, long_param);
                }
                
                
                ///////////////////////////////////////////////////////////////////////////////////////////////////////
                

                
            int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show)
                {
                    
            if(! init_d3d(inst, WIDTH, HEIGHT, true, D3DDEVTYPE_HAL, &g_device))
                    {
                        MessageBox(NULL, "init_d3d() - failed.", 0, MB_OK);
                        
            return 0;
                    }
                
                    
            if(! setup())
                    {
                        MessageBox(NULL, "Steup() - failed.", 0, MB_OK);
                        
            return 0;
                    }
                
                    enter_msg_loop(display);
                
                    cleanup();
                    g_device->Release();
                
                    
            return 0;
                }

            運行截圖:

            下載源程序


            posted on 2008-04-09 14:42 lovedday 閱讀(2422) 評論(0)  編輯 收藏 引用

            公告

            導航

            統計

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關鏈接

            搜索

            最新評論

            99久久这里只精品国产免费| 久久久久久久久无码精品亚洲日韩 | 亚洲午夜久久久久久久久久| 久久综合中文字幕| 波多野结衣中文字幕久久| 亚洲中文字幕无码一久久区| 国内精品久久国产| 久久精品国产亚洲AV香蕉| 狠狠色丁香婷婷久久综合五月| 久久免费大片| 伊人色综合九久久天天蜜桃| 国产精品久久久久久久人人看 | 久久w5ww成w人免费| 久久久女人与动物群交毛片| 久久水蜜桃亚洲av无码精品麻豆| 无码AV波多野结衣久久| 狠狠色婷婷久久一区二区三区| 精品久久久久久久无码 | 伊人热人久久中文字幕| 国产精品久久久99| 亚洲精品WWW久久久久久| 久久人人添人人爽添人人片牛牛| 精品久久亚洲中文无码| 久久久久99精品成人片试看 | 国产精品久久久福利| 国产精品99久久久久久董美香| 亚洲人成无码www久久久| 亚洲精品乱码久久久久久自慰 | 狠狠色伊人久久精品综合网| 久久久这里有精品中文字幕| 久久久久亚洲AV无码专区首JN | 国产成人精品综合久久久| 久久天天躁狠狠躁夜夜avapp| 26uuu久久五月天| 99久久国产亚洲综合精品| 国产成人精品久久免费动漫| 久久有码中文字幕| www.久久精品| 伊人久久大香线蕉AV色婷婷色| 香港aa三级久久三级| 狠狠色噜噜色狠狠狠综合久久|