Terep Szécsi László
Mechanizmus NxHeightField-ek definiálása PhysicsModel-be NxHeightFieldShapeDesc-ek betöltése Mesh-ek gyártása az NxHeightField- ekből ShadedMesh a Meshhez PhysicsEntity
PhysicsModel Építés NxHeightField NxHeightFieldShapeDesc Mesh Actor ShadedMesh
XML <PhysicsHeightField name="terrain" numberOfRows="128" numberOfColumns="128" fileName="mindegy" /> <NxHeightFieldShape heightField="terrain" rowScale="16" columnScale="16" heightScale="10" />
XML <Texture name="kdMap" file="chessboard.jpg" />
XML <PhysicsEntity name="terrain" shadedMesh="terrain" physicsModel="terrain" position.x="-1024" position.y="-40" position.z="-1024"/> groundot meg vegyük ki terep sarka
Directory.h typedef std::map< const std::wstring, NxHeightField*> PhysicsHeightFieldDirectory;
EngineCore PhysicsHeightFieldDirectory physicsHeightFieldDirectory; void loadPhysicsHeightFields( XMLNode& xMainNode); void loadNxHeightFieldShapes( XMLNode& physicsModelNode, PhysicsModel* physicsModel);
LPD3DXMESH createMeshFromHeightField( NxHeightField* heightField, double rowScale, double columnScale, double heightScale); void createHeightFieldMeshes( XMLNode& xMainNode);
EngineCore.cpp void EngineCore::loadLevel() { //materialt hozzuk ide előre loadPhysicsMaterials(xMainNode); loadPhysicsHeightFields(xMainNode); createHeightFieldMeshes(xMainNode); loadMeshes(xMainNode); loadShadedMeshes(xMainNode);
ReleaseManagedResources delete sceneRoot; { PhysicsHeightFieldDirectory::iterator i = physicsHeightFieldDirectory.begin(); while(i != physicsHeightFieldDirectory.end()){ nxPhysicsSDK->releaseHeightField( *i->second); i++; } nxPhysicsSDK->releaseScene(*nxScene); nxPhysicsSDK->release();
loadPhysicsHeightFields eleje void EngineCore::loadPhysicsHeightFields( XMLNode& xMainNode) { int iPhysicsHeightField = 0; XMLNode physicsHeightFieldNode; while( !(physicsHeightFieldNode = xMainNode.getChildNode( L"PhysicsHeightField", iPhysicsHeightField)).isEmpty() ) { const wchar_t* fileName = physicsHeightFieldNode|L"fileName";
folyt.: leíró kitöltése NxHeightFieldDesc desc; desc.nbRows = physicsHeightFieldNode.readLong( L"numberOfRows", 128); desc.nbColumns = physicsHeightFieldNode.readLong( L"numberOfColumns", 128); desc.format = NX_HF_S16_TM; desc.sampleStride = sizeof(NxHeightFieldSample); desc.verticalExtent = -1000; desc.thickness = 0; desc.convexEdgeThreshold = 0;
folyt.: random magasságok NxHeightFieldSample* samples = new NxHeightFieldSample[desc.nbRows * desc.nbColumns]; desc.samples = (void*)samples; for(int i=0; i < desc.nbRows; i++){ for(int j=0; j < desc.nbColumns; j++){ NxHeightFieldSample& e = samples[i + j*desc.nbRows]; e.height = rand() % 0xffff; e.materialIndex0 = 0; e.materialIndex1 = 1; e.tessFlag = 0; e.unused = 0;}
loadPhysicsHeightFields vége NxHeightField* nxHeightField = nxPhysicsSDK ->createHeightField(desc); delete samples; const wchar_t* physicsHeightFieldName = physicsHeightFieldNode|L"name"; physicsHeightFieldDirectory [physicsHeightFieldName] = nxHeightField; iPhysicsHeightField++; }}
EngineCore.cpp void EngineCore::loadPhysicsModels( XMLNode& xMainNode) { loadNxWheelShapes(physicsModelNode, physicsModel); loadNxHeightFieldShapes( physicsModelNode, physicsModel);
EngineCore.cpp void EngineCore::loadNxHeightFieldShapes(XMLNode& physicsModelNode, PhysicsModel* physicsModel){ int iShape = 0; XMLNode shapeNode; while( !(shapeNode = physicsModelNode.getChildNode( L"NxHeightFieldShape", iShape)).isEmpty() ) { NxHeightFieldShapeDesc* nxHeightFieldShapeDesc = new NxHeightFieldShapeDesc(); loadShapeDesc(shapeNode, nxHeightFieldShapeDesc); // ide jön a következő dia szövege physicsModel->addShape(nxHeightFieldShapeDesc); iShape++; }
EngineCore.cpp const wchar_t* heightFieldName = shapeNode|L"heightField"; if(heightFieldName) { PhysicsHeightFieldDirectory::iterator iPhysicsHeightField = physicsHeightFieldDirectory.find(heightFieldName); if(iPhysicsHeightField != physicsHeightFieldDirectory.end()) { nxHeightFieldShapeDesc->heightField = iPhysicsHeightField->second; nxHeightFieldShapeDesc->columnScale = shapeNode.readDouble(L"columnScale", 16.0); nxHeightFieldShapeDesc->rowScale = shapeNode.readDouble(L"rowScale", 16.0); nxHeightFieldShapeDesc->heightScale = shapeNode.readDouble(L"heightScale", 20.0) / (double)0xffff; nxHeightFieldShapeDesc->materialIndexHighBits = 0; nxHeightFieldShapeDesc->holeMaterial = 2; nxHeightFieldShapeDesc->meshFlags = 0; }
EngineCore.cpp void EngineCore::createHeightFieldMeshes(XMLNode& xMainNode){ int iMesh = 0; XMLNode meshNode; while( !(meshNode = xMainNode.getChildNode(L"HeightFieldMesh", iMesh)).isEmpty()) { const wchar_t* name = meshNode|L"name"; if(name){ // ide jön a következő dia szövege } iMesh++; }
createHeightFieldMeshes mag const wchar_t* heightFieldName = meshNode|L"heightField"; if(heightFieldName) { PhysicsHeightFieldDirectory::iterator iHeightField = physicsHeightFieldDirectory.find(heightFieldName); if(iHeightField != physicsHeightFieldDirectory.end()) { LPD3DXMESH mesh = createMeshFromHeightField(iHeightField->second, meshNode.readDouble(L"rowScale", 16.0), meshNode.readDouble(L"columnScale", 16.0), meshNode.readDouble(L"heightScale", 20)); ); meshDirectory[name] = mesh; }
createMeshFromHeightField eleje LPD3DXMESH EngineCore::createMeshFromHeightField( NxHeightField* heightField, double rowScale, double columnScale, double heightScale) { unsigned int nCols = heightField->getNbColumns(); unsigned int nRows = heightField->getNbRows(); unsigned int nTileColumns = nCols-1; unsigned int nTileRows = nRows-1; NxHeightFieldSample* samples = new NxHeightFieldSample[nCols * nRows]; heightField->saveCells((void*)samples, sizeof(NxHeightFieldSample) * nCols * nRows);
createMeshFromHeightField folyt. LPD3DXMESH mesh; D3DXCreateMeshFVF(nTileRows * nTileColumns * 2, nRows * nCols, 0, D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0), device, &mesh); LPDIRECT3DINDEXBUFFER9 terrainIndexBuffer; LPDIRECT3DVERTEXBUFFER9 terrainVertexBuffer; mesh->GetVertexBuffer(&terrainVertexBuffer); mesh->GetIndexBuffer(&terrainIndexBuffer);
createMeshFromHeightField folyt. struct TerrainVertex{D3DXVECTOR3 pos; D3DXVECTOR3 normal; D3DXVECTOR2 tex;} *vertexData; terrainVertexBuffer->Lock(0, sizeof(TerrainVertex) * nRows * nCols, (void**)&vertexData, 0); for(int i=0; i<nRows; i++) { for(int j=0; j<nCols; j++){ vertexData[i * nCols + j].pos.x = (float)i * rowScale; vertexData[i * nCols + j].pos.y = samples[i*(nTileColumns+1) + j].height / (double)0xffff * heightScale; vertexData[i * nCols + j].pos.z = (float)j * columnScale; vertexData[i * nCols + j].tex.x = (float)j / nTileRows; vertexData[i * nCols + j].tex.y = (float)i / nTileColumns; vertexData[i * nCols + j].normal.x = 0; vertexData[i * nCols + j].normal.y = 1; vertexData[i * nCols + j].normal.z = 0; } terrainVertexBuffer->Unlock();
createMeshFromHeightField folyt. short* indexData; terrainIndexBuffer->Lock(0, sizeof(short) * 3 * 2 * nTileRows * nTileColumns, í(void**)&indexData, 0); for(int i=0; i<nTileRows; i++) for(int j=0; j<nTileColumns; j++){ if(i%2 == 0) { indexData[ (i * nTileColumns + j) * 6] = i * nCols + j; indexData[ (i * nTileColumns + j) * 6 + 1] = i * nCols + j + 1; indexData[ (i * nTileColumns + j) * 6 + 2] = (i + 1) * nCols + j; indexData[ (i * nTileColumns + j) * 6 + 4] = i * nCols + j + 1; indexData[ (i * nTileColumns + j) * 6 + 3] = (i + 1) * nCols + j; indexData[ (i * nTileColumns + j) * 6 + 5] = (i + 1) * nCols + j + 1; } else { indexData[ (i * nTileColumns + j) * 6] = i * nCols + j; indexData[ (i * nTileColumns + j) * 6 + 1] = (i + 1) * nCols + j + 1; indexData[ (i * nTileColumns + j) * 6 + 2] = (i + 1) * nCols + j; indexData[ (i * nTileColumns + j) * 6 + 4] = i * nCols + j; indexData[ (i * nTileColumns + j) * 6 + 5] = i * nCols + j + 1; indexData[ (i * nTileColumns + j) * 6 + 3] = (i + 1) * nCols + j + 1; } terrainIndexBuffer->Unlock();
createMeshFromHeightField vége terrainVertexBuffer->Release(); terrainIndexBuffer->Release(); return mesh; }
Próba tereprally
Terep textúrázása egy textúra a lehetséges csempékkel terrain_tiles.png egy textúra a talajtípus- információval terrain_type.png
új effect: terrain.fx includeoljuk be az engineCore.fx-be
terrain.fx texture2D typeMap; sampler2D typeSampler = sampler_state { texture = ; MipFilter = Point; MagFilter = Linear; MinFilter = Linear; AddressU = WRAP; AddressV = WRAP; }; texture2D tileMap; sampler2D tileSampler = sampler_state { texture = ; MipFilter = Linear; MagFilter = Linear; MinFilter = Linear; AddressU = WRAP; AddressV = WRAP; };
input-output struct TerrainInput { float4 pos: POSITION; float2tex: TEXCOORD0; }; struct TerrainOutput { float4 pos: POSITION; float2 tex: TEXCOORD0; };
vertex shader TerrainOutput vsTerrain(TerrainInput input) { TerrainOutput output = (TerrainOutput)0; output.pos = mul(input.pos, modelViewProjMatrix); output.tex = input.tex; return output; }
uniform paraméterek float4 terrainTileRatio = float4(1, 0.25, 0, 0); float4 terrainTextureScale = 32; milyen magas egy csempe a tileMap textúrában hány csempével legyen lefedve a megasságmező
pixel shader float4 psTerrain(TerrainOutput input) : COLOR0 { float tileIndex = tex2Dlod(typeSampler, float4(input.tex, 0, 0)) / terrainTileRatio.y; float2 tileTex = frac(input.tex * terrainTextureScale.x); tileTex = (tileTex - float2(0.5, 0.5)) * / float2(0.5, 0.5); tileTex *= terrainTileRatio.xy;
pixel shader folyt. float p1 = floor(tileIndex); float p2 = p1 + 1; float4 c1 = tex2D(tileSampler, tileTex + float2(0, p1 * terrainTileRatio.y)); float4 c2 = tex2D(tileSampler, tileTex + float2(0, p2 * terrainTileRatio.y)); return lerp(c1, c2, tileIndex - p1); }
technique technique terrain { pass ExamplePass { CullMode = None; VertexShader = compile vs_3_0 vsTerrain(); PixelShader = compile ps_3_0 psTerrain(); }
XML
Gond: mipmappelés