Skip to content

Instantly share code, notes, and snippets.

@newpolaris
Last active May 6, 2023 16:31
Show Gist options
  • Select an option

  • Save newpolaris/c44d275dbe71461b89318f26fc2e6f4e to your computer and use it in GitHub Desktop.

Select an option

Save newpolaris/c44d275dbe71461b89318f26fc2e6f4e to your computer and use it in GitHub Desktop.
bullet debug draw
#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