Physics (WIP)

This commit is contained in:
MrLetsplay 2022-11-10 22:00:34 +01:00
parent 8738f94768
commit 4d78ca9d94
16 changed files with 266 additions and 35 deletions

View File

@ -3,6 +3,7 @@
#include "uielements.h" #include "uielements.h"
#include "internal.h" #include "internal.h"
#include "internal/ui.h" #include "internal/ui.h"
#include "internal/physics.h"
namespace kek::Defaults { namespace kek::Defaults {
@ -15,6 +16,7 @@ static KeyBinding
keyDown, keyDown,
keyOptions, keyOptions,
keyToggleCursorMode, keyToggleCursorMode,
keyToggleNoclip,
keyExit; keyExit;
static ButtonElement *options; static ButtonElement *options;
@ -22,30 +24,39 @@ static ButtonElement *options;
static void defaultInput(GLFWwindow *window, void *data) { static void defaultInput(GLFWwindow *window, void *data) {
if(Input::isKeyboardCaptured()) return; if(Input::isKeyboardCaptured()) return;
glm::vec3 direction = glm::vec3(0);
if(Input::getKeyState(keyForward) == GLFW_PRESS) { if(Input::getKeyState(keyForward) == GLFW_PRESS) {
kekData.activeCamera->translate(kekData.activeCamera->direction * KEK_NOCLIP_SPEED * kekData.lastFrameTime); direction += kekData.activeCamera->direction;
} }
if(Input::getKeyState(keyBackward) == GLFW_PRESS) { if(Input::getKeyState(keyBackward) == GLFW_PRESS) {
kekData.activeCamera->translate(kekData.activeCamera->direction * -KEK_NOCLIP_SPEED * kekData.lastFrameTime); direction += -kekData.activeCamera->direction;
} }
if(Input::getKeyState(keyLeft) == GLFW_PRESS) { if(Input::getKeyState(keyLeft) == GLFW_PRESS) {
glm::vec3 camRight = glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f))); direction += -glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
kekData.activeCamera->translate(-camRight * KEK_NOCLIP_SPEED * kekData.lastFrameTime);
} }
if(Input::getKeyState(keyRight) == GLFW_PRESS) { if(Input::getKeyState(keyRight) == GLFW_PRESS) {
glm::vec3 camRight = glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f))); direction += glm::normalize(glm::cross(kekData.activeCamera->direction, glm::vec3(0.0f, 1.0f, 0.0f)));
kekData.activeCamera->translate(camRight * KEK_NOCLIP_SPEED * kekData.lastFrameTime);
} }
if(Input::getKeyState(keyUp) == GLFW_PRESS) { if(Input::getKeyState(keyUp) == GLFW_PRESS) {
kekData.activeCamera->translateY(KEK_NOCLIP_SPEED * kekData.lastFrameTime); direction += glm::vec3(0,1,0);
} }
if(Input::getKeyState(keyDown) == GLFW_PRESS) { if(Input::getKeyState(keyDown) == GLFW_PRESS) {
kekData.activeCamera->translateY(-KEK_NOCLIP_SPEED * kekData.lastFrameTime); direction += glm::vec3(0,-1,0);
}
direction = glm::normalize(direction);
if(glm::length2(direction) > 0) {
if(kekData.player->noclip) {
kekData.activeCamera->translate(direction * KEK_NOCLIP_SPEED * kekData.lastFrameTime);
}else {
kekData.player->physics->body->applyCentralImpulse(Physics::fromGLM(glm::normalize(direction) * (kekData.lastFrameTime * 20)));
}
} }
} }
@ -65,6 +76,10 @@ static void defaultKeyCallback(GLFWwindow *window, int key, int scancode, int ac
Input::setCursorMode(GLFWCursorMode::CAPTURE); Input::setCursorMode(GLFWCursorMode::CAPTURE);
} }
} }
if(key == Input::getKeyBinding(keyToggleNoclip).key && action == GLFW_PRESS) {
kekData.player->noclip = !kekData.player->noclip;
}
} }
static void defaultMouseCallback(GLFWwindow *window, double x, double y, void *data) { static void defaultMouseCallback(GLFWwindow *window, double x, double y, void *data) {
@ -136,6 +151,7 @@ void init() {
keyDown = Input::createKeyBinding("Down", GLFW_KEY_LEFT_CONTROL); keyDown = Input::createKeyBinding("Down", GLFW_KEY_LEFT_CONTROL);
keyOptions = Input::createKeyBinding("Options", GLFW_KEY_Q); keyOptions = Input::createKeyBinding("Options", GLFW_KEY_Q);
keyToggleCursorMode = Input::createKeyBinding("Toggle Cursor Mode", GLFW_KEY_TAB); keyToggleCursorMode = Input::createKeyBinding("Toggle Cursor Mode", GLFW_KEY_TAB);
keyToggleNoclip = Input::createKeyBinding("Toggle Noclip", GLFW_KEY_N);
keyExit = Input::createKeyBinding("Exit", GLFW_KEY_ESCAPE); keyExit = Input::createKeyBinding("Exit", GLFW_KEY_ESCAPE);
Input::addPeriodicCallback(PeriodicCallback(defaultInput, nullptr)); Input::addPeriodicCallback(PeriodicCallback(defaultInput, nullptr));
@ -145,6 +161,15 @@ void init() {
options = new ButtonElement(uiPx(0), uiPx(100), uiPx(100), uiPx(50)); options = new ButtonElement(uiPx(0), uiPx(100), uiPx(100), uiPx(50));
//UI::addElement(options); //UI::addElement(options);
kekData.player = new Player();
btCollisionShape *shape = new btBoxShape(btVector3(1,1,1));
kekData.player->physics = new PhysicsObjectData();
btRigidBody *body = new btRigidBody(1, nullptr, shape);
body->setActivationState(DISABLE_DEACTIVATION);
kekData.physics->world->addRigidBody(body);
kekData.player->physics->body = body;
kekData.player->moveTo(glm::vec3(0,10,0));
} }
void destroy() { void destroy() {

View File

@ -4,11 +4,12 @@
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include "internal.h" #include "internal.h"
#include "internal/physics.h"
namespace kek { namespace kek {
GameObject::GameObject() { GameObject::GameObject() {
this->physics = nullptr;
} }
GameObject::~GameObject() { GameObject::~GameObject() {
@ -23,7 +24,7 @@ void GameObject::addMesh(Mesh *mesh) {
void GameObject::draw(Shader *shader) { void GameObject::draw(Shader *shader) {
glm::mat4 model = glm::mat4(1.0f); glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, position) * glm::mat4_cast(rotation); model = glm::translate(model, getPosition()) * glm::mat4_cast(getRotation());
glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "model"), 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(glGetUniformLocation(kekData.shader->id, "model"), 1, GL_FALSE, glm::value_ptr(model));
for(Mesh *mesh : meshes) { for(Mesh *mesh : meshes) {
@ -31,4 +32,28 @@ void GameObject::draw(Shader *shader) {
} }
} }
void GameObject::addPhysics(btCollisionShape *shape, float mass, int collisionFlags) {
this->physics = new PhysicsObjectData();
btRigidBody *body = new btRigidBody(mass, new btDefaultMotionState(), shape);
kekData.physics->world->addRigidBody(body);
body->setCollisionFlags(collisionFlags);
this->physics->body = body;
}
void GameObject::rotateTo(glm::quat rotation) {
this->physics->body->getWorldTransform().setRotation(Physics::fromGLM(rotation));
}
glm::quat GameObject::getRotation() {
return Physics::toGLM(this->physics->body->getWorldTransform().getRotation());
}
void GameObject::moveTo(glm::vec3 position) {
this->physics->body->getWorldTransform().setOrigin(Physics::fromGLM(position));
}
glm::vec3 GameObject::getPosition() {
return Physics::toGLM(this->physics->body->getWorldTransform().getOrigin());
}
} }

View File

@ -23,7 +23,6 @@ void DefaultObject::translate(glm::vec3 delta) {
} }
void DefaultObject::moveTo(glm::vec3 position) { void DefaultObject::moveTo(glm::vec3 position) {
//this->position = glm::vec3(position.x, position.y, position.z);
this->position.x = position.x; this->position.x = position.x;
this->position.y = position.y; this->position.y = position.y;
this->position.z = position.z; this->position.z = position.z;
@ -45,6 +44,10 @@ void DefaultRotateableObject::rotate(float angle, glm::vec3 axis) {
this->rotation = glm::rotate(rotation, glm::radians(angle), axis); this->rotation = glm::rotate(rotation, glm::radians(angle), axis);
} }
void DefaultRotateableObject::rotateTo(glm::quat rotation) {
this->rotation = rotation;
}
void DefaultRotateableObject::lookAt(glm::vec3 direction) { void DefaultRotateableObject::lookAt(glm::vec3 direction) {
this->rotation = glm::quatLookAt(glm::normalize(direction), glm::vec3(0.0f, 1.0f, 0.0f)); this->rotation = glm::quatLookAt(glm::normalize(direction), glm::vec3(0.0f, 1.0f, 0.0f));
} }

View File

@ -0,0 +1,27 @@
#include "player.h"
#include "internal/physics.h"
namespace kek {
Player::Player(): RotateableObject() {
this->noclip = false;
}
void Player::rotateTo(glm::quat rotation) {
this->physics->body->getWorldTransform().setRotation(Physics::fromGLM(rotation));
}
glm::quat Player::getRotation() {
return Physics::toGLM(this->physics->body->getWorldTransform().getRotation());
}
void Player::moveTo(glm::vec3 position) {
this->physics->body->getWorldTransform().setOrigin(Physics::fromGLM(position));
}
glm::vec3 Player::getPosition() {
return Physics::toGLM(this->physics->body->getWorldTransform().getOrigin());
}
}

View File

@ -3,6 +3,8 @@
#include "internal.h" #include "internal.h"
#include "internal/physics.h" #include "internal/physics.h"
#include <glm/glm.hpp>
namespace kek::Physics { namespace kek::Physics {
void init() { void init() {
@ -14,23 +16,49 @@ void init() {
btSequentialImpulseConstraintSolver *solver = new btSequentialImpulseConstraintSolver(); btSequentialImpulseConstraintSolver *solver = new btSequentialImpulseConstraintSolver();
kekData.physics->world = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConf); kekData.physics->world = new btDiscreteDynamicsWorld(dispatcher, overlappingPairCache, solver, collisionConf);
kekData.physics->world->setGravity(btVector3(0, -10, 0)); kekData.physics->world->setGravity(btVector3(0, -10, 0));
btCollisionShape *shape = new btBoxShape(btVector3(1, 1, 1));
btDefaultMotionState *state = new btDefaultMotionState();
btRigidBody *body = new btRigidBody(1, state, shape);
kekData.physics->world->addRigidBody(body);
} }
void destroy() { void destroy() {
for(int i = kekData.physics->world->getNumCollisionObjects() - 1; i >= 0; i--) {
btCollisionObject *obj = kekData.physics->world->getCollisionObjectArray()[i];
btRigidBody *rigid = btRigidBody::upcast(obj);
if(obj->getCollisionShape()) delete obj->getCollisionShape();
if(rigid && rigid->getMotionState()) delete rigid->getMotionState();
kekData.physics->world->removeCollisionObject(obj);
delete obj;
}
delete kekData.physics; delete kekData.physics;
} }
void step(float deltaT) { void step(float deltaT) {
for(GameObject *obj : kekData.activeScene->objects) {
if(obj->physics) {
obj->physics->body->getWorldTransform().setOrigin(fromGLM(obj->getPosition()));
}
}
kekData.physics->world->stepSimulation(deltaT, 100); kekData.physics->world->stepSimulation(deltaT, 100);
//btRigidBody *body = btRigidBody::upcast(kekData.physics->world->getCollisionObjectArray()[0]); if(!kekData.player->noclip) {
//btTransform &t = body->getWorldTransform(); kekData.activeCamera->moveTo(kekData.player->getEyePosition());
//btVector3 &vec = t.getOrigin(); }
}
glm::vec3 toGLM(btVector3 vec) {
return glm::vec3(vec.x(), vec.y(), vec.z());
}
btVector3 fromGLM(glm::vec3 vec) {
return btVector3(vec.x, vec.y, vec.z);
}
glm::quat toGLM(btQuaternion quat) {
return glm::quat(quat.w(), quat.x(), quat.y(), quat.z());
}
btQuaternion fromGLM(glm::quat quat) {
return btQuaternion(quat.x, quat.y, quat.z, quat.w);
} }
} }

View File

@ -167,8 +167,18 @@ std::vector<kek::Vertex> genCubeVertices(float w, float h, float d, bool texCoor
return vertices; return vertices;
} }
Mesh *genCubeMesh(float w, float h, float d, std::shared_ptr<Texture> ambient, std::shared_ptr<Texture> diffuse, std::shared_ptr<Texture> specular) {
std::vector<Vertex> vertices = genCubeVertices(w, h, d, true);
std::vector<unsigned int> indices;
for(size_t i = 0; i < vertices.size(); i++) {
indices.push_back(i);
}
Material *material = new Material(ambient, diffuse, specular, 80.0f); // FIXME: hard-coded shininess
return new Mesh(vertices, indices, material);
}
std::string toString(glm::vec3 vector) { std::string toString(glm::vec3 vector) {
return std::to_string(vector.x) + " " + std::to_string(vector.y) + " " + std::to_string(vector.z); return std::to_string(vector.x) + " " + std::to_string(vector.y) + " " + std::to_string(vector.z);
} }
} }

View File

@ -15,6 +15,9 @@
#define KEK_LIGHT_LIMIT 64 // Also in shader/include/constants.glsl #define KEK_LIGHT_LIMIT 64 // Also in shader/include/constants.glsl
#define KEK_LIGHT_MAX_DISTANCE 50
#define KEK_LIGHT_MAX_DISTANCE_SQUARED (KEK_LIGHT_MAX_DISTANCE * KEK_LIGHT_MAX_DISTANCE)
#define KEK_NOCLIP_SPEED 10.0f #define KEK_NOCLIP_SPEED 10.0f
#define KEK_CAMERA_NEAR 0.1f #define KEK_CAMERA_NEAR 0.1f
@ -23,9 +26,6 @@
#define KEK_LIGHT_DEFAULT_AMBIENT_STRENGTH 0.05f #define KEK_LIGHT_DEFAULT_AMBIENT_STRENGTH 0.05f
#define KEK_LIGHT_DEFAULT_SPECULAR_STRENGTH 0.1f #define KEK_LIGHT_DEFAULT_SPECULAR_STRENGTH 0.1f
#define KEK_LIGHT_MAX_DISTANCE 30
#define KEK_LIGHT_MAX_DISTANCE_SQUARED (KEK_LIGHT_MAX_DISTANCE * KEK_LIGHT_MAX_DISTANCE)
#define KEK_INVALID_KEY_BINDING_NAME "INVALID" #define KEK_INVALID_KEY_BINDING_NAME "INVALID"
#define KEK_INVALID_ID -1u #define KEK_INVALID_ID -1u
@ -42,3 +42,7 @@
#define KEK_DEFAULT_FONT_SIZE_PIXELS 24 #define KEK_DEFAULT_FONT_SIZE_PIXELS 24
#define KEK_INPUT_DELETE -1u #define KEK_INPUT_DELETE -1u
#define KEK_PLAYER_HEIGHT 2
#define KEK_PLAYER_RADIUS 0.5f
#define KEK_PLAYER_EYE_OFFSET (KEK_PLAYER_HEIGHT / 2 - KEK_PLAYER_RADIUS)

View File

@ -2,24 +2,45 @@
#include "object.h" #include "object.h"
#include "mesh.h" #include "mesh.h"
#include "physics.h"
#include <BulletCollision/CollisionShapes/btCollisionShape.h>
namespace kek { namespace kek {
class GameObject: public DefaultRotateableObject { class GameObject: public RotateableObject {
protected: protected:
std::vector<Mesh *> meshes; std::vector<Mesh *> meshes;
public: public:
PhysicsObjectData *physics;
GameObject(); GameObject();
~GameObject(); virtual ~GameObject();
// Adds a mesh to the GameObject. The GameObject takes ownership of the Mesh, so don't use Meshes in multiple GameObjects // Adds a mesh to the GameObject. The GameObject takes ownership of the Mesh, so don't use Meshes in multiple GameObjects
void addMesh(Mesh *mesh); void addMesh(Mesh *mesh);
void draw(Shader *shader); void draw(Shader *shader);
void addPhysics(btCollisionShape *shape, float mass = 1, int collisionFlags = 0);
virtual void rotate(float angle, glm::vec3 axis) { rotateTo(glm::rotate(getRotation(), angle, axis)); };
virtual void rotateTo(glm::quat rotation);
virtual void lookAt(glm::vec3 direction) { rotateTo(glm::quatLookAt(glm::normalize(direction), glm::vec3(0,1,0))); };
virtual glm::quat getRotation();
virtual void translate(glm::vec3 delta) { moveTo(getPosition() + delta); };
virtual void moveTo(glm::vec3 position);
virtual glm::vec3 getPosition();
}; };
} }

View File

@ -10,6 +10,7 @@
#include "texture.h" #include "texture.h"
#include "fonts.h" #include "fonts.h"
#include "ui.h" #include "ui.h"
#include "player.h"
namespace kek { namespace kek {
@ -24,6 +25,8 @@ struct KekData {
Camera *activeCamera; Camera *activeCamera;
Scene *activeScene; Scene *activeScene;
Player *player;
int screenWidth; int screenWidth;
int screenHeight; int screenHeight;

View File

@ -8,4 +8,18 @@ struct PhysicsData {
btDynamicsWorld *world; btDynamicsWorld *world;
}; };
struct PhysicsObjectData {
btRigidBody *body;
};
namespace Physics {
glm::vec3 toGLM(btVector3 vec);
btVector3 fromGLM(glm::vec3 vec);
glm::quat toGLM(btQuaternion quat);
btQuaternion fromGLM(glm::quat quat);
}
} }

View File

@ -49,6 +49,8 @@ public:
virtual void rotate(float angle, glm::vec3 axis) = 0; virtual void rotate(float angle, glm::vec3 axis) = 0;
virtual void rotateTo(glm::quat rotation) = 0;
virtual void lookAt(glm::vec3 direction) = 0; virtual void lookAt(glm::vec3 direction) = 0;
virtual void lookAtPos(glm::vec3 position); virtual void lookAtPos(glm::vec3 position);
@ -69,6 +71,8 @@ public:
virtual void rotate(float angle, glm::vec3 axis); virtual void rotate(float angle, glm::vec3 axis);
virtual void rotateTo(glm::quat rotation);
virtual void lookAt(glm::vec3 direction); virtual void lookAt(glm::vec3 direction);
virtual glm::quat getRotation(); virtual glm::quat getRotation();
@ -81,4 +85,4 @@ public:
}; };
} }

