⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 techniqueapplication.cpp

📁 real-time(实时渲染技术DirectX)37-40
💻 CPP
字号:
/***************************************************************
* 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 LOOK_AHEAD 0.5f

#define D3DFVF_MESHVERTEX (D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE)

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

CTechniqueApplication::CTechniqueApplication()
{
	m_pTerrainVertexBuffer     = NULL;
	m_pTerrainIndexBuffer      = NULL;
	m_pTerrainMesh             = NULL;
	m_pCubeVertexBuffer        = NULL;
	m_pCubeIndexBuffer         = NULL;
	m_pCubeMesh                = NULL;
	m_BasicShader              = 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
	LoadMeshes();

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

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

	return TRUE;
}

void CTechniqueApplication::Render()
{
	//Set the eye position
	D3DXVECTOR4 EyePos(10.0, 2.5f, 00.0f, 0.0f);

	//Set the view matrix based on the position above.
	D3DXMatrixLookAtLH(&m_ViewMatrix, &(D3DXVECTOR3)EyePos,
		               &D3DXVECTOR3(0.0f, 2.0f, 0.0f),
					   &D3DXVECTOR3(0.0f, 1.0f, 0.0f));


	//Set the current light shader
	m_pD3DDevice->SetVertexShader(m_BasicShader);

	//Set some lighting constants
	D3DXVECTOR4 Ambient    (0.1,  0.1f, 0.1f, 0.0f);
	m_pD3DDevice->SetVertexShaderConstant(5, &Ambient, 1);

	//Set the light direction
	D3DXVECTOR4 LightDir = D3DXVECTOR4(0.0f, -1.0f, 0.0f, 0.0f);
	D3DXMATRIX InverseWorld;
	D3DXMatrixInverse(&InverseWorld, NULL, &m_WorldMatrix);
	D3DXVec4Transform(&LightDir, &LightDir, &InverseWorld);
	D3DXVec4Normalize(&LightDir, &LightDir);
	m_pD3DDevice->SetVertexShaderConstant(4, &LightDir, 1);


	//Create the concatenated transformation matrix
	D3DXMATRIX ShaderMatrix = m_WorldMatrix * m_ViewMatrix * 
				              m_ProjectionMatrix;
	D3DXMatrixTranspose(&ShaderMatrix, &ShaderMatrix);
	m_pD3DDevice->SetVertexShaderConstant(0, &ShaderMatrix, 4);

	//Render the terrain
	m_pD3DDevice->SetStreamSource(0, m_pTerrainVertexBuffer, sizeof(MESH_VERTEX));
	m_pD3DDevice->SetIndices(m_pTerrainIndexBuffer, 0);
	m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 
    								   m_pTerrainMesh->GetNumVertices(), 0,
									   m_pTerrainMesh->GetNumFaces());

	D3DXVECTOR3 Position(0.0f, 0.0f, 2.0f * sin((float)GetTickCount() / 2000.0f));
	D3DXVECTOR3 Position2(0.0f, 0.0f, 2.0f * sin(1.0f + (float)GetTickCount() / 2000.0f));
	D3DXVECTOR3 Direction = Position2 - Position;
	D3DXVec3Normalize(&Direction, &Direction);
	D3DXMATRIX CubeMatrix;
	GetTransformation(&Position, &Direction, &CubeMatrix);

	ShaderMatrix = CubeMatrix * m_ViewMatrix * m_ProjectionMatrix;
	D3DXMatrixTranspose(&ShaderMatrix, &ShaderMatrix);
	m_pD3DDevice->SetVertexShaderConstant(0, &ShaderMatrix, 4);

	m_pD3DDevice->SetVertexShaderConstant(4, &LightDir, 1);

	//render the cube
	m_pD3DDevice->SetStreamSource(0, m_pCubeVertexBuffer, sizeof(MESH_VERTEX));
	m_pD3DDevice->SetIndices(m_pCubeIndexBuffer, 0);
	m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 
    								   m_pCubeMesh->GetNumVertices(), 0,
									   m_pCubeMesh->GetNumFaces());
}

HRESULT CTechniqueApplication::LoadMeshes()
{
	LPD3DXMESH    pOriginalMesh;

	if(FAILED(D3DXLoadMeshFromX("..\\media\\TerrainRamp.x",
								D3DXMESH_MANAGED, 
                                m_pD3DDevice, NULL, NULL,
								NULL, &pOriginalMesh)))
        return FALSE;

	if (pOriginalMesh->GetFVF() != D3DFVF_MESHVERTEX)
	{
		pOriginalMesh->CloneMeshFVF(D3DXMESH_MANAGED,
									D3DFVF_MESHVERTEX,
                                    m_pD3DDevice, &m_pTerrainMesh);
		
		pOriginalMesh->Release();
		pOriginalMesh = NULL;
	}
	else
		m_pTerrainMesh = pOriginalMesh;

	LPD3DXMESH    pOriginalMesh2;

	if(FAILED(D3DXLoadMeshFromX("..\\media\\smallcube.x",
								D3DXMESH_MANAGED, 
                                m_pD3DDevice, NULL, NULL,
								NULL, &pOriginalMesh2)))
        return FALSE;

	if (pOriginalMesh2->GetFVF() != D3DFVF_MESHVERTEX)
	{
		pOriginalMesh2->CloneMeshFVF(D3DXMESH_MANAGED,
									D3DFVF_MESHVERTEX,
                                    m_pD3DDevice, &m_pCubeMesh);
		
		pOriginalMesh2->Release();
		pOriginalMesh2 = NULL;
	}
	else
		m_pCubeMesh = pOriginalMesh2;

	return S_OK;
}

BOOL CTechniqueApplication::PreReset()
{
	//Delete the shaders
	m_pD3DDevice->DeleteVertexShader(m_BasicShader);

	return TRUE;
}

BOOL CTechniqueApplication::PostReset()
{
	SetupDevice();

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

	return TRUE;
}


BOOL CTechniqueApplication::PreTerminate()
{
	//Delete the shaders
	m_pD3DDevice->DeleteVertexShader(m_BasicShader);
	
	//Clean up
	if (m_pTerrainVertexBuffer)
	{
		m_pTerrainVertexBuffer->Release();
		m_pTerrainVertexBuffer = NULL;
	}

	if (m_pTerrainIndexBuffer)
	{
		m_pTerrainIndexBuffer->Release();
		m_pTerrainIndexBuffer  = NULL;
	}

	if (m_pTerrainMesh)
	{
		m_pTerrainMesh->Release();
		m_pTerrainMesh = NULL;
	}

	if (m_pCubeVertexBuffer)
	{
		m_pCubeVertexBuffer->Release();
		m_pCubeVertexBuffer = NULL;
	}

	if (m_pCubeIndexBuffer)
	{
		m_pCubeIndexBuffer->Release();
		m_pCubeIndexBuffer  = NULL;
	}

	if (m_pCubeMesh)
	{
		m_pCubeMesh->Release();
		m_pCubeMesh = NULL;
	}

	return TRUE;
}


void CTechniqueApplication::SetupDevice()
{
	//Do all the basic setup
	RECT WindowRect;
	GetClientRect(m_hWnd, &WindowRect);
	D3DXMatrixPerspectiveFovLH(&m_ProjectionMatrix,
					D3DX_PI / 4,
					(float)(WindowRect.right - WindowRect.left) / 
					(float)(WindowRect.bottom - WindowRect.top),
				    1.0f, 1000.0f);

	D3DXMatrixIdentity(&m_WorldMatrix);
}

HRESULT CTechniqueApplication::ExtractBuffers()
{
	//Get the buffers
	m_pTerrainMesh->GetVertexBuffer(&m_pTerrainVertexBuffer);
	m_pTerrainMesh->GetIndexBuffer(&m_pTerrainIndexBuffer);
	m_pCubeMesh->GetVertexBuffer(&m_pCubeVertexBuffer);
	m_pCubeMesh->GetIndexBuffer(&m_pCubeIndexBuffer);

	//Color the terrain
	MESH_VERTEX *pMeshVertices;

	//Lock the vertex buffer, but allow writing.
	m_pTerrainVertexBuffer->Lock(0, m_pTerrainMesh->GetNumVertices() * sizeof(MESH_VERTEX),
		                        (BYTE **)&pMeshVertices, 0);

	//Set the general terrain color
	D3DXCOLOR Diffuse = 0xff00ff00;

	//Set all the terrain vertices
	for (long Vertex = 0; Vertex < m_pTerrainMesh->GetNumVertices(); Vertex++)
	{
		pMeshVertices[Vertex].color = Diffuse;
	}

	//Give back all of our buffers.
	m_pTerrainVertexBuffer->Unlock();

	//Lock the vertex buffer, but allow writing.
	m_pCubeVertexBuffer->Lock(0, m_pCubeMesh->GetNumVertices() * sizeof(MESH_VERTEX),
		                        (BYTE **)&pMeshVertices, 0);

	//Set the general Cube color
	Diffuse = 0xffffffff;

	//Set all the Cube vertices
	for (Vertex = 0; Vertex < m_pCubeMesh->GetNumVertices(); Vertex++)
	{
		pMeshVertices[Vertex].color = Diffuse;
	}

	//Give back all of our buffers.
	m_pCubeVertexBuffer->Unlock();

	return S_OK;
}

HRESULT CTechniqueApplication::CreateShaders()
{
	//Set up the declaration to match the FVF and to
	//read from stream zero.
	DWORD Declaration[] =
	{
		D3DVSD_STREAM(0),
		D3DVSD_REG(D3DVSDE_POSITION,D3DVSDT_FLOAT3),
		D3DVSD_REG(D3DVSDE_NORMAL,  D3DVSDT_FLOAT3),
		D3DVSD_REG(D3DVSDE_DIFFUSE, D3DVSDT_D3DCOLOR),
		D3DVSD_END()
	};

	
	ID3DXBuffer* pShaderBuffer;
	ID3DXBuffer* pShaderErrors;

	//Assemble and create the first shader. Under real circumstances, you would 
	//probably want to do more error handling.
	if (FAILED(D3DXAssembleShaderFromFile("..\\media\\Shaders\\Basic.vsh", 
		                            0, NULL, &pShaderBuffer, &pShaderErrors)))
		return E_FAIL;

	if (FAILED(m_pD3DDevice->CreateVertexShader(Declaration, 
		                           (DWORD *)pShaderBuffer->GetBufferPointer(),
								   &m_BasicShader, 0)))
		return E_FAIL;

	//release the working buffers
	pShaderBuffer->Release();

	return S_OK;
}

void CTechniqueApplication::PreRender()
{
	//Clear the device
	m_pD3DDevice->Clear(0, NULL,
						D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER,
						D3DCOLOR_XRGB(100, 100, 200), 1.0f, 0);

	//Call BeginScene to set up the device
	m_pD3DDevice->BeginScene();
		
	return;
}



float CTechniqueApplication::GetHeightAt(float X, float Z, 
										 D3DXQUATERNION *pRotation)
{
	//Does the ray intersect? (For this sample the answer should always be yes)
	BOOL Intersection;

	//Pick a starting point far above the terrain
	D3DXVECTOR3 RayStart(X, 10000.0f, Z);

	//The ray points straight down
	D3DXVECTOR3 RayDir(0.0f, -1.0f, 0.0f);

	//Which face?
	DWORD FaceIndex;

	//hit coordinates
	float U, V, Distance;
	ID3DXBuffer*     pHitList;
    DWORD            HitCount;

	D3DXIntersect(m_pTerrainMesh, &RayStart, &RayDir, &Intersection,
		          &FaceIndex, &U, &V, &Distance, &pHitList, &HitCount);

	if (Intersection)
	{
		MESH_VERTEX *pMeshVertices;
		short       *pIndices;
		
		//lock the buffers
		m_pTerrainVertexBuffer->Lock(0, 
								  m_pTerrainMesh->GetNumVertices() * sizeof(MESH_VERTEX),
								  (BYTE **)&pMeshVertices, D3DLOCK_READONLY);

		m_pTerrainIndexBuffer->Lock(0, 3 * m_pTerrainMesh->GetNumFaces() * sizeof(short),
								 (BYTE **)&pIndices, D3DLOCK_READONLY);

		//Get the three vertices
		MESH_VERTEX Vertex0 = pMeshVertices[pIndices[FaceIndex * 3 + 0]];
		MESH_VERTEX Vertex1 = pMeshVertices[pIndices[FaceIndex * 3 + 1]];
		MESH_VERTEX Vertex2 = pMeshVertices[pIndices[FaceIndex * 3 + 2]];

		//Give everything back
		m_pTerrainVertexBuffer->Unlock();
		m_pTerrainIndexBuffer->Unlock();

		//Convert the vertices to D3DX vectors for easier math
		D3DXVECTOR3 V0(Vertex0.x, Vertex0.y, Vertex0.z);
		D3DXVECTOR3 V1(Vertex1.x, Vertex1.y, Vertex1.z);
		D3DXVECTOR3 V2(Vertex2.x, Vertex2.y, Vertex2.z);
		
		//Compute the actual intersection point
		D3DXVECTOR3 IntersectionPoint = V0 + U * (V1 - V0) + V * (V2 - V0);

		//Get the face normal from the plane equation
		D3DXPLANE Plane;
		D3DXPlaneFromPoints(&Plane, &V0, &V1, &V2);
		D3DXVECTOR3 PlaneNormal(Plane.a, Plane.b, Plane.c);
		D3DXVECTOR3 CubeNormal(0.0f, 1.0f, 0.0f);

		D3DXVECTOR3 Axis;
		D3DXVec3Cross(&Axis, &CubeNormal, &PlaneNormal);
		float Angle = acos(D3DXVec3Dot(&CubeNormal, &PlaneNormal));

		//Set the matrix
		D3DXQuaternionRotationAxis(pRotation, &Axis, Angle);

		//Return the height
		return IntersectionPoint.y;
	}
	else
		return 0.0f;
}


void CTechniqueApplication::GetTransformation(D3DXVECTOR3 *pCurrentPosition,
											  D3DXVECTOR3 *pDirection,
											  D3DXMATRIX *pTransform)
{
	//Get all the information about the current state
	D3DXQUATERNION CurrentRotation;
	pCurrentPosition->y = GetHeightAt(pCurrentPosition->x, pCurrentPosition->z,
		                              &CurrentRotation);

	//Get all the information about the future state
	D3DXVECTOR3 FuturePosition = *pCurrentPosition + (LOOK_AHEAD * *pDirection);
	D3DXQUATERNION FutureRotation;
	FuturePosition.y = GetHeightAt(FuturePosition.x, FuturePosition.z,
		                           &FutureRotation);

	//working variable for quaternion transformations
	D3DXMATRIX TempTransform;

	//Rotate the direction vector by the future rotation to get
	//the actual plane aligned direction
	D3DXMatrixRotationQuaternion(&TempTransform, &FutureRotation);
	D3DXVECTOR3 FutureAligned;
	D3DXVec3TransformNormal(&FutureAligned, pDirection, &TempTransform);
	D3DXVec3Normalize(&FutureAligned, &FutureAligned);

	//Get the vector between the current and future position
	D3DXVECTOR3 StraightShot = (FuturePosition - *pCurrentPosition);
	D3DXVec3Normalize(&StraightShot, &StraightShot);

	//Get the dot product of the final direction and the straightshot
	float Interpolator = D3DXVec3Dot(&FutureAligned, &StraightShot);

	//translate according to the height interpolation
	D3DXMatrixTranslation(pTransform, pCurrentPosition->x, 
		                  pCurrentPosition->y, pCurrentPosition->z);

	//interpolate the rotation
	D3DXQUATERNION Slerp;
	D3DXQuaternionSlerp(&Slerp, &CurrentRotation, &FutureRotation, Interpolator);
	D3DXMatrixRotationQuaternion(&TempTransform, &Slerp);

	//concatenate
	*pTransform = TempTransform * *pTransform;
}

⌨️ 快捷键说明

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