int main(int argc, char **argv) { //init and PVD bool initialized = false; NxPhysicsSDK *physicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION); if (!physicsSDK) return 0; else physicsSDK->getFoundationSDK().getRemoteDebugger()->connect("localhost", 5425); physicsSDK->setParameter(NX_CONTINUOUS_CD, true); initialized = true; //create a scene bool sceneInit = false; NxSceneDesc sceneDesc; sceneDesc.gravity.set(0, -9.81f, 0); gScene = physicsSDK->createScene(sceneDesc); if (gScene != NULL) sceneInit = true; //create a plane { NxActorDesc actorDesc; NxPlaneShapeDesc planeDesc; //planeDesc.normal = NxVec3(0, 0, 1); //planeDesc.d = -10.0f; actorDesc.shapes.pushBack(&planeDesc); gScene->createActor(actorDesc); } //create material NxMaterial *defaultMaterial = gScene->getMaterialFromIndex(0); defaultMaterial->setRestitution(0.3f); defaultMaterial->setStaticFriction(0.5f); defaultMaterial->setDynamicFriction(0.5f); //create a box { NxActorDesc actorDesc; NxBodyDesc bodyDesc; bodyDesc.angularDamping = 0.5; bodyDesc.linearVelocity = NxVec3(1, 0, 0); actorDesc.body = &bodyDesc; NxBoxShapeDesc boxDesc; boxDesc.dimensions = NxVec3(2.0f, 3.0f, 4.0f); actorDesc.shapes.pushBack(&boxDesc); actorDesc.density = 10.0f; actorDesc.globalPose.t = NxVec3(10.0f, 10.0f, 10.0f); gScene->createActor(actorDesc)->userData = NULL; } //create a cloth { // Create the objects in the scene NxActor* sphere1 = CreateSphere(NxVec3(-1, 0, -0.5), 1, 10); NxActor* box1 = CreateBox(NxVec3(1, 0, -1), NxVec3(1, 1, 1), 10); NxActor* box2 = CreateBox(NxVec3(0, 6.5, 0), NxVec3(5, 0.5, 0.5), 10); NxActor* box3 = CreateBox(NxVec3(0, 6.5, -7), NxVec3(5, 0.5, 0.5), 10); box2->setLinearDamping(5); box3->setLinearDamping(5); NxD6JointDesc d6Desc; d6Desc.actor[0] = NULL; d6Desc.actor[1] = box2; NxVec3 globalAnchor(0, 7, 0); d6Desc.localAnchor[0] = globalAnchor; box2->getGlobalPose().multiplyByInverseRT(globalAnchor, d6Desc.localAnchor[1]); box2->raiseBodyFlag(NX_BF_DISABLE_GRAVITY); box3->getGlobalPose().multiplyByInverseRT(globalAnchor, d6Desc.localAnchor[1]); box3->raiseBodyFlag(NX_BF_DISABLE_GRAVITY); d6Desc.localAxis[0] = NxVec3(1, 0, 0); d6Desc.localNormal[0] = NxVec3(0, 1, 0); d6Desc.localAxis[1] = NxVec3(1, 0, 0); d6Desc.localNormal[1] = NxVec3(0, 1, 0); d6Desc.twistMotion = NX_D6JOINT_MOTION_LOCKED; d6Desc.swing1Motion = NX_D6JOINT_MOTION_LOCKED; d6Desc.swing2Motion = NX_D6JOINT_MOTION_LOCKED; d6Desc.xMotion = NX_D6JOINT_MOTION_FREE; d6Desc.yMotion = NX_D6JOINT_MOTION_FREE; d6Desc.zMotion = NX_D6JOINT_MOTION_FREE; NxJoint* d6Joint = gScene->createJoint(d6Desc); NxClothDesc clothDesc; clothDesc.globalPose.t = NxVec3(4, 7, 0); clothDesc.thickness = 0.2; //clothDesc.density = 1; clothDesc.bendingStiffness = 0.5; clothDesc.stretchingStiffness = 1; //clothDesc.dampingCoefficient = 0.5; clothDesc.friction = 0.5; //clothDesc.collisionResponseCoefficient = 1; //clothDesc.attachmentResponseCoefficient = 1; //clothDesc.solverIterations = 5; //clothDesc.flags |= NX_CLF_STATIC; //clothDesc.flags |= NX_CLF_DISABLE_COLLISION; //clothDesc.flags |= NX_CLF_VISUALIZATION; //clothDesc.flags |= NX_CLF_GRAVITY; clothDesc.flags |= NX_CLF_BENDING; //clothDesc.flags |= NX_CLF_BENDING_ORTHO; clothDesc.flags |= NX_CLF_DAMPING; //clothDesc.flags |= NX_CLF_COMDAMPING; clothDesc.flags |= NX_CLF_COLLISION_TWOWAY; clothDesc.flags &= ~NX_CLF_HARDWARE; clothDesc.flags |= NX_CLF_FLUID_COLLISION; clothDesc.selfCollisionThickness = 10.0f; NxReal w = 8; NxReal h = 7; NxReal d = 0.05; NxClothMeshDesc meshDesc; bool mInitDone = false; int numX = (int)(w / d) + 1; int numY = (int)(h / d) + 1; meshDesc.numVertices = (numX + 1) * (numY + 1); meshDesc.numTriangles = numX*numY * 2; meshDesc.pointStrideBytes = sizeof(NxVec3); meshDesc.triangleStrideBytes = 3 * sizeof(NxU32); meshDesc.vertexMassStrideBytes = sizeof(NxReal); meshDesc.vertexFlagStrideBytes = sizeof(NxU32); meshDesc.points = (NxVec3*)malloc(sizeof(NxVec3)*meshDesc.numVertices); meshDesc.triangles = (NxU32*)malloc(sizeof(NxU32)*meshDesc.numTriangles * 3); meshDesc.vertexMasses = 0; meshDesc.vertexFlags = 0; meshDesc.flags = 0; int i, j; NxVec3 *p = (NxVec3*)meshDesc.points; for (i = 0; i <= numY; i++) { for (j = 0; j <= numX; j++) { p->set(-d*j, 0.0f, -d*i); p++; } } NxU32 *id = (NxU32*)meshDesc.triangles; for (i = 0; i < numY; i++) { for (j = 0; j < numX; j++) { NxU32 i0 = i * (numX + 1) + j; NxU32 i1 = i0 + 1; NxU32 i2 = i0 + (numX + 1); NxU32 i3 = i2 + 1; if ((j + i) % 2) { *id++ = i0; *id++ = i2; *id++ = i1; *id++ = i1; *id++ = i2; *id++ = i3; } else { *id++ = i0; *id++ = i2; *id++ = i3; *id++ = i0; *id++ = i3; *id++ = i1; } } } // if we want tearing we must tell the cooker // this way it will generate some space for particles that will be generated during tearing if (meshDesc.flags & NX_CLF_TEARABLE) meshDesc.flags |= NX_CLOTH_MESH_TEARABLE; //cooking static NxCookingInterface *gCooking = 0; gCooking = NxGetCookingLib(NX_PHYSICS_SDK_VERSION); gCooking->NxInitCooking(); gCooking->NxCookClothMesh(meshDesc, UserStream("e:\\cooked.bin", false)); //Meshdata Buffers NxMeshData mReceiveBuffers; // here we setup the buffers through which the SDK returns the dynamic cloth data // we reserve more memory for vertices than the initial mesh takes // because tearing creates new vertices // the SDK only tears cloth as long as there is room in these buffers NxU32 numVertices = meshDesc.numVertices; NxU32 numTriangles = meshDesc.numTriangles; NxU32 maxVertices = 2 * numVertices; mReceiveBuffers.verticesPosBegin = (NxVec3*)malloc(sizeof(NxVec3)*maxVertices); mReceiveBuffers.verticesNormalBegin = (NxVec3*)malloc(sizeof(NxVec3)*maxVertices); mReceiveBuffers.verticesPosByteStride = sizeof(NxVec3); mReceiveBuffers.verticesNormalByteStride = sizeof(NxVec3); mReceiveBuffers.maxVertices = maxVertices; mReceiveBuffers.numVerticesPtr = (NxU32*)malloc(sizeof(NxU32)); // the number of triangles is constant, even if the cloth is torn NxU32 maxIndices = 3 * numTriangles; mReceiveBuffers.indicesBegin = (NxU32*)malloc(sizeof(NxU32)*maxIndices); mReceiveBuffers.indicesByteStride = sizeof(NxU32); mReceiveBuffers.maxIndices = maxIndices; mReceiveBuffers.numIndicesPtr = (NxU32*)malloc(sizeof(NxU32)); // the parent index information would be needed if we used textured cloth NxU32 maxParentIndices = maxVertices; mReceiveBuffers.parentIndicesBegin = (NxU32*)malloc(sizeof(NxU32)*maxParentIndices); mReceiveBuffers.parentIndicesByteStride = sizeof(NxU32); mReceiveBuffers.maxParentIndices = maxParentIndices; mReceiveBuffers.numParentIndicesPtr = (NxU32*)malloc(sizeof(NxU32)); // init the buffers in case we want to draw the mesh // before the SDK as filled in the correct values *mReceiveBuffers.numVerticesPtr = 0; *mReceiveBuffers.numIndicesPtr = 0; clothDesc.clothMesh = physicsSDK->createClothMesh(UserStream("e:\\cooked.bin", true)); clothDesc.meshData = mReceiveBuffers; NxCloth *mCloth; mCloth = gScene->createCloth(clothDesc); mCloth->attachToShape(*box2->getShapes(), NX_CLOTH_ATTACHMENT_TWOWAY); mCloth->attachToShape(*box3->getShapes(), NX_CLOTH_ATTACHMENT_TWOWAY); } //create fluid 1 { //fluid = CreateFluid(NxVec3(0, 12, -3.5), 15, 0.1, gScene); } //create fluid 2 { //Create a set of initial particles ParticleSDK* initParticles = new ParticleSDK[max_particles]; unsigned initParticlesNum = 0; //Create particle filled sphere in buffer. NxVec3 fluidPos(0, 2, 0); NxVec3 offsetPos(0, 12, -3.5); float distance = 0.1f; //#ifdef __PPCGEKKO__ // unsigned sideNum = 12; //#else unsigned sideNum = 16; //#endif //Setup structure to pass initial particles. NxParticleData initParticleData; initParticlesNum = 0; initParticleData.numParticlesPtr = &initParticlesNum; initParticleData.bufferPos = &initParticles[0].position.x; initParticleData.bufferPosByteStride = sizeof(ParticleSDK); initParticleData.bufferVel = &initParticles[0].velocity.x; initParticleData.bufferVelByteStride = sizeof(ParticleSDK); CreateParticleSphere(initParticleData, max_particles, false, offsetPos, NxVec3(0, 0, 0), 0.0f, distance, sideNum); //Setup fluid descriptor NxFluidDesc fluidDesc; fluidDesc.maxParticles = max_particles; fluidDesc.kernelRadiusMultiplier = 2.0f; fluidDesc.restParticlesPerMeter = 10.0f; fluidDesc.motionLimitMultiplier = 3.0f; fluidDesc.packetSizeMultiplier = 8; fluidDesc.collisionDistanceMultiplier = 0.1; fluidDesc.stiffness = 50.0f; fluidDesc.viscosity = 40.0f; fluidDesc.restDensity = 1000.0f; fluidDesc.damping = 0.0f; fluidDesc.restitutionForStaticShapes = 0.0f; fluidDesc.dynamicFrictionForStaticShapes = 0.05f; fluidDesc.simulationMethod = NX_F_SPH; fluidDesc.flags &= ~NX_FF_HARDWARE; //Add initial particles to fluid creation. fluidDesc.initialParticleData = initParticleData; //Create user fluid. //- create NxFluid in NxScene //- setup the buffers to read from data from the SDK //- set NxFluid::userData field to MyFluid instance bool trackUserData = false; bool provideCollisionNormals = false; MyFluid* fluid = new MyFluid(gScene, fluidDesc, trackUserData, provideCollisionNormals, NxVec3(0.4f, 0.5f, 0.9f), 0.03f); assert(fluid); gMyFluids.pushBack(fluid); } //simulate for (int i = 0; i < 3000; i++) { gScene->simulate(1.0f / 60.f); gScene->flushStream(); //GetPhysicsResults gScene->fetchResults(NX_RIGID_BODY_FINISHED, true); // update fluid status if (i == 400) { MyFluid* fluid = gMyFluids[0]; const ParticleSDK* particles = fluid->getParticles(); unsigned particlesNum = fluid->getParticlesNum(); if (!gUpdates) { gUpdates = new ParticleUpdateSDK[max_particles]; } for (unsigned i = 0; i < particlesNum; i++) { ParticleUpdateSDK& update = gUpdates[i]; NxVec3& force = update.force; force.set(0, 0, 0); NxU32& flags = update.flags; if (i >= particlesNum/2) { flags = 0; flags |= NX_FP_DELETE; } else { flags = 0; } } //在这里更改粒子的属性 NxParticleUpdateData updateData; updateData.bufferFlag = &gUpdates[0].flags; updateData.bufferFlagByteStride = sizeof(ParticleUpdateSDK); fluid->getNxFluid()->updateParticles(updateData); } } //release if (physicsSDK != NULL) { if (gScene != NULL) physicsSDK->releaseScene(*gScene); gScene = NULL; NxReleasePhysicsSDK(physicsSDK); physicsSDK = NULL; } return 1; }
void UnderlayPlating::InstantiateStructure(bool a_IsBuildPoint) { //an overlay plate is essentially an "outer cover" for the tile in one of the six cardinal directions //system is currently setup to handle any combination of the six, but it probably shouldn't be m_IsBuildPoint = a_IsBuildPoint; Ogre::SceneManager& sceneManager = GetSceneManager(); //std::cout << "instantiating UnderlayPlating with direction " << m_Direction << std::endl; m_AtomFlags = RCD_CAN_DESTROY; //create entity m_pAtomEntity = sceneManager.createEntity("UnderlayPlating_" + num2string(m_AtomID), "cell_underlay.mesh"); m_pAtomEntitySceneNode->attachObject(m_pAtomEntity); StopFlashingColour(); //set up the directional offsets Ogre::Vector3 offsetPos(0, 0, 0); Ogre::Vector3 lookatPos(0, 0, 0); btVector3 halfExtents(0.5f, 0.5f, 0.5f); //std::cout << " new overlay plating" << std::endl; if(m_Direction & NORTH) { offsetPos.z += 0.395f; lookatPos.z += 1; halfExtents.setZ(0.005f); //std::cout << "NORTH " << (isPhysical ? "plating" : "trigger") << std::endl; } if(m_Direction & SOUTH) { offsetPos.z -= 0.395f; lookatPos.z -= 1; halfExtents.setZ(0.005f); //std::cout << "SOUTH " << (isPhysical ? "plating" : "trigger") << std::endl; } if(m_Direction & EAST) { offsetPos.x += 0.395f; lookatPos.x += 1; halfExtents.setX(0.005f); //std::cout << "EAST " << (isPhysical ? "plating" : "trigger") << std::endl; } if(m_Direction & WEST) { offsetPos.x -= 0.395f; lookatPos.x -= 1; halfExtents.setX(0.005f); //std::cout << "WEST " << (isPhysical ? "plating" : "trigger") << std::endl; } if(m_Direction & UP) { offsetPos.y += 0.395f; lookatPos.y += 1; halfExtents.setY(0.005f); //std::cout << "UP " << (isPhysical ? "plating" : "trigger") << std::endl; } if(m_Direction & DOWN) { offsetPos.y -= 0.395f; lookatPos.y -= 1; halfExtents.setY(0.005f); //std::cout << "DOWN " << (isPhysical ? "plating" : "trigger") << std::endl; } m_pAtomEntitySceneNode->setPosition(offsetPos); m_pAtomEntitySceneNode->lookAt(lookatPos, Ogre::Node::TS_LOCAL); m_pAtomEntitySceneNode->yaw(Ogre::Degree(90)); //create physics body and initialise to starting position m_pCollisionShape = new btBoxShape(halfExtents); btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1), OGRE2BT(m_pAtomEntitySceneNode->_getDerivedPosition()))); btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0, groundMotionState, m_pCollisionShape, btVector3(0,0,0)); m_pRigidBody = new btRigidBody(groundRigidBodyCI); m_pRigidBody->setUserPointer(this); //add new rigid body to world btDiscreteDynamicsWorld& dynamicsWorld = GetDynamicsWorld(); if(m_IsBuildPoint) { SetEntityVisible(false); m_pAtomEntity->setMaterialName("cell_highlight_material"); dynamicsWorld.addRigidBody(m_pRigidBody, COLLISION_BUILDPOINT, RAYCAST_BUILD); //todo: is this working? //m_pRigidBody->setCollisionFlags(m_pRigidBody->CF_NO_CONTACT_RESPONSE); } else { dynamicsWorld.addRigidBody(m_pRigidBody, COLLISION_STRUCTURE, RAYCAST_BUILD|COLLISION_OBJ|COLLISION_MOB); } InitCollisionShapeDebugDraw(Ogre::ColourValue::Red); }
void FGWCondition::paintEvent(QPaintEvent *) { QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); QFontMetrics fm = painter.fontMetrics(); if (fm.ascent() + fm.descent() != m_fontHeight) { m_fontHeight = fm.ascent() + fm.descent(); updateTransforms(); } // Y-Axis label QTransform transform; transform.rotate(270); transform.translate(-(height() + fm.width(m_yAxisLabel)) / 2, fm.ascent()); painter.setTransform(transform); painter.drawText(QPointF(0, 0), m_yAxisLabel); // X-Axis label transform.reset(); painter.setTransform(transform); painter.drawText(QPointF((width() - fm.width(m_xAxisLabel)) / 2, height() - fm.descent()), m_xAxisLabel); // The actual graph if (m_forceCondition) { QPointF startPos(-1.0, 0.0); QPointF startViewPos = m_model2View.map(startPos); QPointF endPos(1.0, 0.0); QPointF endViewPos = m_model2View.map(endPos); double negativeSaturation = m_forceCondition->negativeSaturation(); if (m_forceCondition->negativeCoefficient() < 0.0) { negativeSaturation = -negativeSaturation; } double positiveSaturation = m_forceCondition->positiveSaturation(); if (m_forceCondition->positiveCoefficient() < 0.0) { positiveSaturation = -positiveSaturation; } double negativeDeadBandValue = CLIP11(m_forceCondition->offset() - m_forceCondition->deadBand()); double positiveDeadBandValue = CLIP11(m_forceCondition->offset() + m_forceCondition->deadBand()); double negCoeff = m_forceCondition->negativeCoefficient(); double negCoeffValue = 1000.0; if (0.001 < fabs(negCoeff)) { negCoeffValue = (1.0 / fabs(negCoeff)) - 1.0; } negCoeffValue *= m_forceCondition->negativeSaturation(); double negativeSaturationValue = negativeDeadBandValue - negCoeffValue; if (negativeSaturationValue < -1.0) { double negCoeffVisible = negativeDeadBandValue + 1.0; double ratio = negCoeffVisible / negCoeffValue; negativeSaturation *= ratio; negativeSaturationValue = -1.0; } double posCoeff = m_forceCondition->positiveCoefficient(); double posCoeffValue = 1000.0; if (0.001 < fabs(posCoeff)) { posCoeffValue = (1.0 / fabs(posCoeff)) - 1.0; } posCoeffValue *= m_forceCondition->positiveSaturation(); double positiveSaturationValue = positiveDeadBandValue + posCoeffValue; if (1.0 < positiveSaturationValue) { double posCoeffVisible = 1.0 - positiveDeadBandValue; double ratio = posCoeffVisible / posCoeffValue; positiveSaturation *= ratio; positiveSaturationValue = 1.0; } QPointF offsetPos(m_forceCondition->offset(), 0.0); QPointF offsetViewPos = m_model2View.map(offsetPos); QPointF negativeSaturationPos(-1.0, negativeSaturation); QPointF negativeSaturationViewPos = m_model2View.map(negativeSaturationPos); QPointF negativeCoefficientPos(negativeSaturationValue, negativeSaturation); QPointF negativeCoefficientViewPos = m_model2View.map(negativeCoefficientPos); QPointF negativeDeadBandPos(negativeDeadBandValue, 0.0); QPointF negativeDeadBandViewPos = m_model2View.map(negativeDeadBandPos); QPointF positiveDeadBandPos(positiveDeadBandValue, 0.0); QPointF positiveDeadBandViewPos = m_model2View.map(positiveDeadBandPos); QPointF positiveCoefficientPos(positiveSaturationValue, positiveSaturation); QPointF positiveCoefficientViewPos = m_model2View.map(positiveCoefficientPos); QPointF positiveSaturationPos(1.0, positiveSaturation); QPointF positiveSaturationViewPos = m_model2View.map(positiveSaturationPos); painter.setPen(Qt::black); painter.setBrush(Qt::green); QPolygon envelope; envelope << startViewPos.toPoint() << negativeSaturationViewPos.toPoint() << negativeCoefficientViewPos.toPoint() << negativeDeadBandViewPos.toPoint() << positiveDeadBandViewPos.toPoint() << positiveCoefficientViewPos.toPoint() << positiveSaturationViewPos.toPoint() << endViewPos.toPoint(); painter.drawPolygon(envelope); painter.setBrush(QBrush(Qt::red)); painter.drawEllipse(negativeCoefficientViewPos, m_handleRadius, m_handleRadius); painter.drawEllipse(negativeDeadBandViewPos, m_handleRadius, m_handleRadius); painter.drawEllipse(positiveDeadBandViewPos, m_handleRadius, m_handleRadius); painter.drawEllipse(positiveCoefficientViewPos, m_handleRadius, m_handleRadius); if (!m_dragHandler->isDragging()) { double negSatHalfWidth = (negativeCoefficientViewPos.x() - startViewPos.x()) / 2.0; m_dragHandler->setHitAreaView(NegativeSaturation, QPointF(startViewPos.x() + negSatHalfWidth, negativeSaturationViewPos.y()), negSatHalfWidth, m_handleRadius); m_dragHandler->setHitAreaView(NegativeCoefficient, negativeCoefficientViewPos); m_dragHandler->setHitAreaView(NegativeDeadBand, negativeDeadBandViewPos); double offsetHalfWidth = (positiveDeadBandViewPos.x() - negativeDeadBandViewPos.x()) / 2.0; m_dragHandler->setHitAreaView(Offset, offsetViewPos, offsetHalfWidth, m_handleRadius); m_dragHandler->setHitAreaView(PositiveDeadBand, positiveDeadBandViewPos); m_dragHandler->setHitAreaView(PositiveCoefficient, positiveCoefficientViewPos); double posSatHalfWidth = (endViewPos.x() - positiveCoefficientViewPos.x()) / 2.0; m_dragHandler->setHitAreaView(PositiveSaturation, QPointF(endViewPos.x() - posSatHalfWidth, positiveSaturationViewPos.y()), posSatHalfWidth, m_handleRadius); } } }