View File

@ -1,6 +1,10 @@
#pragma once #pragma once
namespace kek::Physics { namespace kek {
struct PhysicsObjectData;
namespace Physics {
void init(); void init();
void destroy(); void destroy();
@ -8,3 +12,5 @@ void destroy();
void step(float deltaT); void step(float deltaT);
} }
}

View File

@ -0,0 +1,35 @@
#pragma once
#include "gameobject.h"
namespace kek {
class Player: public RotateableObject {
public:
PhysicsObjectData *physics;
bool noclip;
Player();
virtual void rotate(float angle, glm::vec3 axis) { rotateTo(glm::rotate(getRotation(), angle, axis)); };
virtual void rotateTo(glm::quat rotation);
virtual void lookAt(glm::vec3 direction) { rotateTo(glm::quatLookAt(glm::normalize(direction), glm::vec3(0,1,0))); };
virtual glm::quat getRotation();
virtual void translate(glm::vec3 delta) { moveTo(getPosition() + delta); };
virtual void moveTo(glm::vec3 position);
virtual glm::vec3 getPosition();
virtual glm::vec3 getEyePosition() { return getPosition() + glm::vec3(0, KEK_PLAYER_EYE_OFFSET, 0); }
virtual glm::vec3 getFootPosition() { return getPosition() - glm::vec3(0, KEK_PLAYER_HEIGHT / 2, 0); };
};
}

