首页 > 代码库 > 游戏框架其九:灯光和材质( Lights and Material )

游戏框架其九:灯光和材质( Lights and Material )

灯光和材质的实现如下:

1. 灯光

#pragma once
//=========================================================================
// Lights.h - implements a simple light class for the scene graph
//=========================================================================


#include "D3DRenderer.h"
#include "Geometry.h"
#include "Scene.h"
#include "SceneNodes.h"

// 光的颜色刚好反映在材质上面
// Note: Light color is stored in the Material structure, which is already present in all SceneNodes.

//
// struct LightProperties
//
struct LightProperties
{
	float	m_Attenuation[3];  /* Attenuation coefficients 衰减系数 */
	float	m_Range;           /* 光照范围 */
	float	m_Falloff;        
	float	m_Theta;
	float	m_Phi;
};


//
// class LightNode
//
//    Note: In the book this class implements the LightNode in D3D11, but here it is a base
//    class. The derived classes make it possible to run the engine in D3D9 or D3D11.
//

typedef unsigned int ActorId;
typedef unsigned int GameViewId;
typedef D3DXCOLOR    Color;
typedef unsigned int  DWORD;
typedef unsigned char  BYTE;
#define GCC_NEW new
enum HRESULT {
    E_INVALIDARG,
    E_FAIL,
    S_OK,
};

class LightNode : public SceneNode
{
protected:
	LightProperties m_LightProps;

public:
	LightNode(const ActorId actorId, WeakBaseRenderComponentPtr renderComponent, const LightProperties &props, const Mat4x4 *t);
};


class D3DLightNode9 : public LightNode
{
public:
	D3DLightNode9(const ActorId actorId, WeakBaseRenderComponentPtr renderComponent, const LightProperties &lightProps, const Mat4x4 *t)
		: LightNode(actorId, renderComponent, lightProps,  t) { }

	D3DLIGHT9	m_d3dLight9;

	virtual HRESULT VOnRestore(Scene *pScene);
	virtual HRESULT VOnUpdate(Scene *, DWORD const elapsedMs);
};


class D3DLightNode11 : public LightNode
{
public:
	D3DLightNode11(const ActorId actorId, WeakBaseRenderComponentPtr renderComponent,  const LightProperties &lightProps, const Mat4x4 *t)
		: LightNode(actorId, renderComponent, lightProps,  t) { }

	virtual HRESULT VOnRestore() { return S_OK; };
	virtual HRESULT VOnUpdate(Scene *, DWORD const elapsedMs);
};


struct ConstantBuffer_Lighting;


//
// class LightManager
//
class LightManager
{
	friend class Scene;

protected:
	Lights					m_Lights;
	Vec4					m_vLightDir[MAXIMUM_LIGHTS_SUPPORTED];
    Color					m_vLightDiffuse[MAXIMUM_LIGHTS_SUPPORTED];
	Vec4					m_vLightAmbient;
public:
	void CalcLighting(Scene *pScene);
	void CalcLighting(ConstantBuffer_Lighting* pLighting, SceneNode *pNode);
	int GetLightCount(const SceneNode *node) { return m_Lights.size(); }
	const Vec4 *GetLightAmbient(const SceneNode *node) { return &m_vLightAmbient; }
	const Vec4 *GetLightDirection(const SceneNode *node) { return m_vLightDir; }
	const Color *GetLightDiffuse(const SceneNode *node) { return m_vLightDiffuse; }
};
//=========================================================================
// Lights.h - implements a simple light class for the GameCode4 scene graph
//=========================================================================


#include "GameCodeStd.h"

#include "GameCode.h"
#include "RenderComponent.h"
#include "Lights.h"


LightNode::LightNode(const ActorId actorId, WeakBaseRenderComponentPtr renderComponent, const LightProperties &props,  const Mat4x4 *t)
 : SceneNode(actorId, renderComponent,  RenderPass_NotRendered,  t) 
{
	m_LightProps = props;
}

