This commit is contained in:
2025-11-28 23:13:44 +05:30
commit a3a8e79709
7360 changed files with 1156074 additions and 0 deletions

View File

@ -0,0 +1,450 @@
//
// 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 "PxPhysicsAPI.h"
#include "PxTkStream.h"
#include "SampleNorthPole.h"
using namespace PxToolkit;
#define USE_MESH_LANDSCAPE // PT: define this to use a triangle mesh for the landscape, instead of a heightfield
static PxReal randomScaled(PxReal value)
{
PxReal val = value*(getSampleRandom().randomFloat());
return val;
}
static void computeTerrain(bool* done, PxReal* pVB, PxU32 x0, PxU32 y0, PxU32 currentSize, PxReal value, PxU32 initSize)
{
// Compute new size
currentSize>>=1;
if (currentSize > 0) {
PxU32 x1 = (x0+currentSize) % initSize;
PxU32 x2 = (x0+currentSize+currentSize) % initSize;
PxU32 y1 = (y0+currentSize) % initSize;
PxU32 y2 = (y0+currentSize+currentSize) % initSize;
if(!done[x1 + y0*initSize]) pVB[(x1 + y0*initSize)] = randomScaled(value) + 0.5f * (pVB[(x0 + y0*initSize)] + pVB[(x2 + y0*initSize)]);
if(!done[x0 + y1*initSize]) pVB[(x0 + y1*initSize)] = randomScaled(value) + 0.5f * (pVB[(x0 + y0*initSize)] + pVB[(x0 + y2*initSize)]);
if(!done[x2 + y1*initSize]) pVB[(x2 + y1*initSize)] = randomScaled(value) + 0.5f * (pVB[(x2 + y0*initSize)] + pVB[(x2 + y2*initSize)]);
if(!done[x1 + y2*initSize]) pVB[(x1 + y2*initSize)] = randomScaled(value) + 0.5f * (pVB[(x0 + y2*initSize)] + pVB[(x2 + y2*initSize)]);
if(!done[x1 + y1*initSize]) pVB[(x1 + y1*initSize)] = randomScaled(value) + 0.5f * (pVB[(x0 + y1*initSize)] + pVB[(x2 + y1*initSize)]);
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);
computeTerrain(done, pVB, x0, y1, currentSize, value, initSize);
computeTerrain(done, pVB, x1, y0, currentSize, value, initSize);
computeTerrain(done, pVB, x1, y1, currentSize, value, initSize);
}
}
static void fractalize(PxReal* heights, const PxU32 size, const PxReal roughness)
{
PxU32 num = size*size;
bool* done = (bool*)SAMPLE_ALLOC(sizeof(bool)*num);
for(PxU32 i=0; i<num; i++)
done[i]=false;
computeTerrain(done,heights,0,0,size,roughness,size);
SAMPLE_FREE(done);
}
PxRigidStatic* SampleNorthPole::buildHeightField()
{
// create a height map
PxU32 hfSize = 32; // some power of 2
PxU32 hfNumVerts = hfSize*hfSize;
PxReal hfScale = 8.0f; // this is how wide one heightfield square is
PxReal* heightmap = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*hfNumVerts);
for(PxU32 i = 0; i < hfNumVerts; i++)
heightmap[i]=-9.0f;
getSampleRandom().setSeed(42);
fractalize(heightmap,hfSize,16);
{ // make a plateau to place the igloo
const PxU32 i = hfSize*hfSize/2+hfSize/2;
PxReal h = 0;
heightmap[i-hfSize-1]=h; heightmap[i-hfSize]=h; heightmap[i-hfSize+1]=h;
heightmap[i-1]=h; heightmap[i]=h; heightmap[i+1]=h;
heightmap[i+hfSize-1]=h; heightmap[i+hfSize]=h; heightmap[i+hfSize+1]=h;
}
{ // make render terrain
PxReal* hfVerts = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*hfNumVerts*3);
PxReal* hfNorms = (PxReal*)SAMPLE_ALLOC(sizeof(PxReal)*hfNumVerts*3);
PxU32 hfNumTris = (hfSize-1)*(hfSize-1)*2;
PxU32* hfTris = (PxU32*)SAMPLE_ALLOC(sizeof(PxU32)*hfNumTris*3);
createLandscape(heightmap,hfSize,hfScale,hfVerts,hfNorms,hfTris);
RAWMesh data;
data.mName = "terrain";
data.mTransform = PxTransform(PxIdentity);
data.mTransform.p = PxVec3(-(hfSize/2*hfScale),0,-(hfSize/2*hfScale));
data.mNbVerts = hfNumVerts;
data.mVerts = (PxVec3*)hfVerts;
data.mVertexNormals = (PxVec3*)hfNorms;
data.mUVs = 0;
data.mMaterialID = 0;
data.mNbFaces = hfNumTris;
data.mIndices = hfTris;
#ifdef USE_MESH_LANDSCAPE
setFilename(getSampleMediaFilename("SampleNorthPole_Mesh"));
newMesh(data);
#else
createRenderMeshFromRawMesh(data);
#endif
SAMPLE_FREE(hfTris);
SAMPLE_FREE(hfNorms);
SAMPLE_FREE(hfVerts);
}
#ifndef USE_MESH_LANDSCAPE
// eventually create the physics heightfield
PxRigidStatic* hfActor = createHeightField(heightmap,hfScale,hfSize);
#endif
SAMPLE_FREE(heightmap);
#ifdef USE_MESH_LANDSCAPE
return 0;
#else
return hfActor;
#endif
}
void SampleNorthPole::createLandscape(PxReal* heightmap, PxU32 width, PxReal hfScale, PxReal* outVerts, PxReal* outNorms, PxU32* outTris)
{
for(PxU32 y=0; y<width; y++)
{
for(PxU32 x=0; x<width; x++)
{
PxU32 index=(x+y*width)*3;
outVerts[index+0]=(PxReal(x))* hfScale;
outVerts[index+1]=heightmap[x+y*width];
outVerts[index+2]=(PxReal(y))*hfScale;
outNorms[index+0]=0;
outNorms[index+1]=1;
outNorms[index+2]=0;
}
}
// Sobel filter
for (PxU32 y=1;y<width-1;y++) {
for (PxU32 x=1;x<width-1;x++) {
// 1 0 -1
// 2 0 -2
// 1 0 -1
PxReal dx;
dx = outVerts[((x-1)+(y-1)*width)*3+1];
dx -= outVerts[((x+1)+(y-1)*width)*3+1];
dx += 2.0f*outVerts[((x-1)+(y+0)*width)*3+1];
dx -= 2.0f*outVerts[((x+1)+(y+0)*width)*3+1];
dx += outVerts[((x-1)+(y+1)*width)*3+1];
dx -= outVerts[((x+1)+(y+1)*width)*3+1];
// 1 2 1
// 0 0 0
// -1 -2 -1
PxReal dy;
dy = outVerts[((x-1)+(y-1)*width)*3+1];
dy += 2.0f*outVerts[((x+0)+(y-1)*width)*3+1];
dy += outVerts[((x+1)+(y-1)*width)*3+1];
dy -= outVerts[((x-1)+(y+1)*width)*3+1];
dy -= 2.0f*outVerts[((x+0)+(y+1)*width)*3+1];
dy -= outVerts[((x+1)+(y+1)*width)*3+1];
PxReal nx = dx/hfScale*0.15f;
PxReal ny = 1.0f;
PxReal nz = dy/hfScale*0.15f;
PxReal len = sqrtf(nx*nx+ny*ny+nz*nz);
outNorms[(x+y*width)*3+0] = nx/len;
outNorms[(x+y*width)*3+1] = ny/len;
outNorms[(x+y*width)*3+2] = nz/len;
}
}
PxU32 numTris = 0;
for(PxU32 j=0; j<width-1; j++)
{
for(PxU32 i=0; i<width-1; i++)
{
outTris[3*numTris+0]= i + j *(width);
outTris[3*numTris+1]= i + (j+1)*(width);
outTris[3*numTris+2]= i+1 + j *(width);
outTris[3*numTris+3]= i + (j+1)*(width);
outTris[3*numTris+4]= i+1 + (j+1)*(width);
outTris[3*numTris+5]= i+1 + j *(width);
numTris+=2;
}
}
}
PxRigidStatic* SampleNorthPole::createHeightField(PxReal* heightmap, PxReal hfScale, PxU32 hfSize)
{
const PxReal heightScale = 0.001f;
PxU32 hfNumVerts = hfSize*hfSize;
PxHeightFieldSample* samples = (PxHeightFieldSample*)SAMPLE_ALLOC(sizeof(PxHeightFieldSample)*hfNumVerts);
memset(samples,0,hfNumVerts*sizeof(PxHeightFieldSample));
for(PxU32 x = 0; x < hfSize; x++)
for(PxU32 y = 0; y < hfSize; y++)
{
samples[x+y*hfSize].height = (PxI16)(heightmap[y+x*hfSize]/heightScale);
samples[x+y*hfSize].setTessFlag();
samples[x+y*hfSize].materialIndex0=1;
samples[x+y*hfSize].materialIndex1=1;
}
PxHeightFieldDesc hfDesc;
hfDesc.format = PxHeightFieldFormat::eS16_TM;
hfDesc.nbColumns = hfSize;
hfDesc.nbRows = hfSize;
hfDesc.samples.data = samples;
hfDesc.samples.stride = sizeof(PxHeightFieldSample);
PxHeightField* heightField = getCooking().createHeightField(hfDesc, getPhysics().getPhysicsInsertionCallback());
if(!heightField)
fatalError("creating the heightfield failed");
PxTransform pose = PxTransform(PxIdentity);
pose.p = PxVec3(-(hfSize/2*hfScale),0,-(hfSize/2*hfScale));
PxRigidStatic* hfActor = getPhysics().createRigidStatic(pose);
if(!hfActor)
fatalError("creating heightfield actor failed");
PxHeightFieldGeometry hfGeom(heightField, PxMeshGeometryFlags(), heightScale, hfScale, hfScale);
PxShape* hfShape = PxRigidActorExt::createExclusiveShape(*hfActor, hfGeom, getDefaultMaterial());
//setCCDActive(*hfShape);
if(!hfShape)
fatalError("creating heightfield shape failed");
getActiveScene().addActor(*hfActor);
SAMPLE_FREE(samples);
return hfActor;
}
PxRigidStatic* SampleNorthPole::buildIglooTriMesh()
{
{ // construct the mesh data
const PxReal innerR = 2.7f;
const PxReal outerR = 3;
const PxU32 numBlocks = 16;
const PxU32 numRows = 8;
const PxU32 doorHeight = 2;
const PxReal accesslength = outerR*1.2f;
const PxReal step = PxPi*2/numBlocks;
const PxReal step2 = PxPi/2/numRows;
const PxReal thickness = (outerR - innerR);
const PxVec3 initpos(1,0,0);
const PxU32 n = 2*numBlocks;
PxVec3 bufferVerts[2][n+2];
PxU32 buf = 0;
PxVec3* currentVerts = bufferVerts[buf];
for(int i = 0; i < (int)numBlocks; i++)
{
PxQuat rotY(i*step-step/2,PxVec3(0,1,0));
PxVec3 pos = rotY.rotate(initpos);
currentVerts[2*i] = pos*innerR;
currentVerts[2*i+1] = pos*outerR;
}
currentVerts[n] = currentVerts[0];
currentVerts[n+1] = currentVerts[1];
for(int j = 0; j < (int)numRows; j++)
{
PxVec3* previousVerts = currentVerts;
currentVerts = bufferVerts[buf=1-buf];
PxQuat rotZ((j+1)*step2,PxVec3(0,0,1));
PxVec3 posX = rotZ.rotate(initpos);
for(int i = 0; i < (int)numBlocks; i++)
{
PxQuat rotY(i*step-step/2,PxVec3(0,1,0));
PxVec3 pos = rotY.rotate(posX);
currentVerts[2*i] = pos*innerR;
currentVerts[2*i+1] = pos*outerR;
}
currentVerts[n] = currentVerts[0];
currentVerts[n+1] = currentVerts[1];
for(int i = 0; i < (int)numBlocks; i++)
{
if( (i==0 && (j<(int)doorHeight)) || (i==numBlocks/3 && j==numRows/2) )
{
// omit the door and window
continue;
}
PxVec3 block[8] =
{
previousVerts[2*i],previousVerts[2*i+1],previousVerts[2*i+2],previousVerts[2*i+3],
currentVerts[2*i], currentVerts[2*i+1], currentVerts[2*i+2], currentVerts[2*i+3]
};
addBlock(block);
}
}
PxQuat rotZ((doorHeight)*step2,PxVec3(0,0,1));
PxQuat rotY(step/2,PxVec3(0,1,0));
PxVec3 topIL = rotY.rotate(rotZ.rotate(initpos))*innerR;
PxVec3 topIR = rotY.rotateInv(rotZ.rotate(initpos))*innerR;
PxVec3 topOL = topIL; topOL.x = accesslength;
PxVec3 topOR = topIR; topOR.x = accesslength;
PxVec3 bottomIL = rotY.rotate(initpos)*innerR;
PxVec3 bottomIR = rotY.rotateInv(initpos)*innerR;
PxVec3 bottomOL = topOL; bottomOL.y = 0;
PxVec3 bottomOR = topOR; bottomOR.y = 0;
PxVec3 dZ = PxVec3(0,0,thickness);
PxVec3 dY = PxVec3(0,thickness,0);
PxVec3 blockL[8] =
{
bottomIL, bottomOL, bottomIL-dZ, bottomOL-dZ,
topIL, topOL, topIL-dZ, topOL-dZ
};
addBlock(blockL);
PxVec3 blockR[8] =
{
bottomIR+dZ, bottomOR+dZ, bottomIR, bottomOR,
topIR+dZ, topOR+dZ, topIR, topOR
};
addBlock(blockR);
PxVec3 blockT[8] =
{
topIR+dZ, topOR+dZ, topIL-dZ, topOL-dZ,
topIR+dY, topOR+dY, topIL+dY, topOL+dY
};
addBlock(blockT);
}
const PxU32 numTris = (PxU32)(mTris.size()/3);
const PxU32 numVerts = (PxU32)(mVerts.size());
// make render mesh
RAWMesh data;
data.mIndices = &mTris[0];
data.mNbFaces = numTris;
data.mVerts = &mVerts[0];
data.mNbVerts = numVerts;
data.mVertexNormals = &mVerts[0];
data.mMaterialID = 0;
data.mTransform = PxTransform(PxVec3(0,0,0));
createRenderMeshFromRawMesh(data);
PxTriangleMesh* triMesh = PxToolkit::createTriangleMesh32(getPhysics(), getCooking(), &mVerts[0], numVerts, &mTris[0], numTris);
if(!triMesh)
fatalError("creating the triangle mesh failed");
mVerts.clear();
mTris.clear();
mNorms.clear();
// create actor
PxRigidStatic* iglooActor = getPhysics().createRigidStatic(PxTransform(PxVec3(0,0,0)));
if(!iglooActor)
fatalError("creating igloo actor failed");
PxTriangleMeshGeometry geom(triMesh);
PxShape* iglooShape = PxRigidActorExt::createExclusiveShape(*iglooActor, geom,getDefaultMaterial());
if(!iglooShape)
fatalError("creating igloo shape failed");
//setCCDActive(*iglooShape);
getActiveScene().addActor(*iglooActor);
return iglooActor;
}
void SampleNorthPole::addBlock(PxVec3 blockVerts[8])
{
PxU32 n = 8;
PxVec3* v = blockVerts;
const PxU32 offset = (PxU32)mVerts.size();
while(n--)
mVerts.push_back(*v++);
// bottom
mTris.push_back(0 + offset); mTris.push_back(3 + offset); mTris.push_back(1 + offset);
mTris.push_back(0 + offset); mTris.push_back(2 + offset); mTris.push_back(3 + offset);
// top
mTris.push_back(4 + offset); mTris.push_back(5 + offset); mTris.push_back(7 + offset);
mTris.push_back(4 + offset); mTris.push_back(7 + offset); mTris.push_back(6 + offset);
// right
mTris.push_back(0 + offset); mTris.push_back(1 + offset); mTris.push_back(4 + offset);
mTris.push_back(5 + offset); mTris.push_back(4 + offset); mTris.push_back(1 + offset);
// left
mTris.push_back(6 + offset); mTris.push_back(7 + offset); mTris.push_back(2 + offset);
mTris.push_back(3 + offset); mTris.push_back(2 + offset); mTris.push_back(7 + offset);
// front
mTris.push_back(5 + offset); mTris.push_back(1 + offset); mTris.push_back(7 + offset);
mTris.push_back(3 + offset); mTris.push_back(7 + offset); mTris.push_back(1 + offset);
// back
mTris.push_back(4 + offset); mTris.push_back(6 + offset); mTris.push_back(0 + offset);
mTris.push_back(2 + offset); mTris.push_back(0 + offset); mTris.push_back(6 + offset);
}