View File

@ -46,6 +46,8 @@ void genCubeVertices(float w, float h, float d, bool texCoords, float **outVerts
std::vector<Vertex> genCubeVertices(float w, float h, float d, bool texCoords); std::vector<Vertex> genCubeVertices(float w, float h, float d, bool texCoords);
Mesh *genCubeMesh(float w, float h, float d, std::shared_ptr<Texture> ambient, std::shared_ptr<Texture> diffuse, std::shared_ptr<Texture> specular);
std::string toString(glm::vec3 vector); std::string toString(glm::vec3 vector);
} }

View File

@ -4,6 +4,9 @@
#include <GL/glew.h> #include <GL/glew.h>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <BulletCollision/CollisionShapes/btBoxShape.h>
#include <BulletCollision/btBulletCollisionCommon.h>
using namespace kek; using namespace kek;
static ButtonElement *button; static ButtonElement *button;
@ -43,24 +46,45 @@ void onButtonClick(void *data) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
if(Engine::init() != KEK_SUCCESS) return 1; if(Engine::init() != KEK_SUCCESS) return 1;
MemoryBuffer *buf = Resource::loadResource("object/sphere/Sphere.obj");
Mesh *mesh = ObjParser::parseMesh(buf, "object/sphere/");
delete buf;
GameObject *test = new GameObject();
test->addMesh(mesh);
Scene *scene = new Scene(); Scene *scene = new Scene();
GameObject *floor = new GameObject();
{
std::shared_ptr<Texture> tex = Texture::load("image/white.png");
floor->addMesh(genCubeMesh(100, 1, 100, tex, tex, tex));
btCollisionShape *shape = new btBoxShape(btVector3(50,0.5,50));
floor->addPhysics(shape, 0, btCollisionObject::CF_STATIC_OBJECT);
scene->addObject(floor);
}
Mesh *mesh = ObjParser::loadMesh("object/sphere/Sphere.obj");
GameObject *test = new GameObject();
btCollisionShape *shape = new btSphereShape(1);
test->addPhysics(shape);
test->addMesh(mesh);
test->moveTo(glm::vec3(0,5,0));
scene->addObject(test); scene->addObject(test);
Mesh *mesh2 = ObjParser::loadMesh("object/cube_colored/Cube.obj");
GameObject *test3 = new GameObject();
btCollisionShape *shape2 = new btBoxShape(btVector3(1,1,1));
test3->addPhysics(shape2, 0, btCollisionObject::CF_STATIC_OBJECT);
test3->addMesh(mesh2);
test3->moveTo(glm::vec3(2, 1, 2));
scene->addObject(test3);
for(int i = 0; i < 10; i++) { for(int i = 0; i < 10; i++) {
GameObject *test2 = new GameObject(); GameObject *test2 = new GameObject();
btCollisionShape *shape = new btBoxShape(btVector3(1,1,1));
test2->addPhysics(shape);
test2->addMesh(ObjParser::loadMesh("object/cube_colored/Cube.obj")); test2->addMesh(ObjParser::loadMesh("object/cube_colored/Cube.obj"));
test2->moveTo(glm::vec3(0.0f, 5.0f, 3 * i)); test2->moveTo(glm::vec3(1.0f, 5.0f, 3 * i));
scene->addObject(test2); scene->addObject(test2);
} }
PointLight *light = new PointLight(glm::vec3(1), 1, 0, 1); PointLight *light = new PointLight(glm::vec3(1), 1, 0, 1);
light->moveTo(glm::vec3(0,1,0));
scene->lights->add(light); scene->lights->add(light);
//DirectionalLight *l = new DirectionalLight(glm::vec3(1), glm::vec3(1, -1, 1)); //DirectionalLight *l = new DirectionalLight(glm::vec3(1), glm::vec3(1, -1, 1));

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB