bullet::Collider::Ptr bullet::Collider::linearFactor(Vector3::Ptr values) { const bool changed = fabsf(values->x() - _linearFactor->x()) > 1e-3f || fabsf(values->y() - _linearFactor->y()) > 1e-3f || fabsf(values->z() - _linearFactor->z()) > 1e-3f; _linearFactor->copyFrom(values); if (changed) _propertiesChanged->execute(std::static_pointer_cast<Collider>(shared_from_this())); return std::static_pointer_cast<Collider>(shared_from_this()); }
void Matrix4x4::decompose(Vector3::Ptr translation, Quaternion::Ptr rotation, Vector3::Ptr scaling) const { static auto matrixR = Matrix4x4::create(); decomposeQR(rotation, matrixR); const std::vector<float>& matR = matrixR->_m; scaling->setTo(matR[0], matR[5], matR[10]); #ifdef DEBUG if (fabsf(matR[1]) > 1e-3f || fabsf(matR[2]) > 1e-3f || fabsf(matR[6]) > 1e-3f) std::cout << "Warning: Matrix decomposition assumes the following composition order : scaling, rotation, and translation." << std::endl; #endif // DEBUG translation->setTo(_m[3], _m[7], _m[11]); }
Vector3::Ptr bullet::PhysicsWorld::getColliderAngularVelocity(Collider::ConstPtr collider, Vector3::Ptr output) const { if (output == nullptr) output = Vector3::create(0.0f, 0.0f, 0.0f); auto foundColliderIt = _colliderMap.find(std::const_pointer_cast<Collider>(collider)); if (foundColliderIt == _colliderMap.end()) return output; auto rigidBody = foundColliderIt->second->rigidBody(); auto vec = rigidBody->getAngularVelocity(); return output->setTo(vec.x(), vec.y(), vec.z()); }
void Geometry::getHitNormal(uint triangle, Vector3::Ptr hitNormal) { auto normalBuffer = vertexBuffer("normal"); auto& normalData = normalBuffer->data(); auto normalPtr = &normalData[0]; auto normalVertexSize = normalBuffer->vertexSize(); auto normalOffset = std::get<2>(*normalBuffer->attribute("normal")); auto& indicesData = _indexBuffer->data(); auto v0 = Vector3::create(normalPtr + indicesData[triangle] * normalVertexSize + normalOffset); auto v1 = Vector3::create(normalPtr + indicesData[triangle] * normalVertexSize + normalOffset); auto v2 = Vector3::create(normalPtr + indicesData[triangle] * normalVertexSize + normalOffset); auto edge1 = Vector3::create(v1)->subtract(v0)->normalize(); auto edge2 = Vector3::create(v2)->subtract(v0)->normalize(); hitNormal->copyFrom(edge2)->cross(edge1); }
int main(int argc, char** argv) { auto canvas = Canvas::create("Minko Example - Leap Motion"); // scene set-up auto sceneManager = SceneManager::create(canvas); auto sceneNode = Node::create("engine") ->addComponent(Transform::create()); auto cameraNode = Node::create("cameraNode") ->addComponent(Transform::create()); // Leap Motion-based controls auto controller = input::leap::Controller::create(canvas); const float MIN_DELTA_HAND_DISTANCE = 5.0f; const float RELATIVE_MOVE_THRESHOLD = 1.0f; const clock_t START_CLOCK = clock(); // frame-persistant variables float relativeMove = 0.0f; auto swipeDirection = Vector3::create(); float goalExplosionValue = 1.0f; float goalCosRotation = 1.0f; float goalSinRotation = 0.0f; float goalCameraDistance = 20.0f; float explosionValue = goalExplosionValue; float cosRotation = goalCosRotation; float sinRotation = goalSinRotation; float cameraDistance = goalCameraDistance; float previousHandDistance = -1.0f; float previousTime = 0.0f; float previousExplosionValue = explosionValue; bool isInProgress = false; auto leapEnterFrame = controller->enterFrame()->connect([&](input::leap::Controller::Ptr c) { if (!c->frame()->isValid()) return; const float currentTime = (clock() - START_CLOCK) / float(CLOCKS_PER_SEC); const float deltaTime = currentTime - previousTime; previousTime = currentTime; auto frame = c->frame(); auto leftHand = frame->leftmostHand(); auto rightHand = frame->rightmostHand(); float handDistance = 0.0f; if (frame->numHands() >= 2) { if (leftHand->isValid() && rightHand->isValid()) handDistance = (leftHand->palmPosition() - rightHand->palmPosition())->length(); if (previousHandDistance < 0.0f) previousHandDistance = handDistance; const float deltaHandDistance = fabsf(handDistance - previousHandDistance); if (deltaHandDistance > MIN_DELTA_HAND_DISTANCE) { const float moveIncr = handDistance < previousHandDistance ? -10.0f : 10.0f; relativeMove += moveIncr * deltaTime; } previousHandDistance = handDistance; const float moveDecr = relativeMove > 0.0f ? 0.5f : -0.5f; relativeMove -= moveDecr * deltaTime; if (!isInProgress) { if (relativeMove > RELATIVE_MOVE_THRESHOLD) { isInProgress = true; goalExplosionValue = 3.5f; relativeMove = 0.0f; #ifdef DEBUG std::cout << "spread mesh" << std::endl; #endif // DEBUG } else if (relativeMove < -RELATIVE_MOVE_THRESHOLD) { isInProgress = true; goalExplosionValue = 1.0f; relativeMove = 0.0f; #ifdef DEBUG std::cout << "restore mesh" << std::endl; #endif // DEBUG } } } else { // consider only the swipe gesture whose direction exhibits the strongest magnitude const uint numGestures = frame->numGestures(); Vector3::Ptr swipeDirection = Vector3::create(); Vector3::Ptr bestSwipeDirection = Vector3::create(); for (uint i = 0; i < numGestures; ++i) { auto gesture = frame->gestureByIndex(i); if (gesture->type() == input::leap::Gesture::Type::Swipe && gesture->state() == input::leap::Gesture::State::Start) { gesture->toSwipeGesture()->direction(swipeDirection); if (swipeDirection->lengthSquared() > bestSwipeDirection->lengthSquared()) bestSwipeDirection->copyFrom(swipeDirection); } } #ifdef DEBUG if (bestSwipeDirection->lengthSquared() > 0.1f) std::cout << "starting swipe direction = " << bestSwipeDirection->toString() << std::endl; #endif // DEBUG if (!isInProgress && bestSwipeDirection->lengthSquared() > 0.1f) { if (fabsf(swipeDirection->y()) > 0.5f) { isInProgress = true; goalCameraDistance = swipeDirection->y() < 0.0f ? 10.0f : 20.0f; #ifdef DEBUG std::cout << "\t-> zoom in/out\tgoal camera distance = " << goalCameraDistance << std::endl; #endif // DEBUG } else if (fabsf(swipeDirection->x()) > 0.5f) { const float goalRotation = atan2f(goalSinRotation, goalCosRotation) + (swipeDirection->x() < 0.0f ? float(M_PI) * 0.25f : - float(M_PI) * 0.25f); isInProgress = true; goalCosRotation = cosf(goalRotation); goalSinRotation = sinf(goalRotation); #ifdef DEBUG std::cout << "\t-> new rotation angle = " << 180.0f * goalRotation / float(M_PI) << std::endl; #endif // DEBUG } } } const float diffExplosionValue = goalExplosionValue - explosionValue; const float diffCameraDistance = goalCameraDistance - cameraDistance; const float diffCosRotation = goalCosRotation - cosRotation; const float diffSinRotation = goalSinRotation - sinRotation; if (fabsf(diffExplosionValue) < 0.01f && fabsf(diffCameraDistance) < 0.01f && fabsf(diffCosRotation) < 0.01f && fabsf(diffSinRotation) < 0.01f) { #ifdef DEBUG if (isInProgress) std::cout << "current motion ended" << std::endl; #endif // DEBUG explosionValue = goalExplosionValue; cameraDistance = goalCameraDistance; cosRotation = goalCosRotation; sinRotation = goalSinRotation; isInProgress = false; } explosionValue += diffExplosionValue * std::min(1.0f, 2.0f * deltaTime); cameraDistance += diffCameraDistance * std::min(1.0f, 2.5f * deltaTime); cosRotation += diffCosRotation * std::min(1.0f, 3.0f * deltaTime); sinRotation += diffSinRotation * std::min(1.0f, 3.0f * deltaTime); explodeModel( explosionValue, previousExplosionValue, sceneNode ); previousExplosionValue = explosionValue; placeCamera( cameraDistance, atan2f(sinRotation, cosRotation), cameraNode->component<Transform>()->matrix() ); }); // on initialization of the Leap controller auto leapConnected = controller->connected()->connect([](input::leap::Controller::Ptr c) { c->enableGesture(input::leap::Gesture::Type::ScreenTap); c->enableGesture(input::leap::Gesture::Type::Swipe); #ifdef DEBUG std::cout << "Leap controller connected (screentap and swipe gestures enabled)" << std::endl; #endif // DEBUG std::cout << "Leap controls\n-------------" << std::endl; std::cout << "\t- Single hand controls\n\t\t- Horizontal swipe\tturn camera\n\t\t- Vertical swipe\tzoom in/out" << std::endl; std::cout << "\t- Two hand controls\n\t\t- Brisk spreading motion\texplose model\n\t\t- Brisk shrinking motion\trestore model" << std::endl; }); auto root = Node::create("root"); // setup assets auto defaultMaterial = Material::create() ->set("diffuseColor", Vector4::create(1.f, 1.f, 1.f, 1.f)) ->set("triangleCulling", render::TriangleCulling::NONE); sceneManager->assets()->context()->errorsEnabled(true); sceneManager->assets()->loader()->options() ->registerParser<file::PNGParser>("png") ->registerParser<file::SceneParser>("scene") ->generateMipmaps(false) ->material(std::static_pointer_cast<Material>( Material::create()->set("triangleCulling", render::TriangleCulling::NONE) )) ->materialFunction([&](const std::string&, Material::Ptr) { return std::static_pointer_cast<Material>(defaultMaterial); }); sceneManager->assets() ->geometry("cube", geometry::CubeGeometry::create(sceneManager->assets()->context())) ->geometry("sphere", geometry::SphereGeometry::create(sceneManager->assets()->context())) ->geometry("skybox", geometry::SphereGeometry::create(sceneManager->assets()->context(), 80, 80, true)); sceneManager->assets()->loader() ->queue(HANGAR_TEXTURE) ->queue("effect/Phong.effect") ->queue("effect/Basic.effect") ->queue(SCENE_NAME); sceneManager->assets()->loader()->options() ->effect(sceneManager->assets()->effect("effect/Phong.effect")); cameraNode ->addComponent(PerspectiveCamera::create(canvas->aspectRatio())) ->addComponent(Renderer::create(0x7F7F7FFF)); placeCamera( cameraDistance, atan2f(sinRotation, cosRotation), cameraNode->component<Transform>()->matrix() ); auto dirLight = Node::create("dirLight") ->addComponent(component::DirectionalLight::create()) ->addComponent(component::Transform::create( Matrix4x4::create()->lookAt(Vector3::zero(), Vector3::create(-1.0f, -1.0f, -1.0f)) )); auto pointLight = Node::create("pointLight") ->addComponent(component::PointLight::create()) ->addComponent(component::Transform::create( Matrix4x4::create()->appendTranslation(0.0f, 10.0f, 0.0f) )); pointLight->component<PointLight>()->color()->setTo(1.0f, 1.0f, 1.0f); auto skybox = Node::create("skybox") ->addComponent(Transform::create( Matrix4x4::create()->appendScale(60.0f, 60.0f, 60.0f) )); root ->addChild(cameraNode) ->addChild(dirLight) ->addChild(pointLight) ->addComponent(sceneManager); auto _ = sceneManager->assets()->loader()->complete()->connect([=](file::Loader::Ptr loader) { sceneNode->addChild(sceneManager->assets()->symbol(SCENE_NAME)); skybox->addComponent(Surface::create( sceneManager->assets()->geometry("skybox"), BasicMaterial::create() ->diffuseColor(Vector4::create(1.0f, 0.0f, 0.0f, 1.0f)) ->diffuseMap(sceneManager->assets()->texture(HANGAR_TEXTURE)) ->triangleCulling(render::TriangleCulling::FRONT), sceneManager->assets()->effect("effect/Basic.effect") )); root ->addChild(dirLight) ->addChild(pointLight) ->addChild(skybox) ->addChild(cameraNode) ->addChild(sceneNode); }); auto resized = canvas->resized()->connect([&](AbstractCanvas::Ptr canvas, uint w, uint h) { cameraNode->component<PerspectiveCamera>()->aspectRatio(float(w) / float(h)); }); auto enterFrame = canvas->enterFrame()->connect([&](Canvas::Ptr canvas, float time, float deltaTime) { sceneManager->nextFrame(time, deltaTime); }); controller->start(); sceneManager->assets()->loader()->load(); canvas->run(); }
Geometry::Ptr Geometry::computeTangentSpace(bool doNormals) { const unsigned int numVertices = this->numVertices(); if (numVertices == 0) return shared_from_this(); if (!_data->hasProperty("position") || !_data->hasProperty("uv")) throw std::logic_error("Computation of tangent space requires positions and uv."); if (doNormals) computeNormals(); const std::vector<unsigned short>& indices (this->indices()->data()); const unsigned int numFaces = indices.size() / 3; unsigned short vertexIds[3] = { 0, 0, 0 }; std::vector<Vector3::Ptr> xyz(3); std::vector<Vector2::Ptr> uv(3); VertexBuffer::Ptr xyzBuffer = _data->get<VertexBuffer::Ptr>("position"); const unsigned int xyzSize = xyzBuffer->vertexSize(); const unsigned int xyzOffset = std::get<2>(*xyzBuffer->attribute("position")); const std::vector<float>& xyzData = xyzBuffer->data(); VertexBuffer::Ptr uvBuffer = _data->get<VertexBuffer::Ptr>("uv"); const unsigned int uvSize = uvBuffer->vertexSize(); const unsigned int uvOffset = std::get<2>(*uvBuffer->attribute("uv")); const std::vector<float>& uvData = uvBuffer->data(); std::vector<float> tangentsData(3 * numVertices, 0.0f); for (unsigned int i = 0, offset = 0; i < numFaces; ++i) { for (unsigned int k = 0; k < 3; ++k) { vertexIds[k] = indices[offset++]; unsigned int index = xyzOffset + vertexIds[k] * xyzSize; xyz[k] = Vector3::create(xyzData[index], xyzData[index + 1], xyzData[index + 2]); index = uvOffset + vertexIds[k] * uvSize; uv[k] = Vector2::create(uvData[index], uvData[index + 1]); } Vector2::Ptr uv02 = uv[0] - uv[2]; Vector2::Ptr uv12 = uv[1] - uv[2]; const float denom = uv02->x() * uv12->y() - uv12->x() * uv02->y(); const float invDenom = fabsf(denom) > 1e-6f ? 1.0f/denom : 1.0f; Vector3::Ptr faceTangent = ((xyz[0]-xyz[2]) * uv12->y() - (xyz[1]-xyz[2]) * uv02->y()) * invDenom; for (unsigned int k=0; k<3; ++k) { const unsigned int index = 3 * vertexIds[k]; tangentsData[index] += faceTangent->x(); tangentsData[index + 1] += faceTangent->y(); tangentsData[index + 2] += faceTangent->z(); } } for (unsigned int i = 0, index = 0; i < numVertices; ++i, index += 3) { const float x = tangentsData[index]; const float y = tangentsData[index + 1]; const float z = tangentsData[index + 2]; const float lengthSquared = x * x + y * y + z * z; const float invLength = lengthSquared > 1e-6f ? 1.0f / sqrtf(lengthSquared) : 1.0f; tangentsData[index] *= invLength; tangentsData[index + 1] *= invLength; tangentsData[index + 2] *= invLength; } VertexBuffer::Ptr tangentsBuffer = VertexBuffer::create(xyzBuffer->context(), tangentsData); tangentsBuffer->addAttribute("tangent", 3, 0); addVertexBuffer(tangentsBuffer); return shared_from_this(); }
Geometry::Ptr Geometry::computeNormals() { const unsigned int numVertices = this->numVertices(); if (numVertices == 0) return shared_from_this(); if (_data->hasProperty("normal")) throw std::logic_error("The geometry already stores precomputed normals."); if (!_data->hasProperty("position")) throw std::logic_error("Computation of normals requires positions."); const std::vector<unsigned short>& indices = this->indices()->data(); const unsigned int numFaces = indices.size() / 3; unsigned short vertexIds[3] = { 0, 0, 0 }; std::vector<Vector3::Ptr> xyz(3); VertexBuffer::Ptr xyzBuffer = _data->get<VertexBuffer::Ptr>("position"); const unsigned int xyzSize = xyzBuffer->vertexSize(); const unsigned int xyzOffset = std::get<2>(*xyzBuffer->attribute("position")); const std::vector<float>& xyzData = xyzBuffer->data(); std::vector<float> normalsData(3 * numVertices, 0.0f); for (unsigned int i = 0, offset = 0; i < numFaces; ++i) { for (unsigned int k = 0; k < 3; ++k) { vertexIds[k] = indices[offset++]; const unsigned int index = xyzOffset + vertexIds[k] * xyzSize; xyz[k] = Vector3::create(xyzData[index], xyzData[index + 1], xyzData[index + 2]); } Vector3::Ptr faceNormal = Vector3::create() ->copyFrom(xyz[0] - xyz[1]) ->cross(xyz[0] - xyz[2]); for (unsigned int k = 0; k < 3; ++k) { const unsigned int index = 3 * vertexIds[k]; normalsData[index] += faceNormal->x(); normalsData[index + 1] += faceNormal->y(); normalsData[index + 2] += faceNormal->z(); } } for (unsigned int i = 0, index = 0; i < numVertices; ++i, index += 3) { const float x = normalsData[index]; const float y = normalsData[index + 1]; const float z = normalsData[index + 2]; const float lengthSquared = x * x + y * y + z * z; const float invLength = lengthSquared > 1e-6f ? 1.0f / sqrtf(lengthSquared) : 1.0f; normalsData[index] *= invLength; normalsData[index + 1] *= invLength; normalsData[index + 2] *= invLength; } VertexBuffer::Ptr normalsBuffer = VertexBuffer::create(xyzBuffer->context(), normalsData); normalsBuffer->addAttribute("normal", 3, 0); addVertexBuffer(normalsBuffer); return shared_from_this(); }
inline void copyTranslation(Vector3::Ptr t) { t->setTo(_m[3], _m[7], _m[11]); }
void bullet::PhysicsWorld::setGravity(Vector3::Ptr gravity) { _bulletDynamicsWorld->setGravity(btVector3(gravity->x(), gravity->y(), gravity->z())); }