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

📄 lightingapplication.cpp

📁 real-time(实时渲染技术DirectX)6-12
💻 CPP
字号:
/***************************************************************
* LightingApplication.cpp                                      *
*                                                              *
* This file contains the implementation of the                 *
* CLightingApplication class.								   *
* To compile correctly, this file must be linked with:         *
* kernel32.lib                                                 *
* user32.lib                                                   *
* d3dx8dt.lib                                                  *
* d3d8.lib                                                     *
* gdi32.lib                                                    *
* advapi32.lib                                                 *
*                                                              *
***************************************************************/

#include "LightingApplication.h"

//define the lights
#define SPOT_LIGHT        0
#define DIR_LIGHT         1
#define POINT_LIGHT       2
#define MAX_LIGHT         2


//define the number of vertices to be used
#define NUM_CIRCLE_POINTS    40
#define NUM_CONE_POINTS      6
#define NUM_VERTICES (NUM_CIRCLE_POINTS + NUM_CONE_POINTS)

//Our new vertex structure for the simple lighting visuals
struct VISUALS_VERTEX
{
	float x, y, z;
	DWORD diffuse;
};

//The FVF for the lighting visuals
#define D3DFVF_VISUALSVERTEX (D3DFVF_XYZ | D3DFVF_DIFFUSE)

//Initialize all the pointers
CLightingApplication::CLightingApplication()
{
	m_pMesh          = NULL;
	m_pMeshMaterials = NULL;
	m_NumMaterials   = 0;
	m_CurrentSubset  = 0;
	m_CurrentLight   = 0;
	m_pLightsBuffer  = NULL;
}

CLightingApplication::~CLightingApplication()
{
}

BOOL CLightingApplication::PostInitialize()
{
	if (FAILED(EasyCreateWindowed(m_hWnd, D3DDEVTYPE_HAL, 
					  D3DCREATE_HARDWARE_VERTEXPROCESSING)))
		return FALSE;

	//Set the device states
	SetupDevice();

	//Initialize the data for the lighting visuals
	if (!InitializeLightVisuals())
		return FALSE;

	//Load the sample mesh
	return LoadMesh();
}

