Hello,
I have been doing some testing with OpenGL and Bullet and I am wondering about some limitations. I have a simple scene set up on which I render X amount of boxes and compare frame rates. I am able to push about 200-400 boxes (all colliding with each other simultaneously) at reasonable FPS. I saw the blog post about some guy pushing 110k objects in real time. I am wondering how on earth this is possible and what the maximum number of simple shaped objects that a common video card/CPU can handle at once. Is their source code available for the 110k project (http://bulletphysics.org/wordpress/?p=340)? I am not sure if my novice coding is why I can only handle a couple hundred objects or if it is a hardware/computing limitation.
My PC has decent specs (640 GTX, 4.0GHz CPU).
Thanks.
General questions about Bullet performance.
-
- Posts: 149
- Joined: Fri Jun 24, 2011 8:53 am
Re: General questions about Bullet performance.
1st fact: GPUs are embarassingly good at massively parallel tasks. CUDA and GPGPU physics have been in the works for a while: I suppose this is beginning to reap the benefits.
2nd: I seriously hope you can move far more than 200 objects, I used to move around 100 on a fairly old machine. Are you referring to the bullet tests? If not, you might have to look at your GL code.
2nd: I seriously hope you can move far more than 200 objects, I used to move around 100 on a fairly old machine. Are you referring to the bullet tests? If not, you might have to look at your GL code.
-
- Site Admin
- Posts: 4221
- Joined: Sun Jun 26, 2005 6:43 pm
- Location: California, USA
Re: General questions about Bullet performance.
The work-in-progress GPU/OpenCL rigid body pipeline source code is available in the Extras folder of the latest Bullet 2.80 version. Note that the code is separate and not integrated in the regular/CPU Bullet version. A lot of effort has been made to improve the performance of the GPU/OpenCL rigid body pipeline. All the data stays on the GPU and rendering is done using instancing.
The regular Bullet version should be able to simulate a lot more than 400 rigid bodies. Are you using an unoptimized/debug build?
The regular Bullet version should be able to simulate a lot more than 400 rigid bodies. Are you using an unoptimized/debug build?
-
- Posts: 2
- Joined: Wed Mar 28, 2012 4:42 am
Re: General questions about Bullet performance.
Thanks for your help guys.
I am running the normal release build which I compiled using the VS2010 project file. My problem is in how I am allocating data (I think). I can render 1000 objects at once on screen as long as they are not colliding with each other, once they do, my frame drops drastically to like 1-2. Here is my source code, sorry its a bit messy . Basically I am initializing a number of PhysicsObjects (class) then adding all the rigid bodies to a world. Then I draw them all by grabbing the opening matrix and drawing a VBO. I am trying not to use any outdated OpenGL stuff.
PS. I know this isn't an OpenGL forum, the Bullet stuff is in the class and the main Init function. Also, I understand if if this is to homework-ish to be answered so no worries.
Thanks.
I am running the normal release build which I compiled using the VS2010 project file. My problem is in how I am allocating data (I think). I can render 1000 objects at once on screen as long as they are not colliding with each other, once they do, my frame drops drastically to like 1-2. Here is my source code, sorry its a bit messy . Basically I am initializing a number of PhysicsObjects (class) then adding all the rigid bodies to a world. Then I draw them all by grabbing the opening matrix and drawing a VBO. I am trying not to use any outdated OpenGL stuff.
PS. I know this isn't an OpenGL forum, the Bullet stuff is in the class and the main Init function. Also, I understand if if this is to homework-ish to be answered so no worries.
Thanks.
Code: Select all
#include "PhysicsObject.h"
PhysicsObject::PhysicsObject()
{
}
PhysicsObject::~PhysicsObject(void)
{
delete [] rigidBody;
delete [] colShape;
}
void PhysicsObject::Init(btCollisionShape* cS) {
colShape = cS;
btScalar mass = 1;
btDefaultMotionState* mS = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0)));
btVector3 fallInertia(0,0,0);
colShape->calculateLocalInertia(mass,fallInertia);
btRigidBody::btRigidBodyConstructionInfo rigidBodyCI(mass,mS,cS,fallInertia);
rigidBody = new btRigidBody(rigidBodyCI);
}
bool PhysicsObject::SetPosition(glm::vec3 nPos)
{
if (rigidBody != NULL) {
btTransform nTrans;
rigidBody->getMotionState()->getWorldTransform(nTrans);
nTrans.setOrigin(btVector3(nPos.x, nPos.y, nPos.z));
delete rigidBody->getMotionState();
rigidBody->setMotionState(new btDefaultMotionState(nTrans));
return true;
}
return false;
}
bool PhysicsObject::SetRotation(glm::vec4)
{
return true;
}
bool PhysicsObject::SetVelocity(glm::vec3 nVelocity)
{
rigidBody->setLinearVelocity(btVector3(nVelocity.x, nVelocity.y, nVelocity.z));
return true;
}
bool PhysicsObject::SetMass(float nMass)
{
rigidBody->setMassProps(nMass, btVector3(0,0,0));
rigidBody->updateInertiaTensor();
}
Code: Select all
#pragma once
#include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h>
#include <glm\glm.hpp>
#include <glm\gtc\matrix_transform.hpp>
#include <glm\gtc\matrix_inverse.hpp>
#include <glm\gtc\type_ptr.hpp>
class PhysicsObject
{
public:
PhysicsObject(void);
~PhysicsObject(void);
btRigidBody *rigidBody;
btCollisionShape *colShape;
void Init(btCollisionShape*);
bool SetPosition(glm::vec3);
bool SetRotation(glm::vec4);
bool SetVelocity(glm::vec3);
bool SetMass(float);
};
Code: Select all
#include <GL\glew.h>
#include <Windows.h>
#include <iostream>
#include <string.h>
#include <fstream>
#include <math.h>
#include <glm\glm.hpp>
#include <glm\gtc\matrix_transform.hpp>
#include <glm\gtc\matrix_inverse.hpp>
#include <glm\gtc\type_ptr.hpp>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <GL\glfw.h>
#include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h>
#include <stack>
#include "ShaderHandler.h"
#include "PhysicsObject.h"
using namespace std;
#define PI 3.14159265
int count = 0;
float screenWidth = 800;
float screenHeight = 800;
int screenMidX = screenWidth/2;
int screenMidY = screenHeight/2;
GLuint vaoID; // Our Vertex Array Object
GLuint vboID; // Our Vertex Buffer Object
GLuint ivboID;
ShaderHandler *shader;
double multi;
bool forwardDown = false;
bool backwardDown = false;
bool leftDown = false;
bool rightDown = false;
bool spacebarDown = false;
glm::vec2 mousePos;
double timeDelta = 0.0;
double timeSinceUpdate = 0.0;
double debugTime = 0.0;
PhysicsObject *boxes;
GLuint vertexShader, fragShader;
GLfloat rot;
GLfloat movementSpeed = .80f;
GLfloat rotationSpeed = 2;
std::stack<glm::mat4> modelMatrix;
glm::mat4 projectionMatrix(1.0);
glm::mat4 viewMatrix(1.0);
glm::mat4 MVP(1.0);
glm::vec3 cameraAngle;
glm::vec3 cameraPosition;
GLfloat lightPos[] = {0.0, 3.0, -10.0, 1.0};
GLfloat ambient[] = {0.2, 0.2, 0.2, 1.0}; // Farbdefinitionen
GLfloat diffuse[] = {0.9, 0.9, 0.9, 1.0};
GLfloat specular[] = {1.0, 1.0, 1.0, 1.0};
long int frames;
GLdouble t;
int l = 6;
int w = 100;
int h = 1;
struct Vertex
{
float x, y, z;
float padding[13];
};
btDiscreteDynamicsWorld* dynamicsWorld;
btRigidBody* fallRigidBody;
void RenderScene(void) {
frames++;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glLoadIdentity();
modelMatrix.push(glm::mat4(1.0));
viewMatrix = glm::mat4(1.0f);
viewMatrix = glm::rotate(viewMatrix, cameraAngle.x, glm::vec3(1.0f, 0.0f, 0.0f));
viewMatrix = glm::rotate(viewMatrix, cameraAngle.y, glm::vec3(0.0f, 1.0f, 0.0f));
viewMatrix = glm::rotate(viewMatrix, cameraAngle.z, glm::vec3(0.0f, 0.0f, 0.1f));
viewMatrix = glm::translate(viewMatrix, glm::vec3(cameraPosition.x, cameraPosition.y, cameraPosition.z));
projectionMatrix = glm::perspective(30.0f, screenWidth / screenHeight, 1.0f, 5000.0f);
MVP = projectionMatrix * viewMatrix * modelMatrix.top();
glUniformMatrix4fv(glGetUniformLocation(shader->shaderProgram, "MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
//glm::mat4 uMVP = glm::inverse(MVP);
//glUniformMatrix4fv(glGetUniformLocation(shader->shaderProgram, "uMVP"), 1, GL_FALSE, glm::value_ptr(uMVP));
glm::mat4 tempMat(1.0);
tempMat = glm::translate(tempMat, glm::vec3(0.0, 0.0, 0.0));
modelMatrix.push(tempMat);
glBegin(GL_LINES);
for (float i = 0; i < 300.0; i+=5.0) {
glVertex3f(i, 0.0f, 0.0);
glVertex3f(i, 0.0f, -300.0f);
}
for (float i = 0; i < 300.0; i+=5.0) {
glVertex3f(0.0, 0.0f, -i);
glVertex3f(300.0f, 0.0f, -i);
}
glEnd();
modelMatrix.pop();
tempMat = glm::translate(tempMat, glm::vec3(5.0, 0.0, 20.0));
modelMatrix.push(tempMat);
MVP = projectionMatrix * viewMatrix * modelMatrix.top();
glUniformMatrix4fv(glGetUniformLocation(shader->shaderProgram, "MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
glBindVertexArray(vaoID); // Bind our Vertex Array Object
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, (void*)ivboID); // Draw our square
glBindVertexArray(0); // Unbind our Vertex Array Object
modelMatrix.pop();
btTransform trans;
glBindVertexArray(vaoID); // Bind our Vertex Array Object
for (int i = 0; i < l*w*h; i++) {
boxes[i].rigidBody->getMotionState()->getWorldTransform(trans);
trans.getOpenGLMatrix(glm::value_ptr(tempMat));
modelMatrix.push(tempMat);
MVP = projectionMatrix * viewMatrix * modelMatrix.top();
glUniformMatrix4fv(glGetUniformLocation(shader->shaderProgram, "MVP"), 1, GL_FALSE, glm::value_ptr(MVP));
glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, (void*)ivboID); // Draw our square
modelMatrix.pop();
}
glBindVertexArray(0); // Unbind our Vertex Array Object
}
void ResizeWindow(int nWidth, int nHeight)
{
glViewport(0, 0, nWidth, nHeight);
screenWidth = nWidth;
screenHeight = nHeight;
}
void CreateSquare(void)
{
float size = 1;
GLfloat vertices[24] = {
-size, -size, -size,
size, -size, -size,
size, size, -size,
-size, size, -size,
-size, -size, size,
size, -size, size,
size, size, size,
-size, size, size,
};
GLuint indices[24] = {
0, 1, 2, 3, // Front face
4, 5, 6, 7, // Back face
0, 3, 7, 4, // Left face
1, 2, 6, 5, // Right face
2, 3, 7, 6, // Top face
0, 1, 5, 4, // Bottom face
};
glGenVertexArrays(1, &vaoID); // Create our Vertex Array Object
glBindVertexArray(vaoID); // Bind our Vertex Array Object so we can use it
glGenBuffers(1, &vboID); // Generate our Vertex Buffer Object
glBindBuffer(GL_ARRAY_BUFFER, vboID); // Bind our Vertex Buffer Object
glBufferData(GL_ARRAY_BUFFER, 24 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); // Set the size and data of our VBO and set it to STATIC_DRAW
glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // Set up our vertex attributes pointer
glGenBuffers(1, &ivboID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ivboID); // Bind our Vertex Buffer Object
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 24 * sizeof(GLuint), indices, GL_STATIC_DRAW); // Set the size and data of our VBO and set it to STATIC_DRAW
glEnableVertexAttribArray(0); // Disable our Vertex Array Object
glBindVertexArray(0); // Disable our Vertex Buffer Object
}
void Initialize(void)
{
glMatrixMode(GL_MODELVIEW);
glEnable(GL_DEPTH_TEST);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
cameraPosition.y = -5.0;
glShadeModel (GL_SMOOTH); //set the shader to smooth shader
ResizeWindow(screenWidth, screenHeight);
CreateSquare();
shader = new ShaderHandler("shader.v", "frag.f", true);
glUseProgram(shader->shaderProgram);
btBroadphaseInterface* broadphase = new btDbvtBroadphase();
btDefaultCollisionConfiguration* collisionConfiguration = new btDefaultCollisionConfiguration();
btCollisionDispatcher* dispatcher = new btCollisionDispatcher(collisionConfiguration);
btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver;
dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);
dynamicsWorld->setGravity(btVector3(0,-9.8,0));
btScalar mass = 1.0;
btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0, 1, 0),0.0);
btCollisionShape* fallShape = new btBoxShape(btVector3(1.0, 1.0, 1.0));
btDefaultMotionState* mS = new btDefaultMotionState(btTransform(btQuaternion(0, 0, 0, 1),btVector3(0, 0, 0)));
btDefaultMotionState* groundMotionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0)));
btRigidBody::btRigidBodyConstructionInfo groundRigidBodyCI(0,groundMotionState,groundShape,btVector3(0,0,0));
btRigidBody* groundRigidBody = new btRigidBody(groundRigidBodyCI);
dynamicsWorld->addRigidBody(groundRigidBody);
boxes = new PhysicsObject[l*w*h];
for (int i = 0; i < l*w*h; i++)
{
boxes[i].Init(fallShape);
}
for (int x = 0; x < l; x++) {
for (int y = 0; y < w; y++) {
for (int z = 0; z < h; z++) {
boxes[count].SetPosition(glm::vec3(x*5, y*2+1.5, -z*5));
count++;
}
}
}
for (int i = 0; i < (l*w*h); i++) {
dynamicsWorld->addRigidBody(boxes[i].rigidBody);
}
}
void KeyboardInput(int key, int action)
{
if (action == GLFW_PRESS) {
if (key == 87) {
forwardDown = true;
}
if (key == 83) {
backwardDown = true;
}
if (key == 65) {
leftDown = true;
}
if (key == 68) {
rightDown = true;
}
if (key == 74) {
boxes[0].SetPosition(-cameraPosition);
boxes[0].SetVelocity(glm::vec3(0.0, 0.0, -100.0));
}
} else {
if (key == 87) {
forwardDown = false;
}
if (key == 83) {
backwardDown = false;
}
if (key == 65) {
leftDown = false;
}
if (key == 68) {
rightDown = false;
}
}
}
void MouseInput(int x, int y)
{
int xDif = screenMidX - x;
int yDif = screenMidY - y;
cameraAngle.x -= (double)yDif/9.0;
cameraAngle.y -= (double)xDif/9.0;
}
void Update(double time)
{
dynamicsWorld->stepSimulation(time,10);
t+= time;
if (debugTime > 1) {
printf("%lf \n", frames/t);
frames = 0;
t = 0;
debugTime = 0.0;
}
debugTime += t;
multi = (60/(1/time));
rot+=1*multi;
if (forwardDown) {
cameraPosition.z += cos(cameraAngle.y * (PI/180))*movementSpeed*multi;
cameraPosition.x += -sin(cameraAngle.y * (PI/180))*movementSpeed*multi;
}
if (backwardDown) {
cameraPosition.z -= cos(cameraAngle.y * (PI/180))*movementSpeed*multi;
cameraPosition.x -= -sin(cameraAngle.y * (PI/180))*movementSpeed*multi;
}
if (leftDown) {
cameraPosition.x += cos((cameraAngle.y) * (PI/180))*movementSpeed*multi;
cameraPosition.z += sin((cameraAngle.y + (PI/2)) * (PI/180))*movementSpeed*multi;
}
if (rightDown) {
cameraPosition.x += -cos(cameraAngle.y * (PI/180))*movementSpeed*multi;
cameraPosition.z += -sin((cameraAngle.y + (PI/2)) * (PI/180))*movementSpeed*multi;
}
glfwGetMousePos((int*)&mousePos.x, (int*)&mousePos.y);
}
int main(int argc, char* argv[])
{
int running = GL_TRUE;
double startTime = 0.0;
glfwInit();
glfwOpenWindowHint(GLFW_FSAA_SAMPLES, 4);
glfwOpenWindow(screenWidth, screenHeight, 0,0,0,0,0,0, GLFW_WINDOW );
glfwSetWindowPos(900, 200);
if (GLEW_OK != glewInit())
{
// GLEW failed!
exit(1);
}
glfwSetWindowSizeCallback(ResizeWindow);
glfwSetKeyCallback(KeyboardInput);
glfwSetMousePosCallback(MouseInput);
glfwDisable(GLFW_MOUSE_CURSOR);
Initialize();
startTime = glfwGetTime();
glfwSetTime(0.0);
//glfwSwapInterval(1);
// Main loop
while( running )
{
glfwSetMousePos(screenWidth/2, screenHeight/2);
timeDelta = glfwGetTime() - startTime;
startTime = glfwGetTime();
// OpenGL rendering goes here...
glClear( GL_COLOR_BUFFER_BIT );
// Swap front and back rendering buffers
Update(timeDelta);
RenderScene();
glfwSwapBuffers();
// Check if ESC key was pressed or window was closed
running = !glfwGetKey( GLFW_KEY_ESC ) &&
glfwGetWindowParam( GLFW_OPENED );
}
delete dynamicsWorld;
glfwTerminate();
return 0;
}