• Direct3D轮回:游戏场景之陆地


    继天空效果之后,这一节简单阐述一点地形生成的基本原理和方法~ 如果哪里说的不对,还望园子的前辈们多多拍砖 ^ ^

    首先,我们准备两张图:

                     

                        grass.dds                                  heightdata.raw                        

    (注:dds为directx支持的特定格式;raw可由photoshop自动生成,在无文件头标准下,其内部仅包含各点颜色值,不再含有其他冗余数据。)

    左边这张草地的图我们作基本的地表纹理只用;右边这张怪模怪样的灰度图,其实就是日常大家口中的“高度图”了,我们以其特定点的颜色数据为依据来形成相应顶点的高度,以产生地形的高低错落感~

    以下,我们来编写这个基本的地形类——CBaseTerrain:

    /*-------------------------------------

    代码清单:BaseTerrain.h
    来自:
    http://www.cnblogs.com/kenkao

    -------------------------------------
    */

    #include 
    "D3DInit.h"

    #pragma once

    class CBaseTerrain
    {
    public:
        CBaseTerrain(
    void);
        
    ~CBaseTerrain(void);
    public:
        
    bool  Create(                               // 构建地形
             int iSizeX,                            // 原始地形图宽
             int iSizeY,                            // 原始地形图高
             int iRate,                             // 放大倍率
             char* szHeightRaw,                     // 原始地形图
             char* szTexture                        // 地形纹理
             );
        
    void  Draw();                               // 绘制地形
        void  Release();                            // 资源释放
        float GetExactHeightAt(float xCoord, float zCoord);                                          // 获得地形高度
    private:
        
    bool  LoadHightData(int iSizeX, int iSizeY, char* szHeightRaw);                              // 加载地形图
        float GetHeightData(int X, int Y){return (float)m_pHeightData[ m_SizeX * Y + X ];}           // 获得地形图数据
        void  CreateTerrainVertices();                                                               // 产生顶点缓冲
        void  CreateTerrainIndices();                                                                // 产生索引缓冲
        void  GenerateNormals(VertexPosNorColorTex* vertices, int* indices);                         // 计算全部法线数据
    private:
        VertexPosNorColorTex
    *   m_pVertices;                                                         // 顶点缓冲区
        int*                    m_pIndices;                                                          // 索引缓冲区
        IDirect3DTexture9*      m_pTexture;                                                          // 地形纹理指针
        unsigned char*          m_pHeightData;                                                       // 地形数据缓冲
        int                     m_SizeX;                                                             // 地形原始长
        int                     m_SizeY;                                                             // 地形原始宽
        int                     m_Rate;                                                              // 地形放大倍率
    };
    BaseTerrain.cpp
    /*-------------------------------------

    代码清单:BaseTerrain.cpp
    来自:
    http://www.cnblogs.com/kenkao

    -------------------------------------
    */

    #include 
    "StdAfx.h"
    #include 
    "BaseTerrain.h"
    #include 
    "Ken3DGame.h"
    #include 
    "D3DCamera.h"
    #include 
    <fstream>

    extern IDirect3DDevice9 *g_pD3DDevice;
    extern CD3DCamera       *g_pD3DCamera;

    CBaseTerrain::CBaseTerrain(
    void) : m_pVertices(NULL),
                                       m_pIndices(NULL),
                                       m_pTexture(NULL),
                                       m_pHeightData(NULL),
                                       m_SizeX(
    0),
                                       m_SizeY(
    0),
                                       m_Rate(
    1)
    {
    }

    CBaseTerrain::
    ~CBaseTerrain(void)
    {
    }

    void CBaseTerrain::Release()
    {
        delete[] m_pHeightData;
        ReleaseCOM(m_pTexture);
        delete[] m_pVertices;
        delete[] m_pIndices;
    }

    bool CBaseTerrain::Create(int iSizeX, int iSizeY, int iRate, char* szHeightRaw, char* szTexture)
    {
        m_Rate 
    = iRate;
        
    // 加载高度数据
        if(!LoadHightData(iSizeX,iSizeY,szHeightRaw))
            
    return false;
        
    // 产生顶点缓冲
        CreateTerrainVertices();
        
    // 产生索引缓冲
        CreateTerrainIndices();
        
    // 计算发现数据
        GenerateNormals(m_pVertices,m_pIndices);
        
    // 产生地形纹理
        HRESULT hr = D3DXCreateTextureFromFile(g_pD3DDevice,szTexture,&m_pTexture);
        
    if(FAILED(hr))
            
    return false;
        
    return true;
    }

    void CBaseTerrain::Draw()
    {
        
    // 地形绘制
        g_pD3DDevice->SetTexture(0,m_pTexture);
        g_pD3DDevice
    ->SetFVF(VertexPosNorColorTex::FVF);
        g_pD3DDevice
    ->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, m_SizeX * m_SizeY, (m_SizeX - 1* (m_SizeY - 1* 2&m_pIndices[0],
            D3DFMT_INDEX32, 
    &m_pVertices[0], sizeof(VertexPosNorColorTex));
    }

    bool CBaseTerrain::LoadHightData(int iSizeX, int iSizeY, char* szHeightRaw)
    {
        m_SizeX 
    = iSizeX;
        m_SizeY 
    = iSizeY;
        m_pHeightData 
    = new unsigned char[iSizeX * iSizeY];
        memset(m_pHeightData, 
    0, iSizeX * iSizeY);
        
    // 从.raw地形图读取高度数据
        std::ifstream inFile(szHeightRaw, std::ios_base::binary);
        
    if(!inFile)
        {
            delete[] m_pHeightData;
            
    return false;
        }
        inFile.read((
    char*)&m_pHeightData[0], iSizeX * iSizeY);
        inFile.close();
        
    return true;
    }

    void CBaseTerrain::CreateTerrainVertices()
    {
        
    // 产生顶点缓冲
        
    // 高度图中有多少数据便产生多少顶点,或者你也可以仅仅使用其中的一部分数据,这个很好理解 :)
        m_pVertices = new VertexPosNorColorTex[m_SizeX * m_SizeY];
        
    int i = 0;
        
    for (int z = 0; z < m_SizeY; z++)
        {
            
    for (int x = 0; x < m_SizeX; x++)
            {
                
    float y = GetHeightData(x,z);
                m_pVertices[i
    ++= VertexPosNorColorTex(
                    x 
    * m_Rate, y, z * m_Rate,                // 注意x、z坐标m_Rate倍率的使用,相应的y值即为由地形图获得的高度数据
                    000
                    D3DXCOLOR_WHITE, 
                    (
    float)x / 30.0f, (float)z / 30.0f);
            }
        }
    }

    void CBaseTerrain::CreateTerrainIndices()
    {
        
    // 产生全部的索引数据
        /*
          *---*---*
          | / | / |
          *---*---*  
          | / | / |
          *---*---*

          索引缓冲包含的元素个数 = 三角形个数 x 3
          N 行顶点形成 N-1 行“三角形【对】”,每行三角形对个数为列数 M -1,则总的索引缓冲数 = ( N - 1 ) * ( M - 1 )   *   2   *   3
                                                                                              ---------   ---------      ---     ---
                                                                                              行数 - 1     列数 - 1    三角形对  每个三角形三个顶点
        
    */
        m_pIndices 
    = new int[(m_SizeX-1)*(m_SizeY-1)*6];
        
    int i = 0;
        
    for (int z=0; z<m_SizeY-1; z++)
        {
            
    for (int x=0; x<m_SizeX-1; x++)
            {
                
    // 分别为每【对】三角形的顶点索引赋值,注意一下不要被“背面剔除”就可以了 ^ ^
                m_pIndices[i++= z * m_SizeX + x;
                m_pIndices[i
    ++= (z + 1* m_SizeX + x;
                m_pIndices[i
    ++= z * m_SizeX + x + 1;

                m_pIndices[i
    ++= (z + 1* m_SizeX + x;
                m_pIndices[i
    ++= (z + 1* m_SizeX + x + 1;
                m_pIndices[i
    ++= z * m_SizeX + x + 1;
            }
        }
    }

    void CBaseTerrain::GenerateNormals(VertexPosNorColorTex* pVertices, int* pIndices)
    {
        
    // 遍历每个三角形
        for (int i = 0; i < (m_SizeX-1)*(m_SizeY-1)*2; i++
        {
            
    // 获得第一条向量
            D3DXVECTOR3 firstVec = D3DXVECTOR3(
                pVertices[pIndices[i
    *3 + 1]]._x - pVertices[pIndices[i*3]]._x,
                pVertices[pIndices[i
    *3 + 1]]._y - pVertices[pIndices[i*3]]._y,
                pVertices[pIndices[i
    *3 + 1]]._z - pVertices[pIndices[i*3]]._z
                );
            
    // 获得第二条向量
            D3DXVECTOR3 secondVec = D3DXVECTOR3(
                pVertices[pIndices[i
    *3 + 2]]._x - pVertices[pIndices[i*3]]._x,
                pVertices[pIndices[i
    *3 + 2]]._y - pVertices[pIndices[i*3]]._y,
                pVertices[pIndices[i
    *3 + 2]]._z - pVertices[pIndices[i*3]]._z
                );
            
    // 两向量叉乘的该三角形片面的发现数据
            D3DXVECTOR3    normal;
            D3DXVec3Cross(
    &normal,&firstVec,&secondVec);
            D3DXVec3Normalize(
    &normal,&normal);

            
    // 所得法线数据单位化并累计到组成此片面的三个顶点的法线数据中
            D3DXVECTOR3 nfirstVec = D3DXVECTOR3(
                pVertices[pIndices[i 
    * 3]]._nx += normal.x,
                pVertices[pIndices[i 
    * 3]]._ny += normal.y,
                pVertices[pIndices[i 
    * 3]]._nz += normal.z
                );
            D3DXVECTOR3 nsecondVec 
    = D3DXVECTOR3(
                pVertices[pIndices[i 
    * 3 + 1]]._nx += normal.x,
                pVertices[pIndices[i 
    * 3 + 1]]._ny += normal.y,
                pVertices[pIndices[i 
    * 3 + 1]]._nz += normal.z
                );
            D3DXVECTOR3 nthirdVec 
    = D3DXVECTOR3(
                pVertices[pIndices[i 
    * 3 + 2]]._nx += normal.x,
                pVertices[pIndices[i 
    * 3 + 2]]._ny += normal.y,
                pVertices[pIndices[i 
    * 3 + 2]]._nz += normal.z
                );
        } 

        
    // 遍历全部顶点
        for (int i=0;i<m_SizeX * m_SizeY;i++)
        {
            
    // 单位化全部顶点的法线数据
            D3DXVECTOR3 nVec;
            D3DXVec3Normalize(
    &nVec,
                
    &D3DXVECTOR3(pVertices[i]._nx, pVertices[i]._ny, pVertices[i]._nz)
                );
            pVertices[i]._nx 
    = nVec.x;
            pVertices[i]._ny 
    = nVec.y;
            pVertices[i]._nz 
    = nVec.z;
        }
        
    // 以上,基本原理即基于所有三角形片面计算全部顶点法线数据而后求平均 :)


    float CBaseTerrain::GetExactHeightAt(float xCoord, float zCoord) 
    {
        
    // 还原倍率
        xCoord /= m_Rate;
        zCoord 
    /= m_Rate;

        
    // 非法判定
        bool invalid = xCoord < 0
        invalid 
    |= zCoord < 0
        invalid 
    |= xCoord > m_SizeX - 1
        invalid 
    |= zCoord > m_SizeY - 1
        
    if (invalid) 
            
    return 10;  // 默认高度10

        
    // 获得该点所在三角形【对】四点对应高度
        int xLower = (int)xCoord; 
        
    int xHigher = xLower + 1
        
    float xRelative = (xCoord - xLower) / ((float)xHigher - (float)xLower); 
        
    int zLower = (int)zCoord; 
        
    int zHigher = zLower + 1
        
    float zRelative = (zCoord - zLower) / ((float)zHigher - (float)zLower); 
        
    float heightLxLz = GetHeightData(xLower, zLower); 
        
    float heightLxHz = GetHeightData(xLower, zHigher); 
        
    float heightHxLz = GetHeightData(xHigher, zLower); 
        
    float heightHxHz = GetHeightData(xHigher, zHigher); 

        
    // 判断该点位于三角形对中的哪个,并根据该三角形三点高度进行双线性插值计算最终高度
        bool pointAboveLowerTriangle = (xRelative + zRelative < 1); 
        
    float finalHeight; 
        
    if (pointAboveLowerTriangle) 
        { 
            finalHeight 
    = heightLxLz; 
            finalHeight 
    += zRelative * (heightLxHz - heightLxLz); 
            finalHeight 
    += xRelative * (heightHxLz - heightLxLz); 
        }
        
    else 
        {
            finalHeight 
    = heightHxHz; 
            finalHeight 
    += (1.0f - zRelative) * (heightHxLz - heightHxHz); 
            finalHeight 
    += (1.0f - xRelative) * (heightLxHz - heightHxHz); 
        }
        
    return finalHeight; 

    代码看起来挺长,不过其中并没有什么高深的机制 ^ ^

    LoadHightData()用于加载高度图数据。

    函数中使用的是最基本的C++读取文件二进制数据的方法,意在将raw存储的高度数据导入到内存的unsigned char型缓冲区中,已供生成顶点高度(也就是y坐标)之用~

    CreateTerrainVertices()用于产生全部的顶点数据。

    很明显,raw中有多少像素,我们这里便产生多少顶点即可。我在代码中提到的放大倍率,其实就是顶点与顶点间的间隔而已~

    CreateTerrainIndices()用于产生全部的索引数据。

    我在代码中画的那个简陋的图图不知道大家看懂没有,呵呵~ 简单而言就是索引数据永远是三角形个数的3倍,而三角形对数永远是 (行数-1)*(列数-1)。各索引值取得皆有公式,龙书中有详细的阐述,大家看不懂的话可以留言~

    GenerateNormals()用于为所有顶点生成法线数据。

    要实现地形的光照效果,顶点法线是必不可少的数据成分。单个顶点的法线其实就是其所在三角形面的法线,如果一个顶点为多个三角形共有,则累加之后单位化即可(相当于求平均)~

    GetExactHeightAt()用于求取某点的高度。

    高度图中仅存有各顶点的高度数据,而地形中并不是每个点都位于顶点的位置。如果某点位于顶点与顶点之间,则我们需要采取双线性差值的方法求得改点合适的高度,其中的原理跟高中学过的相似三角形类似,挺简单~

    有关双线性差值的相关理论,可以参看老师为大家翻译的这篇文章:http://shiba.hpe.sh.cn/jiaoyanzu/WULI/showArticle.aspx?articleId=473&classId=4

    之后是主体代码:

    D3DGame.cpp
    /*-------------------------------------

    代码清单:D3DGame.cpp
    来自:
    http://www.cnblogs.com/kenkao

    -------------------------------------
    */

    #include 
    "StdAfx.h"
    #include 
    "D3DGame.h"
    #include 
    "D3DCamera.h"
    #include 
    "D3DEffect.h"
    #include 
    "CoordCross.h"
    #include 
    "SimpleXMesh.h"
    #include 
    "Texture2D.h"
    #include 
    "D3DSprite.h"
    #include 
    "Skybox.h"
    #include 
    "SpriteBatch.h"
    #include 
    "BaseTerrain.h"
    #include 
    <stdio.h>

    //---通用全局变量

    HINSTANCE  g_hInst;
    HWND       g_hWnd;
    D3DXMATRIX g_matProjection;

    //---D3D全局变量

    IDirect3D9       
    *g_pD3D           = NULL;
    IDirect3DDevice9 
    *g_pD3DDevice     = NULL;
    CMouseInput      
    *g_pMouseInput    = NULL;
    CKeyboardInput   
    *g_pKeyboardInput = NULL;
    CD3DCamera       
    *g_pD3DCamera     = NULL;
    CCoordCross      
    *g_pCoordCross    = NULL;
    CSimpleXMesh     
    *g_pSimpleXMesh   = NULL;
    CD3DEffect       
    *g_pD3DEffect     = NULL;
    CD3DSprite       
    *g_pD3DSprite     = NULL;
    CTexture2D       
    *g_pTexture2D     = NULL;
    CSpriteBatch     
    *g_SpriteBatch    = NULL;
    CTexture2D       
    *g_pTexture2D2    = NULL;
    CD3DEffect       
    *g_pD3DEffect2    = NULL;
    CSkybox          
    *g_pSkybox        = NULL;
    CBaseTerrain     
    *g_pBaseTerrain   = NULL;


    //---HLSL全局变量句柄

    D3DXHANDLE   g_CurrentTechHandle 
    = NULL;
    D3DXHANDLE   g_matWorldViewProj  
    = NULL;  
    D3DXHANDLE   g_matWorld          
    = NULL;
    D3DXHANDLE   g_vecEye            
    = NULL;
    D3DXHANDLE   g_vecLightDir       
    = NULL;
    D3DXHANDLE   g_vDiffuseColor     
    = NULL;
    D3DXHANDLE   g_vSpecularColor    
    = NULL;
    D3DXHANDLE   g_vAmbient          
    = NULL;

    D3DXHANDLE   g_CurrentTechHandle2 
    = NULL;
    D3DXHANDLE   g_Scale              
    = NULL;

    // HLSL特效参数设置
    void GetParameters();
    void SetParameters();


    void Initialize(HINSTANCE hInst, HWND hWnd)
    {
        g_hInst 
    = hInst;
        g_hWnd  
    = hWnd;
        InitD3D(
    &g_pD3D, &g_pD3DDevice, g_matProjection, hWnd);
        g_pMouseInput 
    = new CMouseInput;
        g_pMouseInput
    ->Initialize(hInst,hWnd);
        g_pKeyboardInput 
    = new CKeyboardInput;
        g_pKeyboardInput
    ->Initialize(hInst,hWnd);
        g_pD3DCamera 
    = new CD3DCamera;
    }

    void LoadContent()
    {
        g_pCoordCross 
    = new CCoordCross;

        g_pD3DCamera
    ->SetCameraPos(D3DXVECTOR3(0.0f,0.0f,0.0f));

        g_pSimpleXMesh 
    = new CSimpleXMesh;
        g_pSimpleXMesh
    ->LoadXMesh("teapot.X");

        g_pD3DEffect 
    = new CD3DEffect;
        g_pD3DEffect2 
    = new CD3DEffect;
        g_pD3DEffect
    ->LoadEffect("Light.fx");
        g_pD3DEffect2
    ->LoadEffect("Thunder.fx");

        GetParameters();

        g_pD3DSprite 
    = new CD3DSprite(g_pD3DDevice);
        g_SpriteBatch 
    = new CSpriteBatch(g_pD3DDevice);

        g_pTexture2D 
    = new CTexture2D;
        g_pTexture2D
    ->LoadTexture("img.jpg");
        g_pTexture2D2 
    = new CTexture2D;
        g_pTexture2D2
    ->LoadTexture("img2.jpg");

        g_pSkybox 
    = new CSkybox;
        g_pSkybox
    ->Create("Skybox_0.JPG","Skybox_1.JPG","Skybox_2.JPG"
            ,
    "Skybox_3.JPG","Skybox_4.JPG","Skybox_5.JPG");

        g_pBaseTerrain 
    = new CBaseTerrain;
        g_pBaseTerrain
    ->Create(128,128,10,"HeightData_128x128.raw","Grass.dds");
    }

    void Update()
    {
        g_pMouseInput
    ->GetState();
        g_pKeyboardInput
    ->GetState();
        
    // 更新摄影机高度
        D3DXVECTOR3 CameraPos = g_pD3DCamera->GetCameraPos();
        
    float roleHeight = 25.0f;
        
    float Ty = g_pBaseTerrain->GetExactHeightAt(CameraPos.x,CameraPos.z) + roleHeight;
        g_pD3DCamera
    ->SetCameraPos(D3DXVECTOR3(
            CameraPos.x,
            Ty,
            CameraPos.z));
        g_pD3DCamera
    ->Update();
        
    // 更新g_pD3DEffect中的视点位置
        D3DXVECTOR4 vecEye = D3DXVECTOR4(CameraPos.x,Ty,CameraPos.z,0.0f);
        g_pD3DEffect 
    -> GetEffect() -> SetVector(g_vecEye,&vecEye);
    }

    void Draw()
    {
        
    // 参数设定
        SetParameters();
        g_pD3DDevice
    ->SetTransform(D3DTS_VIEW,&g_pD3DCamera->GetViewMatrix());

        g_pD3DDevice
    ->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(100,149,237,255), 1.0f0);
        
    if(SUCCEEDED(g_pD3DDevice->BeginScene())) 
        {
            
    // 天空处在无限远处,因此必须最先绘制天空盒
            g_pSkybox->Draw();

            UINT numPasses;
            
    // 开启特效
            g_pD3DEffect->BeginEffect(numPasses);
            
    for(UINT i=0;i<numPasses;i++)
            {
                
    // 开启路径
                g_pD3DEffect->GetEffect()->BeginPass(i);
                
    // 绘制地形
                g_pBaseTerrain->Draw();
                
    // 路径结束
                g_pD3DEffect->GetEffect()->EndPass();
            }
            
    // 特效结束
            g_pD3DEffect->EndEffect();
        
            g_pD3DDevice
    ->EndScene();
        }
        g_pD3DDevice
    ->Present(NULL, NULL, NULL, NULL);
    }

    void UnloadContent()
    {
        ReleaseCOM(g_pBaseTerrain);
        ReleaseCOM(g_pSkybox);
        ReleaseCOM(g_pTexture2D2);
        ReleaseCOM(g_pTexture2D);
        ReleaseCOM(g_SpriteBatch);
        ReleaseCOM(g_pD3DSprite);
        ReleaseCOM(g_pD3DEffect2);
        ReleaseCOM(g_pD3DEffect);
        ReleaseCOM(g_pSimpleXMesh);
        ReleaseCOM(g_pCoordCross);
    }

    void Dispose()
    {
        ReleaseCOM(g_pD3DCamera);
        ReleaseCOM(g_pKeyboardInput);
        ReleaseCOM(g_pMouseInput);
        ReleaseCOM(g_pD3DDevice);
        ReleaseCOM(g_pD3D);
    }

    void GetParameters()
    {
        
    // 获得HLSL中各个全局变量句柄
        g_CurrentTechHandle = g_pD3DEffect -> GetEffect() -> GetTechniqueByName("SpecularLight");
        g_matWorldViewProj  
    = g_pD3DEffect -> GetEffect() -> GetParameterByName(0"matWorldViewProj");
        g_matWorld          
    = g_pD3DEffect -> GetEffect() -> GetParameterByName(0"matWorld");
        g_vecEye            
    = g_pD3DEffect -> GetEffect() -> GetParameterByName(0"vecEye");
        g_vecLightDir       
    = g_pD3DEffect -> GetEffect() -> GetParameterByName(0"vecLightDir");
        g_vDiffuseColor     
    = g_pD3DEffect -> GetEffect() -> GetParameterByName(0"vDiffuseColor");
        g_vSpecularColor    
    = g_pD3DEffect -> GetEffect() -> GetParameterByName(0"vSpecularColor");  
        g_vAmbient          = g_pD3DEffect -> GetEffect() -> GetParameterByName(0"vAmbient");

        g_CurrentTechHandle2 
    = g_pD3DEffect2 -> GetEffect() -> GetTechniqueByName("Technique1");
        g_Scale              
    = g_pD3DEffect2 -> GetEffect() -> GetParameterByName(0"Scale");
    }

    void SetParameters()
    {
        
    // 设定当前技术
        g_pD3DEffect -> GetEffect() -> SetTechnique(g_CurrentTechHandle);
        
    // 设定HLSL中的各个参数
        D3DXMATRIX worldMatrix;
        D3DXMatrixTranslation(
    &worldMatrix,0.0f,0.0f,0.0f);
        g_pD3DEffect 
    -> GetEffect() -> SetMatrix(g_matWorldViewProj,&(worldMatrix*g_pD3DCamera->GetViewMatrix()*g_matProjection));
        g_pD3DEffect 
    -> GetEffect() -> SetMatrix(g_matWorld,&worldMatrix);

        D3DXVECTOR4 vLightDirection 
    = D3DXVECTOR4(-5.0f-1.0f2.0f1.0f);
        g_pD3DEffect 
    -> GetEffect() -> SetVector(g_vecLightDir,&vLightDirection);
        D3DXVECTOR4 vColorDiffuse 
    = D3DXVECTOR4(0.0f0.0f0.0f1.0f);
        D3DXVECTOR4 vColorSpecular 
    = D3DXVECTOR4(1.0f1.0f1.0f1.0f);
        D3DXVECTOR4 vColorAmbient 
    = D3DXVECTOR4(0.0f0.0f0.0f1.0f);
        g_pD3DEffect 
    -> GetEffect() -> SetVector(g_vDiffuseColor,&vColorDiffuse);
        // g_pD3DEffect 
    -> GetEffect() -> SetVector(g_vSpecularColor,&vColorSpecular); //暂时不加入镜面高光 ^ ^
        g_pD3DEffect 
    -> GetEffect() -> SetVector(g_vAmbient,&vColorAmbient);

        g_pD3DEffect2 
    -> GetEffect() -> SetTechnique(g_CurrentTechHandle2);
        g_pD3DEffect2 
    -> GetEffect() -> SetFloat(g_Scale,0.8f);
    }

    我们使用light.fx为新生成的地形添加光照效果。这里我在其原有基础上作了改动。

    首先添加一个纹理采样器:

    sampler2D TextureSampler = sampler_state
    {
     magfilter=LINEAR;
     minfilter=LINEAR;
     mipfilter=LINEAR;
    };

    然后让像素着色器最终的输出结果累计地形纹理原有的颜色:

    return vAmbient + vDiffuseColor * Diff + vSpecularColor * Specular + tex2D(TextureSampler, vtop.uv);   //---最后的颜色 = 环境光 + 漫射光 + 镜面高光 + 本来颜色(纹理)

    我们来看看效果:

              

    山地跟沟壑~ 都是高度图的功劳,呵呵~

    主体代码中我注释掉了镜面光的颜色赋值,因为按理说草地是不会反射阳光的。我们不妨换一张冷峻的岩石地表,然后再打开镜面光,试试看效果如何~

    怎么样,很耀眼吧?呵呵 ^ ^

    到此,以上阐述了地形生成方法中的诸多基本原理,但如果要用于生成大型的地形或者无边界地形的话,仅仅靠这样简单的方法是不堪重负的。不过大家无需担心,地形生成的基本原理大致都是相同的,只不过复杂的大地形在此基础上加入了一些特殊的算法和机制,以动态数据的方法减轻了CPU和显卡的负担。如果后续有机会深度研究这些,我会尽我所能,为大家一一道来~

    谢谢~ ^ ^

  • 相关阅读:
    文字上下滚动效果
    导航点击变化
    腾讯新闻导航栏
    Docker 数据卷和DockerFile
    Docker 容器
    Docker 镜像
    Docker的初始和架构
    面向对象的设计模式与原则
    安装CentOS 7MInimal版本
    ASP.NET WebApi 启动默认的HelpPage文档注释
  • 原文地址:https://www.cnblogs.com/kenkao/p/2114767.html
Copyright © 2020-2023  润新知