glm::mat4 getModelTransform(const Json::Value &model_desc) { glm::mat4 ret(1.f); if (!model_desc.isMember("transform")) { return ret; } Json::Value transform_desc = model_desc["transform"]; if (transform_desc.isMember("origin")) { ret = glm::translate(ret, -toVec3(transform_desc["origin"])); } if (transform_desc.isMember("up")) { glm::vec3 up = glm::normalize( toVec3(transform_desc["up"])); glm::vec3 forward = glm::normalize( toVec3(must_have_idx(transform_desc, "forward"))); glm::vec3 right = glm::cross(up, forward); glm::vec4 cols[] = { glm::vec4(forward, 0.f), glm::vec4(right, 0.f), glm::vec4(up, 0.f), }; for (int i = 0; i < 3; i++) { ret[i] = cols[i]; } } if (transform_desc.isMember("scale")) { ret = glm::scale(ret, glm::vec3(transform_desc["scale"].asFloat())); } return ret; }
glm::vec3 Object::nextPosOf(QTProfile* terrain) { if (terrain->node == NULL) { return glm::vec3(0.0f); } int using_buffer_data_index = 0; glm::vec3 using_buffer_dataNormal = terrain->getResultNormalFromCoord(calcCoordFromPos(position + toVec3(using_vertex_offset)), using_vertex, &using_buffer_data_index); glm::vec3 facePoint_to_pos_vector = position - using_vertex[using_buffer_data_index]; if (glm::dot(facePoint_to_pos_vector, using_buffer_dataNormal) < 0.0f) { position += -velocity * timeStep; velocity = glm::reflect(velocity, using_buffer_dataNormal) * 0.9f; } else { velocity += gravity * timeStep * glm::normalize(-position - toVec3(using_vertex_offset)); position += velocity * timeStep; } return position; }
void renderEntityFromJSON(GameEntity *e, const Json::Value &v) { invariant(e, "must have entity to render to"); if (v.isMember("alive")) { for (auto &sample : v["alive"]) { e->setAlive(sample[0].asFloat(), sample[1].asBool()); } } if (v.isMember("model")) { for (auto &sample : v["model"]) { e->setModelName(sample[1].asString()); } } if (v.isMember("properties")) { for (auto &sample : v["properties"]) { for (auto &prop : sample[1]) { e->addProperty(prop.asInt()); } } } if (v.isMember("pid")) { for (auto &sample : v["pid"]) { e->setPlayerID(sample[0].asFloat(), toID(sample[1])); } } if (v.isMember("tid")) { for (auto &sample : v["tid"]) { e->setTeamID(sample[0].asFloat(), toID(sample[1])); } } if (v.isMember("pos")) { for (auto &sample : v["pos"]) { e->setPosition(sample[0].asFloat(), toVec2(sample[1])); } } if (v.isMember("size")) { for (auto &sample : v["size"]) { e->setSize(sample[0].asFloat(), toVec3(sample[1])); } } if (v.isMember("angle")) { for (auto &sample : v["angle"]) { e->setAngle(sample[0].asFloat(), sample[1].asFloat()); } } if (v.isMember("sight")) { for (auto &sample : v["sight"]) { e->setSight(sample[0].asFloat(), sample[1].asFloat()); } } if (v.isMember("visible")) { for (auto &sample : v["visible"]) { float t = sample[0].asFloat(); VisibilitySet set; for (auto pid : sample[1]) { set.insert(toID(pid)); } e->setVisibilitySet(t, set); } } if (v.isMember("actions")) { for (auto &sample : v["actions"]) { float t = sample[0].asFloat(); std::vector<UIAction> actions; for (auto &action_json : sample[1]) { auto uiaction = UIActionFromJSON(action_json); uiaction.owner_id = e->getGameID(); actions.push_back(uiaction); } if (!actions.empty()) { e->setActions(t, actions); } } } if (v.isMember("ui_info")) { for (auto &&sample : v["ui_info"]) { const float t = sample[0].asFloat(); GameEntity::UIInfo uiinfo = UIInfoFromJSON(sample[1]); e->setUIInfo(t, uiinfo); } } }
SimpleVec3d SimpleVec3d::rotateBy(SimpleVec3d axis, float angle) { return SimpleVec3d(glm::rotate(toVec3(), angle, axis.toVec3())); }
Entity SceneLoader::instantiate(Json def, Resources& resources, const string& pathContext) { ASSERT(def.is_object()); if (def["prefab"].is_string()) { const string& prefabName = def["prefab"].string_value(); auto prefabIter = prefabs.find(prefabName); if (prefabIter != prefabs.end()) { def = assign(prefabIter->second, def); } else if (endsWith(prefabName, ".json")) { string err; Json extPrefab = Json::parse(resources.getText(resolvePath(pathContext, prefabName), Resources::NO_CACHE), err); if (!err.empty()) { logError("Failed to parse prefab \"%s\": %s", prefabName.c_str(), err.c_str()); } else { def = assign(extPrefab, def); prefabs[prefabName] = extPrefab; } } else { logError("Could not find prefab \"%s\"", prefabName.c_str()); } } Entity entity = world->create(); if (def["name"].is_string()) { entity.tag(def["name"].string_value()); #ifdef USE_DEBUG_NAMES DebugInfo info; info.name = def["name"].string_value(); entity.add<DebugInfo>(info); } else { static uint debugId = 0; DebugInfo info; if (def["prefab"].is_string()) info.name = def["prefab"].string_value() + "#"; else if (def["geometry"].is_string()) info.name = def["geometry"].string_value() + "#"; else info.name = "object#"; info.name += std::to_string(debugId++); entity.tag(info.name); entity.add<DebugInfo>(info); #endif } // Parse transform if (!def["position"].is_null() || !def["rotation"].is_null() || !def["scale"].is_null() || !def["geometry"].is_null()) { Transform transform; setVec3(transform.position, def["position"]); setVec3(transform.scale, def["scale"]); if (!def["rotation"].is_null()) { const Json& rot = def["rotation"]; if (rot.is_array() && rot.array_items().size() == 4) transform.rotation = quat(rot[3].number_value(), rot[0].number_value(), rot[1].number_value(), rot[2].number_value()); else transform.rotation = quat(toVec3(rot)); } entity.add(transform); } // Parse light const Json& lightDef = def["light"]; if (!lightDef.is_null()) { Light light; const string& lightType = lightDef["type"].string_value(); if (lightType == "ambient") light.type = Light::AMBIENT_LIGHT; else if (lightType == "point") light.type = Light::POINT_LIGHT; else if (lightType == "directional") light.type = Light::DIRECTIONAL_LIGHT; else if (lightType == "spot") light.type = Light::SPOT_LIGHT; else if (lightType == "area") light.type = Light::AREA_LIGHT; else if (lightType == "hemisphere") light.type = Light::HEMISPHERE_LIGHT; else logError("Unknown light type \"%s\"", lightType.c_str()); setColor(light.color, lightDef["color"]); if (!def["position"].is_null()) light.position = toVec3(def["position"]); if (!lightDef["direction"].is_null()) light.direction = toVec3(lightDef["direction"]); setNumber(light.distance, lightDef["distance"]); setNumber(light.decay, lightDef["decay"]); entity.add(light); numLights++; } if (!def["geometry"].is_null()) { Model model; parseModel(model, def, resources, pathContext); entity.add(model); numModels++; } // Patch bounding box // TODO: Bounding box is not correct if scale changed at runtime if (entity.has<Model>() && entity.has<Transform>()) { Model& model = entity.get<Model>(); const Transform& trans = entity.get<Transform>(); model.bounds.min = model.lods[0].geometry->bounds.min * trans.scale; model.bounds.max = model.lods[0].geometry->bounds.max * trans.scale; model.bounds.radius = model.lods[0].geometry->bounds.radius * glm::compMax(trans.scale); } // Parse body (needs to be after geometry, transform, bounds...) if (!def["body"].is_null()) { const Json& bodyDef = def["body"]; ASSERT(bodyDef.is_object()); ASSERT(entity.has<Model>()); ASSERT(entity.has<Transform>()); const Model& model = entity.get<Model>(); const Transform& transform = entity.get<Transform>(); float mass = 0.f; setNumber(mass, bodyDef["mass"]); btCollisionShape* shape = NULL; const string& shapeStr = bodyDef["shape"].string_value(); vec3 extents = model.bounds.max - model.bounds.min; if (shapeStr == "box") { shape = new btBoxShape(convert(extents * 0.5f)); } else if (shapeStr == "sphere") { shape = new btSphereShape(model.bounds.radius); } else if (shapeStr == "cylinder") { shape = new btCylinderShape(convert(extents * 0.5f)); } else if (shapeStr == "capsule") { float r = glm::max(extents.x, extents.z) * 0.5f; shape = new btCapsuleShape(r, extents.y); } else if (shapeStr == "trimesh") { Geometry* colGeo = nullptr; if (bodyDef["geometry"].is_string()) { colGeo = resources.getGeometry(bodyDef["geometry"].string_value()); } else { if (bodyDef["geometry"].is_array()) logError("LODs not supported for collision mesh."); colGeo = model.lods[0].geometry; } if (!colGeo->collisionMesh) colGeo->generateCollisionTriMesh(); if (mass <= 0.f) { // Static mesh shape = new btBvhTriangleMeshShape(colGeo->collisionMesh, true); } else { shape = new btGImpactMeshShape(colGeo->collisionMesh); static_cast<btGImpactMeshShape*>(shape)->updateBound(); } } else { logError("Unknown shape %s", shapeStr.c_str()); } ASSERT((shapeStr == "trimesh" || bodyDef["geometry"].is_null()) && "Trimesh shape type required if body.geometry is specified"); ASSERT(shape); btVector3 inertia(0, 0, 0); shape->calculateLocalInertia(mass, inertia); btRigidBody::btRigidBodyConstructionInfo info(mass, NULL, shape, inertia); info.m_startWorldTransform = btTransform(convert(transform.rotation), convert(transform.position)); setNumber(info.m_friction, bodyDef["friction"]); setNumber(info.m_rollingFriction, bodyDef["rollingFriction"]); setNumber(info.m_restitution, bodyDef["restitution"]); if (bodyDef["noSleep"].bool_value()) { info.m_linearSleepingThreshold = 0.f; info.m_angularSleepingThreshold = 0.f; } entity.add<btRigidBody>(info); numBodies++; btRigidBody& body = entity.get<btRigidBody>(); if (!bodyDef["angularFactor"].is_null()) body.setAngularFactor(convert(toVec3(bodyDef["angularFactor"]))); if (!bodyDef["linearFactor"].is_null()) body.setLinearFactor(convert(toVec3(bodyDef["linearFactor"]))); if (bodyDef["noGravity"].bool_value()) body.setFlags(body.getFlags() | BT_DISABLE_WORLD_GRAVITY); body.setUserIndex(entity.get_id()); if (world->has_system<PhysicsSystem>()) world->get_system<PhysicsSystem>().add(entity); } if (!def["animation"].is_null()) { ASSERT(entity.has<Model>()); const Json& animDef = def["animation"]; BoneAnimation anim; setNumber(anim.speed, animDef["speed"]); entity.add(anim); if (animDef["play"].is_bool() && animDef["play"].bool_value()) world->get_system<AnimationSystem>().play(entity); else world->get_system<AnimationSystem>().stop(entity); } if (def["trackGround"].bool_value()) { ASSERT(entity.has<btRigidBody>()); entity.add<GroundTracker>(); } if (def["trackContacts"].bool_value()) { ASSERT(entity.has<btRigidBody>()); entity.add<ContactTracker>(); } if (def["triggerVolume"].is_object()) { ASSERT(entity.has<Transform>()); const Json& triggerDef = def["triggerVolume"]; TriggerVolume& trigger = entity.add<TriggerVolume>(); setNumber(trigger.times, triggerDef["times"]); setNumber(trigger.bounds.radius, triggerDef["radius"]); setVec3(trigger.bounds.min, triggerDef["min"]); setVec3(trigger.bounds.min, triggerDef["max"]); if (triggerDef["receiver"].is_string()) trigger.receiverModule = id::hash(triggerDef["receiver"].string_value()); if (triggerDef["enterMessage"].is_string()) trigger.enterMessage = id::hash(triggerDef["enterMessage"].string_value()); else if (triggerDef["enterMessage"].is_number()) trigger.enterMessage = triggerDef["enterMessage"].number_value(); if (triggerDef["exitMessage"].is_string()) trigger.exitMessage = id::hash(triggerDef["exitMessage"].string_value()); else if (triggerDef["exitMessage"].is_number()) trigger.exitMessage = triggerDef["exitMessage"].number_value(); if (triggerDef["groups"].is_number()) trigger.groups = 1 << (uint)triggerDef["groups"].number_value(); else if (triggerDef["groups"].is_array()) { for (const auto& item : triggerDef["groups"].array_items()) trigger.groups |= 1 << (uint)item.number_value(); } } if (def["triggerGroup"].is_number()) { ASSERT(entity.has<Transform>()); entity.add<TriggerGroup>().group = 1 << (uint)def["triggerGroup"].number_value(); } if (!def["moveSound"].is_null()) { const Json& soundDef = def["moveSound"]; MoveSound sound; if (soundDef["event"].is_string()) sound.event = id::hash(soundDef["event"].string_value()); setNumber(sound.stepLength, soundDef["step"]); ASSERT(sound.event); ASSERT(entity.has<Transform>()); sound.prevPos = entity.get<Transform>().position; entity.add(sound); } if (!def["contactSound"].is_null()) { const Json& soundDef = def["contactSound"]; ContactSound sound; if (soundDef["event"].is_string()) sound.event = id::hash(soundDef["event"].string_value()); ASSERT(sound.event); ASSERT(entity.has<Transform>()); ASSERT(entity.has<ContactTracker>()); entity.add(sound); } return entity; }
osg::Node* createNodeForActor( PxRigidActor* actor ) { if ( !actor ) return NULL; std::vector<PxShape*> shapes( actor->getNbShapes() ); osg::ref_ptr<osg::MatrixTransform> transform = new osg::MatrixTransform; transform->setMatrix( toMatrix(PxMat44(actor->getGlobalPose())) ); osg::ref_ptr<osg::Geode> geode = new osg::Geode; transform->addChild( geode.get() ); PxU32 num = actor->getShapes( &(shapes[0]), actor->getNbShapes() ); for ( PxU32 i=0; i<num; ++i ) { PxShape* shape = shapes[i]; osg::Matrix localMatrix = toMatrix( PxMat44(actor->getGlobalPose()) ); osg::Vec3 localPos = toVec3( shape->getLocalPose().p ); osg::Quat localQuat(shape->getLocalPose().q.x, shape->getLocalPose().q.y, shape->getLocalPose().q.z, shape->getLocalPose().q.w); switch ( shape->getGeometryType() ) { case PxGeometryType::eSPHERE: { PxSphereGeometry sphere; shape->getSphereGeometry( sphere ); osg::Sphere* sphereShape = new osg::Sphere(localPos, sphere.radius); geode->addDrawable( new osg::ShapeDrawable(sphereShape) ); } break; case PxGeometryType::ePLANE: // TODO break; case PxGeometryType::eCAPSULE: { PxCapsuleGeometry capsule; shape->getCapsuleGeometry( capsule ); osg::Capsule* capsuleShape = new osg::Capsule( localPos, capsule.radius, capsule.halfHeight * 2.0f); capsuleShape->setRotation( localQuat ); geode->addDrawable( new osg::ShapeDrawable(capsuleShape) ); } break; case PxGeometryType::eBOX: { PxBoxGeometry box; shape->getBoxGeometry( box ); osg::Box* boxShape = new osg::Box(localPos, box.halfExtents[0] * 2.0f, box.halfExtents[1] * 2.0f, box.halfExtents[2] * 2.0f); boxShape->setRotation( localQuat ); geode->addDrawable( new osg::ShapeDrawable(boxShape) ); } break; case PxGeometryType::eCONVEXMESH: { PxConvexMeshGeometry convexMeshGeom; shape->getConvexMeshGeometry( convexMeshGeom ); // TODO: consider convexMeshGeom.scale PxConvexMesh* convexMesh = convexMeshGeom.convexMesh; if ( convexMesh ) { /*for ( unsigned int i=0; i<convexMesh->getNbPolygons(); ++i ) { }*/ // TODO } } break; case PxGeometryType::eTRIANGLEMESH: { PxTriangleMeshGeometry triangleMeshGeom; shape->getTriangleMeshGeometry( triangleMeshGeom ); // TODO: consider triangleMeshGeom.scale PxTriangleMesh* triangleMesh = triangleMeshGeom.triangleMesh; if ( triangleMesh ) { osg::ref_ptr<osg::Vec3Array> va = new osg::Vec3Array( triangleMesh->getNbVertices() ); for ( unsigned int i=0; i<va->size(); ++i ) (*va)[i] = toVec3( *(triangleMesh->getVertices() + i) ) * localMatrix; osg::ref_ptr<osg::DrawElements> de; if ( triangleMesh->getTriangleMeshFlags()&PxTriangleMeshFlag::eHAS_16BIT_TRIANGLE_INDICES ) { osg::DrawElementsUShort* de16 = new osg::DrawElementsUShort(GL_TRIANGLES); de = de16; const PxU16* indices = (const PxU16*)triangleMesh->getTriangles(); for ( unsigned int i=0; i<triangleMesh->getNbTriangles(); ++i ) { de16->push_back( indices[3 * i + 0] ); de16->push_back( indices[3 * i + 1] ); de16->push_back( indices[3 * i + 2] ); } } else { osg::DrawElementsUInt* de32 = new osg::DrawElementsUInt(GL_TRIANGLES); de = de32; const PxU32* indices = (const PxU32*)triangleMesh->getTriangles(); for ( unsigned int i=0; i<triangleMesh->getNbTriangles(); ++i ) { de32->push_back( indices[3 * i + 0] ); de32->push_back( indices[3 * i + 1] ); de32->push_back( indices[3 * i + 2] ); } } geode->addDrawable( createGeometry(va.get(), NULL, NULL, de.get()) ); } } break; case PxGeometryType::eHEIGHTFIELD: { PxHeightFieldGeometry hfGeom; shape->getHeightFieldGeometry( hfGeom ); // TODO: consider hfGeom.*scale PxHeightField* heightField = hfGeom.heightField; if ( heightField ) { // TODO } } break; } } return transform.release(); }
kvs::Vec4 RGBAColor::toVec4() const { return kvs::Vec4( toVec3(), m_opacity ); }
Geometry::SRT toSRT(const btTransform& t){ return Geometry::SRT(toVec3(t.getOrigin()), toMatrix3x3(t.getBasis()),1.0); }
Geometry::Matrix3x3 toMatrix3x3(const btMatrix3x3& btm){ Geometry::Matrix3x3 tmp; for(int i = 0; i<3; ++i) tmp.setRow(i,toVec3(btm.getRow(i))); return tmp; }