您的位置:首页 > 编程语言

Shaders for Game Programmers and Artists代码实现Chapter_0502

2011-05-05 11:50 447 查看
此处最后往屏幕上渲染时没有使用ScreenAlignedQuad.3ds模型,而是在程序中手动建立了一个背板模型,道理一样,读者也可以使用这个模型。







代码:

/********************************
*  Author: rabbit729
*  E-mail: wlq_729@163.com
*  Date:   2011-05-04
*  Description: 实现如何渲染到纹理
********************************/
#include <d3dx9.h>

//-----------------------------------------------------------------------------
// Desc: 全局变量
//-----------------------------------------------------------------------------
LPDIRECT3D9             g_pD3D                 = NULL;  //Direct3D对象
LPDIRECT3DDEVICE9       g_pd3dDevice           = NULL;  //Direct3D设备对象

LPD3DXMESH              g_pMeshTeapot          = NULL;  //茶壶网格模型对象
LPDIRECT3DTEXTURE9      g_pMeshTeapotTexture   = NULL;  //茶壶网格模型纹理
DWORD                   g_dwTeapotNumMaterials = 0;     //茶壶网格模型材质数量

LPD3DXMESH              g_pMeshElephant         = NULL; //大象网格模型对象
LPDIRECT3DTEXTURE9      g_pMeshElephantTexture  = NULL; //大象网格模型纹理
DWORD                   g_dwElephantNumMaterials = 0;   //大象网格模型材质数量

LPDIRECT3DTEXTURE9      g_pTextureScreen        = NULL; //待渲染Texture
LPDIRECT3DSURFACE9      g_pRTScreen             = NULL; //待渲染表面

ID3DXEffect*            g_pEffect               = NULL;  //效果指针

//常量句柄
D3DXHANDLE              hWVPMatrixHandle        = NULL;  //变换矩阵句柄
D3DXHANDLE              hTexTeapot              = NULL;  //茶壶纹理句柄
D3DXHANDLE              hTexElephant            = NULL;  //大象纹理句柄
D3DXHANDLE              hTexScreen              = NULL;  //rt句柄
D3DXHANDLE              hPos                    = NULL;  //大象位置句柄
D3DXHANDLE              hTechTeapot             = NULL;  //茶壶技术句柄
D3DXHANDLE              hTechElephant           = NULL;  //大象技术句柄
D3DXHANDLE              hTechScreen             = NULL;  //平面板技术句柄
D3DXHANDLE              hViewPortWidthInv       = NULL;  //视口宽倒数句柄
D3DXHANDLE              hViewPortHeightInv      = NULL;  //视口高倒数句柄

LPDIRECT3DVERTEXBUFFER9 g_pScreenSpaceQuad      = NULL;  //背板VB

const int WIDTH  = 600;
const int HEIGHT = 500;

#define D3DFVF_CUSTOMVERTEX (D3DFVF_XYZ | D3DFVF_TEX1)

struct Vertex
{
	Vertex(){}
	Vertex(float x, float y, float z, float w)
	{
		_x = x;   _y = y;   _z = z; _w = w;
	}

	float _x, _y, _z, _w;

	static const DWORD FVF;
};
const DWORD Vertex::FVF = D3DFVF_XYZW;

//-----------------------------------------------------------------------------
// Desc: 设置世界矩阵
//-----------------------------------------------------------------------------
VOID SetWorldMatrix()
{
    //创建并设置世界矩阵
    D3DXMATRIXA16 matWorld, matRotateX, matRotateY;
	D3DXMATRIXA16 matScale;
	D3DXMatrixIdentity(&matScale);
	matScale._11 = matScale._22 = matScale._33 = 0.5f;

	D3DXMatrixIdentity(&matWorld);
	D3DXMatrixIdentity(&matRotateX);
	D3DXMatrixIdentity(&matRotateY);
    D3DXMatrixRotationX( &matRotateX, D3DX_PI / 3.0 );
	D3DXMatrixRotationY( &matRotateY, -D3DX_PI / 8.0 );
	D3DXMatrixMultiply(&matWorld, &matRotateX, &matRotateY);

	D3DXMatrixMultiply(&matWorld, &matScale, &matWorld);
    g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
}

