首页 > 代码库 > 游戏架构其九:光线投射和天空 { 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 }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。