HRESULT D3DLightNode9::VOnRestore(Scene *pScene)
{
	ZeroMemory( &m_d3dLight9, sizeof(D3DLIGHT9) );
    m_d3dLight9.Type        = D3DLIGHT_DIRECTIONAL;

	// These parameters are constant for the list after the scene is loaded
	m_d3dLight9.Range        = m_LightProps.m_Range;
    m_d3dLight9.Falloff		= m_LightProps.m_Falloff;
	m_d3dLight9.Attenuation0	= m_LightProps.m_Attenuation[0];
    m_d3dLight9.Attenuation1	= m_LightProps.m_Attenuation[0];
    m_d3dLight9.Attenuation2	= m_LightProps.m_Attenuation[0];
    m_d3dLight9.Theta			= m_LightProps.m_Theta;
    m_d3dLight9.Phi			= m_LightProps.m_Phi;

	return S_OK;
}


HRESULT D3DLightNode9::VOnUpdate(Scene *, DWORD const elapsedMs)
{
	// light color can change anytime! Check the BaseRenderComponent!
	LightRenderComponent* lrc = static_cast<LightRenderComponent*>(m_RenderComponent);
	m_Props.GetMaterial().SetDiffuse(lrc->GetColor());

	m_d3dLight9.Diffuse = m_Props.GetMaterial().GetDiffuse();
	float power;
	Color spec;
    m_Props.GetMaterial().GetSpecular(spec, power);
	m_d3dLight9.Specular = spec;
    m_d3dLight9.Ambient = m_Props.GetMaterial().GetAmbient();

	m_d3dLight9.Position = GetPosition();
	m_d3dLight9.Direction = GetDirection();
	return S_OK;
}

HRESULT D3DLightNode11::VOnUpdate(Scene *, DWORD const elapsedMs)
{ 
	// light color can change anytime! Check the BaseRenderComponent!
	LightRenderComponent* lrc = static_cast<LightRenderComponent*>(m_RenderComponent);
	m_Props.GetMaterial().SetDiffuse(lrc->GetColor());
	return S_OK; 
}


//
// LightManager::CalcLighting
//
void LightManager::CalcLighting(Scene *pScene)
{
	// FUTURE WORK: There might be all kinds of things you'd want to do here for optimization, especially turning off lights on actors that can't be seen, etc.
	pScene->GetRenderer()->VCalcLighting(&m_Lights, MAXIMUM_LIGHTS_SUPPORTED);

	int count = 0;

	GCC_ASSERT(m_Lights.size() < MAXIMUM_LIGHTS_SUPPORTED);
	for(Lights::iterator i=m_Lights.begin(); i!=m_Lights.end(); ++i, ++count)
	{
		shared_ptr<LightNode> light = *i;

		if (count==0)
		{
			// Light 0 is the only one we use for ambient lighting. The rest are ignored in the simple shaders used for GameCode4.
			Color ambient = light->VGet()->GetMaterial().GetAmbient();
			m_vLightAmbient = D3DXVECTOR4(ambient.r, ambient.g, ambient.b, 1.0f); 		
		}

		Vec3 lightDir = light->GetDirection();
		m_vLightDir[count] = D3DXVECTOR4(lightDir.x, lightDir.y, lightDir.z, 1.0f);
		m_vLightDiffuse[count] = light->VGet()->GetMaterial().GetDiffuse();
	}
}


void LightManager::CalcLighting(ConstantBuffer_Lighting* pLighting, SceneNode *pNode)
{
	int count = GetLightCount(pNode);
	if (count)
	{
		pLighting->m_vLightAmbient = *GetLightAmbient(pNode);
		memcpy(pLighting->m_vLightDir, GetLightDirection(pNode), sizeof( Vec4 ) * count );
		memcpy(pLighting->m_vLightDiffuse, GetLightDiffuse(pNode), sizeof( Vec4 ) * count);
		pLighting->m_nNumLights = count;
	}
}
2. 材质
#pragma once
//==============================================================================
// File: Material.h - stores texture and material information for D3D9 and D3D11
//==============================================================================

//  class Material

#include "Geometry.h"
#include "ResCache.h"

class Material
{
	D3DMATERIAL9 m_D3DMaterial;// This structure stores diffuse,ambient,specular,emissive,power.
public:
	Material();
	void SetAmbient(const Color &color);
	const Color GetAmbient() { return m_D3DMaterial.Ambient; }

	void SetDiffuse(const Color &color);
	const Color GetDiffuse() { return m_D3DMaterial.Diffuse; }

	void SetSpecular(const Color &color, const float power);
	void GetSpecular(Color &_color, float &_power) 
		{ _color = m_D3DMaterial.Specular; _power = m_D3DMaterial.Power; }

	void SetEmissive(const Color &color);
	const Color GetEmissive() { return m_D3DMaterial.Emissive; }

	void SetAlpha(const float alpha);
	bool HasAlpha() const { return GetAlpha() != fOPAQUE; }
	float GetAlpha() const { return m_D3DMaterial.Diffuse.a; }

	void D3DUse9();
};

// 
//  class D3DTextureResourceExtraData9, also see D3DTextureResourceExtraData11
//
class D3DTextureResourceExtraData9 : public IResourceExtraData
{
	friend class TextureResourceLoader;

public:
	D3DTextureResourceExtraData9();
	virtual ~D3DTextureResourceExtraData9() { SAFE_RELEASE(m_pTexture); }
	virtual std::string VToString() { return "D3DTextureResourceExtraData9"; }

	LPDIRECT3DTEXTURE9 const GetTexture() { return m_pTexture; }

protected:
	LPDIRECT3DTEXTURE9		m_pTexture;			
};

// 
//  class D3DTextureResourceExtraData11
//
class D3DTextureResourceExtraData11 : public IResourceExtraData
{
	friend class TextureResourceLoader;

public:
	D3DTextureResourceExtraData11();
	virtual ~D3DTextureResourceExtraData11() { SAFE_RELEASE(m_pTexture); SAFE_RELEASE(m_pSamplerLinear); }
	virtual std::string VToString() { return "D3DTextureResourceExtraData11"; }

	ID3D11ShaderResourceView * const *GetTexture() { return &m_pTexture; }
	ID3D11SamplerState * const *GetSampler() { return &m_pSamplerLinear; }

protected:
	ID3D11ShaderResourceView *m_pTexture;			
	ID3D11SamplerState* m_pSamplerLinear;
};



// 
//  class TextureResourceLoader				
//
class TextureResourceLoader : public IResourceLoader
{
public:
	virtual bool VUseRawFile() { return false; }
	virtual bool VDiscardRawBufferAfterLoad() { return true; }
	virtual unsigned int VGetLoadedResourceSize(char *rawBuffer, unsigned int rawSize);
	virtual bool VLoadResource(char *rawBuffer, unsigned int rawSize, shared_ptr<ResHandle> handle);
};
//================================================================================
// File: Material.cpp - stores texture and material information for D3D9 and D3D11
//================================================================================

#include "GameCodeStd.h"
#include "GameCode.h"
#include "ResCache.h"
#include "SceneNodes.h"


////////////////////////////////////////////////////
// class Material				
////////////////////////////////////////////////////

Material::Material()
{
	ZeroMemory( &m_D3DMaterial, sizeof( D3DMATERIAL9 ) );
	m_D3DMaterial.Diffuse = g_White;
	m_D3DMaterial.Ambient = Color(0.10f, 0.10f, 0.10f, 1.0f);		
	m_D3DMaterial.Specular = g_White;
	m_D3DMaterial.Emissive = g_Black;
}

void Material::SetAmbient(const Color &color)
{
	m_D3DMaterial.Ambient = color;
}

void Material::SetDiffuse(const Color &color)
{
	m_D3DMaterial.Diffuse = color;
}