//-----------------------------------------------------------------------------
// Desc: 设置观察矩阵和投影矩阵
//-----------------------------------------------------------------------------
VOID SetViewAndProjMatrix()
{
    //创建并设置观察矩阵
    D3DXVECTOR3 vEyePt( 0.0f, 0.0f,-250.0f );
    D3DXVECTOR3 vLookatPt( 0.0f, 0.0f, 0.0f );
    D3DXVECTOR3 vUpVec( 0.0f, 1.0f, 0.0f );
    D3DXMATRIXA16 matView;
    D3DXMatrixLookAtLH( &matView, &vEyePt, &vLookatPt, &vUpVec );
    g_pd3dDevice->SetTransform( D3DTS_VIEW, &matView );

    //创建并设置投影矩阵
    D3DXMATRIXA16 matProj;
    D3DXMatrixPerspectiveFovLH( &matProj, D3DX_PI/4, 1.0f, 1.0f, 1000.0f );
    g_pd3dDevice->SetTransform( D3DTS_PROJECTION, &matProj );
}

//-----------------------------------------------------------------------------
// Desc: 初始化Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
	//创建Direct3D对象, 该对象用于创建Direct3D设备对象
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;

	//设置D3DPRESENT_PARAMETERS结构, 准备创建Direct3D设备对象
    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;

    //创建Direct3D设备对象
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
    {
        return E_FAIL;
    }

	//创建Effect
	ID3DXBuffer* errBuffer = NULL;
	if (FAILED(D3DXCreateEffectFromFile(g_pd3dDevice, L"0401.fx", NULL, NULL, D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, NULL, &g_pEffect, &errBuffer)))
	{
		if (errBuffer)
		{
			MessageBox(0, (LPCTSTR)errBuffer->GetBufferPointer(), 0, 0);
			errBuffer->Release();
		}
		return E_FAIL;
	}

	//获取常量句柄
	hWVPMatrixHandle    = g_pEffect->GetParameterByName(0, "matWVP");
	hTexTeapot          = g_pEffect->GetParameterByName(0, "TexTeapot");
	hTexElephant        = g_pEffect->GetParameterByName(0, "TexElephant");
	hTexScreen          = g_pEffect->GetParameterByName(0, "TexScreen");
	hPos                = g_pEffect->GetParameterByName(0, "vPos");
	hTechTeapot         = g_pEffect->GetTechniqueByName("Teapot");
	hTechElephant       = g_pEffect->GetTechniqueByName("Elephant");
	hTechScreen         = g_pEffect->GetTechniqueByName("Screen");
	hViewPortWidthInv   = g_pEffect->GetParameterByName(0, "viewport_inv_width");
	hViewPortHeightInv  = g_pEffect->GetParameterByName(0, "viewport_inv_height");

	//设置环境光
    g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );

	//设置观察矩阵和投影矩阵
	SetViewAndProjMatrix();

    return S_OK;
}

//-----------------------------------------------------------------------------
// Desc: 从绝对路径中提取纹理文件名
//-----------------------------------------------------------------------------
void RemovePathFromFileName(LPSTR fullPath, LPWSTR fileName)
{
	//先将fullPath的类型变换为LPWSTR
	WCHAR wszBuf[MAX_PATH];
	MultiByteToWideChar( CP_ACP, 0, fullPath, -1, wszBuf, MAX_PATH );
	wszBuf[MAX_PATH-1] = L'/0';

	WCHAR* wszFullPath = wszBuf;

	//从绝对路径中提取文件名
	LPWSTR pch=wcsrchr(wszFullPath,'//');
	if (pch)
		lstrcpy(fileName, ++pch);
	else
		lstrcpy(fileName, wszFullPath);
}

