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

📄 techniqueapplication.cpp

📁 real-time(实时渲染技术DirectX)19-24
💻 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 FIRST_BONE 20.0f

struct PALETTESKIN_VERTEX
{
	float x, y, z;
	float nx, ny, nz;
	float Bone1, Weight1, Bone2, Weight2;
};

DWORD PaletteSkinDeclaration[] =
{
	D3DVSD_STREAM(0),
	D3DVSD_REG(D3DVSDE_POSITION, D3DVSDT_FLOAT3),
	D3DVSD_REG(D3DVSDE_NORMAL,   D3DVSDT_FLOAT3),
	D3DVSD_REG(D3DVSDE_TEXCOORD0,D3DVSDT_FLOAT4),
	D3DVSD_END()
};

#define D3DFVF_PALETTESKINVERTEX  (D3DFVF_XYZ | D3DFVF_NORMAL | \
								   D3DFVF_TEX0 | D3DFVF_TEXCOORDSIZE4(0))

CTechniqueApplication::CTechniqueApplication()
{
	m_pMeshVertexBuffer     = NULL;
	m_pBoneVertexBuffer     = NULL;
	m_pMeshIndexBuffer      = NULL;
	m_pMesh                 = NULL;
	m_pMeshMaterials        = NULL;
	m_NumMaterials          = 0;
	m_SkinShader            = 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
	if (FAILED(LoadMesh()))
		return FALSE;

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

	//Create the grid visuals
	if (FAILED(CreateBones()))
		return FALSE;

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

	return TRUE;
}

void CTechniqueApplication::Render()
{
	SetBoneConstants();
	
	//D3DXMatrixRotationY(&m_WorldMatrix, (float)GetTickCount() / 1000.0f);
	
	//Create the concatenated transformation matrix
	D3DXMATRIX ShaderMatrix = m_WorldMatrix * 
		                      m_ViewMatrix * 
							  m_ProjectionMatrix;

	D3DXMatrixTranspose(&ShaderMatrix, &ShaderMatrix);
	m_pD3DDevice->SetVertexShaderConstant(0, &ShaderMatrix, 4);

	//Set some basic parameters
	D3DXVECTOR4 LightDir(0.0f,  -1.0f, 0.0f, 0.0f);
	D3DXVECTOR4 Ambient (0.1f,  0.1f, 0.1f, 1.0f);
	D3DXVECTOR4 One     (1.0f,  0.0f, 0.0f, 0.0f);

	//Convert the light direction to object space and normalize
	D3DXMATRIX WorldInverse;
	D3DXMatrixInverse(&WorldInverse, NULL, &m_WorldMatrix);
	D3DXVec4Transform(&LightDir, &LightDir, &WorldInverse);
	D3DXVec4Normalize(&LightDir, &LightDir);

	//Set the Constants
	m_pD3DDevice->SetVertexShaderConstant(4, &LightDir, 1);
	m_pD3DDevice->SetVertexShaderConstant(5, &Ambient, 1);
	m_pD3DDevice->SetVertexShaderConstant(6, &One, 1);

	m_pD3DDevice->SetVertexShader(m_SkinShader);

	m_pD3DDevice->SetStreamSource(0, m_pMeshVertexBuffer, sizeof(PALETTESKIN_VERTEX));
	m_pD3DDevice->SetIndices(m_pMeshIndexBuffer, 0);

	//Uncomment this to see the wireframe view
	//m_pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);

	m_pD3DDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 
									   m_pMesh->GetNumVertices(), 0,
									   m_pMesh->GetNumFaces());

	//make sure the fillmode is reset for other things (like font rendering)
	m_pD3DDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);

	//Render the control grid. Comment this out if you'd like
	RenderBones();
}

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

	if(FAILED(D3DXLoadMeshFromX("..\\media\\cylinder.x",
								D3DXMESH_MANAGED, 
                                m_pD3DDevice, NULL, &pD3DXMtrlBuffer,
								&m_NumMaterials, &pOriginalMesh)))
        return E_FAIL;

	if(FAILED(pOriginalMesh->CloneMesh(D3DXMESH_MANAGED,
							           PaletteSkinDeclaration,
                                       m_pD3DDevice, &m_pMesh)))
        return E_FAIL;
		
	pOriginalMesh->Release();
	pOriginalMesh = NULL;

	return S_OK;
}

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

	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_SkinShader);
	
	//Clean up
	if (m_pMeshVertexBuffer)
	{
		m_pMeshVertexBuffer->Release();
		m_pMeshVertexBuffer = NULL;
	}

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

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

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

	if (m_pMeshMaterials)
	{
		delete m_pMeshMaterials;
		m_pMeshMaterials = 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);

	D3DXMatrixLookAtLH(&m_ViewMatrix, &D3DXVECTOR3(50.0f, 0.0f, 0.0f),
		               &D3DXVECTOR3(0.0f, -10.0f, 10.0f),
					   &D3DXVECTOR3(0.0f, 1.0f, 0.0f));

	D3DXMatrixIdentity(&m_WorldMatrix);
}

