370 likes | 491 Views
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. NxHeightFieldShapeDesc. Mesh. ShadedMesh. PhysicsEntity. Actor. Építés. NxHeightField.
E N D
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
NxHeightFieldShapeDesc Mesh ShadedMesh PhysicsEntity Actor Építés NxHeightField PhysicsModel
XML • <PhysicsHeightField name="terrain" numberOfRows="128" • numberOfColumns="128" • fileName="mindegy" /> • <PhysicsModel name="terrain" dynamism="static"> • <NxHeightFieldShape • heightField="terrain" • rowScale="16" columnScale="16" heightScale="10"/> • </PhysicsModel> • <HeightFieldMesh name="terrain" heightField="terrain" rowScale="16" columnScale="16" heightScale="10"/>
XML • <ShadedMesh name="terrain" mesh="terrain" > • <Role name="basic"> • <Material technique="basic"> • <Texture name="kdMap" • file="chessboard.jpg" /> • </Material> • </Role> • </ShadedMesh>
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; • LPDIRECT3DVERTEXBUFFER9terrainVertexBuffer; • 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 = <typeMap>; • MipFilter = Point; • MagFilter = Linear; • MinFilter = Linear; • AddressU = WRAP; • AddressV = WRAP; • }; • texture2D tileMap; • sampler2D tileSampler = sampler_state • { • texture = <tileMap>; • MipFilter = Linear; • MagFilter = Linear; • MinFilter = Linear; • AddressU = WRAP; • AddressV = WRAP; • };
input-output • struct TerrainInput • { • float4 pos : POSITION; • float2 tex : 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)) * 496.0 / 512.0 + 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 • <ShadedMesh name="terrain" mesh="terrain" > • <Role name="basic"> • <Material technique="terrain"> • <Texture name="typeMap" file="terrain_type.png" /> • <Texture name="tileMap" file="terrain_tiles.png" /> • </Material> • </Role> • </ShadedMesh>
Gond: mipmappelés • <Texture name="tileMap" file="terrain_tiles.png" mips="4" />