//-----------------------------------------------------------------------------
// Desc: 创建场景图形
//-----------------------------------------------------------------------------
HRESULT InitGeometry()
{
    LPD3DXBUFFER pD3DXMtrlBuffer;  //存储网格模型材质的缓冲区对象

    //从磁盘文件加载网格模型 茶壶模型
    if( FAILED( D3DXLoadMeshFromX( L"teapot.x", D3DXMESH_MANAGED, 
                                   g_pd3dDevice, NULL, 
                                   &pD3DXMtrlBuffer, NULL, &g_dwTeapotNumMaterials, 
                                   &g_pMeshTeapot ) ) )
    {
        MessageBox(NULL, L"Could not find teapot.x", L"Mesh", MB_OK);
        return E_FAIL;
    }

	//从磁盘文件加载网格模型 大象模型
	if( FAILED( D3DXLoadMeshFromX( L"Elephant.x", D3DXMESH_MANAGED, 
		g_pd3dDevice, NULL, 
		&pD3DXMtrlBuffer, NULL, &g_dwElephantNumMaterials, 
		&g_pMeshElephant ) ) )
	{
		MessageBox(NULL, L"Could not find elephant.x", L"Mesh", MB_OK);
		return E_FAIL;
	}

	// 创建屏幕板
	g_pd3dDevice->CreateVertexBuffer(
		6 * sizeof(Vertex),
		D3DUSAGE_WRITEONLY,
		Vertex::FVF, 
		D3DPOOL_MANAGED,
		&g_pScreenSpaceQuad,
		0);

	Vertex* vertices;
	g_pScreenSpaceQuad->Lock(0, 0, (void**)&vertices, 0);

	vertices[0] = Vertex(-1.0f, 1.0f, 0.5f, 1.0f);
	vertices[1] = Vertex(1.0f,  1.0f, 0.5f, 1.0f);
	vertices[2] = Vertex( 1.0f, -1.0f, 0.5f, 1.0f);
	vertices[3] = Vertex(-1.0f, 1.0f, 0.5f, 1.0f);
	vertices[4] = Vertex( 1.0f, -1.0f, 0.5f, 1.0f);
	vertices[5] = Vertex( -1.0f, -1.0f, 0.5f, 1.0f);

	g_pScreenSpaceQuad->Unlock();

    //加载纹理
	HRESULT hr = D3DXCreateTextureFromFile(g_pd3dDevice, L"Fieldstone.tga", &g_pMeshTeapotTexture);
	if (FAILED(hr))
	{
		return E_FAIL;
	}
    
	hr = D3DXCreateTextureFromFile(g_pd3dDevice, L"Earth.jpg", &g_pMeshElephantTexture);
	if (FAILED(hr))
	{
		return E_FAIL;
	}

	// 创建rt
	hr = g_pd3dDevice->CreateTexture(WIDTH, HEIGHT, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &g_pTextureScreen, NULL);
	if (FAILED(hr))
	{
		return E_FAIL;
	}
	g_pTextureScreen->GetSurfaceLevel(0, &g_pRTScreen);

	//释放在加载模型文件时创建的保存模型材质和纹理数据的缓冲区对象
    pD3DXMtrlBuffer->Release();  

    return S_OK;
}

//-----------------------------------------------------------------------------
// Desc: 释放创建的对象
//-----------------------------------------------------------------------------
VOID Cleanup()
{
	//释放网格模型纹理
    if( g_pMeshTeapotTexture )
    {
       g_pMeshTeapotTexture->Release();
    }

	if (g_pMeshElephantTexture)
	{
		g_pMeshElephantTexture->Release();
	}

	//释放网格模型对象
    if( g_pMeshTeapot != NULL )
        g_pMeshTeapot->Release();

	if (g_pMeshElephant != NULL)
	{
		g_pMeshElephant->Release();
	}

	if (g_pScreenSpaceQuad != NULL)
	{
		g_pScreenSpaceQuad->Release();
	}

	if (g_pTextureScreen != NULL)
	{
		g_pTextureScreen->Release();
	}

	if (g_pEffect != NULL)
	{
		g_pEffect->Release();
	}
    
	//释放Direct3D设备对象
    if( g_pd3dDevice != NULL )
        g_pd3dDevice->Release();

	//释放Direct3D对象
    if( g_pD3D != NULL )
        g_pD3D->Release();
}

void RenderTeapot()
{
	// 设置RenderTarget
	g_pd3dDevice->SetRenderTarget(0, g_pRTScreen);

	// 清除缓冲区
	g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255,0,0,0), 1.0f, 0 );

	SetWorldMatrix();  //设置世界矩阵

	g_pd3dDevice->SetFVF(D3DFVF_CUSTOMVERTEX);
	D3DXMATRIX matWorld, matView, matProj;
	g_pd3dDevice->GetTransform(D3DTS_WORLD, &matWorld);
	g_pd3dDevice->GetTransform(D3DTS_VIEW, &matView);
	g_pd3dDevice->GetTransform(D3DTS_PROJECTION, &matProj);
	D3DXMATRIX matWVP = matWorld * matView * matProj;
	g_pEffect->SetMatrix(hWVPMatrixHandle, &matWVP);

	g_pEffect->SetTexture(hTexTeapot, g_pMeshTeapotTexture);

	// 设置要使用的Technique
	g_pEffect->SetTechnique(hTechTeapot);

	//遍历技术中包含的所有过程进行多次渲染
	UINT numPasses = 0;
	g_pEffect->Begin(&numPasses, 0);

	for (int i = 0; i < numPasses; i++)
	{
		g_pEffect->BeginPass(i);

		//茶壶
		for( DWORD i=0; i<g_dwTeapotNumMaterials; i++ )
		{
			//渲染模型
			g_pMeshTeapot->DrawSubset( i );
		}
		g_pEffect->EndPass();
	}
	g_pEffect->End();
}