void CLightingApplication::SetupDevice()
{
	D3DXMatrixLookAtLH(&m_ViewMatrix, &D3DXVECTOR3(0.0f, 20.0f, -20.0f),
		               &D3DXVECTOR3(0.0f, 0.0f, 0.0f),
					   &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
	m_pD3DDevice->SetTransform(D3DTS_VIEW, &m_ViewMatrix);

	D3DXMatrixIdentity(&m_WorldMatrix);
	m_pD3DDevice->SetTransform(D3DTS_WORLD, &m_WorldMatrix);

	RECT WindowRect;
	GetClientRect(m_hWnd, &WindowRect);
	D3DXMatrixPerspectiveFovLH(&m_ProjectionMatrix,
					D3DX_PI / 8,
					(float)(WindowRect.right - WindowRect.left) / 
					(float)(WindowRect.bottom - WindowRect.top),
				    1.0f, 500.0f);
	m_pD3DDevice->SetTransform(D3DTS_PROJECTION, &m_ProjectionMatrix);

	//Tell the device about the new light
	m_pD3DDevice->LightEnable(0, TRUE);

	//Get the number of lights.  We don't actually use this number
	//for anything.
	D3DCAPS8 Caps;
	m_pD3DDevice->GetDeviceCaps(&Caps);
	DWORD NumLights = Caps.MaxActiveLights;
	
	//Make sure lighting is enabled and there is a little 
	//bit of ambient light.
	m_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
    m_pD3DDevice->SetRenderState(D3DRS_AMBIENT, 0x00101010);

	InitializeLights();
}

BOOL CLightingApplication::PreReset()
{
	//Destroy our own viuals (the mesh is "managed")
	DestroyLightVisuals();
	
	return TRUE;
}

BOOL CLightingApplication::PostReset()
{
	//Make sure the states are reset
	SetupDevice();

	//reinitialize the light visuals
	return InitializeLightVisuals();
}

BOOL CLightingApplication::PreTerminate()
{
	//Destroy everything
	DestroyLightVisuals();
	
	if (m_pMesh)
	{
		m_pMesh->Release();
		m_pMesh = NULL;
	}

	if (m_pMeshMaterials)
	{
		delete m_pMeshMaterials;
		m_pMeshMaterials = NULL;
	}

	return TRUE;
}

BOOL CLightingApplication::HandleMessage(MSG *pMessage)
{
	//Handle user input.  F1 sets the current submesh.
	if (pMessage->message == WM_KEYDOWN && pMessage->wParam == VK_F1)
	{
		if (++m_CurrentSubset > m_NumMaterials - 1)
			m_CurrentSubset = 0;
	}

	//F2 runs through the different light types
	if (pMessage->message == WM_KEYDOWN && pMessage->wParam == VK_F2)
	{
		if (++m_CurrentLight > MAX_LIGHT)
			m_CurrentLight = 0;
	}

	//Mke sure the base class receives any messages
	return CHostApplication::HandleMessage(pMessage);
}


BOOL CLightingApplication::LoadMesh()
{
	//Our basic mesh loading function.  In this case, each sub mesh
	//uses a different material, so we denote submeshes by material.
	LPD3DXBUFFER pD3DXMtrlBuffer;

    if(FAILED(D3DXLoadMeshFromX("..\\media\\planes.x",
								D3DXMESH_MANAGED, 
                                m_pD3DDevice, NULL, &pD3DXMtrlBuffer,
								&m_NumMaterials, &m_pMesh)))
        return FALSE;

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

    m_pMeshMaterials = new D3DMATERIAL8[m_NumMaterials];

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

    pD3DXMtrlBuffer->Release();

	return TRUE;
}

void CLightingApplication::Render()
{
	//Make sure lighting is enabled.  That's the point!
	m_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

	//Make sure the current light is set (in case parameters have changed)
	m_pD3DDevice->SetLight(0, &m_Light[m_CurrentLight]);
	
    //Set the current material
	m_pD3DDevice->SetMaterial(&m_pMeshMaterials[m_CurrentSubset]);
   
    //Draw the current subset
	m_pMesh->DrawSubset(m_CurrentSubset);

	//Render the lighting visuals
	RenderLightVisuals();
}

//This function builds each light.  Experiment with different values to
//see the effect.
void CLightingApplication::InitializeLights()
{
	ZeroMemory(&m_Light[POINT_LIGHT], sizeof(D3DLIGHT8));
	m_Light[POINT_LIGHT].Type         = D3DLIGHT_POINT;
	m_Light[POINT_LIGHT].Diffuse.r    = m_Light[POINT_LIGHT].Diffuse.g = 
							            m_Light[POINT_LIGHT].Diffuse.b = 1.0f;
	m_Light[POINT_LIGHT].Position     = D3DXVECTOR3(0.0f, 1.5f, 0.0f);
	m_Light[POINT_LIGHT].Range        = 5.0f;
	m_Light[POINT_LIGHT].Attenuation0 = 0.0f;
	m_Light[POINT_LIGHT].Attenuation1 = 1.0f;

	ZeroMemory(&m_Light[DIR_LIGHT], sizeof(D3DLIGHT8));
	m_Light[DIR_LIGHT].Type         = D3DLIGHT_DIRECTIONAL;
	m_Light[DIR_LIGHT].Diffuse.r    = m_Light[DIR_LIGHT].Diffuse.g = 
							          m_Light[DIR_LIGHT].Diffuse.b = 1.0f;
	m_Light[DIR_LIGHT].Direction    = D3DXVECTOR3(-1.0f, -1.0f, 1.0f);

	ZeroMemory(&m_Light[SPOT_LIGHT], sizeof(D3DLIGHT8));
	m_Light[SPOT_LIGHT].Type         = D3DLIGHT_SPOT;
	m_Light[SPOT_LIGHT].Diffuse.r    = m_Light[SPOT_LIGHT].Diffuse.g = 
							           m_Light[SPOT_LIGHT].Diffuse.b = 1.0f;
	m_Light[SPOT_LIGHT].Direction    = D3DXVECTOR3(0.0f, -1.0f, 0.0f);
	m_Light[SPOT_LIGHT].Position     = D3DXVECTOR3(0.0f,  5.0f, 0.0f);
	m_Light[SPOT_LIGHT].Theta        = D3DXToRadian(10.0f);
	m_Light[SPOT_LIGHT].Phi          = D3DXToRadian(60.0f);
	m_Light[SPOT_LIGHT].Falloff      = 1.0f;
	m_Light[SPOT_LIGHT].Range        = 10.0f;
	m_Light[SPOT_LIGHT].Attenuation0 = 1.0f;
}

//This function creates visuals for point lights and spot lights.
//There is no visualization for directional lights because it is
//a simple vector.
BOOL CLightingApplication::InitializeLightVisuals()
{
	if (FAILED(m_pD3DDevice->CreateVertexBuffer(
										NUM_VERTICES
										* sizeof(VISUALS_VERTEX),
										D3DUSAGE_WRITEONLY,
										D3DFVF_VISUALSVERTEX,
										D3DPOOL_DEFAULT,
										&m_pLightsBuffer)))
		return FALSE;

	VISUALS_VERTEX *pVertices;

	if (FAILED(m_pLightsBuffer->Lock(0,
					NUM_VERTICES * sizeof(VISUALS_VERTEX),
					(BYTE **)&pVertices,
					0)))
	{
		DestroyLightVisuals();
		return FALSE;
	}

	//an easy way to set all the colors to white
	memset(pVertices, 0xFF, NUM_VERTICES * sizeof(VISUALS_VERTEX));

	//Here we set the vertices for the sides of the spotlight cone.
	//They are set to simple unit values so that they can be scaled
	//easily with transformation matrices.
	pVertices[0].x = -1.0f;	pVertices[0].y = -1.0f; pVertices[0].z = 0.0f;
	pVertices[1].x =  0.0f;	pVertices[1].y =  0.0f; pVertices[1].z = 0.0f;
	pVertices[2].x =  1.0f; pVertices[2].y = -1.0f; pVertices[2].z = 0.0f;

	pVertices[3].x = 0.0f; pVertices[3].y = -1.0f; pVertices[3].z = -1.0f;
	pVertices[4].x = 0.0f; pVertices[4].y =  0.0f; pVertices[4].z =  0.0f;
	pVertices[5].x = 0.0f; pVertices[5].y = -1.0f; pVertices[5].z =  1.0f;

	//Here we create a circle of vertices that will be reused for the point
	//light sphere and the umbra and penumbra of the spotlight. We set several
	//vertices in a lkoop and set the last one separately to ensure the 
	//circle is complete.
	long Counter;
	for (Counter = 0; Counter < NUM_CIRCLE_POINTS - 1; Counter++)
	{
		float Angle = 2.0f * D3DX_PI / (NUM_CIRCLE_POINTS - 1) * Counter;
		pVertices[Counter + NUM_CONE_POINTS].x = cos(Angle);
		pVertices[Counter + NUM_CONE_POINTS].y = sin(Angle);
		pVertices[Counter + NUM_CONE_POINTS].z = 0.0f;
	}
	pVertices[Counter + NUM_CONE_POINTS].x = 1.0f;
	pVertices[Counter + NUM_CONE_POINTS].y = 0.0f;
	pVertices[Counter + NUM_CONE_POINTS].z = 0.0f;

	m_pLightsBuffer->Unlock();

	return TRUE;
}

void CLightingApplication::DestroyLightVisuals()
{
	//Destroy the visuals vertex buffer
	if (m_pLightsBuffer)
	{
		m_pLightsBuffer->Release();
		m_pLightsBuffer = NULL;
	}
}

void CLightingApplication::RenderLightVisuals()
{
	//Here are several reusable matrices.
	D3DXMATRIX Translation;
	D3DXMATRIX Rotation;
	D3DXMATRIX Scaling;
	D3DXMATRIX Transform;
	
	//Here we make sure that lighting is disabled so that it
	//does not affect the simple lines.  We also set the 
	//vertex shader and source.
	m_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
	m_pD3DDevice->SetVertexShader(D3DFVF_VISUALSVERTEX);
	m_pD3DDevice->SetStreamSource(0, m_pLightsBuffer, sizeof(VISUALS_VERTEX));
	
	//Render the spotlight visuals
	if (m_CurrentLight == SPOT_LIGHT)
	{
		//Translate to the light's position
		D3DXMatrixTranslation(&Translation, m_Light[SPOT_LIGHT].Position.x, 
			                                m_Light[SPOT_LIGHT].Position.y, 
									        m_Light[SPOT_LIGHT].Position.z);

		//We'll scale the spotlight cone according to it's distance
		//from the origin.  That defines the "cone of interest" and
		//we can then scale the width of the cone according to the angle.
		//Scale for the penumbra
		FLOAT ConeLength = D3DXVec3Length(&D3DXVECTOR3(m_Light[SPOT_LIGHT].Position));
		FLOAT ConeWidth = ConeLength * tan(m_Light[SPOT_LIGHT].Phi / 2.0f);
		D3DXMatrixScaling(&Scaling, ConeWidth, ConeLength, ConeWidth);
		Transform = Scaling * Translation;
		m_pD3DDevice->SetTransform(D3DTS_WORLD, &Transform);
		m_pD3DDevice->DrawPrimitive(D3DPT_LINESTRIP, 0, 2);
		m_pD3DDevice->DrawPrimitive(D3DPT_LINESTRIP, 3, 2);

		//Now draw the circle - translate to the new position, but keep the
		//circle flush with the mesh.
		D3DXMatrixTranslation(&Translation, m_Light[SPOT_LIGHT].Position.x, 
			                                0.0f, 
									        m_Light[SPOT_LIGHT].Position.z);
		//Rotate the circle so that it is aligned with the mesh. Scale it 
		//according to the cone width.  Set the transform and render it.
		D3DXMatrixRotationX(&Rotation, D3DX_PI / 2.0f);
		D3DXMatrixScaling(&Scaling, ConeWidth, ConeWidth, ConeWidth);
		Transform = Rotation * Scaling * Translation;
		m_pD3DDevice->SetTransform(D3DTS_WORLD, &Transform);
		m_pD3DDevice->DrawPrimitive(D3DPT_LINESTRIP, NUM_CONE_POINTS,
			                        NUM_CIRCLE_POINTS - 1);

		//Now repeat for the umbra
		D3DXMatrixTranslation(&Translation, m_Light[SPOT_LIGHT].Position.x, 
			                                m_Light[SPOT_LIGHT].Position.y, 
									        m_Light[SPOT_LIGHT].Position.z);
		ConeWidth = ConeLength * tan(m_Light[SPOT_LIGHT].Theta / 2.0f);
		D3DXMatrixScaling(&Scaling, ConeWidth, ConeLength, ConeWidth);

		Transform = Scaling * Translation;
		m_pD3DDevice->SetTransform(D3DTS_WORLD, &Transform);

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

		D3DXMatrixTranslation(&Translation, m_Light[SPOT_LIGHT].Position.x, 
			                                0.0f, 
									        m_Light[SPOT_LIGHT].Position.z);
		D3DXMatrixRotationX(&Rotation, D3DX_PI / 2.0f);
		D3DXMatrixScaling(&Scaling, ConeWidth, ConeWidth, ConeWidth);
		Transform = Rotation * Scaling * Translation;
		m_pD3DDevice->SetTransform(D3DTS_WORLD, &Transform);
		m_pD3DDevice->DrawPrimitive(D3DPT_LINESTRIP, NUM_CONE_POINTS,
			                        NUM_CIRCLE_POINTS - 1);
	}

	//For the point light, we position it, scale it, and draw two instances of
	//the circle, rotating the second circle by 90 degrees to create a very
	//simple wireframe.
	if (m_CurrentLight == POINT_LIGHT)
	{	
		D3DXMatrixTranslation(&Translation, m_Light[POINT_LIGHT].Position.x, 
			                                m_Light[POINT_LIGHT].Position.y, 
									        m_Light[POINT_LIGHT].Position.z);
		D3DXMatrixScaling(&Scaling, m_Light[POINT_LIGHT].Range, 
			                        m_Light[POINT_LIGHT].Range, 
									m_Light[POINT_LIGHT].Range);
		Transform = Scaling * Translation;
		m_pD3DDevice->SetTransform(D3DTS_WORLD, &Transform);
		m_pD3DDevice->DrawPrimitive(D3DPT_LINESTRIP, NUM_CONE_POINTS,
			                        NUM_CIRCLE_POINTS - 1);
		D3DXMatrixRotationY(&Rotation, D3DX_PI / 2.0f);
		Transform = Scaling * Rotation * Translation;
		m_pD3DDevice->SetTransform(D3DTS_WORLD, &Transform);
		m_pD3DDevice->DrawPrimitive(D3DPT_LINESTRIP, NUM_CONE_POINTS,
			                        NUM_CIRCLE_POINTS - 1);
	}

	//Make sure that the world transform is set back to the identity matrix.
	D3DXMatrixIdentity(&Transform);
	m_pD3DDevice->SetTransform(D3DTS_WORLD, &Transform);
}

⌨️ 快捷键说明

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