HRESULT CTechniqueApplication::ExtractBuffers()
{
	//Get the buffers
	m_pMesh->GetVertexBuffer(&m_pMeshVertexBuffer);
	m_pMesh->GetIndexBuffer(&m_pMeshIndexBuffer);

	PALETTESKIN_VERTEX *pMeshVertices;

	//Lock the vertex buffer, but allow writing.
	m_pMeshVertexBuffer->Lock(0, 
		                      m_pMesh->GetNumVertices() * sizeof(PALETTESKIN_VERTEX),
		                      (BYTE **)&pMeshVertices, 0);

	//The cylinder is 36 units long, so it's broken up into three 12 unit
	//segments...
	for (long Vertex = 0; Vertex < m_pMesh->GetNumVertices(); Vertex++)
	{
		if (pMeshVertices[Vertex].z < 12.0f)
		{
			pMeshVertices[Vertex].Bone1 = FIRST_BONE + 4.0f; 
			pMeshVertices[Vertex].Weight1 = 1.0f;
			pMeshVertices[Vertex].Bone2 = FIRST_BONE + 4.0f;
			pMeshVertices[Vertex].Weight2 = 0.0f;
		}
		else if (pMeshVertices[Vertex].z < 24.0f)
		{
			pMeshVertices[Vertex].Bone1 = FIRST_BONE + 4.0f; 
			pMeshVertices[Vertex].Weight1 = 0.0f;
			pMeshVertices[Vertex].Bone2 = FIRST_BONE + 8.0f;
			pMeshVertices[Vertex].Weight2 = 1.0f;
		}
		else
		{
			pMeshVertices[Vertex].Bone1 = FIRST_BONE + 8.0f; 
			pMeshVertices[Vertex].Weight1 = 0.0f;
			pMeshVertices[Vertex].Bone2 = FIRST_BONE + 12.0f;
			pMeshVertices[Vertex].Weight2 = 1.0f;
		}
	}

	//This smoothens out the joints. In this case, I only smooth out one side and let the
	//inner part of the joint collapse on itself. Other cases may require a different setup.
	for (Vertex = 0; Vertex < m_pMesh->GetNumVertices(); Vertex++)
	{
		if (pMeshVertices[Vertex].z > 11.0f && 
			pMeshVertices[Vertex].z < 13.0f && 
			pMeshVertices[Vertex].y > 0.0f)
		{
			float Weight = (pMeshVertices[Vertex].z - 11.0f) / 2.0f;
			pMeshVertices[Vertex].Bone1 = FIRST_BONE + 4.0f; 
			pMeshVertices[Vertex].Weight1 = 1.0f - Weight;
			pMeshVertices[Vertex].Bone2 = FIRST_BONE + 8.0f;
			pMeshVertices[Vertex].Weight2 = Weight;
		}
		if (pMeshVertices[Vertex].z > 23.0f && 
			pMeshVertices[Vertex].z < 25.0f && 
			pMeshVertices[Vertex].y > 0.0f)
		{
			float Weight = (pMeshVertices[Vertex].z - 23.0f) / 2.0f;
			pMeshVertices[Vertex].Bone1 = FIRST_BONE + 8.0f; 
			pMeshVertices[Vertex].Weight1 = 1.0f - Weight;
			pMeshVertices[Vertex].Bone2 = FIRST_BONE + 12.0f;
			pMeshVertices[Vertex].Weight2 = Weight;
		}
	}

	//Give back the buffer.
	m_pMeshVertexBuffer->Unlock();

	return S_OK;
}

HRESULT CTechniqueApplication::CreateShaders()
{	
	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\\PaletteSkin.vsh", 
		                            0, NULL, &pShaderBuffer, &pShaderErrors)))
		return E_FAIL;

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

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

	return S_OK;
}

void CTechniqueApplication::RenderBones()
{
	//use the ambient light to color the data (c5 is ambient light)
	D3DXVECTOR4 LineColor (1.0f,  0.0f, 0.0f, 1.0f);
	m_pD3DDevice->SetVertexShaderConstant(5, &LineColor, 1);
	
	m_pD3DDevice->SetStreamSource(0, m_pBoneVertexBuffer, sizeof(PALETTESKIN_VERTEX));

	m_pD3DDevice->DrawPrimitive(D3DPT_LINESTRIP, 0, 3);

	D3DXVECTOR4 PointColor (1.0f,  1.0f, 0.0f, 1.0f);
	m_pD3DDevice->SetVertexShaderConstant(5, &PointColor, 1);

	float PointSize = 5.0f;
	m_pD3DDevice->SetRenderState(D3DRS_POINTSIZE, *((DWORD*)&PointSize));
	m_pD3DDevice->DrawPrimitive(D3DPT_POINTLIST, 0, 4);
}