void RenderElephant()
{
	// 设置RenderTarget,此处不能清除缓冲区,需要保留上次茶壶渲染结果
	g_pd3dDevice->SetRenderTarget(0, g_pRTScreen);

	g_pEffect->SetTexture(hTexElephant, g_pMeshElephantTexture);

	D3DXVECTOR4 vPos(100.f, -64.f, 100.f, 0.f);
	g_pEffect->SetValue(hPos, vPos, D3DX_DEFAULT);

	// 设置要使用的Technique
	g_pEffect->SetTechnique(hTechElephant);

	//遍历技术中包含的所有过程进行多次渲染
	UINT numPasses = 0;
	g_pEffect->Begin(&numPasses, 0);

	for (int i = 0; i < numPasses; i++)
	{
		g_pEffect->BeginPass(i);

		//茶壶
		for( DWORD i=0; i<g_dwElephantNumMaterials; i++ )
		{
			//渲染模型
			g_pMeshElephant->DrawSubset( i );
		}
		g_pEffect->EndPass();
	}
	g_pEffect->End();
}

VOID RenderScreen()
{
	//将RenderTarget作为纹理
	g_pEffect->SetTexture(hTexScreen, g_pTextureScreen);

	float fWidthInv = 1.0f / WIDTH;
	float fHeightInv = 1.0f / HEIGHT;
	g_pEffect->SetFloat(hViewPortWidthInv, fWidthInv);
	g_pEffect->SetFloat(hViewPortHeightInv, fHeightInv);

	g_pd3dDevice->SetStreamSource(0, g_pScreenSpaceQuad, 0, sizeof(Vertex));
	g_pd3dDevice->SetFVF(Vertex::FVF);

	// 设置要使用的Technique
	g_pEffect->SetTechnique(hTechScreen);

	//遍历技术中包含的所有过程进行多次渲染
	UINT numPasses = 0;
	g_pEffect->Begin(&numPasses, 0);

	for (int i = 0; i < numPasses; i++)
	{
		g_pEffect->BeginPass(i);

		g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);

		g_pEffect->EndPass();
	}
	g_pEffect->End();
}

//-----------------------------------------------------------------------------
// Desc: 渲染场景
//-----------------------------------------------------------------------------
VOID Render()
{    
	// 获取backbuffer
	LPDIRECT3DSURFACE9 pBackbuffer;
	g_pd3dDevice->GetRenderTarget(0, &pBackbuffer);

    //开始渲染场景
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
		RenderTeapot();
		RenderElephant();

		//设回backbuffer
		g_pd3dDevice->SetRenderTarget(0, pBackbuffer);
		RenderScreen();

        //场景渲染结束
        g_pd3dDevice->EndScene();
    }

    //在屏幕上显示场景
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

//-----------------------------------------------------------------------------
// Desc: 窗口过程, 处理消息
//-----------------------------------------------------------------------------
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
			Cleanup();
            PostQuitMessage( 0 );
            return 0;
    }

    return DefWindowProc( hWnd, msg, wParam, lParam );
}

//-----------------------------------------------------------------------------
// Desc: 入口函数
//-----------------------------------------------------------------------------
INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
    //注册窗口类
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L, 
                      GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
                      L"ClassName", NULL };
    RegisterClassEx( &wc );

    //创建窗口
    HWND hWnd = CreateWindow( L"ClassName", L"Effect 实现", 
                              WS_OVERLAPPEDWINDOW, 200, 100, WIDTH, HEIGHT,
                              GetDesktopWindow(), NULL, wc.hInstance, NULL );

	//初始化Direct3D
    if( SUCCEEDED( InitD3D( hWnd ) ) )
    { 
		//创建场景图形
        if( SUCCEEDED( InitGeometry() ) )
        {
            //显示窗口
            ShowWindow( hWnd, SW_SHOWDEFAULT );
            UpdateWindow( hWnd );

            //进入消息循环
            MSG msg; 
            ZeroMemory( &msg, sizeof(msg) );
            while( msg.message!=WM_QUIT )
            {
                if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
                {
                    TranslateMessage( &msg );
                    DispatchMessage( &msg );
                }
                else
				{
                    Render();  //渲染场景
				}
            }
        }
    }

    UnregisterClass( L"ClassName", wc.hInstance );
    return 0;
}




