Make possible to apply force to bodies in the testbed application

This commit is contained in:
Daniel Chappuis 2020-06-07 18:51:52 +02:00
parent 594e948ae7
commit e7c5432936
6 changed files with 112 additions and 7 deletions

View File

@ -139,6 +139,7 @@ void Gui::createSimulationPanel() {
new Label(mSimulationPanel, "Scene","sans-bold");
ComboBox* comboBoxScenes = new ComboBox(mSimulationPanel, scenesNames);
comboBoxScenes->set_fixed_width(150);
comboBoxScenes->popup()->child_at(0)->set_fixed_height(800);
comboBoxScenes->set_callback([&, scenes](int index) {
mApp->switchScene(scenes[index]);
});

View File

@ -91,8 +91,7 @@ bool Scene::mapMouseCoordinatesToSphere(double xMouse, double yMouse,
}
// Called when a mouse button event occurs
bool Scene::mouseButtonEvent(int button, bool down, int mods,
double mousePosX, double mousePosY) {
bool Scene::mouseButtonEvent(int button, bool down, int mods, double mousePosX, double mousePosY) {
// If the mouse button is pressed
if (down) {

View File

@ -199,8 +199,7 @@ class Scene : public rp3d::EventListener {
virtual bool keyboardEvent(int key, int scancode, int action, int mods);
/// Called when a mouse button event occurs
virtual bool mouseButtonEvent(int button, bool down, int mods,
double mousePosX, double mousePosY);
virtual bool mouseButtonEvent(int button, bool down, int mods, double mousePosX, double mousePosY);
/// Called when a mouse motion event occurs
virtual bool mouseMotionEvent(double xMouse, double yMouse, int leftButtonState,

View File

@ -47,7 +47,8 @@ SceneDemo::SceneDemo(const std::string& name, EngineSettings& settings, bool isP
mColorShader("shaders/color.vert", "shaders/color.frag"),
mQuadShader("shaders/quad.vert", "shaders/quad.frag"),
mVBOQuad(GL_ARRAY_BUFFER), mDebugVBOLinesVertices(GL_ARRAY_BUFFER), mDebugVBOTrianglesVertices(GL_ARRAY_BUFFER),
mMeshFolderPath("meshes/"), mPhysicsWorld(nullptr), mIsPhysicsWorldSimulated(isPhysicsWorldSimulated) {
mMeshFolderPath("meshes/"), mPhysicsWorld(nullptr), mIsPhysicsWorldSimulated(isPhysicsWorldSimulated),
mIsMovingBody(false), mMovingBody(nullptr) {
shadowMapTextureLevel++;
@ -612,6 +613,75 @@ void SceneDemo::removeAllVisualContactPoints() {
mVisualContactPoints.clear();
}
// Called when the user is moving a body with the mouse
void SceneDemo::moveBodyWithMouse(double mousePosX, double mousePosY) {
if (!mIsMovingBody) {
// Find the body and the position of the mouse on that body (with raycasting)
openglframework::Vector4 screenPoint1((mousePosX / mWindowWidth) * 2.0 - 1.0, ((mWindowHeight - mousePosY) / mWindowHeight) * 2.0 - 1.0, -1, 1);
openglframework::Vector4 screenPoint2((mousePosX / mWindowWidth) * 2.0 - 1.0, ((mWindowHeight - mousePosY) / mWindowHeight) * 2.0 - 1.0, 1, 1);
openglframework::Vector4 worldP1 = (mCamera.getTransformMatrix() * mCamera.getProjectionMatrix().getInverse()) * screenPoint1;
openglframework::Vector4 worldP2 = (mCamera.getTransformMatrix() * mCamera.getProjectionMatrix().getInverse()) * screenPoint2;
openglframework::Vector3 cameraPos = mCamera.getOrigin();
rp3d::Vector3 worldPoint1(worldP1.x, worldP1.y, worldP1.z);
rp3d::Vector3 worldPoint2(worldP2.x, worldP2.y, worldP2.z);
rp3d::Ray ray(worldPoint1, worldPoint2);
mPhysicsWorld->raycast(ray, this);
}
if (mMovingBody != nullptr) {
openglframework::Vector4 previousScreenPos(mLastMouseX / mWindowWidth, (mWindowHeight - mLastMouseY) / mWindowHeight, 0, 0);
openglframework::Vector4 currentScreenPos(mousePosX / mWindowWidth, (mWindowHeight - mousePosY) / mWindowHeight, 0, 0);
openglframework::Vector4 forceScreen = currentScreenPos - previousScreenPos;
openglframework::Vector4 f = mCamera.getTransformMatrix() * forceScreen * MOUSE_MOVE_BODY_FORCE;
rp3d::Vector3 force(f.x, f.y, f.z);
mMovingBody->applyForceAtLocalPosition(force, mMovingBodyLocalPoint);
}
mLastMouseX = mousePosX;
mLastMouseY = mousePosY;
mIsMovingBody = true;
}
// Called when a mouse button event occurs
bool SceneDemo::mouseButtonEvent(int button, bool down, int mods, double mousePosX, double mousePosY) {
// Left mouse click with CTRL key pressed on keyboard (moving a body)
if (down && (mods & GLFW_MOD_CONTROL)) {
moveBodyWithMouse(mousePosX, mousePosY);
return true;
}
mIsMovingBody = false;
mMovingBody = nullptr;
return Scene::mouseButtonEvent(button, down, mods, mousePosX, mousePosY);
}
// Called when a mouse motion event occurs
bool SceneDemo::mouseMotionEvent(double xMouse, double yMouse, int leftButtonState, int rightButtonState, int middleButtonState, int altKeyState) {
if (mIsMovingBody) {
moveBodyWithMouse(xMouse, yMouse);
return true;
}
return Scene::mouseMotionEvent(xMouse, yMouse, leftButtonState, rightButtonState, middleButtonState, altKeyState);
}
// Called when a raycast hit occurs (used to move a body with the mouse)
rp3d::decimal SceneDemo::notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) {
rp3d::RigidBody* body = dynamic_cast<rp3d::RigidBody*>(raycastInfo.body);
mMovingBody = body;
const rp3d::Transform localToWorldTransform = raycastInfo.collider->getLocalToWorldTransform();
mMovingBodyLocalPoint = localToWorldTransform.getInverse() * raycastInfo.worldPoint;
return raycastInfo.hitFraction;
}
// Update the engine settings
void SceneDemo::updateEngineSettings() {

View File

@ -35,11 +35,12 @@
// Constants
const int SHADOWMAP_WIDTH = 2048;
const int SHADOWMAP_HEIGHT = 2048;
const float MOUSE_MOVE_BODY_FORCE = 100000.0f;
// Class SceneDemo
// Abstract class that represents a 3D scene for the ReactPhysics3D examples.
// This scene has a single light source with shadow mapping.
class SceneDemo : public Scene {
class SceneDemo : public Scene, rp3d::RaycastCallback {
protected:
@ -121,6 +122,15 @@ class SceneDemo : public Scene {
/// True if we need to step the physics simulation each frame
bool mIsPhysicsWorldSimulated;
/// True if the user is currently moving a body with the mouse
bool mIsMovingBody;
/// Local-space point on the body use to move it with the mouse
rp3d::Vector3 mMovingBodyLocalPoint;
/// Pointer to the body that is currently moved with the mouse by the user
rp3d::RigidBody* mMovingBody;
// -------------------- Methods -------------------- //
/// Create the Shadow map FBO and texture
@ -150,6 +160,9 @@ class SceneDemo : public Scene {
/// Remove all contact points
void removeAllVisualContactPoints();
/// Called when the user is moving a body with the mouse
void moveBodyWithMouse(double mousePosX, double mousePosY);
public:
// -------------------- Methods -------------------- //
@ -181,6 +194,16 @@ class SceneDemo : public Scene {
/// Enable/disable debug rendering
virtual void setIsDebugRendererEnabled(bool isEnabled) override;
/// Called when a mouse button event occurs
virtual bool mouseButtonEvent(int button, bool down, int mods, double mousePosX, double mousePosY) override;
/// Called when a mouse motion event occurs
virtual bool mouseMotionEvent(double xMouse, double yMouse, int leftButtonState,
int rightButtonState, int middleButtonState, int altKeyState) override;
/// Called when a raycast hit occurs (used to move a body with the mouse)
virtual rp3d::decimal notifyRaycastHit(const rp3d::RaycastInfo& raycastInfo) override;
};
// Enabled/Disable the shadow mapping

View File

@ -110,7 +110,7 @@ void TestbedApplication::createScenes() {
mScenes.push_back(cubeStackScene);
// Joints scene
JointsScene* jointsScene = new JointsScene("Joints", mEngineSettings);
JointsScene* jointsScene = new JointsScene("HingeJoint - Bridge", mEngineSettings);
mScenes.push_back(jointsScene);
// Collision shapes scene
@ -356,6 +356,19 @@ bool TestbedApplication::keyboard_event(int key, int scancode, int action, int m
return true;
}
// Close application on escape key
if (key == GLFW_KEY_P && action == GLFW_PRESS) {
if (mTimer.isRunning()) {
pauseSimulation();
}
else {
playSimulation();
}
return true;
}
return mCurrentScene->keyboardEvent(key, scancode, action, modifiers);
}