首页 > 代码库 > 游戏架构其九:光线投射和天空 { Raycast and Sky }

游戏架构其九:光线投射和天空 { Raycast and Sky }

光线和天空能够大大增强游戏的画面效果,以下是实现:

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 )的实现~~




游戏架构其九:光线投射和天空 { Raycast and Sky }