HRESULT CTechniqueApplication::CreateBones()
{
	//Create as managed so we don't have to worry about recreating it
	//if the device is lost.
	if (FAILED(m_pD3DDevice->CreateVertexBuffer(4 * sizeof(PALETTESKIN_VERTEX), 
		                                        0, D3DFVF_PALETTESKINVERTEX,
									            D3DPOOL_MANAGED,
												&m_pBoneVertexBuffer)))
		return E_FAIL;

	//Render the control grid. Comment this out if you don't care.
	PALETTESKIN_VERTEX *pVertices;

	//Lock the vertex buffer, but allow writing.
	m_pBoneVertexBuffer->Lock(0, 4 * sizeof(PALETTESKIN_VERTEX), (BYTE **)&pVertices, 0);

	pVertices[0].x = 0.0f;	pVertices[0].y = 0.0f;	pVertices[0].z =  0.0f;
	pVertices[1].x = 0.0f;	pVertices[1].y = 0.0f;	pVertices[1].z =  12.0f;
	pVertices[2].x = 0.0f;	pVertices[2].y = 0.0f;	pVertices[2].z =  24.0f;
	pVertices[3].x = 0.0f;	pVertices[3].y = 0.0f;	pVertices[3].z =  36.0f;

	
	//The bone indices are 0 based, and there are three constants
	//per bone, so we set the vertices accordingly.
	pVertices[0].Bone1 = FIRST_BONE + 0.0f;  pVertices[0].Weight1 = 1.0f;
	pVertices[0].Bone2 = FIRST_BONE + 0.0f;  pVertices[0].Weight2 = 0.0f;

	pVertices[1].Bone1 = FIRST_BONE + 4.0f;  pVertices[1].Weight1 = 1.0f;
	pVertices[1].Bone2 = FIRST_BONE + 4.0f;  pVertices[1].Weight2 = 0.0f;

	pVertices[2].Bone1 = FIRST_BONE + 8.0f;  pVertices[2].Weight1 = 1.0f;
	pVertices[2].Bone2 = FIRST_BONE + 8.0f;  pVertices[2].Weight2 = 0.0f;

	pVertices[3].Bone1 = FIRST_BONE + 12.0f; pVertices[3].Weight1 = 1.0f;
	pVertices[3].Bone2 = FIRST_BONE + 12.0f; pVertices[3].Weight2 = 0.0f;

	m_pBoneVertexBuffer->Unlock();

	return S_OK;
}

void CTechniqueApplication::SetBoneConstants()
{
	D3DXMATRIX Bone1;
	D3DXMATRIX Bone2;
	D3DXMATRIX Bone3;
	D3DXMATRIX Bone4;

	//our good friend the general purpose animator...
	float Time = (float)GetTickCount() / 2000.0f;
	float Angle = (D3DX_PI / 2.0f) * fabs(sin(Time));

	D3DXMATRIX PosOffset;
	D3DXMATRIX NegOffset;
	D3DXMatrixTranslation(&PosOffset, 0.0f, 0.0f,  12.0f);
	D3DXMatrixTranslation(&NegOffset, 0.0f, 0.0f, -12.0f);


	//This code is just here to mimic the setup that would normally be done 
	//in a modelling tool. It generates a simple rotation matrix, and then...
	D3DXMATRIX SimpleRotate;
	D3DXMatrixRotationX(&SimpleRotate, Angle);

	//Move the base bone a little bit. If this were an arm, we'd be moving
	//the shoulder.
	D3DXMatrixTranslation(&Bone1, 0.0f, 5.0f * sin(Time), 0.0f);

	//Rotate the "shoulder"
	Bone2 = SimpleRotate * Bone1;

	//Offset the matrix along the arm so that the rotation happens
	//at the "elbow"
	Bone3 = SimpleRotate * PosOffset * Bone2;

	//Offset again and rotate at the "wrist"
	Bone4 = SimpleRotate * PosOffset * Bone3;

	//Undo the translation offsets so that the translation does not
	//affect the actual model.
	Bone3 = NegOffset * Bone3;
	Bone4 = NegOffset * NegOffset * Bone4;

	//Transpose the matrices and send them out...
	D3DXMatrixTranspose(&Bone1, &Bone1);
	D3DXMatrixTranspose(&Bone2, &Bone2);
	D3DXMatrixTranspose(&Bone3, &Bone3);
	D3DXMatrixTranspose(&Bone4, &Bone4);

	m_pD3DDevice->SetVertexShaderConstant(FIRST_BONE + 0,  &Bone1, 4);
	m_pD3DDevice->SetVertexShaderConstant(FIRST_BONE + 4,  &Bone2, 4);
	m_pD3DDevice->SetVertexShaderConstant(FIRST_BONE + 8,  &Bone3, 4);
	m_pD3DDevice->SetVertexShaderConstant(FIRST_BONE + 12, &Bone4, 4);

}

⌨️ 快捷键说明

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