游戏场景中的天空效果实现起来其实很简单,我们使用一个称之为“天空盒”的技术即可~
如下是一个天空盒对象的简单实现:
/*-------------------------------------
代码清单:Skybox.h
来自:http://www.cnblogs.com/kenkao
-------------------------------------*/
#include "Texture2D.h"
#pragma once
// 天空盒顶点缓冲结构定义
struct VertexSkybox{
VertexSkybox(){}
VertexSkybox(float x, float y, float z, float nx, float ny, float nz, D3DCOLOR color, float u, float v){
_x = x; _y = y; _z = z;
_nx = nx; _ny = ny; _nz = nz;
_color = color;
_u = u; _v = v;
}
float _x, _y, _z;
float _nx, _ny, _nz;
D3DCOLOR _color;
float _u, _v;
static const DWORD FVF;
};
class CSkybox
{
public:
CSkybox(void);
~CSkybox(void);
public:
bool Create( // 构建天空盒
char* szFrontTex, // 前、后、左、右、上、下 纹理路径
char* szBackTex,
char* szLeftTex,
char* szRightTex,
char* szTopTex,
char* szBottomTex
);
void Draw(); // 绘制天空盒
void Release(); // 释放天空盒
private:
void InitVertices(); // 初始化顶点及索引缓冲区
private:
CTexture2D** m_ppTextureArray; // 天空盒纹理数组
VertexSkybox* m_pVertex; // 顶点缓冲
UINT16* m_pIndices; // 索引缓冲
D3DXMATRIX m_WorldTransMatrix; // 当前世界变换矩阵
D3DXMATRIX m_OriWorldTransMatrix; // 原始世界变换矩阵
};
代码清单:Skybox.h
来自:http://www.cnblogs.com/kenkao
-------------------------------------*/
#include "Texture2D.h"
#pragma once
// 天空盒顶点缓冲结构定义
struct VertexSkybox{
VertexSkybox(){}
VertexSkybox(float x, float y, float z, float nx, float ny, float nz, D3DCOLOR color, float u, float v){
_x = x; _y = y; _z = z;
_nx = nx; _ny = ny; _nz = nz;
_color = color;
_u = u; _v = v;
}
float _x, _y, _z;
float _nx, _ny, _nz;
D3DCOLOR _color;
float _u, _v;
static const DWORD FVF;
};
class CSkybox
{
public:
CSkybox(void);
~CSkybox(void);
public:
bool Create( // 构建天空盒
char* szFrontTex, // 前、后、左、右、上、下 纹理路径
char* szBackTex,
char* szLeftTex,
char* szRightTex,
char* szTopTex,
char* szBottomTex
);
void Draw(); // 绘制天空盒
void Release(); // 释放天空盒
private:
void InitVertices(); // 初始化顶点及索引缓冲区
private:
CTexture2D** m_ppTextureArray; // 天空盒纹理数组
VertexSkybox* m_pVertex; // 顶点缓冲
UINT16* m_pIndices; // 索引缓冲
D3DXMATRIX m_WorldTransMatrix; // 当前世界变换矩阵
D3DXMATRIX m_OriWorldTransMatrix; // 原始世界变换矩阵
};
Skybox.cpp
/*-------------------------------------
代码清单:Skybox.cpp
来自:http://www.cnblogs.com/kenkao
-------------------------------------*/
#include "StdAfx.h"
#include "Skybox.h"
#include "D3DGame.h"
#include "D3DCamera.h"
extern IDirect3DDevice9 *g_pD3DDevice;
extern CD3DCamera *g_pD3DCamera;
// 顶点格式的初始化放到.cpp里,避免重定义错误
const DWORD VertexSkybox::FVF = (D3DFVF_XYZ | D3DFVF_NORMAL |D3DFVF_DIFFUSE | D3DFVF_TEX1);
CSkybox::CSkybox(void) : m_ppTextureArray(NULL),
m_pVertex(NULL),
m_pIndices(NULL)
{
}
CSkybox::~CSkybox(void)
{
}
bool CSkybox::Create(char* szFrontTex, char* szBackTex, char* szLeftTex,
char* szRightTex, char* szTopTex, char* szBottomTex)
{
// 初始化顶点及索引缓冲区
InitVertices();
// 初始化天空盒纹理
m_ppTextureArray = new CTexture2D*[6];
for (int ti=0;ti<6;ti++)
{
m_ppTextureArray[ti] = new CTexture2D;
}
// 如果初始化过程中失败,则立即释放已有资源
if( !m_ppTextureArray[0]->LoadTexture(szFrontTex)||
!m_ppTextureArray[1]->LoadTexture(szBackTex) ||
!m_ppTextureArray[2]->LoadTexture(szLeftTex) ||
!m_ppTextureArray[3]->LoadTexture(szRightTex)||
!m_ppTextureArray[4]->LoadTexture(szTopTex) ||
!m_ppTextureArray[5]->LoadTexture(szBottomTex)
)
{
Release();
return false;
}
return true;
}
void CSkybox::InitVertices()
{
// 初始化索引缓冲
m_pIndices = new UINT16[6];
m_pIndices[0] = 0;
m_pIndices[1] = 1;
m_pIndices[2] = 2;
m_pIndices[3] = 0;
m_pIndices[4] = 2;
m_pIndices[5] = 3;
// 初始化顶点缓冲
const float t = 1.0f;
const float o = 0.0f;
m_pVertex = new VertexSkybox[24];
// 前
m_pVertex[0] = VertexSkybox(-1,-1,-1, 0,0, 1, D3DXCOLOR_WHITE, t, t);
m_pVertex[1] = VertexSkybox( 1,-1,-1, 0,0, 1, D3DXCOLOR_WHITE, o, t);
m_pVertex[2] = VertexSkybox( 1, 1,-1, 0,0, 1, D3DXCOLOR_WHITE, o, o);
m_pVertex[3] = VertexSkybox(-1, 1,-1, 0,0, 1, D3DXCOLOR_WHITE, t, o);
// 后
m_pVertex[4] = VertexSkybox( 1,-1, 1, 0,0,-1, D3DXCOLOR_WHITE, t, t);
m_pVertex[5] = VertexSkybox(-1,-1, 1, 0,0,-1, D3DXCOLOR_WHITE, o, t);
m_pVertex[6] = VertexSkybox(-1, 1, 1, 0,0,-1, D3DXCOLOR_WHITE, o, o);
m_pVertex[7] = VertexSkybox( 1, 1, 1, 0,0,-1, D3DXCOLOR_WHITE, t, o);
// 左
m_pVertex[8] = VertexSkybox( 1,-1,-1, -1,0,0, D3DXCOLOR_WHITE, t, t);
m_pVertex[9] = VertexSkybox( 1,-1, 1, -1,0,0, D3DXCOLOR_WHITE, o, t);
m_pVertex[10] = VertexSkybox( 1, 1, 1, -1,0,0, D3DXCOLOR_WHITE, o, o);
m_pVertex[11] = VertexSkybox( 1, 1,-1, -1,0,0, D3DXCOLOR_WHITE, t, o);
// 右
m_pVertex[12] = VertexSkybox(-1,-1, 1, 1,0,0, D3DXCOLOR_WHITE, t, t);
m_pVertex[13] = VertexSkybox(-1,-1,-1, 1,0,0, D3DXCOLOR_WHITE, o, t);
m_pVertex[14] = VertexSkybox(-1, 1,-1, 1,0,0, D3DXCOLOR_WHITE, o, o);
m_pVertex[15] = VertexSkybox(-1, 1, 1, 1,0,0, D3DXCOLOR_WHITE, t, o);
// 上
m_pVertex[16] = VertexSkybox( 1, 1,-1, 0,-1,0, D3DXCOLOR_WHITE, t, t);
m_pVertex[17] = VertexSkybox( 1, 1, 1, 0,-1,0, D3DXCOLOR_WHITE, o, t);
m_pVertex[18] = VertexSkybox(-1, 1, 1, 0,-1,0, D3DXCOLOR_WHITE, o, o);
m_pVertex[19] = VertexSkybox(-1, 1,-1, 0,-1,0, D3DXCOLOR_WHITE, t, o);
// 下
m_pVertex[20] = VertexSkybox( 1,-1, 1, 0, 1,0, D3DXCOLOR_WHITE, o, o);
m_pVertex[21] = VertexSkybox( 1,-1,-1, 0, 1,0, D3DXCOLOR_WHITE, t, o);
m_pVertex[22] = VertexSkybox(-1,-1,-1, 0, 1,0, D3DXCOLOR_WHITE, t, t);
m_pVertex[23] = VertexSkybox(-1,-1, 1, 0, 1,0, D3DXCOLOR_WHITE, o, t);
}
void CSkybox::Release()
{
// 释放天空盒纹理
for (int ti=0;ti<6;ti++)
{
ReleaseCOM(m_ppTextureArray[ti]);
}
delete[] m_ppTextureArray;
// 释放索引缓冲
delete[] m_pIndices;
// 释放顶点缓冲
delete[] m_pVertex;
}
void CSkybox::Draw()
{
// 绘制之前,根据摄影机位置,更新世界矩阵
D3DXVECTOR3 pos = g_pD3DCamera->GetCameraPos();
D3DXMatrixTranslation(&m_WorldTransMatrix,pos.x,pos.y,pos.z);
g_pD3DDevice->GetTransform(D3DTS_WORLD, &m_OriWorldTransMatrix);
g_pD3DDevice->SetTransform(D3DTS_WORLD, &m_WorldTransMatrix);
// 禁用深度缓冲
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
// 更改采样方式,平滑纹理间过度
g_pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
g_pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
// 分6次绘制天空盒6个面
for (int i=0;i<6;i++)
{
// 应用纹理
g_pD3DDevice->SetTexture(0, m_ppTextureArray[i]->GetTexture());
// 应用顶点格式
g_pD3DDevice->SetFVF(VertexSkybox::FVF);
// 绘制一个面的4个顶点
g_pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &m_pIndices[0],
D3DFMT_INDEX16, &m_pVertex[i * 4], sizeof(VertexSkybox));
}
// 还原默认采样方式
g_pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
g_pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
// 重用深度缓冲
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
// 还原世界矩阵
g_pD3DDevice->SetTransform(D3DTS_WORLD, &m_OriWorldTransMatrix);
}
代码清单:Skybox.cpp
来自:http://www.cnblogs.com/kenkao
-------------------------------------*/
#include "StdAfx.h"
#include "Skybox.h"
#include "D3DGame.h"
#include "D3DCamera.h"
extern IDirect3DDevice9 *g_pD3DDevice;
extern CD3DCamera *g_pD3DCamera;
// 顶点格式的初始化放到.cpp里,避免重定义错误
const DWORD VertexSkybox::FVF = (D3DFVF_XYZ | D3DFVF_NORMAL |D3DFVF_DIFFUSE | D3DFVF_TEX1);
CSkybox::CSkybox(void) : m_ppTextureArray(NULL),
m_pVertex(NULL),
m_pIndices(NULL)
{
}
CSkybox::~CSkybox(void)
{
}
bool CSkybox::Create(char* szFrontTex, char* szBackTex, char* szLeftTex,
char* szRightTex, char* szTopTex, char* szBottomTex)
{
// 初始化顶点及索引缓冲区
InitVertices();
// 初始化天空盒纹理
m_ppTextureArray = new CTexture2D*[6];
for (int ti=0;ti<6;ti++)
{
m_ppTextureArray[ti] = new CTexture2D;
}
// 如果初始化过程中失败,则立即释放已有资源
if( !m_ppTextureArray[0]->LoadTexture(szFrontTex)||
!m_ppTextureArray[1]->LoadTexture(szBackTex) ||
!m_ppTextureArray[2]->LoadTexture(szLeftTex) ||
!m_ppTextureArray[3]->LoadTexture(szRightTex)||
!m_ppTextureArray[4]->LoadTexture(szTopTex) ||
!m_ppTextureArray[5]->LoadTexture(szBottomTex)
)
{
Release();
return false;
}
return true;
}
void CSkybox::InitVertices()
{
// 初始化索引缓冲
m_pIndices = new UINT16[6];
m_pIndices[0] = 0;
m_pIndices[1] = 1;
m_pIndices[2] = 2;
m_pIndices[3] = 0;
m_pIndices[4] = 2;
m_pIndices[5] = 3;
// 初始化顶点缓冲
const float t = 1.0f;
const float o = 0.0f;
m_pVertex = new VertexSkybox[24];
// 前
m_pVertex[0] = VertexSkybox(-1,-1,-1, 0,0, 1, D3DXCOLOR_WHITE, t, t);
m_pVertex[1] = VertexSkybox( 1,-1,-1, 0,0, 1, D3DXCOLOR_WHITE, o, t);
m_pVertex[2] = VertexSkybox( 1, 1,-1, 0,0, 1, D3DXCOLOR_WHITE, o, o);
m_pVertex[3] = VertexSkybox(-1, 1,-1, 0,0, 1, D3DXCOLOR_WHITE, t, o);
// 后
m_pVertex[4] = VertexSkybox( 1,-1, 1, 0,0,-1, D3DXCOLOR_WHITE, t, t);
m_pVertex[5] = VertexSkybox(-1,-1, 1, 0,0,-1, D3DXCOLOR_WHITE, o, t);
m_pVertex[6] = VertexSkybox(-1, 1, 1, 0,0,-1, D3DXCOLOR_WHITE, o, o);
m_pVertex[7] = VertexSkybox( 1, 1, 1, 0,0,-1, D3DXCOLOR_WHITE, t, o);
// 左
m_pVertex[8] = VertexSkybox( 1,-1,-1, -1,0,0, D3DXCOLOR_WHITE, t, t);
m_pVertex[9] = VertexSkybox( 1,-1, 1, -1,0,0, D3DXCOLOR_WHITE, o, t);
m_pVertex[10] = VertexSkybox( 1, 1, 1, -1,0,0, D3DXCOLOR_WHITE, o, o);
m_pVertex[11] = VertexSkybox( 1, 1,-1, -1,0,0, D3DXCOLOR_WHITE, t, o);
// 右
m_pVertex[12] = VertexSkybox(-1,-1, 1, 1,0,0, D3DXCOLOR_WHITE, t, t);
m_pVertex[13] = VertexSkybox(-1,-1,-1, 1,0,0, D3DXCOLOR_WHITE, o, t);
m_pVertex[14] = VertexSkybox(-1, 1,-1, 1,0,0, D3DXCOLOR_WHITE, o, o);
m_pVertex[15] = VertexSkybox(-1, 1, 1, 1,0,0, D3DXCOLOR_WHITE, t, o);
// 上
m_pVertex[16] = VertexSkybox( 1, 1,-1, 0,-1,0, D3DXCOLOR_WHITE, t, t);
m_pVertex[17] = VertexSkybox( 1, 1, 1, 0,-1,0, D3DXCOLOR_WHITE, o, t);
m_pVertex[18] = VertexSkybox(-1, 1, 1, 0,-1,0, D3DXCOLOR_WHITE, o, o);
m_pVertex[19] = VertexSkybox(-1, 1,-1, 0,-1,0, D3DXCOLOR_WHITE, t, o);
// 下
m_pVertex[20] = VertexSkybox( 1,-1, 1, 0, 1,0, D3DXCOLOR_WHITE, o, o);
m_pVertex[21] = VertexSkybox( 1,-1,-1, 0, 1,0, D3DXCOLOR_WHITE, t, o);
m_pVertex[22] = VertexSkybox(-1,-1,-1, 0, 1,0, D3DXCOLOR_WHITE, t, t);
m_pVertex[23] = VertexSkybox(-1,-1, 1, 0, 1,0, D3DXCOLOR_WHITE, o, t);
}
void CSkybox::Release()
{
// 释放天空盒纹理
for (int ti=0;ti<6;ti++)
{
ReleaseCOM(m_ppTextureArray[ti]);
}
delete[] m_ppTextureArray;
// 释放索引缓冲
delete[] m_pIndices;
// 释放顶点缓冲
delete[] m_pVertex;
}
void CSkybox::Draw()
{
// 绘制之前,根据摄影机位置,更新世界矩阵
D3DXVECTOR3 pos = g_pD3DCamera->GetCameraPos();
D3DXMatrixTranslation(&m_WorldTransMatrix,pos.x,pos.y,pos.z);
g_pD3DDevice->GetTransform(D3DTS_WORLD, &m_OriWorldTransMatrix);
g_pD3DDevice->SetTransform(D3DTS_WORLD, &m_WorldTransMatrix);
// 禁用深度缓冲
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
// 更改采样方式,平滑纹理间过度
g_pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
g_pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
// 分6次绘制天空盒6个面
for (int i=0;i<6;i++)
{
// 应用纹理
g_pD3DDevice->SetTexture(0, m_ppTextureArray[i]->GetTexture());
// 应用顶点格式
g_pD3DDevice->SetFVF(VertexSkybox::FVF);
// 绘制一个面的4个顶点
g_pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &m_pIndices[0],
D3DFMT_INDEX16, &m_pVertex[i * 4], sizeof(VertexSkybox));
}
// 还原默认采样方式
g_pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
g_pD3DDevice->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
// 重用深度缓冲
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
// 还原世界矩阵
g_pD3DDevice->SetTransform(D3DTS_WORLD, &m_OriWorldTransMatrix);
}
原理很简单,我们首先绘制一个盒子,并在其6个表面分别贴上对应的天空纹理,而后绘制即可~
需要注意的地方有三点:
1> 虚拟出的天空效果要给人一种“无限远”的视觉体验,因此,我们要保证摄影机始终处在天空盒的中央位置,即天空盒随摄影机的移动而移动;
2> 我们不可能真的做一个无限大的天空盒出来,为了使有限大的天空盒不会遮挡其他物体,绘制时要关闭深度缓冲,且先于其他物体绘制;
3> 绘制时,我们需要临时更改纹理采样状态,以平滑面与面纹理间的过渡~
另外,关于天空盒的绘制,其实还有部分优化的余地~
Irrlicht引擎的做法是,当摄影机呈直角角度,即当摄影机完全正对其中一个面的时候,采用类似CSpriteBatch的方法,仅绘制这个面即可。这个做法是有必要的,不过出现的概率并不大。
我们延续Irrlicht的思路,还可以找到另一种优化的方法,即:无论任何时刻,正常状态下,我们只能看到天空盒6个面其中的3个~
不过,相应的条件判断都要由CPU来完成,各类方法的优劣还未详细测试。大家感兴趣的话不妨一试~
然后是主体代码:
D3DGame.cpp
/*-------------------------------------
代码清单:D3DGame.cpp
来自:http://www.cnblogs.com/kenkao
-------------------------------------*/
#include "StdAfx.h"
#include "D3DGame.h"
#include "D3DCamera.h"
#include "D3DEffect.h"
#include "CoordCross.h"
#include "SimpleXMesh.h"
#include "Texture2D.h"
#include "D3DSprite.h"
#include "Skybox.h"
#include "SpriteBatch.h"
#include <stdio.h>
//---通用全局变量
HINSTANCE g_hInst;
HWND g_hWnd;
D3DXMATRIX g_matProjection;
//---D3D全局变量
IDirect3D9 *g_pD3D = NULL;
IDirect3DDevice9 *g_pD3DDevice = NULL;
CMouseInput *g_pMouseInput = NULL;
CKeyboardInput *g_pKeyboardInput = NULL;
CD3DCamera *g_pD3DCamera = NULL;
CCoordCross *g_pCoordCross = NULL;
CSimpleXMesh *g_pSimpleXMesh = NULL;
CD3DEffect *g_pD3DEffect = NULL;
CD3DSprite *g_pD3DSprite = NULL;
CTexture2D *g_pTexture2D = NULL;
CSpriteBatch *g_SpriteBatch = NULL;
CTexture2D *g_pTexture2D2 = NULL;
CD3DEffect *g_pD3DEffect2 = NULL;
CSkybox *g_pSkybox = NULL;
//---HLSL全局变量句柄
D3DXHANDLE g_CurrentTechHandle = NULL;
D3DXHANDLE g_matWorldViewProj = NULL;
D3DXHANDLE g_matWorld = NULL;
D3DXHANDLE g_vecEye = NULL;
D3DXHANDLE g_vecLightDir = NULL;
D3DXHANDLE g_vDiffuseColor = NULL;
D3DXHANDLE g_vSpecularColor = NULL;
D3DXHANDLE g_vAmbient = NULL;
D3DXHANDLE g_CurrentTechHandle2 = NULL;
D3DXHANDLE g_Scale = NULL;
// HLSL特效参数设置
void GetParameters();
void SetParameters();
void Initialize(HINSTANCE hInst, HWND hWnd)
{
g_hInst = hInst;
g_hWnd = hWnd;
InitD3D(&g_pD3D, &g_pD3DDevice, g_matProjection, hWnd);
g_pMouseInput = new CMouseInput;
g_pMouseInput->Initialize(hInst,hWnd);
g_pKeyboardInput = new CKeyboardInput;
g_pKeyboardInput->Initialize(hInst,hWnd);
g_pD3DCamera = new CD3DCamera;
}
void LoadContent()
{
g_pCoordCross = new CCoordCross;
g_pD3DCamera->SetCameraPos(D3DXVECTOR3(0.5f,0.5f,-5.0f));
g_pSimpleXMesh = new CSimpleXMesh;
g_pSimpleXMesh->LoadXMesh("teapot.X");
g_pD3DEffect = new CD3DEffect;
g_pD3DEffect2 = new CD3DEffect;
g_pD3DEffect->LoadEffect("Light.fx");
g_pD3DEffect2->LoadEffect("Thunder.fx");
GetParameters();
g_pD3DSprite = new CD3DSprite(g_pD3DDevice);
g_SpriteBatch = new CSpriteBatch(g_pD3DDevice);
g_pTexture2D = new CTexture2D;
g_pTexture2D->LoadTexture("img.jpg");
g_pTexture2D2 = new CTexture2D;
g_pTexture2D2->LoadTexture("img2.jpg");
g_pSkybox = new CSkybox;
g_pSkybox->Create("Skybox_0.JPG","Skybox_1.JPG","Skybox_2.JPG"
,"Skybox_3.JPG","Skybox_4.JPG","Skybox_5.JPG");
}
void Update()
{
g_pMouseInput->GetState();
g_pKeyboardInput->GetState();
g_pD3DCamera->Update();
}
void Draw()
{
// 参数设定
SetParameters();
g_pD3DDevice->SetTransform(D3DTS_VIEW,&g_pD3DCamera->GetViewMatrix());
POINT pos;
pos.x=0;
pos.y=0;
POINT pos2;
pos2.x = 440;
pos2.y = 260;
g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(100,149,237,255), 1.0f, 0);
if(SUCCEEDED(g_pD3DDevice->BeginScene()))
{
// 天空处在无限远处,因此必须最先绘制天空盒
g_pSkybox->Draw();
//g_pCoordCross->Draw();
//// 开始绘制并应用特效
//g_SpriteBatch->Begin(g_pD3DEffect2);
//// CSpriteBatch绘制
//g_SpriteBatch->Draw(g_pTexture2D2,pos);
//g_SpriteBatch->Draw(g_pTexture2D,pos2);
//// 结束绘制并终止特效
//g_SpriteBatch->End();
UINT numPasses;
// 开启特效
g_pD3DEffect->BeginEffect(numPasses);
for(UINT i=0;i<numPasses;i++)
{
// 开启路径
g_pD3DEffect->GetEffect()->BeginPass(i);
for(DWORD j=0;j<g_pSimpleXMesh->GetMaterialNum();j++)
{
g_pSimpleXMesh->DrawXMeshSubset(j);
}
// 路径结束
g_pD3DEffect->GetEffect()->EndPass();
}
// 特效结束
g_pD3DEffect->EndEffect();
g_pD3DDevice->EndScene();
}
g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}
void UnloadContent()
{
ReleaseCOM(g_pSkybox);
ReleaseCOM(g_pTexture2D2);
ReleaseCOM(g_pTexture2D);
ReleaseCOM(g_SpriteBatch);
ReleaseCOM(g_pD3DSprite);
ReleaseCOM(g_pD3DEffect2);
ReleaseCOM(g_pD3DEffect);
ReleaseCOM(g_pSimpleXMesh);
ReleaseCOM(g_pCoordCross);
}
void Dispose()
{
ReleaseCOM(g_pD3DCamera);
ReleaseCOM(g_pKeyboardInput);
ReleaseCOM(g_pMouseInput);
ReleaseCOM(g_pD3DDevice);
ReleaseCOM(g_pD3D);
}
void GetParameters()
{
// 获得HLSL中各个全局变量句柄
g_CurrentTechHandle = g_pD3DEffect -> GetEffect() -> GetTechniqueByName("SpecularLight");
g_matWorldViewProj = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "matWorldViewProj");
g_matWorld = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "matWorld");
g_vecEye = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vecEye");
g_vecLightDir = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vecLightDir");
g_vDiffuseColor = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vDiffuseColor");
g_vSpecularColor = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vSpecularColor");
g_vAmbient = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vAmbient");
g_CurrentTechHandle2 = g_pD3DEffect2 -> GetEffect() -> GetTechniqueByName("Technique1");
g_Scale = g_pD3DEffect2 -> GetEffect() -> GetParameterByName(0, "Scale");
}
void SetParameters()
{
// 设定当前技术
g_pD3DEffect -> GetEffect() -> SetTechnique(g_CurrentTechHandle);
// 设定HLSL中的各个参数
D3DXMATRIX worldMatrix;
D3DXMatrixTranslation(&worldMatrix,0.0f,0.0f,0.0f);
g_pD3DEffect -> GetEffect() -> SetMatrix(g_matWorldViewProj,&(worldMatrix*g_pD3DCamera->GetViewMatrix()*g_matProjection));
g_pD3DEffect -> GetEffect() -> SetMatrix(g_matWorld,&worldMatrix);
D3DXVECTOR3 cameraPos = g_pD3DCamera->GetCameraPos();
D3DXVECTOR4 vecEye = D3DXVECTOR4(cameraPos.x,cameraPos.y,cameraPos.z,0.0f);
g_pD3DEffect -> GetEffect() -> SetVector(g_vecEye,&vecEye);
D3DXVECTOR4 vLightDirection = D3DXVECTOR4(0.0f, 0.0f, -1.0f, 1.0f);
g_pD3DEffect -> GetEffect() -> SetVector(g_vecLightDir,&vLightDirection);
D3DXVECTOR4 vColorDiffuse = D3DXVECTOR4(0.8f, 0.0f, 0.0f, 1.0f);
D3DXVECTOR4 vColorSpecular = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
D3DXVECTOR4 vColorAmbient = D3DXVECTOR4(0.1f, 0.1f, 0.1f, 1.0f);
g_pD3DEffect -> GetEffect() -> SetVector(g_vDiffuseColor,&vColorDiffuse);
g_pD3DEffect -> GetEffect() -> SetVector(g_vSpecularColor,&vColorSpecular);
g_pD3DEffect -> GetEffect() -> SetVector(g_vAmbient,&vColorAmbient);
g_pD3DEffect2 -> GetEffect() -> SetTechnique(g_CurrentTechHandle2);
g_pD3DEffect2 -> GetEffect() -> SetFloat(g_Scale,0.8f);
}
代码清单:D3DGame.cpp
来自:http://www.cnblogs.com/kenkao
-------------------------------------*/
#include "StdAfx.h"
#include "D3DGame.h"
#include "D3DCamera.h"
#include "D3DEffect.h"
#include "CoordCross.h"
#include "SimpleXMesh.h"
#include "Texture2D.h"
#include "D3DSprite.h"
#include "Skybox.h"
#include "SpriteBatch.h"
#include <stdio.h>
//---通用全局变量
HINSTANCE g_hInst;
HWND g_hWnd;
D3DXMATRIX g_matProjection;
//---D3D全局变量
IDirect3D9 *g_pD3D = NULL;
IDirect3DDevice9 *g_pD3DDevice = NULL;
CMouseInput *g_pMouseInput = NULL;
CKeyboardInput *g_pKeyboardInput = NULL;
CD3DCamera *g_pD3DCamera = NULL;
CCoordCross *g_pCoordCross = NULL;
CSimpleXMesh *g_pSimpleXMesh = NULL;
CD3DEffect *g_pD3DEffect = NULL;
CD3DSprite *g_pD3DSprite = NULL;
CTexture2D *g_pTexture2D = NULL;
CSpriteBatch *g_SpriteBatch = NULL;
CTexture2D *g_pTexture2D2 = NULL;
CD3DEffect *g_pD3DEffect2 = NULL;
CSkybox *g_pSkybox = NULL;
//---HLSL全局变量句柄
D3DXHANDLE g_CurrentTechHandle = NULL;
D3DXHANDLE g_matWorldViewProj = NULL;
D3DXHANDLE g_matWorld = NULL;
D3DXHANDLE g_vecEye = NULL;
D3DXHANDLE g_vecLightDir = NULL;
D3DXHANDLE g_vDiffuseColor = NULL;
D3DXHANDLE g_vSpecularColor = NULL;
D3DXHANDLE g_vAmbient = NULL;
D3DXHANDLE g_CurrentTechHandle2 = NULL;
D3DXHANDLE g_Scale = NULL;
// HLSL特效参数设置
void GetParameters();
void SetParameters();
void Initialize(HINSTANCE hInst, HWND hWnd)
{
g_hInst = hInst;
g_hWnd = hWnd;
InitD3D(&g_pD3D, &g_pD3DDevice, g_matProjection, hWnd);
g_pMouseInput = new CMouseInput;
g_pMouseInput->Initialize(hInst,hWnd);
g_pKeyboardInput = new CKeyboardInput;
g_pKeyboardInput->Initialize(hInst,hWnd);
g_pD3DCamera = new CD3DCamera;
}
void LoadContent()
{
g_pCoordCross = new CCoordCross;
g_pD3DCamera->SetCameraPos(D3DXVECTOR3(0.5f,0.5f,-5.0f));
g_pSimpleXMesh = new CSimpleXMesh;
g_pSimpleXMesh->LoadXMesh("teapot.X");
g_pD3DEffect = new CD3DEffect;
g_pD3DEffect2 = new CD3DEffect;
g_pD3DEffect->LoadEffect("Light.fx");
g_pD3DEffect2->LoadEffect("Thunder.fx");
GetParameters();
g_pD3DSprite = new CD3DSprite(g_pD3DDevice);
g_SpriteBatch = new CSpriteBatch(g_pD3DDevice);
g_pTexture2D = new CTexture2D;
g_pTexture2D->LoadTexture("img.jpg");
g_pTexture2D2 = new CTexture2D;
g_pTexture2D2->LoadTexture("img2.jpg");
g_pSkybox = new CSkybox;
g_pSkybox->Create("Skybox_0.JPG","Skybox_1.JPG","Skybox_2.JPG"
,"Skybox_3.JPG","Skybox_4.JPG","Skybox_5.JPG");
}
void Update()
{
g_pMouseInput->GetState();
g_pKeyboardInput->GetState();
g_pD3DCamera->Update();
}
void Draw()
{
// 参数设定
SetParameters();
g_pD3DDevice->SetTransform(D3DTS_VIEW,&g_pD3DCamera->GetViewMatrix());
POINT pos;
pos.x=0;
pos.y=0;
POINT pos2;
pos2.x = 440;
pos2.y = 260;
g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA(100,149,237,255), 1.0f, 0);
if(SUCCEEDED(g_pD3DDevice->BeginScene()))
{
// 天空处在无限远处,因此必须最先绘制天空盒
g_pSkybox->Draw();
//g_pCoordCross->Draw();
//// 开始绘制并应用特效
//g_SpriteBatch->Begin(g_pD3DEffect2);
//// CSpriteBatch绘制
//g_SpriteBatch->Draw(g_pTexture2D2,pos);
//g_SpriteBatch->Draw(g_pTexture2D,pos2);
//// 结束绘制并终止特效
//g_SpriteBatch->End();
UINT numPasses;
// 开启特效
g_pD3DEffect->BeginEffect(numPasses);
for(UINT i=0;i<numPasses;i++)
{
// 开启路径
g_pD3DEffect->GetEffect()->BeginPass(i);
for(DWORD j=0;j<g_pSimpleXMesh->GetMaterialNum();j++)
{
g_pSimpleXMesh->DrawXMeshSubset(j);
}
// 路径结束
g_pD3DEffect->GetEffect()->EndPass();
}
// 特效结束
g_pD3DEffect->EndEffect();
g_pD3DDevice->EndScene();
}
g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}
void UnloadContent()
{
ReleaseCOM(g_pSkybox);
ReleaseCOM(g_pTexture2D2);
ReleaseCOM(g_pTexture2D);
ReleaseCOM(g_SpriteBatch);
ReleaseCOM(g_pD3DSprite);
ReleaseCOM(g_pD3DEffect2);
ReleaseCOM(g_pD3DEffect);
ReleaseCOM(g_pSimpleXMesh);
ReleaseCOM(g_pCoordCross);
}
void Dispose()
{
ReleaseCOM(g_pD3DCamera);
ReleaseCOM(g_pKeyboardInput);
ReleaseCOM(g_pMouseInput);
ReleaseCOM(g_pD3DDevice);
ReleaseCOM(g_pD3D);
}
void GetParameters()
{
// 获得HLSL中各个全局变量句柄
g_CurrentTechHandle = g_pD3DEffect -> GetEffect() -> GetTechniqueByName("SpecularLight");
g_matWorldViewProj = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "matWorldViewProj");
g_matWorld = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "matWorld");
g_vecEye = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vecEye");
g_vecLightDir = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vecLightDir");
g_vDiffuseColor = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vDiffuseColor");
g_vSpecularColor = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vSpecularColor");
g_vAmbient = g_pD3DEffect -> GetEffect() -> GetParameterByName(0, "vAmbient");
g_CurrentTechHandle2 = g_pD3DEffect2 -> GetEffect() -> GetTechniqueByName("Technique1");
g_Scale = g_pD3DEffect2 -> GetEffect() -> GetParameterByName(0, "Scale");
}
void SetParameters()
{
// 设定当前技术
g_pD3DEffect -> GetEffect() -> SetTechnique(g_CurrentTechHandle);
// 设定HLSL中的各个参数
D3DXMATRIX worldMatrix;
D3DXMatrixTranslation(&worldMatrix,0.0f,0.0f,0.0f);
g_pD3DEffect -> GetEffect() -> SetMatrix(g_matWorldViewProj,&(worldMatrix*g_pD3DCamera->GetViewMatrix()*g_matProjection));
g_pD3DEffect -> GetEffect() -> SetMatrix(g_matWorld,&worldMatrix);
D3DXVECTOR3 cameraPos = g_pD3DCamera->GetCameraPos();
D3DXVECTOR4 vecEye = D3DXVECTOR4(cameraPos.x,cameraPos.y,cameraPos.z,0.0f);
g_pD3DEffect -> GetEffect() -> SetVector(g_vecEye,&vecEye);
D3DXVECTOR4 vLightDirection = D3DXVECTOR4(0.0f, 0.0f, -1.0f, 1.0f);
g_pD3DEffect -> GetEffect() -> SetVector(g_vecLightDir,&vLightDirection);
D3DXVECTOR4 vColorDiffuse = D3DXVECTOR4(0.8f, 0.0f, 0.0f, 1.0f);
D3DXVECTOR4 vColorSpecular = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
D3DXVECTOR4 vColorAmbient = D3DXVECTOR4(0.1f, 0.1f, 0.1f, 1.0f);
g_pD3DEffect -> GetEffect() -> SetVector(g_vDiffuseColor,&vColorDiffuse);
g_pD3DEffect -> GetEffect() -> SetVector(g_vSpecularColor,&vColorSpecular);
g_pD3DEffect -> GetEffect() -> SetVector(g_vAmbient,&vColorAmbient);
g_pD3DEffect2 -> GetEffect() -> SetTechnique(g_CurrentTechHandle2);
g_pD3DEffect2 -> GetEffect() -> SetFloat(g_Scale,0.8f);
}
最后是实际的效果图:
大家可以尝试变动一下HLSL中光源的方向,使其朝向天空纹理中的太阳,会有更加真实的视觉体验哦^ ^