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

天行健 君子當(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>
            欧美日韩99| 在线亚洲电影| 黑人巨大精品欧美一区二区小视频| 欧美激情一区二区三区高清视频| 久久精品视频导航| 久久综合国产精品| 欧美精品久久久久久久免费观看| 欧美国产日韩精品| 国产精品毛片大码女人| 国产欧美一区二区三区沐欲| 国产偷国产偷亚洲高清97cao| 激情欧美日韩| 一区二区三区欧美激情| 午夜精品久久久久久久| 久久综合久色欧美综合狠狠| 最新亚洲一区| 亚洲午夜性刺激影院| 久久精品五月婷婷| 久热综合在线亚洲精品| 欧美偷拍另类| 国产综合精品一区| 亚洲理伦在线| 国产精品欧美风情| 在线综合视频| 久久久一区二区| 亚洲高清久久| 亚洲伊人观看| 欧美黄色免费网站| 国产在线高清精品| 亚洲一区二区久久| 欧美电影在线观看完整版| 亚洲四色影视在线观看| 欧美www视频在线观看| 国产视频综合在线| 亚洲欧美成人一区二区在线电影 | 午夜性色一区二区三区免费视频| 老司机一区二区三区| 夜夜嗨av一区二区三区中文字幕| 久热精品视频在线| 国产在线国偷精品产拍免费yy| 在线一区二区三区做爰视频网站| 免费高清在线视频一区·| 亚洲一区二区三区激情| 欧美黄色影院| 亚洲欧洲精品一区二区三区波多野1战4 | 欧美α欧美αv大片| 国产午夜精品久久久久久久| 一区二区av在线| 亚洲国产毛片完整版| 久久精品在线视频| 国产日韩专区| 久久久久久久久久久久久女国产乱 | 免费观看成人| 久久av一区二区三区漫画| 国产精品成人在线观看| 一本久道久久综合狠狠爱| 欧美国产三区| 蜜桃久久精品乱码一区二区| 影视先锋久久| 女人香蕉久久**毛片精品| 久久99在线观看| 樱桃国产成人精品视频| 欧美.日韩.国产.一区.二区| 久久久亚洲午夜电影| 在线高清一区| 欧美刺激午夜性久久久久久久| 免费观看一区| 国内精品久久久久影院 日本资源| 欧美亚洲免费在线| 亚洲欧美国产精品va在线观看| 国产伦精品一区二区三区| 欧美一区2区三区4区公司二百 | 欧美一区二区私人影院日本 | 亚洲第一色在线| 欧美成人激情在线| 99视频一区| 亚洲一区在线看| 国产亚洲高清视频| 免费成人高清在线视频| 欧美成人免费大片| 亚洲无吗在线| 午夜一区二区三视频在线观看| 黄色一区二区在线观看| 亚洲国产精品高清久久久| 欧美伦理在线观看| 亚洲欧美日韩国产综合在线| 欧美亚洲自偷自偷| 亚洲国产精品热久久| 亚洲精选中文字幕| 国产精品手机视频| 美日韩精品免费| 欧美日韩在线视频首页| 欧美中文字幕在线观看| 另类亚洲自拍| 亚洲欧美国产精品专区久久| 久久久久国产免费免费| 中文有码久久| 久久精品中文字幕一区二区三区| 亚洲精品视频在线观看免费| 亚洲影院在线| aⅴ色国产欧美| 久久久av毛片精品| 亚洲一区二区日本| 久久综合九九| 欧美一级在线播放| 欧美国产精品专区| 久久亚裔精品欧美| 国产精品人人做人人爽人人添| 亚洲第一精品电影| 国产一区99| 亚洲免费人成在线视频观看| 99re6这里只有精品| 久久久亚洲国产美女国产盗摄| 欧美亚洲在线观看| 欧美日韩精品系列| 欧美国产免费| 韩国一区二区三区在线观看 | 在线观看欧美一区| 亚洲午夜日本在线观看| 99精品视频网| 欧美成人国产一区二区| 毛片一区二区| 亚洲视频日本| 国产精品久久国产三级国电话系列| 久久中文字幕导航| 国产精品久久久免费| 91久久久久久国产精品| 在线看日韩av| 久久久999精品免费| 欧美一级淫片aaaaaaa视频| 羞羞答答国产精品www一本 | 狠狠色伊人亚洲综合成人| 亚洲一区二区三区免费观看| 一本色道久久99精品综合| 欧美福利视频在线观看| 欧美激情精品久久久久久变态| 伊人久久亚洲热| 久久女同精品一区二区| 蜜臀av性久久久久蜜臀aⅴ| 一区二区三区亚洲| 久久亚洲午夜电影| 亚洲福利视频二区| 99在线精品观看| 欧美激情按摩在线| 亚洲精品视频在线| 中文日韩欧美| 国产精品色在线| 欧美一区二区三区免费在线看| 欧美在线91| 在线日韩视频| 欧美国产视频在线| 99精品黄色片免费大全| 亚洲欧美日韩精品一区二区| 国产麻豆视频精品| 久久久久综合| 亚洲国产精品一区二区第四页av| 亚洲伦理中文字幕| 美女脱光内衣内裤视频久久影院| 最新国产成人av网站网址麻豆| 亚洲视频1区| 国产一区二区三区在线免费观看 | 欧美96在线丨欧| 亚洲精品一二三| 国产精品久久久久av| 欧美主播一区二区三区美女 久久精品人| 久久丁香综合五月国产三级网站| 国内精品国产成人| 欧美精品二区三区四区免费看视频| 夜夜嗨av色一区二区不卡| 亚洲女优在线| 亚洲激情在线| 欧美视频一区二区三区…| 性伦欧美刺激片在线观看| 亚洲国产天堂久久国产91| 日韩网站在线观看| 国产伦精品一区二区三区视频黑人| 久久阴道视频| 亚洲欧美国产77777| 六月婷婷一区| 亚洲午夜日本在线观看| 激情五月***国产精品| 欧美深夜影院| 欧美不卡高清| 久久全国免费视频| 亚洲视频欧美在线| 亚洲黄色成人网| 欧美一区二区三区视频在线| 亚洲激情一区二区| 亚洲国产1区| 亚洲男人的天堂在线aⅴ视频| 亚洲韩国精品一区| 国产精品日本欧美一区二区三区| 久久中文精品| 久久久精品性| 欧美一区二区视频观看视频| 一区二区免费在线播放| 最新国产乱人伦偷精品免费网站| 欧美α欧美αv大片| 久久午夜激情| 久久久久久亚洲精品杨幂换脸|