光线和天空能够大大增强游戏的画面效果,以下是实现:
1. 光线效果 Raycast
#pragma once
//========================================================================
// Raycast.h - implements a raycast into the rendered scene
//========================================================================
#include "Geometry.h"
typedef unsigned int DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned int ActorId;
typedef unsigned int GameViewId;
typedef D3DXCOLOR Color;
typedef float FLOAT;
typedef unsigned int UINT;
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef unsigned char TCHAR;
#endif
typedef unsigned char CHAR;
typedef unsigned wchar_t WCHAR;
enum HRESULT
{
E_INVALIDARG,
E_FAIL,
S_OK,
};
class Intersection
{
public:
FLOAT m_fDist; // distance from ray origin to intersection
DWORD m_dwFace; // the face index of the intersection
FLOAT m_fBary1, m_fBary2; // Barycentric质心 coordinates of the intersection
FLOAT m_tu, m_tv; // texture coords of intersection
ActorId m_actorId; // Which actor was intersected if there was one
Vec3 m_worldLoc; // world location of intersection
Vec3 m_actorLoc; // actor local coordinates of intersection
Vec3 m_normal; // normal of intersection
bool const operator <(Intersection const &other) { return m_fDist < other.m_fDist; }
};
template <class T>
void InitIntersection(Intersection &intersection, DWORD faceIndex, FLOAT dist, FLOAT u, FLOAT v, ActorId actorId, WORD* pIndices, T* pVertices, const Mat4x4 &matWorld);
typedef std::vector<Intersection> IntersectionArray;
class CDXUTSDKMesh;
class RayCast
{
protected:
LPDIRECT3DVERTEXBUFFER9 m_pVB;
public:
RayCast(Point point, DWORD maxIntersections = 16);
DWORD m_MaxIntersections;
DWORD m_NumIntersections;
bool m_bUseD3DXIntersect; // Whether to use D3DXIntersect
bool m_bAllHits; // Whether to just get the first "hit" or all "hits"
Point m_Point;
D3DXVECTOR3 m_vPickRayDir;
D3DXVECTOR3 m_vPickRayOrig;
IntersectionArray m_IntersectionArray;
HRESULT Pick(Scene *pScene, ActorId actorId, ID3DXMesh *pMesh);
HRESULT Pick(Scene *pScene, ActorId actorId, CDXUTSDKMesh *pMesh);
HRESULT Pick(Scene *pScene, ActorId actorId, LPDIRECT3DVERTEXBUFFER9 pVerts, LPDIRECT3DINDEXBUFFER9 pIndices, DWORD numPolys);
HRESULT Pick(Scene *pScene, ActorId actorId, LPDIRECT3DVERTEXBUFFER9 pVerts, DWORD numPolys);
void Sort();
};
//========================================================================
// Raycast.cpp - implements a raycast into the rendered scene
//========================================================================
#include "GameCodeStd.h"
#include "GameCode.h"
#include "Geometry.h"
#include "Raycast.h"
#include "SceneNodes.h"
template <class T>
void InitIntersection(Intersection &intersection, DWORD faceIndex, FLOAT dist, FLOAT u, FLOAT v, ActorId actorId, WORD* pIndices, T* pVertices, const Mat4x4 &matWorld)
{
intersection.m_dwFace = faceIndex;
intersection.m_fDist = dist;
intersection.m_fBary1 = u;
intersection.m_fBary2 = v;
T *v0 = &pVertices[pIndices[3 * faceIndex + 0]];
T *v1 = &pVertices[pIndices[3 * faceIndex + 1]];
T *v2 = &pVertices[pIndices[3 * faceIndex + 2]];
// If all you want is the vertices hit, then you are done. In this sample, we
// want to show how to infer texture coordinates as well, using the BaryCentric
// coordinates supplied by D3DXIntersect
FLOAT dtu1 = v1->tu - v0->tu;
FLOAT dtu2 = v2->tu - v0->tu;
FLOAT dtv1 = v1->tv - v0->tv;
FLOAT dtv2 = v2->tv - v0->tv;
intersection.m_tu = v0->tu + intersection.m_fBary1 * dtu1 + intersection.m_fBary2 * dtu2;
intersection.m_tv = v0->tv + intersection.m_fBary1 * dtv1 + intersection.m_fBary2 * dtv2;
Vec3 a = v0->position - v1->position;
Vec3 b = v2->position - v1->position;
Vec3 cross = a.Cross(b);
cross /= cross.Length();
Vec3 actorLoc = BarycentricToVec3(v0->position, v1->position, v2->position, intersection.m_fBary1, intersection.m_fBary2);
intersection.m_actorLoc = actorLoc;
intersection.m_worldLoc = matWorld.Xform(actorLoc);
intersection.m_actorId = actorId;
intersection.m_normal = cross;
}
RayCast::RayCast(Point point, DWORD maxIntersections)
{
m_MaxIntersections = maxIntersections;
m_IntersectionArray.reserve(m_MaxIntersections);
m_bUseD3DXIntersect = true;
m_bAllHits = true;
m_NumIntersections = 0;
m_Point = point;
}
HRESULT RayCast::Pick(Scene *pScene, ActorId actorId, ID3DXMesh *pMesh)
{
if (!m_bAllHits && m_NumIntersections > 0)
return S_OK;
HRESULT hr;
IDirect3DDevice9* pD3Device = DXUTGetD3D9Device();
// Get the inverse view matrix
const Mat4x4 matView = pScene->GetCamera()->GetView();
const Mat4x4 matWorld = pScene->GetTopMatrix();
const Mat4x4 proj = pScene->GetCamera()->GetProjection();
// Compute the vector of the Pick ray in screen space
D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * m_Point.x ) / g_pApp->GetScreenSize().x ) - 1 ) / proj._11;
v.y = -( ( ( 2.0f * m_Point.y ) / g_pApp->GetScreenSize().y ) - 1 ) / proj._22;
v.z = 1.0f;
D3DXMATRIX mWorldView = matWorld * matView;
D3DXMATRIX m;
D3DXMatrixInverse( &m, NULL, &mWorldView );
// Transform the screen space Pick ray into 3D space
m_vPickRayDir.x = v.x * m._11 + v.y * m._21 + v.z * m._31;
m_vPickRayDir.y = v.x * m._12 + v.y * m._22 + v.z * m._32;
m_vPickRayDir.z = v.x * m._13 + v.y * m._23 + v.z * m._33;
m_vPickRayOrig.x = m._41;
m_vPickRayOrig.y = m._42;
m_vPickRayOrig.z = m._43;
ID3DXMesh* pTempMesh;
V( pMesh->CloneMeshFVF( pMesh->GetOptions(), D3D9Vertex_UnlitTextured::FVF,
DXUTGetD3D9Device(), &pTempMesh ) );
LPDIRECT3DVERTEXBUFFER9 pVB;
LPDIRECT3DINDEXBUFFER9 pIB;
pTempMesh->GetVertexBuffer( &pVB );
pTempMesh->GetIndexBuffer( &pIB );
WORD* pIndices;
D3D9Vertex_UnlitTextured* pVertices;
pIB->Lock( 0, 0, ( void** )&pIndices, 0 );
pVB->Lock( 0, 0, ( void** )&pVertices, 0 );
DWORD intersections = 0;
// When calling D3DXIntersect, one can get just the closest intersection and not
// need to work with a D3DXBUFFER. Or, to get all intersections between the ray and
// the Mesh, one can use a D3DXBUFFER to receive all intersections. We show both
// methods.
if( !m_bAllHits )
{
// Collect only the closest intersection
BOOL bHit;
DWORD dwFace;
FLOAT fBary1, fBary2, fDist;
D3DXIntersect( pTempMesh, &m_vPickRayOrig, &m_vPickRayDir, &bHit, &dwFace, &fBary1, &fBary2, &fDist,
NULL, NULL );
if( bHit )
{
m_NumIntersections = 1;
m_IntersectionArray.resize(1);
InitIntersection(m_IntersectionArray[0], dwFace, fDist, fBary1, fBary2, actorId, pIndices, pVertices, matWorld);
}
else
{
m_NumIntersections = 0;
}
}
else
{
// Collect all intersections
BOOL bHit;
LPD3DXBUFFER pBuffer = NULL;
D3DXINTERSECTINFO* pIntersectInfoArray;
if( FAILED( hr = D3DXIntersect( pTempMesh, &m_vPickRayOrig, &m_vPickRayDir, &bHit, NULL, NULL, NULL, NULL,
&pBuffer, &intersections ) ) )
{
SAFE_RELEASE( pTempMesh );
SAFE_RELEASE( pVB );
SAFE_RELEASE( pIB );
return hr;
}
if( intersections > 0 )
{
m_IntersectionArray.resize(m_NumIntersections + intersections);
pIntersectInfoArray = ( D3DXINTERSECTINFO* )pBuffer->GetBufferPointer();
if( m_NumIntersections > m_MaxIntersections )
m_NumIntersections = m_MaxIntersections;
for( DWORD i = 0; i < intersections; i++ )
{
Intersection* pIntersection;
pIntersection = &m_IntersectionArray[i + m_NumIntersections];
InitIntersection(*pIntersection, pIntersectInfoArray[i].FaceIndex,
pIntersectInfoArray[i].Dist,
pIntersectInfoArray[i].U,
pIntersectInfoArray[i].V,
actorId, pIndices, pVertices, matWorld);
}
}
SAFE_RELEASE( pBuffer );
}
m_NumIntersections += intersections;
pVB->Unlock();
pIB->Unlock();
SAFE_RELEASE( pTempMesh );
SAFE_RELEASE( pVB );
SAFE_RELEASE( pIB );
return S_OK;
}
HRESULT RayCast::Pick(Scene *pScene, ActorId actorId, CDXUTSDKMesh *pMesh)
{
if (!m_bAllHits && m_NumIntersections > 0)
return S_OK;
IDirect3DDevice9* pD3Device = DXUTGetD3D9Device();
// Get the inverse view matrix
const Mat4x4 matView = pScene->GetCamera()->GetView();
const Mat4x4 matWorld = pScene->GetTopMatrix();
const Mat4x4 proj = pScene->GetCamera()->GetProjection();
// Compute the vector of the Pick ray in screen space
D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * m_Point.x ) / g_pApp->GetScreenSize().x ) - 1 ) / proj._11;
v.y = -( ( ( 2.0f * m_Point.y ) / g_pApp->GetScreenSize().y ) - 1 ) / proj._22;
v.z = 1.0f;
D3DXMATRIX mWorldView = matWorld * matView;
D3DXMATRIX m;
D3DXMatrixInverse( &m, NULL, &mWorldView );
// Transform the screen space Pick ray into 3D space
m_vPickRayDir.x = v.x * m._11 + v.y * m._21 + v.z * m._31;
m_vPickRayDir.y = v.x * m._12 + v.y * m._22 + v.z * m._32;
m_vPickRayDir.z = v.x * m._13 + v.y * m._23 + v.z * m._33;
m_vPickRayOrig.x = m._41;
m_vPickRayOrig.y = m._42;
m_vPickRayOrig.z = m._43;
return E_FAIL;
}
HRESULT RayCast::Pick(Scene *pScene, ActorId actorId, LPDIRECT3DVERTEXBUFFER9 pVB, LPDIRECT3DINDEXBUFFER9 pIB, DWORD numPolys)
{
if (!m_bAllHits && m_NumIntersections > 0)
return S_OK;
WORD* pIndices;
D3D9Vertex_ColoredTextured* pVertices;
pIB->Lock( 0, 0, ( void** )&pIndices, 0 );
pVB->Lock( 0, 0, ( void** )&pVertices, 0 );
IDirect3DDevice9* pD3Device = DXUTGetD3D9Device();
// Get the inverse view matrix
const Mat4x4 matView = pScene->GetCamera()->GetView();
const Mat4x4 matWorld = pScene->GetTopMatrix();
const Mat4x4 proj = pScene->GetCamera()->GetProjection();
// Compute the vector of the Pick ray in screen space
D3DXVECTOR3 v;
v.x = ( ( ( 2.0f * m_Point.x ) / g_pApp->GetScreenSize().x ) - 1 ) / proj._11;
v.y = -( ( ( 2.0f * m_Point.y ) / g_pApp->GetScreenSize().y ) - 1 ) / proj._22;
v.z = 1.0f;
D3DXMATRIX mWorldView = matWorld * matView;
D3DXMATRIX m;
D3DXMatrixInverse( &m, NULL, &mWorldView );
// Transform the screen space Pick ray into 3D space
m_vPickRayDir.x = v.x * m._11 + v.y * m._21 + v.z * m._31;
m_vPickRayDir.y = v.x * m._12 + v.y * m._22 + v.z * m._32;
m_vPickRayDir.z = v.x * m._13 + v.y * m._23 + v.z * m._33;
m_vPickRayOrig.x = m._41;
m_vPickRayOrig.y = m._42;
m_vPickRayOrig.z = m._43;
FLOAT fBary1, fBary2;
FLOAT fDist;
for( DWORD i = 0; i < numPolys; i++ )
{
Vec3 v0 = pVertices[pIndices[3 * i + 0]].position;
Vec3 v1 = pVertices[pIndices[3 * i + 1]].position;
Vec3 v2 = pVertices[pIndices[3 * i + 2]].position;
// Check if the Pick ray passes through this point
if( IntersectTriangle( m_vPickRayOrig, m_vPickRayDir, v0, v1, v2,
&fDist, &fBary1, &fBary2 ) )
{
if( m_bAllHits || m_NumIntersections == 0 || fDist < m_IntersectionArray[0].m_fDist )
{
if( !m_bAllHits )
m_NumIntersections = 0;
++m_NumIntersections;
m_IntersectionArray.resize(m_NumIntersections);
Intersection* pIntersection;
pIntersection = &m_IntersectionArray[m_NumIntersections-1];
InitIntersection(*pIntersection, i, fDist, fBary1, fBary2, actorId, pIndices, pVertices, matWorld);
if( m_NumIntersections == m_MaxIntersections )
break;
}
}
}
pVB->Unlock();
pIB->Unlock();
return S_OK;
}
void RayCast::Sort()
{
std::sort(m_IntersectionArray.begin(), m_IntersectionArray.end()) ;
}
以上就是光线的实现情况,下面是天空场景
2. 天空场景 Sky
#pragma once
//========================================================================
// Sky.h - implements a sky box in either D3D9 or D3D11
//========================================================================
#include "Geometry.h"
#include "Material.h"
#include "Shaders.h"
// Forward declarations
class SceneNode;
class Scene;
//
// class SkyNode
//
// Implements a believable sky that follows
// the camera around - this is a base class that the D3D9 and D3D11 classes
// inherit from
//
typedef unsigned int DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned int ActorId;
typedef unsigned int GameViewId;
typedef D3DXCOLOR Color;
typedef float FLOAT;
typedef unsigned int UINT;
#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef unsigned char TCHAR;
#endif
typedef unsigned char CHAR;
typedef unsigned wchar_t WCHAR;
enum HRESULT
{
E_INVALIDARG,
E_FAIL,
S_OK,
};
class SkyNode : public SceneNode
{
protected:
DWORD m_numVerts;
DWORD m_sides;
const char * m_textureBaseName;
shared_ptr<CameraNode> m_camera;
bool m_bActive;
std::string GetTextureName(const int side);
public:
SkyNode(const char *textureFile);
virtual ~SkyNode() { }
HRESULT VPreRender(Scene *pScene);
bool VIsVisible(Scene *pScene) const { return m_bActive; }
};
class D3DSkyNode9 : public SkyNode
{
protected:
LPDIRECT3DTEXTURE9 m_pTexture[5]; // the sky textures
LPDIRECT3DVERTEXBUFFER9 m_pVerts; // the sky verts
public:
D3DSkyNode9(const char *pTextureBaseName );
virtual ~D3DSkyNode9();
HRESULT VOnRestore(Scene *pScene);
HRESULT VRender(Scene *pScene);
};
// 增加Shader支持.
class D3DSkyNode11 : public SkyNode
{
public:
D3DSkyNode11(const char *pTextureBaseName );
virtual ~D3DSkyNode11();
HRESULT VOnRestore(Scene *pScene);
HRESULT VRender(Scene *pScene);
protected:
ID3D11Buffer* m_pIndexBuffer;
ID3D11Buffer* m_pVertexBuffer;
GameCode4_Hlsl_VertexShader m_VertexShader;
GameCode4_Hlsl_PixelShader m_PixelShader;
};
//========================================================================
// File: Sky.cpp - implements a sky box in D3D9 or D3D11
//========================================================================
#include "GameCodeStd.h"
#include "GameCode.h"
#include "D3DRenderer.h"
#include "Geometry.h"
#include "SceneNodes.h"
#include "Shaders.h"
#include "Sky.h"
// SkyNode Implementation
//
// SkyNode::SkyNode
//
const ActorId INVALID_ACTOR_ID = 0;
enum RenderPass
{
RenderPass_0,
RenderPass_Static = RenderPass_0,
RenderPass_Actor,
RenderPass_Sky,
RenderPass_NotRendered,
RenderPass_Last
};
SkyNode::SkyNode(const char *pTextureBaseName)
: SceneNode(INVALID_ACTOR_ID, WeakBaseRenderComponentPtr(), RenderPass_Sky, &Mat4x4::g_Identity)
, m_bActive(true)
{
m_textureBaseName = pTextureBaseName;
}
//
// SkyNode::VPreRender 渲染前准备环境
//
HRESULT SkyNode::VPreRender(Scene *pScene)
{
Vec3 cameraPos = m_camera->VGet()->ToWorld().GetPosition();
Mat4x4 mat = m_Props.ToWorld();
mat.SetPosition(cameraPos);
VSetTransform(&mat);
return SceneNode::VPreRender(pScene);
}
//
// D3DSkyNode9::D3DSkyNode9
D3DSkyNode9::D3DSkyNode9(const char *pTextureBaseName)
: SkyNode(pTextureBaseName)
{
for (int i=0; i<5; ++i)
{
m_pTexture[i] = NULL;
}
m_pVerts = NULL;
}
//
// D3DSkyNode9::~D3DSkyNode9
//
#define SAFE_RELEASE(x) if(x) x->Release(); x=NULL;
D3DSkyNode9::~D3DSkyNode9()
{
for (int i=0; i<5; ++i)
{
SAFE_RELEASE(m_pTexture[i]);
}
SAFE_RELEASE(m_pVerts);
}
//
// D3DSkyNode9::VOnRestore
//
HRESULT D3DSkyNode9::VOnRestore(Scene *pScene)
{
// Call the base class's restore
SceneNode::VOnRestore(pScene);
m_camera = pScene->GetCamera(); // added post press!
m_numVerts = 20;
SAFE_RELEASE(m_pVerts);
if( FAILED( DXUTGetD3D9Device()->CreateVertexBuffer(
m_numVerts*sizeof(D3D9Vertex_ColoredTextured),
D3DUSAGE_WRITEONLY, D3D9Vertex_ColoredTextured::FVF,
D3DPOOL_MANAGED, &m_pVerts, NULL ) ) )
{
return E_FAIL;
}
// Fill the vertex buffer. We are setting the tu and tv texture
// coordinates, which range from 0.0 to 1.0
D3D9Vertex_ColoredTextured* pVertices;
if( FAILED( m_pVerts->Lock( 0, 0, (void**)&pVertices, 0 ) ) )
return E_FAIL;
// Loop through the grid squares and calc the values
// of each index. Each grid square has two triangles:
//
// A - B
// | / |
// C - D
D3D9Vertex_ColoredTextured skyVerts[4];
D3DCOLOR skyVertColor = 0xffffffff;
float dim = 50.0f;
skyVerts[0].position = Vec3( dim, dim, dim ); skyVerts[0].color=skyVertColor; skyVerts[0].tu=1; skyVerts[0].tv=0;
skyVerts[1].position = Vec3(-dim, dim, dim ); skyVerts[1].color=skyVertColor; skyVerts[1].tu=0; skyVerts[1].tv=0;
skyVerts[2].position = Vec3( dim,-dim, dim ); skyVerts[2].color=skyVertColor; skyVerts[2].tu=1; skyVerts[2].tv=1;
skyVerts[3].position = Vec3(-dim,-dim, dim ); skyVerts[3].color=skyVertColor; skyVerts[3].tu=0; skyVerts[3].tv=1;
Vec3 triangle[3];
triangle[0] = Vec3(0.f,0.f,0.f);
triangle[1] = Vec3(5.f,0.f,0.f);
triangle[2] = Vec3(5.f,5.f,0.f);
Vec3 edge1 = triangle[1]-triangle[0];
Vec3 edge2 = triangle[2]-triangle[0];
Vec3 normal;
normal = edge1.Cross(edge2);
normal.Normalize();
Mat4x4 rotY;
rotY.BuildRotationY(GCC_PI/2.0f);
Mat4x4 rotX;
rotX.BuildRotationX(-GCC_PI/2.0f);
m_sides = 5;
for (DWORD side = 0; side < m_sides; side++)
{
for (DWORD v = 0; v < 4; v++)
{
Vec4 temp;
if (side < m_sides-1)
{
temp = rotY.Xform(Vec3(skyVerts[v].position));
}
else
{
skyVerts[0].tu=1; skyVerts[0].tv=1;
skyVerts[1].tu=1; skyVerts[1].tv=0;
skyVerts[2].tu=0; skyVerts[2].tv=1;
skyVerts[3].tu=0; skyVerts[3].tv=0;
temp = rotX.Xform(Vec3(skyVerts[v].position));
}
skyVerts[v].position = Vec3(temp.x, temp.y, temp.z);
}
memcpy(&pVertices[side*4], skyVerts, sizeof(skyVerts));
}
m_pVerts->Unlock();
return S_OK;
}
//
// D3DSkyNode9::VRender
//
HRESULT D3DSkyNode9::VRender(Scene *pScene)
{
// Setup our texture. Using textures introduces the texture stage states,
// which govern how textures get blended together (in the case of multiple
// textures) and lighting information. In this case, we are modulating
// (blending) our texture with the diffuse color of the vertices.
DXUTGetD3D9Device()->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_MODULATE );
DXUTGetD3D9Device()->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
DXUTGetD3D9Device()->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
DXUTGetD3D9Device()->SetStreamSource( 0, m_pVerts, 0, sizeof(D3D9Vertex_ColoredTextured) );
DXUTGetD3D9Device()->SetFVF( D3D9Vertex_ColoredTextured::FVF );
for (DWORD side = 0; side < m_sides; side++)
{
// FUTURE WORK: A good optimization would be to transform the camera's
// world look vector into local space, and do a dot product. If the
// result is positive, we shouldn't draw the side since it has to be
// behind the camera!
// Sky boxes aren't culled by the normal mechanism
std::string name = GetTextureName(side);
/***
// [mrmike] - This was slightly changed post press, look at the lines below this commented out code
const char *suffix[] = { "_n.jpg", "_e.jpg", "_s.jpg", "_w.jpg", "_u.jpg" };
name += suffix[side];
****/
Resource resource(name);
shared_ptr<ResHandle> texture = g_pApp->m_ResCache->GetHandle(&resource);
shared_ptr<D3DTextureResourceExtraData9> extra = static_pointer_cast<D3DTextureResourceExtraData9>(texture->GetExtra());
DXUTGetD3D9Device()->SetTexture( 0, extra->GetTexture() );
DXUTGetD3D9Device()->DrawPrimitive( D3DPT_TRIANGLESTRIP , 4 * side, 2);
}
DXUTGetD3D9Device()->SetTexture (0, NULL);
return S_OK;
}
//
// D3DSkyNode11::D3DSkyNode11
//
D3DSkyNode11::D3DSkyNode11(const char *pTextureBaseName)
: SkyNode(pTextureBaseName)
{
m_pVertexBuffer = NULL;
m_pIndexBuffer = NULL;
m_VertexShader.EnableLights(false);
}
//
// D3DSkyNode11::~D3DSkyNode11
//
D3DSkyNode11::~D3DSkyNode11()
{
SAFE_RELEASE(m_pVertexBuffer);
SAFE_RELEASE(m_pIndexBuffer);
}
//
// D3DSkyNode11::VOnRestore
//
HRESULT D3DSkyNode11::VOnRestore(Scene *pScene)
{
HRESULT hr;
V_RETURN(SceneNode::VOnRestore(pScene) );
m_camera = pScene->GetCamera();
SAFE_RELEASE(m_pVertexBuffer);
SAFE_RELEASE(m_pIndexBuffer);
V_RETURN (m_VertexShader.OnRestore(pScene) );
V_RETURN (m_PixelShader.OnRestore(pScene) );
m_numVerts = 20;
// Fill the vertex buffer. We are setting the tu and tv texture
// coordinates, which range from 0.0 to 1.0
D3D11Vertex_UnlitTextured *pVertices = GCC_NEW D3D11Vertex_UnlitTextured[m_numVerts];
GCC_ASSERT(pVertices && "Out of memory in D3DSkyNode11::VOnRestore()");
if (!pVertices)
return E_FAIL;
// Loop through the grid squares and calc the values
// of each index. Each grid square has two triangles:
//
// A - B
// | / |
// C - D
D3D11Vertex_UnlitTextured skyVerts[4];
D3DCOLOR skyVertColor = 0xffffffff;
float dim = 50.0f;
skyVerts[0].Pos = Vec3( dim, dim, dim ); skyVerts[0].Uv = Vec2(1.0f, 0.0f);
skyVerts[1].Pos = Vec3(-dim, dim, dim ); skyVerts[1].Uv = Vec2(0.0f, 0.0f);
skyVerts[2].Pos = Vec3( dim,-dim, dim ); skyVerts[2].Uv = Vec2(1.0f, 1.0f);
skyVerts[3].Pos = Vec3(-dim,-dim, dim ); skyVerts[3].Uv = Vec2(0.0f, 1.0f);
Vec3 triangle[3];
triangle[0] = Vec3(0.f,0.f,0.f);
triangle[1] = Vec3(5.f,0.f,0.f);
triangle[2] = Vec3(5.f,5.f,0.f);
Vec3 edge1 = triangle[1]-triangle[0];
Vec3 edge2 = triangle[2]-triangle[0];
Vec3 normal;
normal = edge1.Cross(edge2);
normal.Normalize();
Mat4x4 rotY;
rotY.BuildRotationY(GCC_PI/2.0f);
Mat4x4 rotX;
rotX.BuildRotationX(-GCC_PI/2.0f);
m_sides = 5;
for (DWORD side = 0; side < m_sides; side++)
{
for (DWORD v = 0; v < 4; v++)
{
Vec4 temp;
if (side < m_sides-1)
{
temp = rotY.Xform(Vec3(skyVerts[v].Pos));
}
else
{
skyVerts[0].Uv = Vec2(1.0f, 1.0f);
skyVerts[1].Uv = Vec2(1.0f, 1.0f);
skyVerts[2].Uv = Vec2(1.0f, 1.0f);
skyVerts[3].Uv = Vec2(1.0f, 1.0f);
temp = rotX.Xform(Vec3(skyVerts[v].Pos));
}
skyVerts[v].Pos = Vec3(temp.x, temp.y, temp.z);
}
memcpy(&pVertices[side*4], skyVerts, sizeof(skyVerts));
}
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( D3D11Vertex_UnlitTextured ) * m_numVerts;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = pVertices;
hr = DXUTGetD3D11Device()->CreateBuffer( &bd, &InitData, &m_pVertexBuffer );
SAFE_DELETE(pVertices);
if( FAILED( hr ) )
return hr;
// Loop through the grid squares and calc the values
// of each index. Each grid square has two triangles:
//
// A - B
// | / |
// C - D
WORD *pIndices = GCC_NEW WORD[m_sides * 2 * 3];
WORD *current = pIndices;
for (DWORD i=0; i<m_sides; i++)
{
// Triangle #1 ACB
*(current) = WORD(i*4);
*(current+1) = WORD(i*4 + 2);
*(current+2) = WORD(i*4 + 1);
// Triangle #2 BCD
*(current+3) = WORD(i*4 + 1);
*(current+4) = WORD(i*4 + 2);
*(current+5) = WORD(i*4 + 3);
current+=6;
}
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( WORD ) * m_sides * 2 * 3; // each side has 2 triangles
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
InitData.pSysMem = pIndices;
hr = DXUTGetD3D11Device()->CreateBuffer( &bd, &InitData, &m_pIndexBuffer );
SAFE_DELETE_ARRAY(pIndices);
if( FAILED( hr ) )
return hr;
return S_OK;
}
//
// D3DSkyNode11::VRender
//
HRESULT D3DSkyNode11::VRender(Scene *pScene)
{
HRESULT hr;
V_RETURN (m_VertexShader.SetupRender(pScene, this) );
V_RETURN (m_PixelShader.SetupRender(pScene, this) );
// Set vertex buffer
UINT stride = sizeof( D3D11Vertex_UnlitTextured );
UINT offset = 0;
DXUTGetD3D11DeviceContext()->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &stride, &offset );
// Set index buffer
DXUTGetD3D11DeviceContext()->IASetIndexBuffer( m_pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
// Set primitive topology
DXUTGetD3D11DeviceContext()->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
for (DWORD side = 0; side < m_sides; side++)
{
// FUTURTE WORK: A good optimization would be to transform the camera's
// world look vector into local space, and do a dot product. If the
// result is positive, we shouldn't draw the side since it has to be
// behind the camera!
// Sky boxes aren't culled by the normal mechanism
/***
// [mrmike] - This was slightly changed post press, look at the lines below this commented out code
const char *suffix[] = { "_n.jpg", "_e.jpg", "_s.jpg", "_w.jpg", "_u.jpg" };
name += suffix[side];
****/
std::string name = GetTextureName(side);
m_PixelShader.SetTexture(name.c_str());
DXUTGetD3D11DeviceContext()->DrawIndexed( 6, side * 6, 0 );
}
return S_OK;
}
std::string SkyNode::GetTextureName(const int side)
{
std::string name = m_textureBaseName;
char *letters[] = { "n", "e", "s", "w", "u" };
unsigned int index = name.find_first_of("_");
GCC_ASSERT(index >= 0 && index < name.length()-1);
if (index >= 0 && index < name.length()-1)
{
name[index+1] = *letters[side];
}
return name;
}
以上是天空场景的实现,他继承自场景节点~~
下一篇是关于WSAD方向控制 ( MoveController )的实现~~