void Material::SetSpecular(const Color &color, const float power)
{
	m_D3DMaterial.Specular = color;
	m_D3DMaterial.Power = power;
}

void Material::SetEmissive(const Color &color)
{
	m_D3DMaterial.Emissive = color;
}

void Material::SetAlpha(float alpha)
{
	m_D3DMaterial.Diffuse.a = alpha;
}

void Material::D3DUse9()
{
	DXUTGetD3D9Device()->SetMaterial( &m_D3DMaterial );	
}


//
// class DdsResourceLoader	- creates an interface with the Resource cache to load DDS files
//
class DdsResourceLoader : public TextureResourceLoader
{
public:
	virtual std::string VGetPattern() { return "*.dds"; }
};

shared_ptr<IResourceLoader> CreateDDSResourceLoader()
{
	return shared_ptr<IResourceLoader>(GCC_NEW DdsResourceLoader());
}

//
// class JpgResourceLoader - creates an interface with the Resource cache to load JPG files
//
class JpgResourceLoader : public TextureResourceLoader
{
public:
	virtual std::string VGetPattern() { return "*.jpg"; }
};

shared_ptr<IResourceLoader> CreateJPGResourceLoader()
{
	return shared_ptr<IResourceLoader>(GCC_NEW JpgResourceLoader());
}

D3DTextureResourceExtraData9::D3DTextureResourceExtraData9()
: m_pTexture(NULL) 
{	
}

D3DTextureResourceExtraData11::D3DTextureResourceExtraData11()
: m_pTexture(NULL), m_pSamplerLinear(NULL)
{	
}


unsigned int TextureResourceLoader::VGetLoadedResourceSize(char *rawBuffer, unsigned int rawSize)
{
	// This will keep the resource cache from allocating memory for the texture, so DirectX can manage it on it's own.
	return 0;
}

//
// TextureResourceLoader::VLoadResource
//
bool TextureResourceLoader::VLoadResource(char *rawBuffer, unsigned int rawSize, shared_ptr<ResHandle> handle)
{
	GameCodeApp::Renderer renderer = GameCodeApp::GetRendererImpl();
	if (renderer == GameCodeApp::Renderer_D3D9)
	{
		shared_ptr<D3DTextureResourceExtraData9> extra = shared_ptr<D3DTextureResourceExtraData9>(GCC_NEW D3DTextureResourceExtraData9());

		if ( FAILED ( D3DXCreateTextureFromFileInMemory( DXUTGetD3D9Device(), rawBuffer, rawSize, &extra->m_pTexture ) ) )
			return false;
		else 
		{
			handle->SetExtra(shared_ptr<D3DTextureResourceExtraData9>(extra));
			return true;
		}
	}
	else if (renderer == GameCodeApp::Renderer_D3D11)
	{
		shared_ptr<D3DTextureResourceExtraData11> extra = shared_ptr<D3DTextureResourceExtraData11>(GCC_NEW D3DTextureResourceExtraData11());

		// Load the Texture
		if ( FAILED ( D3DX11CreateShaderResourceViewFromMemory( DXUTGetD3D11Device(), rawBuffer, rawSize, NULL, NULL, &extra->m_pTexture, NULL ) ) )
			return false;

		// Create the sample state
		D3D11_SAMPLER_DESC sampDesc;
		ZeroMemory( &sampDesc, sizeof(sampDesc) );
		sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
		sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
		sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
		sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
		sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
		sampDesc.MinLOD = 0;
		sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
		if( FAILED( DXUTGetD3D11Device()->CreateSamplerState( &sampDesc, &extra->m_pSamplerLinear ) ) ) 
			return false;

		handle->SetExtra(shared_ptr<D3DTextureResourceExtraData11>(extra));
		return true;
	}

	GCC_ASSERT(0 && "Unsupported Renderer in TextureResourceLoader::VLoadResource");
	return false;
}

下一篇是网 Mesh 和 着色器 Shader ~~~


游戏框架其九:灯光和材质( Lights and Material )