Effect:

/********************************
*  Author: rabbit729
*  E-mail: wlq_729@163.com
*  Date:   2011-05-04
********************************/

///////////////// 茶壶 //////////////////////

//------------------------------
//  顶点着色器
//------------------------------
matrix matWVP;
float4 vPos;

struct VS_OUTPUTTEAPOT
{
   float4 Pos:     POSITION;
   float2 Txr1:    TEXCOORD0;
};

VS_OUTPUTTEAPOT vs_mainPassTeapot( 
   float4 inPos: POSITION,
   float2 Txr1: TEXCOORD0
)
{
   VS_OUTPUTTEAPOT Out;

   Out.Pos = mul(inPos, matWVP);
   Out.Txr1 = Txr1;

   return Out;
}

//------------------------------
//  像素着色器
//------------------------------
Texture2D TexTeapot;

sampler2D TexMapTeapot {
    Texture = <TexTeapot>;
};

float4 ps_mainPassTeapot( 
   float4 inPosition: COLOR0, 
   float2 inTxr1: TEXCOORD0
) : COLOR0
{
   return tex2D(TexMapTeapot,inTxr1);
}

//////////////// 大象 ///////////////////////

//------------------------------
//  顶点着色器
//------------------------------

struct VS_OUTPUTPELEPHANT
{
   float4 Pos:     POSITION;
   float2 Txr1:    TEXCOORD0;
};

VS_OUTPUTPELEPHANT vs_mainPassElephant(
   float4 inPos: POSITION,
   float2 Txr1: TEXCOORD0
)
{
   VS_OUTPUTPELEPHANT Out;
   Out.Pos  = mul(inPos + vPos, matWVP);
   Out.Txr1 = Txr1;
   
   return Out;
}

//------------------------------
//  像素着色器
//------------------------------
Texture2D TexElephant;

sampler2D TexMapElephant {
    Texture = <TexElephant>;
};

float4 ps_mainPassElephant( 
   float4 inPosition: COLOR0, 
   float2 inTxr1: TEXCOORD0
) : COLOR0
{
   return tex2D(TexMapElephant,inTxr1);
}

///////// 全屏特技 /////////////////

//------------------------------
//  顶点着色器
//------------------------------

float viewport_inv_width;
float viewport_inv_height;
struct VS_OUTPUTSCREEN {
   float4 Pos: POSITION;
   float2 texCoord: TEXCOORD0;
};

VS_OUTPUTSCREEN vs_mainPassScreen(float4 Pos: POSITION){
   VS_OUTPUTSCREEN Out;

   Out.Pos = float4(Pos.xy, 0, 1);

   Out.texCoord.x = 0.5 * (1 + Pos.x - viewport_inv_width);
   Out.texCoord.y = 0.5 * (1 - Pos.y - viewport_inv_height);

   return Out;
}

//------------------------------
//  像素着色器
//------------------------------
Texture2D TexScreen;

sampler2D TexMapScreen {
    Texture = <TexScreen>;
};

float4 ps_mainPassScreen(float2 texCoord: TEXCOORD0) : COLOR 
{
   return tex2D(TexMapScreen,  texCoord);
}

//------------------------------
//  效果框架
//------------------------------
technique Teapot
{
   pass P0
   {
      VertexShader = compile vs_3_0 vs_mainPassTeapot();
      PixelShader  = compile ps_3_0 ps_mainPassTeapot();
   }
}

technique Elephant
{   
   pass P0
   {
      VertexShader = compile vs_3_0 vs_mainPassElephant();
      PixelShader  = compile ps_3_0 ps_mainPassElephant();
   }
}

technique Screen
{
   pass P0
   {
      VertexShader = compile vs_3_0 vs_mainPassScreen();
      PixelShader  = compile ps_3_0 ps_mainPassScreen();
   }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: