techniqueapplication.cpp

来自「real-time(实时渲染技术DirectX)25-30(1)」· C++ 代码 · 共 553 行 · 第 1/2 页

CPP
553
字号
/***************************************************************
* TechniqueApplication.cpp                                     *
*                                                              *
* This file contains the implementation of the                 *
* TechniqueApplication class.    	        				   *
* To compile correctly, this file must be linked with:         *
* kernel32.lib                                                 *
* user32.lib                                                   *
* d3dx8dt.lib                                                  *
* d3d8.lib                                                     *
*                                                              *
***************************************************************/

#include "TechniqueApplication.h"

#define D3DFVF_MESHVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE)
#define D3DFVF_MASKVERTEX (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)

struct MESH_VERTEX
{
	float x, y, z;
	float nx, ny, nz;
	DWORD color;
};

struct MASK_VERTEX
{
	float x, y, z, rhw;
	DWORD color;
};

CTechniqueApplication::CTechniqueApplication()
{
	m_pPlaneVertexBuffer       = NULL;
	m_pMaskVertexBuffer        = NULL;
	m_pMeshVertexBuffer        = NULL;
	m_pMeshIndexBuffer         = NULL;
	m_pMesh                    = NULL;
	m_pMeshMaterials           = NULL;
	m_NumMaterials             = 0;
	m_BasicShader              = 0;
	m_VolumeShader             = 0;
}

CTechniqueApplication::~CTechniqueApplication()
{
}

BOOL CTechniqueApplication::PostInitialize()
{	
	D3DCAPS8 Caps;
	m_pD3D->GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, &Caps);
	if (Caps.VertexShaderVersion == D3DVS_VERSION(1,1))
	{
		if (FAILED(EasyCreateWindowed(m_hWnd, D3DDEVTYPE_HAL, 
						  D3DCREATE_HARDWARE_VERTEXPROCESSING)))
			return FALSE;
	}
	else
	{
		if (FAILED(EasyCreateWindowed(m_hWnd, D3DDEVTYPE_HAL, 
						  D3DCREATE_SOFTWARE_VERTEXPROCESSING)))
			return FALSE;
	}


	//Do the basic camera positioning, etc.
	SetupDevice();
	
	//Load the mesh object
	LoadMesh();

	//Create the buffers we're actually going to use
	ExtractBuffers();

	if (FAILED(CreatePlaneBuffers()))
		return FALSE;

	//Create the shader
	if (FAILED(CreateShaders()))
		return FALSE;

	return TRUE;
}

void CTechniqueApplication::Render()
{
	//Set the view parameters
	D3DXVECTOR4 EyePos(0.0, 60.0f, -60.0f, 0.0f);
	D3DXMatrixLookAtLH(&m_ViewMatrix, &(D3DXVECTOR3)EyePos,
		               &D3DXVECTOR3(0.0f, 0.0f, 0.0f),
					   &D3DXVECTOR3(0.0f, 1.0f, 0.0f));

	//The light is moving side to side over the model.
	float Time = (float)GetTickCount() / 2000.0f;
	D3DXVECTOR4 LightPos(150.0f * sin(Time), 90.0f, 0.0f, 1.0f);

	//Set the light direction based on what was computed for the shadow.
	//Assume the light is pointer toward the origin.
	D3DXVECTOR4 LightDir = D3DXVECTOR4(0.0f, 0.0f, 0.0f, 0.0f) - LightPos;
	D3DXVec4Normalize(&LightDir, &LightDir);

	//Set the ambient light value.
	D3DXVECTOR4 Ambient    (0.0f,  0.0f, 0.0f, 0.0f);
	m_pD3DDevice->SetVertexShaderConstant(5, &Ambient, 1);

	//Set the expansion amount in c8.x. 
	//Also, the shader expects the Y value to be 0.0
	D3DXVECTOR4 PushDistance(100.0f, 0.0f, 0.0f, 0.0f);
	m_pD3DDevice->SetVertexShaderConstant(8, &PushDistance, 1);

	//Set up the basic shader first
	m_pD3DDevice->SetVertexShader(m_BasicShader);

	//The real objects are always in front of the shadow passes
	m_pD3DDevice->SetRenderState(D3DRS_ZBIAS, 1);
		
	//First, Draw the plane
	RenderPlane();

	//Some reusable matrices.
	D3DXMATRIX Rotation;
    D3DXMATRIX Translation;

	//This first instance of the mesh is just an object for the 
	//shadow caster to cast shadows on. In this case, I'm not
	//setting it up to cast it's own shadows.
	D3DXMatrixTranslation(&m_WorldMatrix, 20.0f, 10.0f, 0.0f);
	D3DXMATRIX ShaderMatrix = m_WorldMatrix * m_ViewMatrix * 
				              m_ProjectionMatrix;
	D3DXMatrixTranspose(&ShaderMatrix, &ShaderMatrix);
	m_pD3DDevice->SetVertexShaderConstant(0, &ShaderMatrix, 4);

	//Set the light direction so that the mesh rendering code can use it.
	//Convert the light direction to object space.
	D3DXMATRIX InverseWorld;
	float Det;
	D3DXMatrixInverse(&InverseWorld, &Det, &m_WorldMatrix);
	D3DXVec4Transform(&LightDir, &LightDir, &InverseWorld);
	D3DXVec4Normalize(&LightDir, &LightDir);
	m_pD3DDevice->SetVertexShaderConstant(4, &LightDir, 1);

	//Do the same for the light position
	D3DXVec4Transform(&LightPos, &LightPos, &InverseWorld);
	m_pD3DDevice->SetVertexShaderConstant(7, &LightPos, 1);

	//Draw the mesh object that does not cast shadoww, but does "receive" them.
	m_pD3DDevice->SetStreamSource(0, m_pMeshVertexBuffer, sizeof(MESH_VERTEX));
	m_pD3DDevice->SetIndices(m_pMeshIndexBuffer, 0);
	m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 
    								   m_pMesh->GetNumVertices(), 0,
									   m_pMesh->GetNumFaces());


	D3DXMatrixRotationY(&Rotation, (float)GetTickCount() / 1000.0f);
	D3DXMatrixTranslation(&Translation, 0.0f, 20.0f, 0.0f);
	m_WorldMatrix = Rotation * Translation;
	
	//Set the world matrix and the shader matrix as usual. Also,
	//transform the light parameters to object space. This is all the
	//same as what we've seen before...
	ShaderMatrix = m_WorldMatrix * m_ViewMatrix * m_ProjectionMatrix;
	D3DXMatrixTranspose(&ShaderMatrix, &ShaderMatrix);
	m_pD3DDevice->SetVertexShaderConstant(0, &ShaderMatrix, 4);
	D3DXMatrixInverse(&InverseWorld, &Det, &m_WorldMatrix);
	D3DXVec4Transform(&LightDir, &LightDir, &InverseWorld);
	D3DXVec4Normalize(&LightDir, &LightDir);
	m_pD3DDevice->SetVertexShaderConstant(4, &LightDir, 1);
	D3DXVec4Transform(&LightPos, &LightPos, &InverseWorld);
	m_pD3DDevice->SetVertexShaderConstant(7, &LightPos, 1);

	//Draw the mesh - this is the mesh that is actually seen.
	m_pD3DDevice->SetStreamSource(0, m_pMeshVertexBuffer, sizeof(MESH_VERTEX));
	m_pD3DDevice->SetIndices(m_pMeshIndexBuffer, 0);
	m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 
    								   m_pMesh->GetNumVertices(), 0,
									   m_pMesh->GetNumFaces());


	//Clear the stencil buffer and set it up to always pass.
	//When it passes, have it increment the stencil value.
	m_pD3DDevice->Clear(0, NULL, D3DCLEAR_STENCIL, 0, 1.0f, 0);
    m_pD3DDevice->SetRenderState(D3DRS_STENCILENABLE, TRUE);
    m_pD3DDevice->SetRenderState(D3DRS_STENCILFUNC,   D3DCMP_ALWAYS);
    m_pD3DDevice->SetRenderState(D3DRS_STENCILPASS,   D3DSTENCILOP_INCR);
    m_pD3DDevice->SetRenderState(D3DRS_STENCILREF,    1);
   
	//Make sure that the shadow volume steps do not "corrupt" the
	//real depth values.
	m_pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, FALSE);

    //Don't write to the color buffer
	m_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
    m_pD3DDevice->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_ZERO);
    m_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);

	//Set the volume shader
	m_pD3DDevice->SetVertexShader(m_VolumeShader);

	//The shadows are always under the real objects
	m_pD3DDevice->SetRenderState(D3DRS_ZBIAS, 0);

	//First, draw only the front facing triangles. Any pixel that passes
	//the depth test will set that stencil value to 1
	m_pD3DDevice->SetRenderState(D3DRS_CULLMODE,         D3DCULL_CCW);
	m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 
    							   m_pMesh->GetNumVertices(), 0,
								   m_pMesh->GetNumFaces());


	//Now, draw only the back facing triangles. They will decrement
	//the stencil value. This will essentially clear all the values
	//except for the real surfaces that intersect the shadow volume.
	m_pD3DDevice->SetRenderState(D3DRS_CULLMODE,         D3DCULL_CW);
    m_pD3DDevice->SetRenderState(D3DRS_STENCILPASS,   D3DSTENCILOP_DECR);
	m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 
    							   m_pMesh->GetNumVertices(), 0,
    							   m_pMesh->GetNumFaces());


    //Now, we set up the stencil test to draw the big shadow rectangle.
	//This test will draw a "shadow" everywhere that the stencil value is 1
	m_pD3DDevice->SetRenderState(D3DRS_STENCILFUNC,   D3DCMP_LESSEQUAL);
    m_pD3DDevice->SetRenderState(D3DRS_STENCILPASS,   D3DSTENCILOP_KEEP);
    m_pD3DDevice->SetRenderState(D3DRS_STENCILREF,    1);

	//Turn off depth testing and culling for our big rectangle. Also,
	//set the alpha blending to use the transparency of the rectangle. The 
	//more transparent it is, the lighter the shadow.
	m_pD3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
	m_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
    m_pD3DDevice->SetRenderState(D3DRS_SRCBLEND,  D3DBLEND_SRCALPHA);
    m_pD3DDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

	//Draw..
	m_pD3DDevice->SetVertexShader(D3DFVF_MASKVERTEX);
	m_pD3DDevice->SetStreamSource(0, m_pMaskVertexBuffer, sizeof(MASK_VERTEX));
	m_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

    //Set all the tests back to "normal" for the next drawing pass
	m_pD3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE);
    m_pD3DDevice->SetRenderState(D3DRS_STENCILENABLE, FALSE);
    m_pD3DDevice->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);
    m_pD3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
}

HRESULT CTechniqueApplication::LoadMesh()
{
	LPD3DXBUFFER pD3DXMtrlBuffer;
	LPD3DXMESH   pOriginalMesh;

    //Load and initialize the mesh. This is a repeat of the code
	//from Chapter 10.
	if(FAILED(D3DXLoadMeshFromX("..\\media\\fattorus.x",
								D3DXMESH_MANAGED, 
                                m_pD3DDevice, NULL, &pD3DXMtrlBuffer,
								&m_NumMaterials, &pOriginalMesh)))
        return FALSE;

	D3DXMATERIAL* d3dxMaterials = 
		(D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();

    m_pMeshMaterials = new D3DMATERIAL8[m_NumMaterials];

    for(long MatCount = 0; MatCount < m_NumMaterials; MatCount++)
		m_pMeshMaterials[MatCount] = d3dxMaterials[MatCount].MatD3D;

    pD3DXMtrlBuffer->Release();

	//This is new. If the FVF doesn't match, clone the mesh and
	//create one that does. Then, release the loaded mesh. If the 
	//FVF does match, set the member mesh and move on.
	if (pOriginalMesh->GetFVF() != D3DFVF_MESHVERTEX)
	{
		pOriginalMesh->CloneMeshFVF(D3DXMESH_MANAGED,
									D3DFVF_MESHVERTEX,
                                    m_pD3DDevice, &m_pMesh);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?