// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions // are met: // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of NVIDIA CORPORATION nor the names of its // contributors may be used to endorse or promote products derived // from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Copyright (c) 2008-2021 NVIDIA Corporation. All rights reserved. // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved. // Copyright (c) 2001-2004 NovodeX AG. All rights reserved. #include "SampleVehicle.h" #include "SampleVehicle_SceneQuery.h" #include "SampleRandomPrecomputed.h" #include "SampleAllocatorSDKClasses.h" #include "RendererMemoryMacros.h" #include "RenderMaterial.h" #include "RenderMeshActor.h" #include "cooking/PxTriangleMeshDesc.h" #include "geometry/PxHeightFieldGeometry.h" #include "geometry/PxHeightFieldSample.h" #include "geometry/PxHeightFieldDesc.h" #include "cooking/PxCooking.h" #include "PxScene.h" #include "PxRigidStatic.h" #include "PxTkStream.h" #include "PxTkFile.h" //using namespace physx; using namespace PxToolkit; //Use a mesh (instead of a height field) static bool gRecook = false; enum MaterialID { MATERIAL_TERRAIN_MUD = 1000, MATERIAL_ROAD_TARMAC = 1001, MATERIAL_ROAD_SNOW = 1002, MATERIAL_ROAD_GRASS = 1003, }; static void computeTerrain(bool* done, float* pVB, PxU32 x0, PxU32 y0, PxU32 currentSize, float value, PxU32 initSize, SampleRandomPrecomputed& randomPrecomputed) { // Compute new size currentSize>>=1; if(currentSize > 0) { const PxU32 x1 = (x0+currentSize) % initSize; const PxU32 x2 = (x0+currentSize+currentSize) % initSize; const PxU32 y1 = (y0+currentSize) % initSize; const PxU32 y2 = (y0+currentSize+currentSize) % initSize; if(!done[x1 + y0*initSize]) pVB[(x1 + y0*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y0*initSize)*9+1] + pVB[(x2 + y0*initSize)*9+1]); if(!done[x0 + y1*initSize]) pVB[(x0 + y1*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y0*initSize)*9+1] + pVB[(x0 + y2*initSize)*9+1]); if(!done[x2 + y1*initSize]) pVB[(x2 + y1*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x2 + y0*initSize)*9+1] + pVB[(x2 + y2*initSize)*9+1]); if(!done[x1 + y2*initSize]) pVB[(x1 + y2*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y2*initSize)*9+1] + pVB[(x2 + y2*initSize)*9+1]); if(!done[x1 + y1*initSize]) pVB[(x1 + y1*initSize)*9+1] = randomPrecomputed.getRandomInRange(-0.5f*value, 0.5f*value) + 0.5f * (pVB[(x0 + y1*initSize)*9+1] + pVB[(x2 + y1*initSize)*9+1]); done[x1 + y0*initSize] = true; done[x0 + y1*initSize] = true; done[x2 + y1*initSize] = true; done[x1 + y2*initSize] = true; done[x1 + y1*initSize] = true; // Recurse through 4 corners value *= 0.5f; computeTerrain(done, pVB, x0, y0, currentSize, value, initSize, randomPrecomputed); computeTerrain(done, pVB, x0, y1, currentSize, value, initSize, randomPrecomputed); computeTerrain(done, pVB, x1, y0, currentSize, value, initSize, randomPrecomputed); computeTerrain(done, pVB, x1, y1, currentSize, value, initSize, randomPrecomputed); } } void SampleVehicle::createTerrain(PxU32 size, float width, float chaos) { mNbTerrainVerts = size*size; // Vertex buffer mTerrainVB = (float*)SAMPLE_ALLOC(sizeof(float)*mNbTerrainVerts*3*3); for(PxU32 y=0;y size*0.5f && y < size*0.7f) { mTerrainVB[(x+y*size)*9+1]=ay+sinf(((float)y)*12.0f+4.0f)*2.0f; smoothBorder = false; } else { mTerrainVB[(x+y*size)*9+1]=ay; } if(y > size*0.55f && y < size*0.75f) { mTerrainVB[(y+x*size)*9+1]=ay+sinf(y*12.0f)*0.75f; //mTerrainVB[(y+x*size)*9+1]=ay; tagBuffer[y+x*size] = 3; tagBuffer[x+y*size] = 3; smoothBorder = false; } else if(y < size*0.15f) { const float s = size*0.15f-(float)y; mTerrainVB[(y+x*size)*9+1]=ay+s*0.25f; smoothBorder = false; } else if(y > size*0.85f) { const float s = (float)y-size*0.85f; mTerrainVB[(y+x*size)*9+1]=ay+s*0.7f; smoothBorder = false; } else { mTerrainVB[(y+x*size)*9+1]=ay; tagBuffer[y+x*size] = 1; tagBuffer[x+y*size] = 1; } } if(smoothBorder) { mTerrainVB[((street0-1)+y*size)*9+1]=ay*0.5f+mTerrainVB[((street0-1)+y*size)*9+1]*0.5f; mTerrainVB[(y+(street0-1)*size)*9+1]=ay*0.5f+mTerrainVB[(y+(street0-1)*size)*9+1]*0.5f; mTerrainVB[((street0+1)+y*size)*9+1]=ay*0.5f+mTerrainVB[((street0+1)+y*size)*9+1]*0.5f; mTerrainVB[(y+(street0+1)*size)*9+1]=ay*0.5f+mTerrainVB[(y+(street0+1)*size)*9+1]*0.5f; } } // Circle street for(PxU32 y=0;y= r && d < r+streetSize) { mTerrainVB[(y+x*size)*9+1]=ay; if(y > size*0.55f && y < size*0.75f) tagBuffer[y+x*size] = 2; else tagBuffer[y+x*size] = 1; } else if(d >= r+streetSize && d < r+streetSize+g) { const float a = (d-(r+streetSize))/g; mTerrainVB[(y+x*size)*9+1]=ay*(1.0f-a) + mTerrainVB[(y+x*size)*9+1]*a; } else if(d >= r-g && d < r) { const float a = (d-(r-g))/g; mTerrainVB[(y+x*size)*9+1]=ay*a+mTerrainVB[(y+x*size)*9+1]*(1.0f-a); } } } // Borders const float b = size/25.0f; const float bd = size/2.0f-b; for(PxU32 y=0;y bd || y0 > bd) { float a0 = (x0-bd)/b; float a1 = (y0-bd)/b; if(a1 > a0) a0 = a1; mTerrainVB[(y+x*size)*9+1]=20.0f*a0 + mTerrainVB[(y+x*size)*9+1]*(1-a0); } } } // Sobel filter for(PxU32 y=1;y maxX) { maxX = v[i].x; } if (v[i].z > maxZ) { maxZ = v[i].z; } curVerts += 3*3; meshBound.include(v[i]); } PxReal* uv = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*nVerts*2); curVerts = verts; const float scaleX = (maxX-minX)/64.0f; const float scaleZ = (maxZ-minZ)/64.0f; for(PxU32 i=0;isetWorldBounds(meshBound); renderActor->setEnableCameraCull(true); } SAMPLE_FREE(uv); DELETEARRAY(v); } void SampleVehicle::createTrack(PxU32 size, float width, float chaos) { createTerrain(size, width, chaos); createLandscapeMesh(); } void SampleVehicle::createLandscapeMesh() { RAWTexture data; data.mName = "gravel_diffuse.dds"; RenderTexture* gravelTexture = createRenderTextureFromRawTexture(data); mTerrainMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(0.5f, 0.25f, 0.125f), 1.0f, false, MATERIAL_TERRAIN_MUD, gravelTexture); mRenderMaterials.push_back(mTerrainMaterial); data.mName = "asphalt_diffuse.dds"; RenderTexture* asphaltTexture = createRenderTextureFromRawTexture(data); mRoadMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_ROAD_TARMAC, asphaltTexture); mRenderMaterials.push_back(mRoadMaterial); data.mName = "ice_diffuse.dds"; RenderTexture* snowTexture = createRenderTextureFromRawTexture(data); mRoadIceMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(0.05f, 0.05f, 0.75f), 1.0f, false, MATERIAL_ROAD_SNOW, snowTexture); mRenderMaterials.push_back(mRoadIceMaterial); data.mName = "grass_diffuse.dds"; RenderTexture* grassTexture = createRenderTextureFromRawTexture(data); mRoadGravelMaterial = SAMPLE_NEW(RenderMaterial)(*getRenderer(), PxVec3(1.0f, 1.0f, 1.0f), 1.0f, false, MATERIAL_ROAD_GRASS, grassTexture); mRenderMaterials.push_back(mRoadGravelMaterial); PxTransform pose; pose = PxTransform(PxIdentity); // pose.p.y -= 10.0f; mHFActor = getPhysics().createRigidStatic(pose); for(PxU32 i=0;i 0) { char filename[512]; sprintf(filename, "SampleVehicleGroundMeshes_Part%d", i); addMesh(mHFActor, mTerrainVB, mNbTerrainVerts, mIB[i], mNbTriangles[i], i, filename); if (mNbTriangles[i] > (1<<16)) { PxU32 firstBatch = mNbTriangles[i]/2; addRenderMesh(mTerrainVB, mNbTerrainVerts, mIB[i], firstBatch, MATERIAL_TERRAIN_MUD); addRenderMesh(mTerrainVB, mNbTerrainVerts, mIB[i]+(firstBatch*3), mNbTriangles[i]-firstBatch, mRenderMaterial[i]); } else { addRenderMesh(mTerrainVB, mNbTerrainVerts, mIB[i], mNbTriangles[i], mRenderMaterial[i]); } } } PxSceneWriteLock scopedLock(*mScene); mScene->addActor(*mHFActor); PxShape* shapeBuffer[MAX_NUM_INDEX_BUFFERS]; mHFActor->getShapes(shapeBuffer, MAX_NUM_INDEX_BUFFERS); PxFilterData simulationFilterData; simulationFilterData.word0=COLLISION_FLAG_GROUND; simulationFilterData.word1=COLLISION_FLAG_GROUND_AGAINST; PxFilterData queryFilterData; SampleVehicleSetupDrivableShapeQueryFilterData(&queryFilterData); for(PxU32 i=0;isetSimulationFilterData(simulationFilterData); shapeBuffer[i]->setQueryFilterData(queryFilterData); shapeBuffer[i]->setFlag(PxShapeFlag::eVISUALIZATION,false); } }