void Gu::ConvexMesh::debugVisualize(Cm::RenderOutput& out, const PxTransform& pose, const PxMeshScale& scale) const { const PxU32 scolor = PxU32(PxDebugColor::eARGB_MAGENTA); const PxVec3* vertices = mHullData.getHullVertices(); const PxU8* indexBuffer = mHullData.getVertexData8(); const PxU32 nbPolygons = getNbPolygonsFast(); const PxMat44 m44(PxMat33(pose.q) * scale.toMat33(), pose.p); out << m44 << scolor; // PT: no need to output this for each segment! for (PxU32 i = 0; i < nbPolygons; i++) { const PxU32 pnbVertices = mHullData.mPolygons[i].mNbVerts; PxVec3 begin = m44.transform(vertices[indexBuffer[0]]); // PT: transform it only once before the loop starts for (PxU32 j = 1; j < pnbVertices; j++) { PxVec3 end = m44.transform(vertices[indexBuffer[j]]); out.outputSegment(begin, end); begin = end; } out.outputSegment(begin, m44.transform(vertices[indexBuffer[0]])); indexBuffer += pnbVertices; } }
mat4 getMatFromPhysXTransform(PxTransform transform) { PxMat44 mat = PxMat44(transform); float m[16]; for (int i = 0; i < 16; ++i) m[i] = *(mat.front() + i); return mat4(m); }
PxVec3 EmitterGeomSphereShellImpl::randomPosInFullVolume(const PxMat44& pose, QDSRand& rand) const { float hemisphere = 2.0f * *mHemisphere - 1.0f; bool moreThanHalf = true; if (*mHemisphere > 0.5f) { moreThanHalf = false; } // There are two cases here - 1-st for hemisphere cut above the center of the sphere // and 2-nd for hemisphere cut below the center of the sphere. // The reason for this is that in case very high hemisphere cut is set, so the area // of the actual emitter is very small in compare to the whole sphere emitter, it would take too // much time [on average] to generate suitable point using randomPointOnUnitSphere // function, so in this case it is more efficient to use another method. // in case we have at least half of the sphere shell present the randomPointOnUnitSphere should // be sufficient. PxVec3 pos; if(!moreThanHalf) { // 1-st case : // * generate random unit vector within a cone // * clamp to big radius const float sphereCapBaseHeight = -1.0f + 2 * (*mHemisphere); const float phi = rand.getScaled(0.0f, PxTwoPi); const float cos_theta = sphereCapBaseHeight; const float z = rand.getScaled(cos_theta, 1.0f); const float oneMinusZSquared = PxSqrt(1.0f - z * z); pos = PxVec3(oneMinusZSquared * PxCos(phi), z, oneMinusZSquared * PxSin(phi)); } else { // 2-nd case : // * get random pos on unit sphere, until its height is above hemisphere cut do { pos = randomPointOnUnitSphere(rand); } while(pos.y < hemisphere); } // * add negative offset withing the thickness // * solve edge case [for the 1-st case] - regenerate offset from the previous step // in case point is below hemisphere cut PxVec3 tmp; const float sphereCapBaseHeight = -(*mRadius + *mShellThickness) + 2 * (*mRadius + *mShellThickness) * (*mHemisphere); do { float thickness = rand.getScaled(0, *mShellThickness); tmp = pos * (*mRadius + *mShellThickness - thickness); } while(tmp.y < sphereCapBaseHeight); pos = tmp; pos += pose.getPosition(); return pos; }
void RenderPhysX3Debug::addConvex(const PxConvexMeshGeometry& cg, const PxTransform& tr, const RendererColor& color, PxU32 renderFlags) { const PxConvexMesh& mesh = *cg.convexMesh; const PxMat33 rot = PxMat33(tr.q) * cg.scale.toMat33(); // PT: you can't use PxTransform with a non-uniform scaling const PxMat44 globalPose(rot, tr.p); const PxU32 polygonCount = mesh.getNbPolygons(); const PxU8* indexBuffer = mesh.getIndexBuffer(); const PxU32 vertexCount = mesh.getNbVertices(); const PxVec3* vertexBuffer = mesh.getVertices(); if(renderFlags & RENDER_DEBUG_WIREFRAME) { for(PxU32 i=0; i<polygonCount; i++) { PxHullPolygon data; mesh.getPolygonData(i, data); const PxU32 vertexCount = data.mNbVerts; PxU32 i0 = indexBuffer[vertexCount-1]; PxU32 i1 = *indexBuffer++; addLine(globalPose.transform(vertexBuffer[i0]), globalPose.transform(vertexBuffer[i1]), color); for(PxU32 j=1; j<vertexCount; j++) { i0 = indexBuffer[-1]; i1 = *indexBuffer++; addLine(globalPose.transform(vertexBuffer[i0]), globalPose.transform(vertexBuffer[i1]), color); } } } if(renderFlags & RENDER_DEBUG_SOLID) { for(PxU32 i=0; i<polygonCount; i++) { PxHullPolygon data; mesh.getPolygonData(i, data); const PxU32 vertexCount = data.mNbVerts; const PxVec3& v0 = vertexBuffer[indexBuffer[0]]; for(PxU32 j=0; j<vertexCount-2; j++) { const PxVec3& v1 = vertexBuffer[indexBuffer[j+1]]; const PxVec3& v2 = vertexBuffer[indexBuffer[j+2]]; addTriangle(globalPose.transform(v0), globalPose.transform(v1), globalPose.transform(v2), color); } indexBuffer += vertexCount; } } }
bool EmitterGeomSphereShellImpl::isInEmitter(const PxVec3& pos, const PxMat44& pose) const { PxVec3 localPos = pose.inverseRT().transform(pos); const float sphereCapBaseHeight = -(*mRadius + *mShellThickness) + 2 * (*mRadius + *mShellThickness) * (*mHemisphere); float d2 = localPos.x * localPos.x + localPos.y * localPos.y + localPos.z * localPos.z; bool isInBigSphere = d2 < (*mRadius + *mShellThickness) * (*mRadius + *mShellThickness); bool isInSmallSphere = d2 < *mRadius * *mRadius; bool higherThanHemisphereCut = pos.y > sphereCapBaseHeight; return isInBigSphere && !isInSmallSphere && higherThanHemisphereCut; }
void EmitterGeomSphereShellImpl::drawPreview(float scale, RenderDebugInterface* renderDebug) const { using RENDER_DEBUG::DebugColors; RENDER_DEBUG_IFACE(renderDebug)->pushRenderState(); RENDER_DEBUG_IFACE(renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::Yellow), RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::Yellow)); RENDER_DEBUG_IFACE(renderDebug)->debugSphere(PxVec3(0.0f), *mRadius * scale); RENDER_DEBUG_IFACE(renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::DarkGreen), RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::DarkGreen)); RENDER_DEBUG_IFACE(renderDebug)->debugSphere(PxVec3(0.0f), (*mRadius + *mShellThickness) * scale); const float radius = *mRadius + *mShellThickness; const float radiusSquared = radius * radius; const float hemisphere = *mHemisphere; const float sphereCapBaseHeight = -radius + 2 * radius * hemisphere; const float sphereCapBaseRadius = PxSqrt(radiusSquared - sphereCapBaseHeight * sphereCapBaseHeight); if(hemisphere > 0.0f) { RENDER_DEBUG_IFACE(renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(renderDebug)->getDebugColor(DebugColors::DarkPurple)); PxMat44 circlePose = PxMat44(PxIdentity); circlePose.setPosition(PxVec3(0.0f, sphereCapBaseHeight, 0.0f)); RENDER_DEBUG_IFACE(renderDebug)->setPose(circlePose); RENDER_DEBUG_IFACE(renderDebug)->debugCircle(PxVec3(0.0f), sphereCapBaseRadius, 3); RENDER_DEBUG_IFACE(renderDebug)->debugLine(PxVec3(0.0f), PxVec3(0.0f, radius - sphereCapBaseHeight, 0.0f)); for(float t = 0.0f; t < 2 * PxPi; t += PxPi / 3) { PxVec3 offset(PxSin(t) * sphereCapBaseRadius, 0.0f, PxCos(t) * sphereCapBaseRadius); RENDER_DEBUG_IFACE(renderDebug)->debugLine(offset, PxVec3(0.0f, radius - sphereCapBaseHeight, 0.0f)); } RENDER_DEBUG_IFACE(renderDebug)->setPose(PxIdentity); } RENDER_DEBUG_IFACE(renderDebug)->popRenderState(); }
void EmitterGeomSphereShellImpl::visualize(const PxTransform& pose, RenderDebugInterface& renderDebug) { using RENDER_DEBUG::DebugColors; RENDER_DEBUG_IFACE(&renderDebug)->pushRenderState(); RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkGreen)); // outer sphere RENDER_DEBUG_IFACE(&renderDebug)->setPose(pose); RENDER_DEBUG_IFACE(&renderDebug)->debugSphere(PxVec3(0.0f), *mRadius); // intter sphere RENDER_DEBUG_IFACE(&renderDebug)->debugSphere(PxVec3(0.0f), *mRadius + *mShellThickness); const float radius = *mRadius + *mShellThickness; const float radiusSquared = radius * radius; const float hemisphere = *mHemisphere; const float sphereCapBaseHeight = -radius + 2 * radius * hemisphere; const float sphereCapBaseRadius = PxSqrt(radiusSquared - sphereCapBaseHeight * sphereCapBaseHeight); // cone depicting the hemisphere if(hemisphere > 0.0f) { RENDER_DEBUG_IFACE(&renderDebug)->setCurrentColor(RENDER_DEBUG_IFACE(&renderDebug)->getDebugColor(DebugColors::DarkPurple)); PxMat44 circlePose = PxMat44(PxIdentity); circlePose.setPosition(PxVec3(0.0f, sphereCapBaseHeight, 0.0f)); RENDER_DEBUG_IFACE(&renderDebug)->setPose(circlePose); RENDER_DEBUG_IFACE(&renderDebug)->debugCircle(PxVec3(0.0f), sphereCapBaseRadius, 3); RENDER_DEBUG_IFACE(&renderDebug)->debugLine(circlePose.getPosition(), circlePose.getPosition() + PxVec3(0.0f, radius - sphereCapBaseHeight, 0.0f)); for(float t = 0.0f; t < 2 * PxPi; t += PxPi / 3) { PxVec3 offset(PxSin(t) * sphereCapBaseRadius, 0.0f, PxCos(t) * sphereCapBaseRadius); RENDER_DEBUG_IFACE(&renderDebug)->debugLine(circlePose.getPosition() + offset, circlePose.getPosition() + PxVec3(0.0f, radius - sphereCapBaseHeight, 0.0f)); } RENDER_DEBUG_IFACE(&renderDebug)->setPose(PxIdentity); } RENDER_DEBUG_IFACE(&renderDebug)->popRenderState(); }
void CTank::Update( float fDT ) { if( m_pActor ) { PxMat44 Matrix = physx::PxMat44( physx::PxMat33( m_pActor->getGlobalPose().q ), m_pActor->getGlobalPose().p ); D3DXMATRIX dxmat; memcpy( &dxmat._11, Matrix.front(), 4 * 4 * sizeof(float) ); if( GameObject* pBody = GetDetail( BODY ) ) pBody->SetReleaseMatrix( dxmat, true ); if( true ) { if( PxVehicleWheels* pDriveTank = CPhysX::GetPhysX()->GetTank() ) { PxShape* carShapes[ MAX_DETAIL ]; const PxU32 numShapes = m_pActor->getNbShapes(); m_pActor->getShapes( carShapes, numShapes ); for( PxU32 i = 0; i < numShapes - 1; ++i ) { const PxTransform& Trans = carShapes[ i ]->getLocalPose(); PxMat44 MatrixR = physx::PxMat44(physx::PxMat33( Trans.q ), Trans.p ); D3DXMATRIX dxmatR; memcpy( &dxmatR._11, MatrixR.front(), 4 * 4 * sizeof(float) ); if( GameObject* pObj = GetDetail( (EDetailTank)i ) ) pObj->SetReleaseMatrix( dxmatR * dxmat, true ); } PxVehicleDriveTank& vehDriveTank = static_cast< PxVehicleDriveTank& >( *pDriveTank ); PxVehicleDriveDynData& driveDynData = vehDriveTank.mDriveDynData; PxReal e = driveDynData.getEngineRotationSpeed(); m_fSpeedTank = pDriveTank->computeForwardSpeed(); static char t[ 256 ] = {0}; sprintf( t, "EngineRotationSpeed=%f, EngineRotationSpeed=%f", m_fSpeedTank, e ); //SetWindowText( GetForegroundWindow(), t ); PxVehicleDriveTankRawInputData carRawInputs( PxVehicleDriveTank::eDRIVE_MODEL_STANDARD ); carRawInputs.setDigitalAccel( m_bMoveForward || m_bMoveBack || m_bTurnLeft || m_bTurnRight ); carRawInputs.setDigitalLeftBrake( m_bTurnLeft ); // левая кнопка тормоза carRawInputs.setDigitalRightBrake( m_bTurnRight ); // правая кнопка тормоза carRawInputs.setDigitalLeftThrust( m_bMoveForward || !m_bTurnLeft ); carRawInputs.setDigitalRightThrust( m_bMoveForward || !m_bTurnRight ); if( !m_bMoveForward && !m_bMoveBack && !m_bTurnLeft && !m_bTurnRight ) { carRawInputs.setDigitalLeftBrake( true ); // левая кнопка тормоза carRawInputs.setDigitalRightBrake( true ); // правая кнопка тормоза } //carRawInputs.setGearUp( !m_bMoveForward && m_bMoveBack); //carRawInputs.setGearDown( !m_bMoveBack && m_bMoveForward ); // if( m_bMoveBack ) // { // carRawInputs.setDigitalLeftBrake( true ); // левая кнопка тормоза // carRawInputs.setDigitalRightBrake( true ); // правая кнопка тормоза // } static PxVehicleKeySmoothingData KeySmoothingData = { { 3.f, //rise rate eANALOG_INPUT_ACCEL 3.f, //rise rate eANALOG_INPUT_BRAKE 5.f, //rise rate eANALOG_INPUT_HANDBRAKE 2.f, //rise rate eANALOG_INPUT_STEER_LEFT 2.f, //rise rate eANALOG_INPUT_STEER_RIGHT }, { 5.f, //fall rate eANALOG_INPUT__ACCEL 5.f, //fall rate eANALOG_INPUT__BRAKE 10.f, //fall rate eANALOG_INPUT__HANDBRAKE 5.f, //fall rate eANALOG_INPUT_STEER_LEFT 5.f //fall rate eANALOG_INPUT_STEER_RIGHT } }; PxVehicleDriveTankSmoothDigitalRawInputsAndSetAnalogInputs( KeySmoothingData, carRawInputs, fDT, vehDriveTank ); } } } if( GameObject* pTankTrack = GetDetail( TRACK_L ) ) pTankTrack->SetOffsetUV( D3DXVECTOR4( 0.f, m_fSpeedTank*3, 0.f, 0.f ) ); if( GameObject* pTankTrack = GetDetail( TRACK_R ) ) pTankTrack->SetOffsetUV( D3DXVECTOR4( 0.f, m_fSpeedTank*3, 0.f, 0.f ) ); for( std::map< EDetailTank, GameObject* >::iterator iter = m_ObjectsTank.begin(), iter_end = m_ObjectsTank.end(); iter != iter_end; ++iter ) { GameObject* pObj = iter->second; pObj->Update( fDT ); } }
osg::Matrix toMatrix( const PxMat44& pmatrix ) { double m[16]; for ( int i=0; i<16; ++i ) m[i] = *(pmatrix.front() + i); return osg::Matrix(&m[0]); }
static void outputConvexToStream(PxShape* convexShape, const PxRigidActor* actor, const PxTransform& absPose_, IntArray& geomStream, TriArray& worldTriangles, IntArray& triIndicesArray, const PxExtendedVec3& origin, const PxBounds3& tmpBounds, const CCTParams& params, Cm::RenderBuffer* renderBuffer, PxU16& nbTessellation) { PX_ASSERT(convexShape->getGeometryType() == PxGeometryType::eCONVEXMESH); PxConvexMeshGeometry cg; convexShape->getConvexMeshGeometry(cg); PX_ASSERT(cg.convexMesh); // Do AABB-mesh query PxU32* TF; // Collide AABB against current mesh // The overlap function doesn't exist for convexes so let's just dump all tris PxConvexMesh& cm = *cg.convexMesh; // PT: convex triangles are not exposed anymore so we need to access convex polygons & triangulate them // PT: TODO: this is copied from "DrawObjects", move this to a shared place. Actually a helper directly in PxConvexMesh would be useful. PxU32 Nb = 0; { const PxU32 nbPolys = cm.getNbPolygons(); const PxU8* polygons = cm.getIndexBuffer(); for(PxU32 i=0;i<nbPolys;i++) { PxHullPolygon data; cm.getPolygonData(i, data); Nb += data.mNbVerts - 2; } // PT: revisit this code. We don't use the polygon offset? TF = (PxU32*)PxAlloca(sizeof(PxU32)*Nb*3); PxU32* t = TF; for(PxU32 i=0;i<nbPolys;i++) { PxHullPolygon data; cm.getPolygonData(i, data); const PxU32 nbV = data.mNbVerts; const PxU32 nbTris = nbV - 2; const PxU8 vref0 = *polygons; for(PxU32 j=0;j<nbTris;j++) { const PxU32 vref1 = polygons[(j+1)%nbV]; const PxU32 vref2 = polygons[(j+2)%nbV]; *t++ = vref0; *t++ = vref1; *t++ = vref2; } polygons += nbV; } } // PT: you can't use PxTransform with a non-uniform scaling const PxMat33 rot = PxMat33(absPose_.q) * cg.scale.toMat33(); const PxMat44 absPose(rot, absPose_.p); const PxVec3 p = absPose.getPosition(); const PxVec3 MeshOffset(float(p.x - origin.x), float(p.y - origin.y), float(p.z - origin.z)); // LOSS OF ACCURACY const PxVec3 offset(float(-origin.x), float(-origin.y), float(-origin.z)); TouchedMesh* touchedMesh = (TouchedMesh*)reserve(geomStream, sizeof(TouchedMesh)/sizeof(PxU32)); touchedMesh->mType = TouchedGeomType::eMESH; touchedMesh->mTGUserData = convexShape; touchedMesh->mActor = actor; touchedMesh->mOffset = origin; touchedMesh->mIndexWorldTriangles = worldTriangles.size(); const PxVec3* verts = cm.getVertices(); // Loop through touched triangles if(params.mTessellation) { const PxBoxGeometry boxGeom(tmpBounds.getExtents()); const PxBounds3 cullingBox = PxBounds3::centerExtents(tmpBounds.getCenter() + offset, boxGeom.halfExtents); PxU32 nbCreatedTris = 0; while(Nb--) { // Compute triangle in world space, add to array PxTriangle currentTriangle; const PxU32 vref0 = *TF++; const PxU32 vref1 = *TF++; const PxU32 vref2 = *TF++; currentTriangle.verts[0] = MeshOffset + absPose.rotate(verts[vref0]); currentTriangle.verts[1] = MeshOffset + absPose.rotate(verts[vref1]); currentTriangle.verts[2] = MeshOffset + absPose.rotate(verts[vref2]); PxU32 nbNewTris = 0; tessellateTriangle(nbNewTris, currentTriangle, PX_INVALID_U32, worldTriangles, triIndicesArray, cullingBox, params, nbTessellation); nbCreatedTris += nbNewTris; } touchedMesh->mNbTris = nbCreatedTris; } else { // Reserve memory for incoming triangles PxTriangle* TouchedTriangles = reserve(worldTriangles, Nb); touchedMesh->mNbTris = Nb; while(Nb--) { // Compute triangle in world space, add to array PxTriangle& currentTriangle = *TouchedTriangles++; const PxU32 vref0 = *TF++; const PxU32 vref1 = *TF++; const PxU32 vref2 = *TF++; currentTriangle.verts[0] = MeshOffset + absPose.rotate(verts[vref0]); currentTriangle.verts[1] = MeshOffset + absPose.rotate(verts[vref1]); currentTriangle.verts[2] = MeshOffset + absPose.rotate(verts[vref2]); triIndicesArray.pushBack(PX_INVALID_U32); } } if(gVisualizeTouchedTris) visualizeTouchedTriangles(touchedMesh->mNbTris, touchedMesh->mIndexWorldTriangles, &worldTriangles[0], renderBuffer, offset, params.mUpDirection); }