青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

天行健 君子當(dāng)自強(qiáng)而不息

頂點(diǎn)著色器入門(4)

新建網(wǎng)頁 1

17.5.3輪廓勾勒

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

 

17.5.3.1 邊的表示法

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

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

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

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

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

 

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

 

 

17.5.3.2 輪廓邊測試

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

 

接下來,為了檢測一個頂點(diǎn)是否在輪廓邊上,我們必須以每個頂點(diǎn)為基礎(chǔ)了解face0 face1的法線向量。我們的邊的頂點(diǎn)數(shù)據(jù)結(jié)構(gòu)反映如下:

                  
        

struct         VS_INPUT

        

{

        

             vector position    : POSITION;

        

             vector normal      : NORMAL0;

        

             vector faceNormal1 : NORMAL1;

        

             vector faceNormal2 : NORMAL2;

        

};

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

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

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

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

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

 

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

 

 

17.5.3.3 邊的生成

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

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

 

 

輪廓邊的實(shí)現(xiàn)代碼:

 

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 輪廓邊頂點(diǎn)著色器代碼

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

    /*************************************************************************************
      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;
    }

執(zhí)行程序:
            /**************************************************************************************************
      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;
    }

運(yùn)行截圖:

下載源程序


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


只有注冊用戶登錄后才能發(fā)表評論。
網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


公告

導(dǎo)航

統(tǒng)計(jì)

常用鏈接

隨筆分類(178)

3D游戲編程相關(guān)鏈接

搜索

最新評論

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            黑人巨大精品欧美一区二区小视频| 国产一区清纯| 亚洲——在线| 国产精品综合网站| 久久久综合网站| 亚洲精品久久久一区二区三区| 欧美日韩一区在线| 欧美一区永久视频免费观看| 亚洲国产经典视频| 亚洲欧美国产精品桃花| 亚洲国产欧美日韩另类综合| 国产欧美日韩三级| 欧美1区免费| 午夜精品免费在线| 99视频精品| 亚洲国产精品黑人久久久| 亚洲永久免费观看| 香蕉久久a毛片| 在线视频欧美一区| 亚洲精品一区二区三| 亚洲一区精品视频| 91久久久亚洲精品| 欧美福利电影在线观看| 久久阴道视频| 国产精品夜夜夜| 欧美国产大片| 欧美成人在线免费视频| 久久久在线视频| 欧美日韩mv| 欧美日韩国产色综合一二三四| 欧美日韩国产在线看| 国产亚洲精品aa午夜观看| 国产精品人人爽人人做我的可爱| 国产综合色产在线精品| 一区二区高清在线观看| 另类欧美日韩国产在线| 美女露胸一区二区三区| 久久久久9999亚洲精品| 久久久精彩视频| 亚洲久久一区二区| 久久九九久精品国产免费直播| 欧美专区在线播放| 欧美三区在线视频| 国产精品综合色区在线观看| 亚洲黄色av| 久久综合五月| 欧美一区二区在线视频| 久久精品国亚洲| 国产精品自拍视频| 在线中文字幕不卡| 亚洲欧洲一区| 麻豆国产精品一区二区三区 | 永久免费毛片在线播放不卡| 国产主播一区| 欧美伊人久久| 美国十次了思思久久精品导航| 亚洲专区国产精品| 久久久久一区| 国产一区二区按摩在线观看| 欧美一区二区三区的| 亚洲影视在线播放| 国产乱码精品一区二区三区五月婷| 一区二区三区四区五区在线| 亚洲欧洲在线看| 欧美国产日本| 99re视频这里只有精品| 欧美淫片网站| 香蕉久久一区二区不卡无毒影院 | 国产精品揄拍500视频| 亚洲视频成人| 久久亚洲风情| 欧美亚洲视频| 国外精品视频| 欧美激情91| 午夜精彩视频在线观看不卡| 另类春色校园亚洲| 先锋a资源在线看亚洲| 欧美四级在线| 午夜亚洲激情| 亚洲日本中文字幕| 欧美激情亚洲视频| 国内精品久久久久影院色| 久久国产精品久久久久久久久久 | 欧美黄色aaaa| 欧美日韩高清在线观看| 亚洲欧美国产高清| 欧美在线免费| 艳女tv在线观看国产一区| 欧美成人激情在线| 欧美一区二区在线| 亚洲欧洲综合另类| 久久综合色天天久久综合图片| 老色鬼精品视频在线观看播放| 日韩一级成人av| 亚洲欧美日韩国产一区二区三区 | 麻豆久久婷婷| 欧美日韩免费| 久久婷婷国产综合精品青草| 欧美电影免费观看大全| 欧美一级片一区| 欧美福利视频网站| 久久精品国产久精国产思思| 欧美承认网站| 久久躁日日躁aaaaxxxx| 欧美日韩小视频| 欧美1区2区3区| 国产精品视频大全| 亚洲精品1区| 尤物视频一区二区| 亚洲在线不卡| 一区二区三区视频在线| 久久一区二区三区国产精品 | 亚洲视频网站在线观看| 久久九九免费| 欧美伊久线香蕉线新在线| 欧美精品v日韩精品v国产精品| 久久久午夜电影| 久久蜜桃资源一区二区老牛| 亚洲一区二区三区四区五区午夜| 99国产精品久久久久久久成人热| 国际精品欧美精品| 亚洲性色视频| 国内外成人在线| 9久草视频在线视频精品| 亚洲国产成人av在线| 亚洲日产国产精品| 亚洲国产成人在线| 欧美一区免费视频| 欧美一级成年大片在线观看| 欧美日韩精品欧美日韩精品一| 欧美chengren| 一区二区三区在线视频免费观看| 狠狠色狠狠色综合人人| 在线亚洲成人| 国产在线视频欧美一区二区三区| 一区二区三区高清在线观看| 国产亚洲欧美aaaa| 亚洲综合首页| 欧美在线免费观看| 欧美99在线视频观看| 免费在线看一区| 亚洲国产日韩欧美在线动漫| 久久夜色精品国产欧美乱| 蜜桃久久av一区| 亚洲激情婷婷| 欧美激情综合亚洲一二区| 亚洲激情第一区| 中文一区二区在线观看| 欧美日韩午夜视频在线观看| 国产精品99久久久久久www| 亚洲摸下面视频| 国产农村妇女毛片精品久久莱园子 | 欧美一区二区三区在| 久久精品二区| 精品51国产黑色丝袜高跟鞋| 久久夜色精品亚洲噜噜国产mv| 亚洲电影观看| 亚洲一区二区三区中文字幕在线 | 亚洲男人的天堂在线aⅴ视频| 午夜精品一区二区在线观看 | 99这里只有久久精品视频| 亚洲欧美三级伦理| 激情欧美一区二区三区| 女女同性精品视频| 一本久道久久综合中文字幕| 久久国产精品第一页| 亚洲国产裸拍裸体视频在线观看乱了中文| 麻豆精品视频在线观看视频| 亚洲久久一区| 久久久久久久久综合| 亚洲美女视频在线观看| 欧美一区综合| 欧美国产一区二区三区激情无套| 妖精成人www高清在线观看| 国产精品美女久久久浪潮软件| 亚洲美女性视频| 亚洲国产精品一区| 欧美日韩理论| 久久精品系列| 亚洲视频一区在线| 欧美黄色免费| 久久久久国产精品厨房| 亚洲看片网站| 好看的av在线不卡观看| 欧美视频在线观看| 久久综合一区| 欧美一区二区三区在线观看| 亚洲美女诱惑| 亚洲国产精品一区二区三区| 欧美在线视频网站| 亚洲视频欧美在线| 亚洲日本va午夜在线影院| 午夜精品久久| 亚洲国产精品va| 久久人人97超碰国产公开结果| 在线亚洲精品| 亚洲麻豆av| 亚洲国产天堂久久国产91| 国产亚洲人成a一在线v站| 国产精品久久久久9999吃药|