Skip to content

Instantly share code, notes, and snippets.

@elliotpotts
Last active August 29, 2015 14:10
Show Gist options
  • Save elliotpotts/e84f1737fa0ed71abdbd to your computer and use it in GitHub Desktop.
Save elliotpotts/e84f1737fa0ed71abdbd to your computer and use it in GitHub Desktop.
#version 440
smooth in vec3 out_normal;
out vec4 colour;
void main() {
colour = vec4(out_normal, 1.0);
}
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <oglplus/all.hpp>
#include <oglplus/interop/glm.hpp>
#include <memory>
#include <string>
#include <vector>
#include <random>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <tinyobjloader/tiny_obj_loader.h>
#include <btBulletDynamicsCommon.h>
#include <btBulletCollisionCommon.h>
#include "micro/MeshRenderer.hpp"
class Suzanne {
private:
std::unique_ptr<btSphereShape> shape;
std::unique_ptr<btDefaultMotionState> motion_state;
std::unique_ptr<btRigidBody> body;
public:
Suzanne(btDiscreteDynamicsWorld& world, glm::vec3 position = {0.0f, 0.0f, 0.0f}) :
shape(std::make_unique<btSphereShape>(0.8)),
motion_state(std::make_unique<btDefaultMotionState>(btTransform(btQuaternion::getIdentity(), btVector3(position.x, position.y, position.z))))
{
btScalar mass = 1;
btVector3 fall_inertia;
shape->calculateLocalInertia(mass, fall_inertia);
auto construction_info = btRigidBody::btRigidBodyConstructionInfo{mass, motion_state.get(), shape.get(), fall_inertia};
body = std::make_unique<btRigidBody>(construction_info);
world.addRigidBody(body.get());
};
glm::mat4 model() {
return glm::translate(glm::mat4(), position()) * glm::mat4_cast(orientation());
}
glm::vec3 position() {
btTransform transform;
motion_state->getWorldTransform(transform);
return {transform.getOrigin().getX(), transform.getOrigin().getY(), transform.getOrigin().getZ()};
}
glm::quat orientation() {
btTransform transform;
motion_state->getWorldTransform(transform);
return glm::angleAxis(
transform.getRotation().getAngle(),
glm::normalize(glm::vec3(
transform.getRotation().getAxis().getX(),
transform.getRotation().getAxis().getY(),
transform.getRotation().getAxis().getZ()
))
);
}
void apply_impulse(glm::vec3 impulse) {
body->applyCentralImpulse(btVector3(impulse.x, impulse.y, impulse.z));
}
};
static micro::Mesh load_suzanne() {
std::vector<tinyobj::shape_t> shapes;
std::vector<tinyobj::material_t> materials;
std::string error = tinyobj::LoadObj(shapes, materials, "assets/suzzane.obj");
std::cout << error << "\n";
return {shapes[0].mesh};
}
using gl = oglplus::Context;
void error_callback(int error, const char* description) {
std::cout << "Error " << error << "\n";
std::cout << description << "\n";
}
int main() {
glfwSetErrorCallback(error_callback);
if(!glfwInit()) {
std::cout << "glfw didn't init\n";
return -1;
}
glfwWindowHint(GLFW_SAMPLES, 80);
GLFWwindow* window = glfwCreateWindow(640, 480, "Hello, World", nullptr, nullptr);
if(!window) {
std::cout << "couldn't create window\n";
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if(glewInit() != GLEW_OK) {
std::cout << "glew didn't init\n";
return -1;
}
auto broadphase = std::make_unique<btDbvtBroadphase>();
auto collision_configuration = std::make_unique<btDefaultCollisionConfiguration>();
auto collision_dispatcher = std::make_unique<btCollisionDispatcher>(collision_configuration.get());
auto solver = std::make_unique<btSequentialImpulseConstraintSolver>();
auto world = std::make_unique<btDiscreteDynamicsWorld>(collision_dispatcher.get(), broadphase.get(), solver.get(), collision_configuration.get());
world->setGravity(btVector3(0, -10, 0));
auto ground_shape = std::make_unique<btStaticPlaneShape>(btVector3(0, 1, 0), 0);
auto ground_motion_state = std::make_unique<btDefaultMotionState>(btTransform(btQuaternion(0, 0, 0, 1), btVector3(0, 0, 0)));
auto ground_construction_info = btRigidBody::btRigidBodyConstructionInfo{0, ground_motion_state.get(), ground_shape.get(), btVector3(0, 0, 0)};
auto ground_rigid_body = std::make_unique<btRigidBody>(ground_construction_info);
world->addRigidBody(ground_rigid_body.get());
std::vector<Suzanne> suzannes;
{
std::mt19937 random_engine;
std::uniform_real_distribution<double> random_range(0.0, 50.0);
for(int i = 0; i < 30; i++) {
suzannes.emplace_back(*world, glm::vec3(random_range(random_engine), random_range(random_engine), random_range(random_engine)));
}
}
Suzanne suzanne(*world, glm::vec3(0.0f, 50.0f, 0.0f));
micro::Mesh suzanne_mesh = load_suzanne();
micro::MeshRenderer renderer;
auto projection = glm::infinitePerspective(90.0f, 1.0f, 0.004f);
double camera_ρ = 1.0;
double camera_θ = 1.0;
double camera_φ = 0.0;
auto global_up = glm::vec3(0.0f, 1.0f, 0.0f);
auto origin = glm::vec3(0.0f, 0.0f, 0.0f);
while(!glfwWindowShouldClose(window)) {
glfwPollEvents();
int width, height;
glfwGetFramebufferSize(window, &width, &height);
gl::Viewport(width, height);
projection = glm::infinitePerspective(90.0f, static_cast<float>(width)/static_cast<float>(height), 0.004f);
if(glfwGetKey(window, GLFW_KEY_LEFT) == GLFW_PRESS) {
camera_φ -= 0.05;
suzanne.apply_impulse({1.0f, 0.0f, 1.0f});
}
if(glfwGetKey(window, GLFW_KEY_RIGHT) == GLFW_PRESS) {
camera_φ += 0.05;
suzanne.apply_impulse({-1.0f, 0.0f, -1.0f});
}
if(glfwGetKey(window, GLFW_KEY_UP) == GLFW_PRESS) {
camera_θ += 0.05;
}
if(glfwGetKey(window, GLFW_KEY_DOWN) == GLFW_PRESS) {
camera_θ -= 0.05;
}
if(glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) {
camera_ρ -= 0.05;
}
if(glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS) {
camera_ρ += 0.05;
}
camera_φ = glm::mod(camera_φ, 2.0 * glm::pi<double>());
camera_θ = glm::mod(camera_θ, 2.0 * glm::pi<double>());
glm::tvec3<float> camera_pos(
camera_ρ * std::sin(camera_θ) * std::sin(camera_φ),
camera_ρ * std::cos(camera_θ),
camera_ρ * std::sin(camera_θ) * std::cos(camera_φ)
);
camera_pos.x = 0.0f;
camera_pos.y = 10.0f;
camera_pos.z = -4.0f;
world->stepSimulation(1 / 50.f, 0);
renderer.Render(
suzanne.model(),
glm::lookAt(camera_pos, suzanne.position(), global_up),
projection,
suzanne_mesh
);
/* Commenting out this section fixes it! */
for(auto& s : suzannes) {
renderer.Render(
s.model(),
glm::lookAt(camera_pos, suzanne.position(), global_up),
projection,
suzanne_mesh
);
}
/* commenting out the above section fixes it */
glfwSwapBuffers(window);
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
void micro::MeshRenderer::Render(glm::mat4 model, glm::mat4 view, glm::mat4 projection, const Mesh& mesh) {
program.Use();
model_uniform.Set(model);
view_uniform.Set(view);
projection_uniform.Set(projection);
oglplus::VertexArray vertex_attributes;
vertex_attributes.Bind();
oglplus::VertexArrayAttrib position(program, "position");
mesh.positions.Bind(oglplus::Buffer::Target::Array);
position.Setup<float>(3);
position.Enable();
oglplus::VertexArrayAttrib normal(program, "in_normal");
mesh.normals.Bind(oglplus::Buffer::Target::Array);
normal.Setup<float>(3);
normal.Enable();
mesh.elements.Bind(oglplus::Buffer::Target::ElementArray);
gl::Clear().ColorBuffer();
gl::Clear().DepthBuffer();
gl::DrawElements(oglplus::PrimitiveType::Triangles, oglplus::Buffer::Size(oglplus::Buffer::Target::ElementArray), oglplus::DataType::UnsignedInt);
}
#version 440
in vec3 position;
in vec3 in_normal;
out vec3 out_normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() {
out_normal = in_normal;
gl_Position = projection * view * model * vec4(position, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment