zoukankan      html  css  js  c++  java
  • 3DShader之移位贴图(Displacement Mapping)

    我们知道法线贴图是只是改了物体的法线属性,用来计算光照,但是并没有改变物体本身的网格.但是移位贴图就不一样了,它会移动物体的顶点.我用移位贴图做了个海洋,好了,上了图再讲:





    注意看海的边缘的顶点,已经实现了移动


    最后,添加了一个笛卡尔转球形坐标的函数将其转为球形坐标,到时候我会提供球形版本的源码,如果需要平面的只需要在shader将调用这个函数的语句注释掉即可.




    好了,不啰嗦了,困得不行了!


    类似于法线贴图,移位贴图的每一个纹素中存储了一个向量,这个向量代表了对应顶点的位移。


    注意,此处的纹素并不是与像素一一对应,而是与顶点一一对应,因此,纹理的纹素个数与网格的顶点个数是相等的。为什么必须相等,源代码里写

    了原因的

     

    在VS阶段,需要获取每个顶点对应的纹素中的位移向量. 注意只有3.0版本以上的vs才支持在VS阶段获取纹理数据,之前的版本只有ps才能获取纹理数据


    好了,讲下这个项目的大概原理

    这个项目,有两张移位纹理和两张法线纹理,目的就是为了进一步随机化.所以跟这里的实质内容关系不大,我会把它当成一张来讲

    移位纹理可以存储需要移位的向量,而我们这里只存储了一个r通道,g,b通道都为1,所以我们的移位纹理储存的是[0,255]的随机值,注意移位纹理是128*128的,其实就是一个128*128的高度图.用的就是这个高度图去波动128*128网格的顶点的y值,当然采样高度图的坐标是移动的.

    移动了顶点的y坐标,前面我们在法线贴图也提到过可以通过高度图生成法线纹理,这里一样,通过变化后的Y坐标也可以生成这个点的法向量.

    这个法向量就用来算光照.当然这样算出来的光照很粗略,如下图所示:


    所以,法线贴图又来了,这个是为了增加细节效果的,跟移位没有点关系,具体的方法是:将摄像机,灯光全转换到顶点的切线空间,然后通过纹理坐标对法线纹理进行采样,然后再以这三个变量来算光照.注意项目中的采样法线纹理的坐标经过缩放的,它重复了8次.

    加上细节后:




    好了,贴源代码

     

    /*------------------------------------------------------------
    	DisplacementMapping.fx -- achieve displacement mapping
    			(c) Seamanj.2013/9/1
    ------------------------------------------------------------*/
    #include "DXUT.h"
    #include "resource.h"
    
    // phase1 : add camera
    // phase2 : add sky box
    // phase3 : add grid mesh
    // phase4 : add FX
    #define phase1 1
    #define phase2 1
    #define phase3 1
    #define phase4 1
    #if phase1
    #include "DXUTcamera.h"
    CFirstPersonCamera g_Camera;
    #endif
    #if phase2
    // Vertex Buffer
    LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL;
    // Index Buffer
    LPDIRECT3DINDEXBUFFER9 g_pIB = NULL;
    PDIRECT3DCUBETEXTURE9	g_pCubeTex = 0;
    #endif
    #if phase3
    #include <vector>
    int g_iVerticesNumPerRow = 128;
    int g_iVerticesNumPerCol = 128;
    //注意:这里的尺寸一定要给位移图片的大小一样,我原本也想过用129个顶点(第0到第128个),然后将第0和第128
    //顶点的坐标和纹理都设为一样,纹理坐标u坐标设为0,这样是不行的,虽然看上去纹理重合,但并不是每一个顶点
    //对应一个点,必然会有一个纹理坐标重合,这样就破坏了纹理的连续性,就相当于把纹理从中拉开了一个距离
    //出来一样,并且这个距离平行U方向的颜色都一样.所以一旦位移纹理偏移就不会连续了,同理如果只有127个点
    //那么纹理也会失去连续性
    float g_fDeltaX = 0.25f;
    float g_fDeltaZ = 0.25f;
    
    const float EPSILON  = 0.001f;
    IDirect3DVertexDeclaration9* g_pVertexDecl;
    ID3DXMesh* g_pMesh;
    // The two normal maps to scroll.
    IDirect3DTexture9* g_pNormalTex1;
    IDirect3DTexture9* g_pNormalTex2;
    
    // The two displacement maps to scroll.
    IDirect3DTexture9* g_pDisplacementTex1;
    IDirect3DTexture9* g_pDisplacementTex2;
    
    //===============================================================
    // Colors and Materials
    
    const D3DXCOLOR WHITE(1.0f, 1.0f, 1.0f, 1.0f);
    const D3DXCOLOR BLACK(0.0f, 0.0f, 0.0f, 1.0f);
    const D3DXCOLOR RED(1.0f, 0.0f, 0.0f, 1.0f);
    const D3DXCOLOR GREEN(0.0f, 1.0f, 0.0f, 1.0f);
    const D3DXCOLOR BLUE(0.0f, 0.0f, 1.0f, 1.0f);
    
    
    struct DirectionalLight
    {
    	D3DXCOLOR ambient;
    	D3DXCOLOR diffuse;
    	D3DXCOLOR specular;
    	D3DXVECTOR3 directionInWorld;
    };
    
    
    struct Material
    {
    	Material()
    		:ambient(WHITE), diffuse(WHITE), specular(WHITE), specularPower(8.0f){}
    	Material(const D3DXCOLOR& a, const D3DXCOLOR& d, 
    		 const D3DXCOLOR& s, float power)
    		:ambient(a), diffuse(d), specular(s), specularPower(power){}
    
    	D3DXCOLOR ambient;
    	D3DXCOLOR diffuse;
    	D3DXCOLOR specular;
    	float specularPower;
    };
    
    
    DirectionalLight g_structDirectionalLight;
    
    
    Material g_structMaterial;
    
    
    D3DXVECTOR2 g_scaleHeights = D3DXVECTOR2(0.7f, 1.1f);
    float g_fTexScale = 8.0f;
    
    D3DXVECTOR2 g_normalMapVelocity1 = D3DXVECTOR2(0.05f, 0.07f);
    D3DXVECTOR2 g_normalMapVelocity2 = D3DXVECTOR2(-0.01f, 0.13f);
    D3DXVECTOR2 g_displacementMapVelocity1 = D3DXVECTOR2(0.012f, 0.015f);
    D3DXVECTOR2 g_displacementMapVelocity2 = D3DXVECTOR2(0.014f, 0.05f);
    
    // Offset of normal maps for scrolling (vary as a function of time)
    D3DXVECTOR2 g_normalMapOffset1(0.0f, 0.0f);
    D3DXVECTOR2 g_normalMapOffset2(0.0f, 0.0f);
    
    // Offset of displacement maps for scrolling (vary as a function of time)
    D3DXVECTOR2 g_displacementMapOffset1(0.0f, 0.0f);
    D3DXVECTOR2 g_displacementMapOffset2(0.0f, 0.0f);
    
    
    #endif
    
    #if phase4
    #include "SDKmisc.h"//加载文件时会用到
    ID3DXEffect*		g_pEffect = NULL;       // D3DX effect interface
    D3DXHANDLE			g_hTech = 0;
    D3DXHANDLE			g_hWorld = 0;
    D3DXHANDLE			g_hWorldInv = 0;
    D3DXHANDLE			g_hWorldViewProj = 0;
    D3DXHANDLE			g_hEyePositionInWorld = 0;
    D3DXHANDLE			g_hDirectionalLightStruct = 0;
    D3DXHANDLE			g_hMaterialStruct = 0;
    D3DXHANDLE			g_hNormalTex1 = 0;
    D3DXHANDLE			g_hNormalTex2 = 0;
    D3DXHANDLE			g_hDisplacementTex1 = 0;
    D3DXHANDLE			g_hDisplacementTex2 = 0;
    D3DXHANDLE			g_hNormalOffset1 = 0;
    D3DXHANDLE			g_hNormalOffset2 = 0;
    D3DXHANDLE			g_hDisplacementOffset1 = 0;
    D3DXHANDLE			g_hDisplacementOffset2 = 0;
    D3DXHANDLE			g_hScaleHeights = 0; //缩放移位1,2纹理得到的高度
    D3DXHANDLE			g_hDelta = 0;	//网格X,Z轴方向的步长
    
    #endif
    //--------------------------------------------------------------------------------------
    // Rejects any D3D9 devices that aren't acceptable to the app by returning false
    //--------------------------------------------------------------------------------------
    bool CALLBACK IsD3D9DeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat,
                                          bool bWindowed, void* pUserContext )
    {
        // Typically want to skip back buffer formats that don't support alpha blending
        IDirect3D9* pD3D = DXUTGetD3D9Object();
        if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
                                             AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING,
                                             D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
            return false;
    
        return true;
    }
    
    
    //--------------------------------------------------------------------------------------
    // Before a device is created, modify the device settings as needed
    //--------------------------------------------------------------------------------------
    bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
    {
    #if phase1
    	pDeviceSettings->d3d9.pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    #endif
        return true;
    }
    #if phase3
    //create Vertex Declaration
    HRESULT createVertexDeclaration( IDirect3DDevice9* pd3dDevice )
    {
    
    	D3DVERTEXELEMENT9 decl[] = 
    	{
    		// offsets in bytes
    		{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
    		{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
    		{0, 20, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
    		D3DDECL_END()
    	};
    
    	return pd3dDevice->CreateVertexDeclaration(decl, &g_pVertexDecl);
    
    }
    struct GridVertexFormat
    {
    	D3DXVECTOR3 pos;
    	D3DXVECTOR2 scaledTexCoord;     // [a, b]
    	D3DXVECTOR2 normalizedTexCoord; // [0, 1]
    };
    //将顶点位置以及索引写入指定的vector中,为后面写入缓冲区打下基础
    void writeVertexPosAndIndicesToVectors(int iVerticesNumPerRow, int iVerticesNumPerCol,float fDeltaX, float fDeltaZ, 
    				const D3DXVECTOR3& center,std::vector<D3DXVECTOR3>& vecVertexPosData,
    				std::vector<DWORD>& vecIndexData)
    {
    	int iVerticesNum = (iVerticesNumPerRow) * (iVerticesNumPerCol);
    	int iCellsNumPerRow = iVerticesNumPerRow - 1;
    	int iCellsNumPerCol = iVerticesNumPerCol - 1;
    
    	int iTrianglesNum = iCellsNumPerRow * iCellsNumPerCol * 2;
    
    	float fWidth = (float)iCellsNumPerCol * fDeltaX;
    	float fDepth = (float)iCellsNumPerRow * fDeltaZ;
    
    	//===========================================
    	// Build vertices.
    
    	// We first build the grid geometry centered about the origin and on
    	// the xz-plane, row-by-row and in a top-down fashion.  We then translate
    	// the grid vertices so that they are centered about the specified 
    	// parameter 'center'.从左上角开始,列序优先的方式放置顶点数据
    
    	vecVertexPosData.resize( iVerticesNum );
    
    	// Offsets to translate grid from quadrant 4 to center of 
    	// coordinate system.
    	float fOffsetX = -fWidth * 0.5f; 
    	float fOffsetZ =  fDepth * 0.5f;
    
    	int k = 0;
    	for(int i = 0; i < iVerticesNumPerRow; ++i)
    	{
    		for(int j = 0; j < iVerticesNumPerCol; ++j)
    		{
    			// Negate the depth coordinate to put in quadrant four.  
    			// Then offset to center about coordinate system.
    			vecVertexPosData[k].x = j * fDeltaX + fOffsetX;
    			vecVertexPosData[k].z = -i * fDeltaZ + fOffsetZ;
    			vecVertexPosData[k].y =  0.0f;
    
    			// Translate so that the center of the grid is at the
    			// specified 'center' parameter.
    			D3DXMATRIX T;
    			D3DXMatrixTranslation(&T, center.x, center.y, center.z);
    			D3DXVec3TransformCoord(&vecVertexPosData[k], &vecVertexPosData[k], &T);
    			
    			++k; // Next vertex
    		}
    	}
    
    	//===========================================
    	// Build indices.
    
    	vecIndexData.resize(iTrianglesNum * 3);
    	 
    	// Generate indices for each quad.
    	k = 0;
    	for(DWORD i = 0; i < (DWORD)iCellsNumPerRow; ++i)
    	{
    		for(DWORD j = 0; j < (DWORD)iCellsNumPerCol; ++j)
    		{
    			vecIndexData[k]     =   i   * iVerticesNumPerCol + j;
    			vecIndexData[k + 1] =   i   * iVerticesNumPerCol + j + 1;
    			vecIndexData[k + 2] = (i+1) * iVerticesNumPerCol + j;
    					
    			vecIndexData[k + 3] = (i+1) * iVerticesNumPerCol + j;
    			vecIndexData[k + 4] =   i   * iVerticesNumPerCol + j + 1;
    			vecIndexData[k + 5] = (i+1) * iVerticesNumPerCol + j + 1;
    			
    // 			1---2   5
    // 			|  /  / |
    // 			| /  /  | 
    // 			3   4---6
    			// next quad
    			k += 6;
    		}
    	}
    }
    
    #endif
    //--------------------------------------------------------------------------------------
    // Create any D3D9 resources that will live through a device reset (D3DPOOL_MANAGED)
    // and aren't tied to the back buffer size
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnD3D9CreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                         void* pUserContext )
    {
    #if phase3
    	HRESULT hr;
    #endif
    #if phase1
    // Setup the camera's view parameters    
    	D3DXVECTOR3 vecEye( 0.0f, 0.0f, -5.0f );  
    	D3DXVECTOR3 vecAt ( 0.0f, 0.0f, -0.0f );  
    	g_Camera.SetViewParams( &vecEye, &vecAt );  
    	FLOAT fObjectRadius=1;  
    	//摄像机缩放的3个参数
    	//g_Camera.SetRadius( fObjectRadius * 3.0f, fObjectRadius * 0.5f, fObjectRadius * 10.0f );
    	g_Camera.SetEnablePositionMovement( true );
    #endif
    #if phase2
    	D3DXCreateCubeTextureFromFile(pd3dDevice, L"grassenvmap1024.dds", &g_pCubeTex);
    #endif
    #if phase3
    	createVertexDeclaration(pd3dDevice);
    	DWORD dwTrianglesNum  = (g_iVerticesNumPerRow - 1) * (g_iVerticesNumPerCol - 1) * 2;
    	DWORD dwVerticesNum = g_iVerticesNumPerRow * g_iVerticesNumPerCol;
    	D3DVERTEXELEMENT9 elems[MAX_FVF_DECL_SIZE];
    	UINT uElemsNum = 0;
    	g_pVertexDecl->GetDeclaration(elems, &uElemsNum);
    	V(	D3DXCreateMesh(dwTrianglesNum, dwVerticesNum, D3DXMESH_MANAGED, elems, pd3dDevice, &g_pMesh) );
    	//===============================================================
    	// Write the grid vertices and triangles to the mesh.
    	GridVertexFormat *pVertices = NULL;
    	V( g_pMesh->LockVertexBuffer(0, (void**)&pVertices) );
    	std::vector<D3DXVECTOR3> vecVertexPosData;
    	std::vector<DWORD> vecIndexData;
    	writeVertexPosAndIndicesToVectors(g_iVerticesNumPerRow, g_iVerticesNumPerCol, g_fDeltaX, 
    		g_fDeltaZ, D3DXVECTOR3(0.0f, 0.0f, 0.0f), vecVertexPosData, vecIndexData);
    	for(int i = 0; i < g_iVerticesNumPerRow; ++i)
    	{
    		for(int j = 0; j < g_iVerticesNumPerCol; ++j)
    		{
    			DWORD index   = i * g_iVerticesNumPerCol + j;
    			pVertices[index].pos  = vecVertexPosData[index];
    				//注意每步步长为1/127,最后一个点的U纹理坐标为1,第一个点的U纹理坐标为0,实现了无缝结合
    				//有人会问为什么129个点就不行呢?因为纹理只有128个点的位置,129个点的话,必然会有一个纹理
    				//坐标重合,这样就破坏了纹理的连续性,就相当于把纹理从中拉开了一个距离出来一样,并且这个
    				//距离平行U方向的颜色都一样.所以一旦位移纹理偏移就不会连续了
    				pVertices[index].scaledTexCoord = D3DXVECTOR2((float)j / (g_iVerticesNumPerCol-1), 
    					(float)i / (g_iVerticesNumPerRow-1))* g_fTexScale;
    				//g_fTexScale表示Grid里面用几个纹理,值越大表示纹理重复次数越多
    				pVertices[index].normalizedTexCoord = D3DXVECTOR2((float)j / (g_iVerticesNumPerCol-1) , 
    					(float)i / (g_iVerticesNumPerRow-1));//注意这里应该减1,好实现首尾衔接,当然纹理的V
    				//坐标不用衔接,如果不减1,那么纹理将不会衔接就相当于只用了纹理的前127个像素,虽然没有影响
    				//纹理的连续性,但是会影响衔接性
    		
    		
    		}
    	}
    	V( g_pMesh->UnlockVertexBuffer() );
    	//===============================================================
    	// Write triangle data(Indices & Attributes) so we can compute normals.
    	WORD* pIndices = NULL;
    	V( g_pMesh->LockIndexBuffer(0, (void**)&pIndices) );
    	DWORD* pAttributes = NULL;
    	V( g_pMesh->LockAttributeBuffer(0, &pAttributes) );
    	for(UINT i = 0; i < g_pMesh->GetNumFaces(); ++i)
    	{
    		pIndices[i*3+0] = (WORD)vecIndexData[i*3+0];
    		pIndices[i*3+1] = (WORD)vecIndexData[i*3+1];
    		pIndices[i*3+2] = (WORD)vecIndexData[i*3+2];
    
    		pAttributes[i] = 0; // All in subset 0.
    	}
    	
    	V( g_pMesh->UnlockIndexBuffer() );
    	V( g_pMesh->UnlockAttributeBuffer() );
    	//===============================================================
    	// Optimize for the vertex cache and build attribute table.
    	// D3DXMESHOPT_ATTRSORT optimization builds an attribute table.
    	DWORD* adj = new DWORD[g_pMesh->GetNumFaces() * 3];
    	// Generate adjacency info
    	V(g_pMesh->GenerateAdjacency(EPSILON, adj));
    	V(g_pMesh->OptimizeInplace(D3DXMESHOPT_VERTEXCACHE|D3DXMESHOPT_ATTRSORT,adj, 0, 0, 0));
    	delete[] adj;
    	//===============================================================
    	// Create textures.
    	V(D3DXCreateTextureFromFile(pd3dDevice, L"normal_map1.dds", &g_pNormalTex1));
    	V(D3DXCreateTextureFromFile(pd3dDevice, L"normal_map2.dds", &g_pNormalTex2));
    	V(D3DXCreateTextureFromFileEx(pd3dDevice, L"displacement_map1.dds", g_iVerticesNumPerRow, 
    		g_iVerticesNumPerCol,1, 0, D3DFMT_R32F, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 
    		0, 0, 0, &g_pDisplacementTex1));
    	V(D3DXCreateTextureFromFileEx(pd3dDevice, L"displacement_map2.dds", g_iVerticesNumPerRow, 
    		g_iVerticesNumPerCol,1, 0, D3DFMT_R32F, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 
    		0, 0, 0, &g_pDisplacementTex2));
    #endif
    #if phase4
    	WCHAR str[MAX_PATH];
    	// Read the D3DX effect file
    	V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"DisplacementMapping.fx" ) );
    	// Create the effect 
    	LPD3DXBUFFER pErrorBuff = NULL;
    	V_RETURN( D3DXCreateEffectFromFile(
    		pd3dDevice,		// associated device
    		str,			// effect filename
    		NULL,			// no preprocessor definitions
    		NULL,			// no ID3DXInclude interface
    		D3DXSHADER_DEBUG,	// compile flags
    		NULL,			// don't share parameters
    		&g_pEffect,		// return effect
    		&pErrorBuff			// return error messages
    		) );
    	if( pErrorBuff )
    		MessageBoxA(0, (char*)pErrorBuff->GetBufferPointer(), 0, 0);
    	// get handle
    	g_hTech = g_pEffect->GetTechniqueByName("myTech");
    	g_hWorld = g_pEffect->GetParameterByName(0, "g_mWorld");
    	g_hWorldInv = g_pEffect->GetParameterByName(0, "g_mWorldInv");
    	g_hWorldViewProj = g_pEffect->GetParameterByName(0, "g_mWorldViewProj");
    	g_hEyePositionInWorld = g_pEffect->GetParameterByName(0, "g_eyePositionInWorld");
    	g_hDirectionalLightStruct = g_pEffect->GetParameterByName(0, "g_structDirectionalLight");
    	g_hMaterialStruct = g_pEffect->GetParameterByName(0, "g_structMaterial");
    
    	g_hNormalTex1 = g_pEffect->GetParameterByName(0, "g_texNormalMap1");
    	g_hNormalTex2 = g_pEffect->GetParameterByName(0, "g_texNormalMap2");
    	g_hDisplacementTex1 = g_pEffect->GetParameterByName(0, "g_texDisplacementMap1");
    	g_hDisplacementTex2 = g_pEffect->GetParameterByName(0, "g_texDisplacementMap2");
    	g_hNormalOffset1 = g_pEffect->GetParameterByName(0, "g_normalOffset1");
    	g_hNormalOffset2 = g_pEffect->GetParameterByName(0, "g_normalOffset2");
    	g_hDisplacementOffset1 = g_pEffect->GetParameterByName(0, "g_DisplacementOffset1");
    	g_hDisplacementOffset2 = g_pEffect->GetParameterByName(0, "g_DisplacementOffset2");
    	g_hScaleHeights = g_pEffect->GetParameterByName(0, "g_scaleHeights");
    	g_hDelta = g_pEffect->GetParameterByName(0, "g_delta");
    
    	// We don't need to set these every frame since they do not change.
    
    	V(g_pEffect->SetTechnique(g_hTech));
    	V(g_pEffect->SetTexture(g_hNormalTex1, g_pNormalTex1));
    	V(g_pEffect->SetTexture(g_hNormalTex2, g_pNormalTex2));
    	V(g_pEffect->SetTexture(g_hDisplacementTex1, g_pDisplacementTex1));
    	V(g_pEffect->SetTexture(g_hDisplacementTex2, g_pDisplacementTex2));
    
    	g_structDirectionalLight.directionInWorld = D3DXVECTOR3(0.0f, -1.0f, -3.0f);
    	D3DXVec3Normalize(&g_structDirectionalLight.directionInWorld, &g_structDirectionalLight.directionInWorld);
    	g_structDirectionalLight.ambient = D3DXCOLOR(0.3f, 0.3f, 0.3f, 1.0f);
    	g_structDirectionalLight.diffuse = D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f);
    	g_structDirectionalLight.specular = D3DXCOLOR(0.7f, 0.7f, 0.7f, 1.0f);
    
    	V(g_pEffect->SetValue(g_hDirectionalLightStruct, &g_structDirectionalLight, sizeof(DirectionalLight)));
    
    	g_structMaterial.ambient   = D3DXCOLOR(0.4f, 0.4f, 0.7f, 0.0f);
    	g_structMaterial.diffuse   = D3DXCOLOR(0.4f, 0.4f, 0.7f, 1.0f);
    	g_structMaterial.specular      = 0.8f*WHITE;
    	g_structMaterial.specularPower = 128.0f;
    
    	V(g_pEffect->SetValue(g_hMaterialStruct, &g_structMaterial, sizeof(Material)));
    	V(g_pEffect->SetValue(g_hScaleHeights, &g_scaleHeights, sizeof(D3DXVECTOR2)));
    	D3DXVECTOR2 delta(g_fDeltaX, g_fDeltaZ);
    	V(g_pEffect->SetValue(g_hDelta, &delta, sizeof(D3DXVECTOR2)));
    
    #endif
        return S_OK;
    }
    
    #if phase2
    struct MyVertexFormat
    {
    	FLOAT x, y, z;
    	FLOAT u, v, w;
    };
    #define FVF_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE3(0) )
    static HRESULT initVertexIndexBuffer(IDirect3DDevice9* pd3dDevice)
    {
    	static const MyVertexFormat Vertices[] = 
    	{
    		//+X
    		{  1, -1, -1,  1, -1, -1 },
    		{  1, -1, 1, 1, -1, 1 },
    		{  1, 1, 1 , 1, 1, 1  },
    		{ 1, 1, -1,	1, 1, -1 },
    		//-X
    		{ -1, -1, -1,-1, -1, -1 },
    		{ -1, 1, -1, -1, 1, -1 }, 
    		{ -1, 1, 1 , -1, 1, 1 }, 
    		{ -1, -1, 1, -1, -1, 1}, 
    		//+Y
    		{ -1, 1, -1 ,-1, 1, -1 }, 
    		{ 1, 1, -1 ,1, 1, -1 },
    		{ 1, 1, 1 ,1, 1, 1},
    		{ -1, 1, 1 ,-1, 1, 1 },
    		//-Y
    		{ -1, -1, -1,-1, -1, -1 }, 
    		{ -1, -1, 1,-1, -1, 1 },
    		{ 1, -1, 1,1, -1, 1 },
    		{ 1, -1, -1, 1, -1, -1},
    		//Z
    		{ -1, -1, 1,-1, -1, 1 }, 
    		{ -1, 1, 1,-1, 1, 1 },
    		{ 1, 1, 1,1, 1, 1 },
    		{ 1, -1, 1,1, -1, 1 },
    		//-Z
    		 { -1, -1, -1,-1, -1, -1 }, 
    		{ 1, -1, -1,1, -1, -1 },
    		{ 1, 1, -1,1, 1, -1 },
    		{ -1, 1, -1,-1, 1, -1 }
    	};
    	if (FAILED(pd3dDevice->CreateVertexBuffer(sizeof(Vertices),
    		0, FVF_VERTEX,
    		D3DPOOL_DEFAULT,
    		&g_pVB, NULL))) {
    			return E_FAIL;
    	}
    	void* pVertices;
    	if (FAILED(g_pVB->Lock(0, 0, /* map entire buffer */
    		&pVertices, 0))) {
    			return E_FAIL;
    	}
    	memcpy(pVertices, Vertices, sizeof(Vertices));
    	g_pVB->Unlock();
    
    	// Create and initialize index buffer
    	static const WORD Indices[] =
    	{
    		0, 1, 2,
    		0, 2, 3,
    
    		4, 5, 6,
    		4, 6, 7,
    
    		8, 9, 10,
    		8,10, 11,
    
    		12,13,14,
    		12,14,15,
    
    		16,17,18,
    		16,18,19,
    
    		20,21,22,
    		20,22,23
    	};
    	if (FAILED(pd3dDevice->CreateIndexBuffer(sizeof(Indices),
    		D3DUSAGE_WRITEONLY, 
    		D3DFMT_INDEX16,
    		D3DPOOL_DEFAULT,
    		&g_pIB, NULL))) {
    			return E_FAIL;
    	}
    	void* pIndices;
    	if (FAILED(g_pIB->Lock(0, 0, /* map entire buffer */
    		&pIndices, 0))) {
    			return E_FAIL;
    	}
    	memcpy(pIndices, Indices, sizeof(Indices));
    	g_pIB->Unlock();
    	return S_OK;
    }
    
    
    
    #endif
    //--------------------------------------------------------------------------------------
    // Create any D3D9 resources that won't live through a device reset (D3DPOOL_DEFAULT) 
    // or that are tied to the back buffer size 
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnD3D9ResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                        void* pUserContext )
    {
    #if phase1
    	pd3dDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );  
    	//关闭光照处理, 默认情况下启用光照处理   
    	pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );  
    //Setup the camera's projection parameters   
    	float fAspectRatio = pBackBufferSurfaceDesc->Width / ( FLOAT )pBackBufferSurfaceDesc->Height;  
    	  
    	g_Camera.SetProjParams( D3DX_PI / 2, fAspectRatio, 0.1f, 5000.0f );  
    
    #endif
    #if phase4
    	#if phase3
    	HRESULT hr;
    	if( g_pEffect )
            V_RETURN( g_pEffect->OnResetDevice() );
    #endif
    #endif
    #if !phase2
        return S_OK;
    #else
    	return initVertexIndexBuffer(pd3dDevice);
    #endif
    }
    
    
    //--------------------------------------------------------------------------------------
    // Handle updates to the scene.  This is called regardless of which D3D API is used
    //--------------------------------------------------------------------------------------
    void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
    {
    #if phase1
    	g_Camera.FrameMove( fElapsedTime );
    #endif
    #if phase4
    	g_normalMapOffset1 += g_normalMapVelocity1 * fElapsedTime;
    	g_normalMapOffset2 += g_normalMapVelocity2 * fElapsedTime;
    	g_displacementMapOffset1 += g_displacementMapVelocity1 * fElapsedTime;
    	//g_displacementMapOffset2 += g_displacementMapVelocity2 * fElapsedTime;
    
    	if(g_normalMapOffset1.x >= 1.0f || g_normalMapOffset1.x <= -1.0f)
    		g_normalMapOffset1.x = 0.0f;
    	if(g_normalMapOffset2.x >= 1.0f || g_normalMapOffset2.x <= -1.0f)
    		g_normalMapOffset2.x = 0.0f;
    	if(g_normalMapOffset1.y >= 1.0f || g_normalMapOffset1.y <= -1.0f)
    		g_normalMapOffset1.y = 0.0f;
    	if(g_normalMapOffset2.y >= 1.0f || g_normalMapOffset2.y <= -1.0f)
    		g_normalMapOffset2.y = 0.0f;
    
    	if(g_displacementMapOffset1.x >= 1.0f || g_displacementMapOffset1.x <= -1.0f)
    		g_displacementMapOffset1.x = 0.0f;
    	if(g_displacementMapOffset2.x >= 1.0f || g_displacementMapOffset2.x <= -1.0f)
    		g_displacementMapOffset2.x = 0.0f;
    	if(g_displacementMapOffset1.y >= 1.0f || g_displacementMapOffset1.y <= -1.0f)
    		g_displacementMapOffset1.y = 0.0f;
    	if(g_displacementMapOffset2.y >= 1.0f || g_displacementMapOffset2.y <= -1.0f)
    		g_displacementMapOffset2.y = 0.0f;
    
    #endif
    }
    
    
    //--------------------------------------------------------------------------------------
    // Render the scene using the D3D9 device
    //--------------------------------------------------------------------------------------
    void CALLBACK OnD3D9FrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        HRESULT hr;
    
        // Clear the render target and the zbuffer 
        V( pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB( 0, 45, 50, 170 ), 1.0f, 0 ) );
    
        // Render the scene
        if( SUCCEEDED( pd3dDevice->BeginScene() ) )
        {
    #if phase2
    
    		pd3dDevice->SetRenderState(D3DRS_LIGHTING, false);
    		// Set world matrix  
    		D3DXMATRIX M;
    		D3DXMatrixIdentity( &M ); // M = identity matrix
    		D3DXMatrixScaling(&M,2000, 2000, 2000);
    		pd3dDevice->SetTransform(D3DTS_WORLD, &M) ; 
    		// Set view matrix   
    		D3DXMATRIX view  = *g_Camera.GetViewMatrix() ;  
    		pd3dDevice->SetTransform(D3DTS_VIEW, &view) ;  
    		// Set projection matrix   
    		D3DXMATRIX proj  = *g_Camera.GetProjMatrix() ;
    		pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
    		pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj) ;  
    		pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(MyVertexFormat));
    		pd3dDevice->SetIndices(g_pIB);//sets the current index buffer. 
    		pd3dDevice->SetFVF(FVF_VERTEX);//Sets the current vertex stream declaration.
    		pd3dDevice->SetTexture(0, g_pCubeTex);
    		pd3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 24, 0, 12);	
    
    #endif
    #if phase3
    		D3DXMatrixIdentity( &M ); // M = identity matrix
    		pd3dDevice->SetTransform(D3DTS_WORLD, &M) ; 
    		pd3dDevice->SetTexture(0, 0);
    		g_pMesh->DrawSubset(0);
    #endif
    #if phase4
    		pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    		D3DXMATRIXA16 mWorld, mWorldInv;
    		D3DXMatrixIdentity(&mWorld);
    		V(g_pEffect->SetMatrix(g_hWorld, &mWorld));
    		D3DXMatrixInverse(&mWorldInv, 0, &mWorld);
    		V(g_pEffect->SetMatrix(g_hWorldInv, &mWorldInv));
    		//set WorldViewProject matrix
    		D3DXMATRIXA16 mWorldViewProjection;
    		mWorldViewProjection =  *g_Camera.GetViewMatrix() * *g_Camera.GetProjMatrix();
    		V( g_pEffect->SetMatrix( g_hWorldViewProj, &mWorldViewProjection) );
    		V( g_pEffect->SetFloatArray( g_hEyePositionInWorld, (const float*)(g_Camera.GetEyePt()), 3) );
    		V(g_pEffect->SetValue(g_hNormalOffset1, &g_normalMapOffset1, sizeof(D3DXVECTOR2)));
    		V(g_pEffect->SetValue(g_hNormalOffset2, &g_normalMapOffset2, sizeof(D3DXVECTOR2)));
    		V(g_pEffect->SetValue(g_hDisplacementOffset1, &g_displacementMapOffset1, sizeof(D3DXVECTOR2)));
    		V(g_pEffect->SetValue(g_hDisplacementOffset2, &g_displacementMapOffset2, sizeof(D3DXVECTOR2)));
    		UINT iPass, cPasses;
    		V( g_pEffect->Begin( &cPasses, 0 ) );
    		for( iPass = 0; iPass < cPasses ; iPass++ )
    		{
    			V( g_pEffect->BeginPass( iPass ) );
    			g_pMesh->DrawSubset(0);
    			V( g_pEffect->EndPass() );
    		}
    		V( g_pEffect->End() );
    #endif
    
            V( pd3dDevice->EndScene() );
        }
    }
    
    
    //--------------------------------------------------------------------------------------
    // Handle messages to the application 
    //--------------------------------------------------------------------------------------
    LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                              bool* pbNoFurtherProcessing, void* pUserContext )
    {
    #if phase1
    	g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
    #endif
        return 0;
    }
    
    
    //--------------------------------------------------------------------------------------
    // Release D3D9 resources created in the OnD3D9ResetDevice callback 
    //--------------------------------------------------------------------------------------
    void CALLBACK OnD3D9LostDevice( void* pUserContext )
    {
    #if phase2
    	SAFE_RELEASE(g_pVB);
    	SAFE_RELEASE(g_pIB);
    #endif
    #if phase3
    	SAFE_RELEASE(g_pVertexDecl);
    #endif
    #if phase4
    	if( g_pEffect )
            g_pEffect->OnLostDevice();
    #endif
    }
    
    
    //--------------------------------------------------------------------------------------
    // Release D3D9 resources created in the OnD3D9CreateDevice callback 
    //--------------------------------------------------------------------------------------
    void CALLBACK OnD3D9DestroyDevice( void* pUserContext )
    {
    #if phase2
    	SAFE_RELEASE(g_pCubeTex);
    #endif
    #if phase3
    	SAFE_RELEASE(g_pMesh);
    	SAFE_RELEASE(g_pNormalTex1);
    	SAFE_RELEASE(g_pNormalTex2);
    	SAFE_RELEASE(g_pDisplacementTex1);
    	SAFE_RELEASE(g_pDisplacementTex2);
    #endif
    #if phase4
    	SAFE_RELEASE(g_pEffect);
    #endif
    }
    
    
    //--------------------------------------------------------------------------------------
    // Initialize everything and go into a render loop
    //--------------------------------------------------------------------------------------
    INT WINAPI wWinMain( HINSTANCE, HINSTANCE, LPWSTR, int )
    {
        // Enable run-time memory check for debug builds.
    #if defined(DEBUG) | defined(_DEBUG)
        _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    #endif
    
        // Set the callback functions
        DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable );
        DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice );
        DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice );
        DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender );
        DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice );
        DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice );
        DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
        DXUTSetCallbackMsgProc( MsgProc );
        DXUTSetCallbackFrameMove( OnFrameMove );
    
        // TODO: Perform any application-level initialization here
    
        // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
        DXUTInit( true, true ); // Parse the command line and show msgboxes
        DXUTSetHotkeyHandling( true, true, true );  // handle the default hotkeys
        DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
        DXUTCreateWindow( L"3D_Shader_DisplacementMapping" );
        DXUTCreateDevice( true, 1024, 768 );
    
        // Start the render loop
        DXUTMainLoop();
    
        // TODO: Perform any application-level cleanup here
    
        return DXUTGetExitCode();
    }
    
    


     

    /*------------------------------------------------------------
    	3D_Shader_DisplacementMapping.cpp -- achieve displacement mapping
    			(c) Seamanj.2013/9/2
    ------------------------------------------------------------*/
    
    struct Material
    {
    	float4 ambient;
    	float4 diffuse;
    	float4 specular;
    	float  specularPower;
    };
    
    struct DirectionalLight
    {
    	float4 ambient;
    	float4 diffuse;
    	float4 specular;
    	float3 directionInWorld;  
    };
    
    uniform extern float4x4 g_mWorld;
    uniform extern float4x4 g_mWorldInv;
    uniform extern float4x4 g_mWorldViewProj;
    uniform extern float3   g_eyePositionInWorld;
    uniform extern DirectionalLight g_structDirectionalLight;
    uniform extern Material g_structMaterial;
    
    // Two normal maps and displacement maps.
    uniform extern texture  g_texNormalMap1;
    uniform extern texture  g_texNormalMap2;
    uniform extern texture  g_texDisplacementMap1;
    uniform extern texture  g_texDisplacementMap2;
    
    // Texture coordinate offset vectors for scrolling
    // normal maps and displacement maps.
    uniform extern float2   g_normalOffset1;
    uniform extern float2   g_normalOffset2;
    uniform extern float2   g_DisplacementOffset1;
    uniform extern float2   g_DisplacementOffset2;
    
    
    
    // User-defined scaling factors to scale the heights
    // sampled from the displacement map into a more convenient
    // range.
    uniform extern float2 g_scaleHeights;
    
    // Space between grids in x,z directions in local space
    // used for finite differencing.
    uniform extern float2 g_delta;
    
    // Shouldn't be hardcoded, but ok for demo.
    static const float DISPLACEMENTMAP_SIZE = 128.0f;
    static const float DISPLACEMENTMAP_DELTA   = 1.0f / DISPLACEMENTMAP_SIZE;
    
    sampler g_samNormalMap1 = sampler_state
    {
    	Texture = <g_texNormalMap1>;
    	MinFilter = ANISOTROPIC;
    	MaxAnisotropy = 12;
    	MagFilter = LINEAR;
    	MipFilter = LINEAR;
    	AddressU  = WRAP;
        AddressV  = WRAP;
    };
    
    sampler g_samNormalMap2 = sampler_state
    {
    	Texture = <g_texNormalMap2>;
    	MinFilter = ANISOTROPIC;
    	MaxAnisotropy = 12;
    	MagFilter = LINEAR;
    	MipFilter = LINEAR;
    	AddressU  = WRAP;
        AddressV  = WRAP;
    };
    
    sampler g_samDisplacementMap1 = sampler_state
    {
    	Texture = <g_texDisplacementMap1>;
    	MinFilter = POINT;
    	MagFilter = POINT;
    	MipFilter = POINT;
    	AddressU  = WRAP;
        AddressV  = WRAP;
    };
    
    sampler g_samDisplacementMap2 = sampler_state
    {
    	Texture = <g_texDisplacementMap2>;
    	MinFilter = POINT;
    	MagFilter = POINT;
    	MipFilter = POINT;
    	AddressU  = WRAP;
        AddressV  = WRAP;
    };
    
    
    struct OutputVS
    {
        float4 posInHomogeneous : POSITION0;
        float3 toEyeInTangent    : TEXCOORD0;
        float3 lightDirectionInTangent : TEXCOORD1;
        float2 texcoord1 : TEXCOORD2;
        float2 texcoord2 : TEXCOORD3;
    };
    
    float3 CartesianToSpherical(float3 cartesianCoord,float radius)
    {
    	float gamma,theta;
    	gamma = cartesianCoord.x / (g_delta.x * 127 / 2) * 3.14159265;
    	theta = (g_delta.y * 127 / 2 - cartesianCoord.z) / (g_delta.y * 127 / 2) * 3.14159265 / 2;
    	
    	float sinGamma,cosGamma,sinTheta,cosTheta;
    	sincos(gamma, sinGamma, cosGamma);
    	sincos(theta, sinTheta, cosTheta);
    	float3 sphericalCoord;
    	radius = radius  + cartesianCoord.y ;
    	sphericalCoord.x = radius * sinTheta * cosGamma;
    	sphericalCoord.z = radius * sinTheta * sinGamma;
    	sphericalCoord.y = radius * cosTheta;
    	return sphericalCoord;
    }
    
    
    float DoDisplacementMapping(float2 texCoord1, float2 texCoord2)
    {
    	// Transform to texel space
        float2 texelPos = DISPLACEMENTMAP_SIZE * texCoord1;
            
        // Determine the lerp amounts.           
        float2 lerps = frac(texelPos);
        
    	float height1[4];
    	//由于移位纹理显示青色(即B,G通道都为1,所以应该是R通道存储的是高度
    	height1[0] = tex2Dlod(g_samDisplacementMap1, float4(texCoord1, 0.0f, 0.0f)).r;
    	height1[1] = tex2Dlod(g_samDisplacementMap1, float4(texCoord1, 0.0f, 0.0f)+float4(DISPLACEMENTMAP_DELTA, 0.0f, 0.0f, 0.0f)).r;
    	height1[2] = tex2Dlod(g_samDisplacementMap1, float4(texCoord1, 0.0f, 0.0f)+float4(0.0f, DISPLACEMENTMAP_DELTA, 0.0f, 0.0f)).r;
    	height1[3] = tex2Dlod(g_samDisplacementMap1, float4(texCoord1, 0.0f, 0.0f)+float4(DISPLACEMENTMAP_DELTA, DISPLACEMENTMAP_DELTA, 0.0f, 0.0f)).r;
    	//这里取出来的值范围在[0,1]之内
    	// Filter displacement map:
    	float h1 = lerp( lerp( height1[0], height1[1], lerps.x ),
                         lerp( height1[2], height1[3], lerps.x ),
                         lerps.y );
    	
    	texelPos = DISPLACEMENTMAP_SIZE * texCoord2;
    	lerps    = frac(texelPos);
    	
    	float height2[4];
    	height2[0] = tex2Dlod(g_samDisplacementMap2, float4(texCoord2, 0.0f, 0.0f)).r;
    	height2[1] = tex2Dlod(g_samDisplacementMap2, float4(texCoord2, 0.0f, 0.0f)+float4(DISPLACEMENTMAP_DELTA, 0.0f, 0.0f, 0.0f)).r;
    	height2[2] = tex2Dlod(g_samDisplacementMap2, float4(texCoord2, 0.0f, 0.0f)+float4(0.0f, DISPLACEMENTMAP_DELTA, 0.0f, 0.0f)).r;
    	height2[3] = tex2Dlod(g_samDisplacementMap2, float4(texCoord2, 0.0f, 0.0f)+float4(DISPLACEMENTMAP_DELTA, DISPLACEMENTMAP_DELTA, 0.0f, 0.0f)).r;
    	
    	// Filter displacement map:
    	float h2 = lerp( lerp( height2[0], height2[1], lerps.x ),
                         lerp( height2[2], height2[3], lerps.x ),
                         lerps.y );
                       
    	// Sum and scale the sampled heights.  
        return g_scaleHeights.x * h1 + g_scaleHeights.y * h2;
    
    }
    OutputVS myVertexEntry(float3 positionInLocal : POSITION0, 
                     float2 scaledTexCoord     : TEXCOORD0,//供法线纹理使用
                     float2 normalizedTexCoord : TEXCOORD1)//供移位纹理使用
    {
        // Zero out our output.
    	OutputVS outVS = (OutputVS)0;
    	
    	// Scroll vertex texture coordinates to animate waves.
    	float2 DisplacementTexCoord1 = normalizedTexCoord + g_DisplacementOffset1;
    	float2 DisplacementTexCoord2 = normalizedTexCoord + g_DisplacementOffset2;
    	
    	// Set y-coordinate of water grid vertices based on displacement mapping.
    	positionInLocal.y = DoDisplacementMapping(DisplacementTexCoord1, DisplacementTexCoord2);
    	
    	// Estimate TBN-basis using finite differencing in local space.  
    	float left = DoDisplacementMapping(DisplacementTexCoord1 + float2(DISPLACEMENTMAP_DELTA, 0.0f), 
    	                        DisplacementTexCoord2 + float2(0.0f, DISPLACEMENTMAP_DELTA));
    	float front = DoDisplacementMapping(DisplacementTexCoord1 + float2(DISPLACEMENTMAP_DELTA, 0.0f), 
    	                        DisplacementTexCoord2 + float2(0.0f, DISPLACEMENTMAP_DELTA));  
    	                        
    	float3x3 TBN;                       
    	TBN[0] = normalize(float3(1.0f, (left - positionInLocal.y)/g_delta.x, 0.0f)); //Tangent
    	TBN[1] = normalize(float3(0.0f, (front - positionInLocal.y)/g_delta.y, -1.0f));//Binormal
    	TBN[2] = normalize(cross(TBN[0], TBN[1]));//Normal
    	
    	// Matrix transforms from object space to tangent space.
    	float3x3 toTangentSpace = transpose(TBN);
    	
    	// Transform eye position to local space.
    	float3 eyePositionInLocal = mul(float4(g_eyePositionInWorld, 1.0f), g_mWorldInv).xyz;
    	
    	// Transform to-eye vector to tangent space.
    	float3 toEyeInLocal = eyePositionInLocal - positionInLocal;
    	outVS.toEyeInTangent = mul(toEyeInLocal, toTangentSpace);
    	
    	// Transform light direction to tangent space.
    	float3 lightDirectionInLocal = mul(float4(g_structDirectionalLight.directionInWorld, 0.0f), g_mWorldInv).xyz;
    	outVS.lightDirectionInTangent  = mul(lightDirectionInLocal, toTangentSpace);
    	
    	positionInLocal = CartesianToSpherical(positionInLocal, 30.0f);
    	// Transform to homogeneous clip space.
    	
    	outVS.posInHomogeneous = mul(float4(positionInLocal, 1.0f), g_mWorldViewProj);
    	
    	// Scroll texture coordinates.
    	outVS.texcoord1 = scaledTexCoord+ g_normalOffset1;
    	outVS.texcoord2 = scaledTexCoord+ g_normalOffset2;
    	
    	// Done--return the output.
        return outVS;
    }
    
    float4 myPixelEntry(float3 toEyeInTangent    : TEXCOORD0,
    					float3 lightDirectionInTangent : TEXCOORD1,
    				    float2 texcoord1      : TEXCOORD2,
    				    float2 texcoord2      : TEXCOORD3) : COLOR
    {
    	// Interpolated normals can become unnormal--so normalize.
    	// Note that toEyeW and normalW do not need to be normalized
    	// because they are just used for a reflection and environment
    	// map look-up and only direction matters.
    	toEyeInTangent    = normalize(toEyeInTangent);
    	lightDirectionInTangent = normalize(lightDirectionInTangent);
    	
    	// Light vector is opposite the direction of the light.
    	float3 toLightInTangent = -lightDirectionInTangent;
    	
    	// Sample normal map.
    	float3 normalInTangent1 = tex2D(g_samNormalMap1, texcoord1);
    	float3 normalInTangent2 = tex2D(g_samNormalMap2, texcoord2);
    	
    	// Expand from [0, 1] compressed interval to true [-1, 1] interval.
        normalInTangent1 = 2.0f * normalInTangent1 - 1.0f;
        normalInTangent2 = 2.0f * normalInTangent2 - 1.0f;
        
    	// Average the two vectors.
    	float3 normalInTangent = normalize( 0.5f * ( normalInTangent1 + normalInTangent2));
    	
    	// Compute the reflection vector.
    	float3 r = reflect(lightDirectionInTangent, normalInTangent);
    	
    	// Determine how much (if any) specular light makes it into the eye.
    	float s  = pow(max(dot(r, toEyeInTangent), 0.0f), g_structMaterial.specularPower);
    
    	// Determine the diffuse light intensity that strikes the vertex.
    	float d = max(dot(toLightInTangent, normalInTangent), 0.0f);
    	
    	// If the diffuse light intensity is low, kill the specular lighting term.
    	// It doesn't look right to add specular light when the surface receives 
    	// little diffuse light.
    	if(d <= 0.0f)
    	     s = 0.0f;
    	
    	// Compute the ambient, diffuse and specular terms separatly. 
    	float3 spec = s * ( g_structMaterial.specular * g_structDirectionalLight.specular).rgb;
    	float3 diffuse = d * (g_structMaterial.diffuse*g_structDirectionalLight.diffuse.rgb);
    	float3 ambient = g_structMaterial.ambient * g_structDirectionalLight.ambient;
    	
    	float3 final = ambient + diffuse + spec;
    	
    	// Output the color and the alpha.
        return float4(final, g_structMaterial.diffuse.a);
    }
    
    technique myTech
    {
        pass P0
        {
    		//FillMode = WIREFRAME;
            // Specify the vertex and pixel shader associated with this pass.
            vertexShader = compile vs_3_0 myVertexEntry();
            pixelShader  = compile ps_3_0 myPixelEntry();
            
        }    
    }
    



    好了,收工,睡觉去了,这几天要写个柏林噪声出来!!!!!!!!!!!!


    可执行程序以及相关源代码请点击这里下载



  • 相关阅读:
    HTTP 协议详解
    HTTP抓包工具之Fiddler
    C#网络编程(订立协议和发送文件)
    C#编程总结(十)字符转码
    通信协议:HTTP、TCP、UDP
    C# 对象、文件与二进制串(byte数组)之间的转换
    从输入URL 到页面加载完成的过程
    java动手动脑
    大道至简第二章读后感
    《大道至简》第一章 读后感
  • 原文地址:https://www.cnblogs.com/suncoolcat/p/3303952.html
Copyright © 2011-2022 走看看