Last active
May 6, 2023 16:31
-
-
Save newpolaris/c44d275dbe71461b89318f26fc2e6f4e to your computer and use it in GitHub Desktop.
bullet debug draw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #include <iostream> | |
| #include <bullet/btBulletDynamicsCommon.h> | |
| #include <glad/glad.h> | |
| #include <GLFW/glfw3.h> | |
| #include <vector> | |
| #include <string> | |
| #include <glm/glm.hpp> | |
| #include <glm/gtc/matrix_transform.hpp> | |
| #include <glm/gtc/type_ptr.hpp> | |
| GLuint compileShader(GLenum shaderType, const std::string& shaderSource) { | |
| GLuint shader = glCreateShader(shaderType); | |
| const char* source = shaderSource.c_str(); | |
| glShaderSource(shader, 1, &source, nullptr); | |
| glCompileShader(shader); | |
| GLint success; | |
| glGetShaderiv(shader, GL_COMPILE_STATUS, &success); | |
| if (!success) { | |
| char infoLog[512]; | |
| glGetShaderInfoLog(shader, sizeof(infoLog), nullptr, infoLog); | |
| std::cerr << "ERROR::SHADER::COMPILATION_FAILED\n" << infoLog << std::endl; | |
| } | |
| return shader; | |
| } | |
| GLuint createShaderProgram(const std::string& vertexShaderSource, const std::string& fragmentShaderSource) { | |
| GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource); | |
| GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource); | |
| GLuint shaderProgram = glCreateProgram(); | |
| glAttachShader(shaderProgram, vertexShader); | |
| glAttachShader(shaderProgram, fragmentShader); | |
| glLinkProgram(shaderProgram); | |
| GLint success; | |
| glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); | |
| if (!success) { | |
| char infoLog[512]; | |
| glGetProgramInfoLog(shaderProgram, sizeof(infoLog), nullptr, infoLog); | |
| std::cerr << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl; | |
| } | |
| glDeleteShader(vertexShader); | |
| glDeleteShader(fragmentShader); | |
| return shaderProgram; | |
| } | |
| class OpenGLDebugDrawer : public btIDebugDraw { | |
| public: | |
| OpenGLDebugDrawer() : m_debugMode(0) { | |
| glGenVertexArrays(1, &m_vao); | |
| glGenBuffers(1, &m_vbo); | |
| glGenBuffers(1, &m_ebo); | |
| glGenBuffers(1, &m_colorBuffer); | |
| m_shaderProgram = createShaderProgram(vertexShaderSource, fragmentShaderSource); | |
| } | |
| ~OpenGLDebugDrawer() { | |
| glDeleteVertexArrays(1, &m_vao); | |
| glDeleteBuffers(1, &m_vbo); | |
| glDeleteBuffers(1, &m_ebo); | |
| glDeleteBuffers(1, &m_colorBuffer); | |
| glDeleteProgram(m_shaderProgram); | |
| } | |
| void drawLine(const btVector3& from, const btVector3& to, const btVector3& color) override { | |
| m_vertices.push_back(from); | |
| m_vertices.push_back(to); | |
| m_colors.push_back(color); | |
| m_colors.push_back(color); | |
| m_indices.push_back(m_indices.size()); | |
| m_indices.push_back(m_indices.size()); | |
| } | |
| void drawContactPoint(const btVector3&, const btVector3&, btScalar, int, const btVector3&) override {} | |
| void reportErrorWarning(const char*) override {} | |
| void draw3dText(const btVector3&, const char*) override {} | |
| void setDebugMode(int debugMode) override { m_debugMode = debugMode; } | |
| int getDebugMode() const override { return m_debugMode; } | |
| void render() { | |
| // Create view and projection matrices | |
| glm::vec3 cameraPos(0.0f, 5.0f, 10.0f); | |
| glm::vec3 cameraTarget(0.0f, 0.0f, 0.0f); | |
| glm::vec3 upVector(0.0f, 1.0f, 0.0f); | |
| glm::mat4 view = glm::lookAt(cameraPos, cameraTarget, upVector); | |
| glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 100.0f); | |
| // Bind the VAO and update buffers | |
| // ... | |
| glBindVertexArray(m_vao); | |
| glBindBuffer(GL_ARRAY_BUFFER, m_vbo); | |
| glBufferData(GL_ARRAY_BUFFER, sizeof(btVector3) * m_vertices.size(), m_vertices.data(), GL_STATIC_DRAW); | |
| glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, nullptr); | |
| glEnableVertexAttribArray(0); | |
| glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer); | |
| glBufferData(GL_ARRAY_BUFFER, sizeof(btVector3) * m_colors.size(), m_colors.data(), GL_STATIC_DRAW); | |
| glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, nullptr); | |
| glEnableVertexAttribArray(1); | |
| glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo); | |
| glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * m_indices.size(), m_indices.data(), GL_STATIC_DRAW); | |
| // Set view and projection matrices in the shader | |
| glUseProgram(m_shaderProgram); | |
| glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "uView"), 1, GL_FALSE, glm::value_ptr(view)); | |
| glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "uProjection"), 1, GL_FALSE, glm::value_ptr(projection)); | |
| // Draw the debug lines | |
| glDrawElements(GL_LINES, static_cast<GLsizei>(m_indices.size()), GL_UNSIGNED_INT, nullptr); | |
| m_vertices.clear(); | |
| m_colors.clear(); | |
| m_indices.clear(); | |
| } | |
| private: | |
| int m_debugMode; | |
| std::vector<btVector3> m_vertices; | |
| std::vector<btVector3> m_colors; | |
| std::vector<GLuint> m_indices; | |
| GLuint m_vao, m_vbo, m_ebo, m_colorBuffer; | |
| GLuint m_shaderProgram; | |
| const std::string vertexShaderSource = R"( | |
| #version 430 core | |
| layout (location = 0) in vec3 aPos; | |
| layout (location = 1) in vec3 aColor; | |
| uniform mat4 uView; | |
| uniform mat4 uProjection; | |
| out vec3 vertexColor; | |
| void main() { | |
| gl_Position = uProjection * uView * vec4(aPos, 1.0); | |
| vertexColor = aColor; | |
| } | |
| )"; | |
| const std::string fragmentShaderSource = R"( | |
| #version 430 core | |
| in vec3 vertexColor; | |
| out vec4 FragColor; | |
| void main() { | |
| FragColor = vec4(vertexColor, 1.0); | |
| } | |
| )"; | |
| }; | |
| void APIENTRY glDebugMessageCallbackFunc(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { | |
| std::string sourceStr; | |
| switch (source) { | |
| case GL_DEBUG_SOURCE_API: sourceStr = "API"; break; | |
| case GL_DEBUG_SOURCE_WINDOW_SYSTEM: sourceStr = "Window System"; break; | |
| case GL_DEBUG_SOURCE_SHADER_COMPILER: sourceStr = "Shader Compiler"; break; | |
| case GL_DEBUG_SOURCE_THIRD_PARTY: sourceStr = "Third Party"; break; | |
| case GL_DEBUG_SOURCE_APPLICATION: sourceStr = "Application"; break; | |
| case GL_DEBUG_SOURCE_OTHER: sourceStr = "Other"; break; | |
| default: sourceStr = "Unknown"; | |
| } | |
| std::string typeStr; | |
| switch (type) { | |
| case GL_DEBUG_TYPE_ERROR: typeStr = "Error"; break; | |
| case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: typeStr = "Deprecated Behavior"; break; | |
| case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: typeStr = "Undefined Behavior"; break; | |
| case GL_DEBUG_TYPE_PORTABILITY: typeStr = "Portability"; break; | |
| case GL_DEBUG_TYPE_PERFORMANCE: typeStr = "Performance"; break; | |
| case GL_DEBUG_TYPE_OTHER: typeStr = "Other"; break; | |
| default: typeStr = "Unknown"; | |
| } | |
| std::string severityStr; | |
| switch (severity) { | |
| case GL_DEBUG_SEVERITY_HIGH: severityStr = "High"; break; | |
| case GL_DEBUG_SEVERITY_MEDIUM: severityStr = "Medium"; break; | |
| case GL_DEBUG_SEVERITY_LOW: severityStr = "Low"; break; | |
| case GL_DEBUG_SEVERITY_NOTIFICATION: severityStr = "Notification"; break; | |
| default: severityStr = "Unknown"; | |
| } | |
| std::cout << "OpenGL Debug Message [" << sourceStr << "][" << typeStr << "][" << severityStr << "] ID: " << id << " - " << message << std::endl; | |
| } | |
| // compileShader, createShaderProgram and OpenGLDebugDrawer class implementation go here. | |
| int main() { | |
| // Initialize GLFW | |
| if (!glfwInit()) { | |
| std::cerr << "Failed to initialize GLFW" << std::endl; | |
| return -1; | |
| } | |
| // Create a GLFW window | |
| glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); | |
| glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); | |
| glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
| GLFWwindow* window = glfwCreateWindow(800, 600, "Bullet Physics - GLFW and GLAD", nullptr, nullptr); | |
| if (!window) { | |
| std::cerr << "Failed to create GLFW window" << std::endl; | |
| glfwTerminate(); | |
| return -1; | |
| } | |
| // Make the window's context current | |
| glfwMakeContextCurrent(window); | |
| // Load OpenGL function pointers using GLAD | |
| if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { | |
| std::cerr << "Failed to initialize GLAD" << std::endl; | |
| glfwTerminate(); | |
| return -1; | |
| } | |
| if (true) { // GLAD_GL_KHR_debug) { | |
| glEnable(GL_DEBUG_OUTPUT); | |
| glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); | |
| glDebugMessageCallback(glDebugMessageCallbackFunc, nullptr); | |
| glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, nullptr, GL_TRUE); | |
| } else { | |
| std::cout << "OpenGL KHR_debug extension not available. Debug output disabled." << std::endl; | |
| } | |
| // Enable depth testing | |
| glEnable(GL_DEPTH_TEST); | |
| // Set up the Bullet physics world | |
| btDefaultCollisionConfiguration collisionConfiguration; | |
| btCollisionDispatcher dispatcher(&collisionConfiguration); | |
| btDbvtBroadphase overlappingPairCache; | |
| btSequentialImpulseConstraintSolver solver; | |
| btDiscreteDynamicsWorld dynamicsWorld(&dispatcher, &overlappingPairCache, &solver, &collisionConfiguration); | |
| dynamicsWorld.setGravity(btVector3(0, -9.81, 0)); | |
| // dynamicsWorld.setGravity(btVector3(0, 0.0, 0)); | |
| // Create the ground plane | |
| btStaticPlaneShape groundShape(btVector3(0, 1, 0), 1); | |
| btDefaultMotionState groundMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, -1, 0))); | |
| btRigidBody::btRigidBodyConstructionInfo groundCI(0, &groundMotionState, &groundShape, btVector3(0, 0, 0)); | |
| btRigidBody* groundRigidBody = new btRigidBody(groundCI); | |
| dynamicsWorld.addRigidBody(groundRigidBody); | |
| // Create a box shape | |
| btBoxShape boxShape(btVector3(0.5, 0.5, 0.5)); | |
| btVector3 boxInertia(0, 0, 0); | |
| boxShape.calculateLocalInertia(1.0, boxInertia); | |
| btDefaultMotionState boxMotionState(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 3, 0))); | |
| btRigidBody::btRigidBodyConstructionInfo boxCI(1.0, &boxMotionState, &boxShape, boxInertia); | |
| btRigidBody* boxRigidBody = new btRigidBody(boxCI); | |
| dynamicsWorld.addRigidBody(boxRigidBody); | |
| // Set up the debug drawer | |
| OpenGLDebugDrawer debugDrawer; | |
| dynamicsWorld.setDebugDrawer(&debugDrawer); | |
| debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe); | |
| // Main loop | |
| while (!glfwWindowShouldClose(window)) { | |
| // Clear the screen | |
| glClearColor(0.2f, 0.3f, 0.3f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| // Step the simulation | |
| dynamicsWorld.stepSimulation(1.0 / 60.0, 10); | |
| dynamicsWorld.debugDrawWorld(); | |
| // Render the debug lines | |
| debugDrawer.render(); | |
| // Swap the buffers and poll for events | |
| glfwSwapBuffers(window); | |
| glfwPollEvents(); | |
| } | |
| // Clean up | |
| dynamicsWorld.removeRigidBody(boxRigidBody); | |
| delete boxRigidBody; | |
| dynamicsWorld.removeRigidBody(groundRigidBody); | |
| delete groundRigidBody; | |
| glfwDestroyWindow(window); | |
| glfwTerminate(); | |
| return 0; | |
| } | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment