Sunday, December 4, 2011

Cooks scene in my pathtracer

I managed to get the Cook's scene from his 1980's paper in my GLSL Pathtracer. Here is the snapshot from the demo.

Cook's Billiard Scene

Note that I have deliberately reduced the bounces because natural billiards ball are not that reflective that they bounce more than two times. Here is the video.


Enjoy!!!

Wednesday, November 23, 2011

Snapshot from my latest GLSL Path tracer

Here is a snapshot from my latest GLSL Path tracer which was inspired by the excellently done path tracer in WebGL by Evan Wallace(http://madebyevan.com/webgl-path-tracing/). I have modified his code considerably to make it run even faster on PC.

GLSL Pathtracer

It runs at ~70fps with 128 samples per pixel for an output res. of 1024x1024. Check this video captured live from a session.
Another video showing a live editing session.
Another video showing the famous Cornell Box scene.
This demo renders the famous Cornell Box scene in realtime. You can edit all the parameters live and it renders at ~240 fps on my NVIDIA Quadro FX 5800 on an output resolution of 1024x1024. I have not added importance sampling or any other optimization. Adding those will certainly make it even faster.
Yet another video of Cornell Box
 
This time it is even better with more photons. Takes a bit longer to converge but the output is worth it. GLSL Pathtracer Demo Enjoy!!!

Sunday, November 20, 2011

Friday, November 18, 2011

Twirl filter in GLSL

I had worked on image processing project back in my high school days and so the last memories returned recently when I wanted to implement the twirl filter in GLSL. Mathematically, it is easily given as the following function in polar coordinates,
F(r,theta)=f(r,theta+amt)
In normal world though, we are working in Cartesian coordiates so we need to add that conversion in. Other than that, it is the same function. Here is the output from my shader.
Twirl Filter in GLSL
The Lena image filtered with the twirl filter in GLSL.
And here is the GLSL fragment shader for doing this.

uniform sampler2D textureMap; //image
uniform float amount; //amount of twirl
void main() {
   vec2 uv = gl_TexCoord[0].st-0.5;
   float angle = atan2(uv.y,uv.x);
   float radius = length(uv);
   angle+= radius*amount;
   vec2 shifted = radius*vec2(cos(angle), sin(angle));
   gl_FragColor = texture(textureMap, (shifted+0.5));
}

I hope it is useful for others too.

Enjoy!!!

Monday, October 17, 2011

Cloth in PhysX 3.1

Before I start of this tutorial, here is my disclaimer
I wrote this tutorial based on some hints from the PhysX3.1 guide since it hardly tells the reader how to do the basic cloth. Therefore, this might not be the perfect way of doing cloth with PhysX3.1. Since the documentation is severely lacking such down to core tutorials, I wrote this tutorial to bridge the gap for beginners. If you find anything wrong, please let me know.
This is the first tutorial on doing cloth in PhysX3.1. The major changes in PhysX 3.1 has been the cloth API and hopefully, I will try to detail how to do a simple cloth using the new cloth API. Ok so now lets get started. This tutorial is building up on the picking tutorial I did earlier so head to it if you have not understood it completely. As usual, here are the headers and libs that we would need for this tutorial.
#include < iostream >
#include < GL/freeglut.h >
#include < PxPhysicsAPI.h > 
#include < PxExtensionsAPI.h >   
#include "Stream.h"

using namespace std;
using namespace physx;

#pragma comment(lib, "PhysX3_x86.lib")
#pragma comment(lib, "PhysX3Cooking_x86.lib")
#pragma comment(lib, "PxTask.lib")
#pragma comment(lib, "Foundation.lib")
#pragma comment(lib, "PhysX3Extensions.lib")
#pragma comment(lib, "GeomUtils.lib") 
Next, we generate the cloth variables and vectors to store the cloth positions and normals. In the previous PhysX version, we could hook the receivebuffers but now this has changed and we need to manually copy the data from the cloth and also calculate the normals. In this demo, we will do a simple collision of the cloth with a simple box. In PhysX3.1, there is no direct support for rigid body collision with a cloth. Instead, the new API provides methods for intersection between the cloth and the capsule/spheres.
vector< PxVec3 > pos;
vector< PxVec3 > normal;
vector< PxU32 > indices;
PxCloth* cloth; 
PxClothCollisionSphere box_collider;
The initialization of PhysX and other stuff is similar to the Picking tutorial. After initializing PhysX and the scene, the scene visualization parameters are set.
gScene->setVisualizationParameter(PxVisualizationParameter::eSCALE, 1.0);
gScene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);
Creating the Cloth object:
The steps required to create a cloth are as follows, 1) Fill in the PxClothMeshDesc and specify the cloth geometry and topology. 2) Cook the cloth fabric by using the mesh desc generated in step 1. 3) Use the cooked buffer to generate the PxClothFabric. 4) Initialize and fill the PxClothParticle buffer with the cloth point positions and masses. 5) Call createCloth on physicsSDK pointer. 6) Adjust the cloth properties using the PxClothPhaseSolverConfig (to specify the individual stiffness and stretch limits of the PxClothFabric fibres) and assign the damping using PxCloth::setDampingCoefficient function. 7) Add the cloth actor to the scene. Now we will show the relevant code of each step. Step1:
//Create cloth
PxClothMeshDesc meshDesc;
meshDesc.setToDefault();
 
//Fill the geometry
int w = 8, h=7;
float hw = w / 2.0f;
float hh = h / 2.0f;
d = 0.2f;
int numX = (int)(w / d) + 1;    
int numY = (int)(h / d) + 1;    
meshDesc.points.count= (numX+1) * (numY+1);        
meshDesc.triangles.count= numX*numY*2;    
meshDesc.points.stride= sizeof(PxVec3);  
meshDesc.triangles.stride= 3*sizeof(PxU32);  
meshDesc.points.data= (PxVec3*)malloc(sizeof(PxVec3)*meshDesc.points.count);    
meshDesc.triangles.data= (PxU32*)malloc(sizeof(PxU32)*meshDesc.triangles.count*3);    
meshDesc.edgeFlags = 0;

//Fill the geometry
int i,j;    
PxVec3 *p = (PxVec3*)meshDesc.points.data;   
 
pos.resize(meshDesc.points.count);
normal.resize(meshDesc.points.count);
indices.resize(meshDesc.triangles.count*3);

for (i = 0; i <= numY; i++) {        
   for (j = 0; j <= numX; j++) {            
   p -> x = d*j-hw;
   p -> y = float(h);
   p -> z = d*i;             
   p++;   
   }    
}   

memcpy(&pos[0].x, (meshDesc.points.data), sizeof(PxVec3)*meshDesc.points.count);

//Fill the topology
PxU32 *id = (PxU32*)meshDesc.triangles.data;  
for (i = 0; i < numY; i++) {        
   for (j = 0; j < numX; j++) {            
   PxU32 i0 = i * (numX+1) + j;            
   PxU32 i1 = i0 + 1;            
   PxU32 i2 = i0 + (numX+1);            
   PxU32 i3 = i2 + 1;            
   if ((j+i)%2) {                
  *id++ = i0; *id++ = i2; *id++ = i1;                
  *id++ = i1; *id++ = i2; *id++ = i3;            
   } else {                
  *id++ = i0; *id++ = i2; *id++ = i3;                
  *id++ = i0; *id++ = i3; *id++ = i1;            
   }      
   }    
}
 
memcpy(&indices[0], meshDesc.triangles.data, sizeof(PxU32)*meshDesc.triangles.count*3);

//Make sure everything is fine so far
if(!(meshDesc.isValid()))
   cerr << "Mesh invalid."<< endl;
In the above lines, we generate the cloth mesh descriptor and fill its relevant fields and then give the geometry and topology of our cloth mesh. Within these lines we also store the positions and indices for rendering the cloth later. To make sure that everything that is required has been given,we call the isValid function.
//Start cooking of fibres
PxCookingParams cp; 
PxCooking* cooking = PxCreateCooking(PX_PHYSICS_VERSION, &(gPhysicsSDK->getFoundation()), cp);
MemoryWriteBuffer buf;
bool status = cooking->cookClothFabric(meshDesc,sceneDesc.gravity, buf);
if(!status) {
   cerr << "Problem cooking mesh.\nExiting ..."<< endl;
   exit(1);
}
     
PxClothFabric* fabric=gPhysicsSDK->createClothFabric(MemoryReadBuffer(buf.data));
In the above lines, we cook the meshDesc and then create the Cloth Fabric using the cooked buffer data.
PxTransform tr;
tr.p = PxVec3(0,10,0); tr.q = PxQuat::createIdentity();

PxClothParticle* points=(PxClothParticle*)malloc(sizeof(PxClothParticle)*meshDesc.points.count);
p = (PxVec3*)meshDesc.points.data;  
for(size_t i=0;i < meshDesc.points.count;i++) {
    points[i].pos = *p;
 //Fixing the top corner points
 if(i==0 || i==numX) 
     points[i].invWeight =0;
else 
     points[i].invWeight = 1.f;
     p++;
}
In the above lines, we allocate the ClothParticles buffer filling it with positions and mass weights. To fix the top corner masses, their inverse weights are set as 0.
PxClothCollisionData cd;
cd.setToDefault();
 
cd.numSpheres=1;
cd.pairIndexBuffer=0;
 
box_collider.pos= PxVec3(0.0f,2.0f,0.0f);
box_collider.radius=1;
cd.spheres=&box_collider;

cloth = gPhysicsSDK->createCloth(tr,*fabric,points, cd, PxClothFlag::eSWEPT_CONTACT);
In the above lines, we generate the PxClothCollisionData which is used to performa collision with our box rigid body. In the new PhysX3.1 API, the cloth can only collide with capsules or spheres. We fill in the PxClothCollisionData giving it the sphere primitive's buffer. The cloth global pose, the cloth fabric, the cloth's particles and the collision data are then passed to the gPhysicsSDK::createCloth function that returns the cloth actor.
if(cloth) { 
    PxClothPhaseSolverConfig bendCfg;  
    bendCfg.solverType= PxClothPhaseSolverConfig::eFAST;
    bendCfg.stiffness = 1;
    bendCfg.stretchStiffness = 0.5; 

    cloth->setPhaseSolverConfig(PxClothFabricPhaseType::eBENDING,  bendCfg) ; 
    cloth->setPhaseSolverConfig(PxClothFabricPhaseType::eSTRETCHING, bendCfg) ; 
    cloth->setPhaseSolverConfig(PxClothFabricPhaseType::eSHEARING, bendCfg) ; 
    cloth->setPhaseSolverConfig(PxClothFabricPhaseType::eSTRETCHING_HORIZONTAL, bendCfg) ;
  
    cloth->setDampingCoefficient(0.125f);    
    gScene->addActor(*cloth); 
}
else
    cerr << "Cannot create cloth" << endl;
If we have a valid cloth object, we assign the bending, shearing and stretching stiffness for the three kinds of cloth fibers.Then we assign the cloths damping value and finally add the cloth to the scene.
Extracting the PhysX cloth particle positions for rendering:
Now that we know how the cloth may be generated, we can look into how to extract the modified positions from the PhysX cloth API. Like in the previous tutorials, the render function calls the StepPhysX(); function. For cloth, we can apply some more steps after this function call. First we set the rigid bodies collision sphere as the current clothCollisionSphere. The box_collider object is updated with the box's transform in the box's rendering function. This is done in the following code.
if (gScene) 
{ 
    StepPhysX(); 

    //update collider position based on the new position of box;  
    cloth->setCollisionSpheres(&box_collider); 
Next, we extract the current cloth particle positions using a call to PxCloth::lockClothReadData function.
//update the cloth data
   PxClothReadData* pData = cloth->lockClothReadData();
   PxClothParticle* pParticles = const_cast(pData->particles);
  
   //update the positions
   for(size_t i=0;i < pos.size();i++) {
      pos[i] = pParticles[i].pos;
      if(pos[i].y < 0) {
   pos[i].y=0;
   pParticles[i].pos.y=0;
   }
}
pData->unlock();
The above lines lock the particle positions and then apply the floor collision constraint. Next we generate the cloth normals.
   //update normals
   for(size_t i=0;i < indices.size();i+=3) {
  PxVec3 p1 = pos[indices[i]];
 PxVec3 p2 = pos[indices[i+1]];
 PxVec3 p3 = pos[indices[i+2]];
 PxVec3 n  = (p2-p1).cross(p3-p1);

 normal[indices[i]]    += n/3.0f ; 
 normal[indices[i+1]]  += n/3.0f ; 
 normal[indices[i+2]]  += n/3.0f ;    
   }

   for(size_t i=0;i < normal.size();i++) { 
 PxVec3& n  = normal[i];
 n= n.getNormalized();
   }

Cloth rendering:
For rendering, we simply pass the positions and normals to the vertex arrays and then use the indices to render the cloth as shown in the following lines of code.
void RenderCloth() {
 glEnableClientState(GL_VERTEX_ARRAY);
 glEnableClientState(GL_NORMAL_ARRAY);

 glVertexPointer(3, GL_FLOAT, sizeof(PxVec3), &(pos[0].x));
 glNormalPointer(GL_FLOAT, sizeof(PxVec3), &(normal[0].x));

 glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, &indices[0]);

 glDisableClientState(GL_NORMAL_ARRAY);
 glDisableClientState(GL_VERTEX_ARRAY);
}

That's it. You can now render the cloth in PhysX3.1 using the new cloth API. The performance of the new API is significantly better as compared to the previous PhysX sdks. Running the code gives the following output.
Cloth in PhysX 3.1
PhysX 3.1 version source code of this tutorial
PhysX 3.2.1 version source code of this tutorial

Friday, October 14, 2011

Converting the existing PhysX3.0 Tutorials to PhysX3.1

Recently, NVIDIA has released the new PhysX 3.1 sdk which has revamped the API a little bit. The support for cloth has been improved plus a lot of improvements.

In the new PhsyX 3.1 sdk, the classes have now been added into a namespace called physx so to get any object, you need to either add physx:: to it or you can add the following directive at the top of the code.

using namespace physx;

Once you add the namespace directive, my exisiting PhysX 3.0 tutorials would work in the new sdk. Thats it, the codes should run fine. In a later tutorial, I will be detail how to do cloth and soft bodies in PhysX 3.1 sdk.

You can download all of my PhysX3 tutorials ported to PhysX 3.1 in a single zip file here
Please make sure to copy the PhysX3_x86.dll into the folder containing the .vcproj file of the solution you are working on.

Monday, September 19, 2011

Resolving WebGL cross domain image loading error SECURITY_ERR: DOM Exception 18

If u have tried webGL and specially loading textures recently due to the tighter security features you get
 
Uncaught Error: SECURITY_ERR: DOM Exception 18 in Google Chrome and
Error: uncaught exception: [Exception... "Security error" code: "1000" nsresult: "0x805303e8 (NS_ERROR_DOM_SECURITY_ERR)" location: file:///some directory Line: 46] in Mozilla Firefox

Solution: The solution is quite simple. Just go to command prompt and change directory to where your html page is for example for running WebGL/Simple/Test.html u do this on cmd prompt

c:\> cd D:/WebGL/Simple/
Then simply type this

D:/WebGL/Simple>python -m SimpleHTTPServer

This opens up a local http server, let this cmd prompt run. Now go to the web browser firefox/chrome and type this in the address bar to load the webpage
http://localhost:8000/Test.htm

This should run the WebGL code fine. Once u r done, you can press Ctrl+C to terminate the http server. I hope it helps others from the pain which I had to bear.

Wednesday, July 20, 2011

OpenCloth: A new open source cloth simulation library

I have just released a new open source cloth simulaiton library called OpenCloth. It is intended for beginners so that they can understand the basics required to implement a basic cloth simulation.

Details are here: http://code.google.com/p/opencloth/

Comments and critics welcome.

Monday, May 30, 2011

PhysX3: Simple distance joint

In this tutorial, we will see how to create a simple distance joint. We will reuse the picking code in this tutorial to make things a bit more interesting. So without any further ado, lets get started. We will create two boxes one of which will be a static object. The other box will be manipulated by the mouse hence it will be dynamic.
Creating the boxes
The dynamic box

//2) Create dynamic cube  
PxReal density = 1.0f;
PxTransform transform(PxVec3(0.0f, 3.0, 0.0f), PxQuat::createIdentity());
PxVec3 dimensions(0.5,0.5,0.5);
PxBoxGeometry geometry(dimensions);    
PxRigidDynamic *dyn_box = PxCreateDynamic(*gPhysicsSDK, transform, geometry, *mMaterial, density);
if (!dyn_box)
   cerr<<"create actor failed!"<<endl;
dyn_box->setAngularDamping(0.75);
dyn_box->setLinearVelocity(PxVec3(0,0,0)); 
gScene->addActor(*dyn_box);
boxes.push_back(dyn_box);

The above lines are what we have seen in all the tutorials.
The static box
For static box, we simply create a PxRigidStatic object reusing the same geometry.
//create static cube
transform.p=PxVec3(0,5,0);
PxRigidStatic *static_box = PxCreateStatic(*gPhysicsSDK, transform, geometry, *mMaterial);
if (!static_box)
   cerr<<"create actor failed!"<<endl;
gScene->addActor(*static_box);
boxes.push_back(static_box);


Creating joint
For creating a very basic distance joint, we need to use the PxDistanceJointCreate function. This function takes the PhysX sdk object, the first rigidbody, the local transform of it, the second rigid body and its local transform. Next, the parameters are set for the distance joint as we did for the previous PhysX version.
//create a joint  
PxDistanceJoint* j = PxDistanceJointCreate(*gPhysicsSDK, dyn_box, PxTransform::createIdentity(), static_box, PxTransform::createIdentity());
j->setDamping(1);
j->setSpring(200);
j->setMinDistance(1);
j->setMaxDistance(2);
j->setConstraintFlag(PxConstraintFlag::eCOLLISION_ENABLED, true);
j->setDistanceJointFlag(PxDistanceJointFlag::eMIN_DISTANCE_ENABLED, true);
j->setDistanceJointFlag(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED, true);
j->setDistanceJointFlag(PxDistanceJointFlag::eSPRING_ENABLED, true);


Rendering of the distance joint
For rendering of the distance joint, we do a fairly simple thing by creating a global array for 2 PxVec3 types. When we are about to draw the box actors, we store their current positions in the global array so the new DrawCube function is this,
//Stored globally
PxVec3 pos[2]; //for storing the two end points of spring
void DrawBox(PxShape* pShape) {
static int count=0;
 
PxTransform pT = PxShapeExt::getGlobalPose(*pShape);
pos[(count++)%2] = pT.p;
PxBoxGeometry bg;
pShape->getBoxGeometry(bg);
PxMat33 m = PxMat33Legacy(pT.q );
float mat[16];
getColumnMajor(m,pT.p, mat);
glPushMatrix(); 
glMultMatrixf(mat);
glutSolidCube(bg.halfExtents.x*2);
glPopMatrix(); 
}
 

Next, in the render function, we draw the line between the two positions just stored.
glColor3f(gMouseJoint!=NULL,gMouseJoint==NULL,gMouseJoint==NULL);
//Draw the spring 
glBegin(GL_LINES);
   glVertex3f(pos[0].x, pos[0].y, pos[0].z);
   glVertex3f(pos[1].x, pos[1].y, pos[1].z);
glEnd();


That's it we have a simple distance joint between two boxes. Here is the snapshot from this application.



Source code of this tutorial

Sunday, May 29, 2011

PhysX3: Picking

In this tutorial, we will use the scene of multiple boxes from a previous tutorial. This tutorial assumes that you have successfully understood the basics of how to create an actor using the scene object. If not, u may want to review the previous tutorials as a refresher. Ok so now lets get started. There are a lot of things similar between this and the previous tutorial.

Picking in PhysX3
We have our matrices setup as in the picking tutorial for the previous PhysX version. We now come on the Pick function. This function takes an x, y screen coordinate, cast a ray into the scene and returns true if there is an intersection. It also stores a sphere object at the hit point, stores reference to the intersected actor and also stores a spring between the hitpoint sphere and the actor. We store the used joint and mouse sphere object pointers globally.
PxDistanceJoint *gMouseJoint = NULL;
PxRigidDynamic* gMouseSphere = NULL;
PxReal gMouseDepth = 0.0f;
PxRigidDynamic* gSelectedActor=NULL;


The pick actor function is defined as follows,

bool PickActor(int x, int y)
{
 LetGoActor();

We first release all previous helpers (the spring and the last intersection sphere.

Ray ray;
ViewUnProject(x,y,0.0f, ray.orig);
ViewUnProject(x,y,1.0f, ray.dir);
ray.dir -= ray.orig; ray.dir.normalize();

The above lines create a ray as given in the previous paragraph. In PhysX3 there is no Ray object so we define our own struct for Ray.

PxRaycastHit hit;
PxShape* closestShape;
gScene->raycastSingle(ray.orig, ray.dir, length, PxSceneQueryFlag::eIMPACT  ,hit);
closestShape = hit.shape;
if (!closestShape) return false;
if (!closestShape->getActor().is(PxActorType::eRIGID_DYNAMIC)) return false;

The above lines are where the ray is cast to find the closest actor. If there is none, we return false.

int hitx, hity;
ViewProject(hit.impact, hitx, hity, gMouseDepth);
gMouseSphere = CreateSphere(hit.impact, 0.1f, 1.0f);
gMouseSphere->setRigidDynamicFlag(PxRigidDynamicFlag::eKINEMATIC, true);  

The above lines project the hit point back to get the world space position. This is done so that the picking cursor (sphere) could be drawn at the intersection point.
The sphere's body flag is raised to kinematic since it will be attached to an actor through a distance joint (see next few lines).

gSelectedActor = (PxRigidDynamic*) &closestShape->getActor();
gSelectedActor->wakeUp();
PxTransform mFrame, sFrame;
mFrame.q = gMouseSphere->getGlobalPose().q;
mFrame.p = gMouseSphere->getGlobalPose().transformInv(hit.impact );
sFrame.q = gSelectedActor->getGlobalPose().q;
sFrame.p = gSelectedActor->getGlobalPose().transformInv(hit.impact );
gMouseJoint = PxDistanceJointCreate(*gPhysicsSDK, gMouseSphere, mFrame, gSelectedActor, sFrame);
gMouseJoint->setDamping(1);
gMouseJoint->setSpring(200);
gMouseJoint->setMinDistance(0);
gMouseJoint->setMaxDistance(0);
gMouseJoint->setDistanceJointFlag(PxDistanceJointFlag::eMAX_DISTANCE_ENABLED, true);
gMouseJoint->setDistanceJointFlag(PxDistanceJointFlag::eSPRING_ENABLED, true);
return true;
}

These lines create a distance joint between the mouse sphere and the picked object; having one end point, our sphere cursor and the other end point our intersected actor.
The object's global pose is used to transform the hit point from world space to object's local space so that the joint could be oriented properly.
Finally, the joint parameters are filled in and a joint is created. Note that on every mouse click, the old cursor (sphere) and joint are released and a new pair is created. The LetGoActorfunction is defined as follows,
void LetGoActor()
{
if (gMouseJoint)
  gMouseJoint->release();
  gMouseJoint = NULL;
if (gMouseSphere)
  gMouseSphere->release();
  gMouseSphere = NULL;
}

Nothing fancy here either. We just release the created objects (the sphere cursor and the joint).

That's it. You need to call the pick function in the mouse function and handle the drag event. Enjoy this snapshot from the demo.

Picking in PhysX3.1

Source code of this tutorial

Saturday, May 28, 2011

PhysX3: Using the visual debugger

How to enable remote debugging in your application
On the client side (your application) after you have created the sdk object call this line of code.

PxExtensionVisualDebugger::connect(gPhysicsSDK->getPvdConnectionManager(),"localhost",5425, 10000, true);

The parameters are in sequential order the PVD connection manager, the ip of the debugger, the port where the connection will be made, the timeout after which the connection will be dropped. For details about these parameters, consult the help docs of the visual debugger.

Demo run
We will now try to see the debugger in action. First, run the visual debugger. Then run your application. You should see all of your objects in the visual debugger. The active objects are green and the inactive (sleep) objects are yellow. This can turn out to be an invaluable tool when we are working on a fairly large project.

That's it for this demo. There is no source code for this tutorial. Just use any of the existing codes and add in the code snippet given earlier and see it in action.
Here is a snapshot of a debugging session.

Using PhysX3.1 Visual Debugger

We will look at how to create joints in the next tutorial.

PhysX3: Multiple bouncing boxes

In this tutorial, we will add multiple boxes to the scene. This tutorial assumes that you have successfully understood the basics of how to create an actor using the scene object. If not, u may want to review the previous tutorials as a refresher. Ok so now lets get started. There are a lot of things similar between this and the previous tutorial on the simple box. In fact, the only thing changed when we need to add multiple boxes is the InitializePhysX function. In addition, we need to store the references to the boxes into a vector so we create a new vector.
#include <vector>
vector <PxRigidActor*> boxes;


This InitializePhysX function is given as follows,

void InitializePhysX() {
 gPhysicsSDK = PxCreatePhysics(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback, PxTolerancesScale() );
if(gPhysicsSDK == NULL) {
  cerr<<"Error creating PhysX device."<<endl;
  cerr<<"Exiting..."<<endl;
  exit(1);
 }
 if(!PxInitExtensions(*gPhysicsSDK))
    cerr<< "PxInitExtensions failed!"<<endl;

 
 //Create the scene
 PxSceneDesc sceneDesc(gPhysicsSDK-> getTolerancesScale());
 sceneDesc.gravity=PxVec3(0.0f, -9.8f, 0.0f);
 if(!sceneDesc.cpuDispatcher) {
   PxDefaultCpuDispatcher* mCpuDispatcher = PxDefaultCpuDispatcherCreate(1);
   if(!mCpuDispatcher)
      cerr<<"PxDefaultCpuDispatcherCreate failed!"<<endl;
      sceneDesc.cpuDispatcher = mCpuDispatcher;
   } 
   if(!sceneDesc.filterShader)
      sceneDesc.filterShader  = gDefaultFilterShader;

   gScene = gPhysicsSDK->createScene(sceneDesc);
   if (!gScene)
       cerr<<"createScene failed!"<<endl;
 gScene->setVisualizationParameter(PxVisualizationParameter::eSCALE,     1.0);
 gScene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);
PxMaterial* mMaterial = gPhysicsSDK->createMaterial(0.5,0.5,0.5);
  
//Create actors 
//1) Create ground plane
PxReal d = 0.0f;  
PxTransform pose = PxTransform(PxVec3(0.0f, 0, 0.0f),PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f)));
PxRigidStatic* plane = gPhysicsSDK->createRigidStatic(pose);
if (!plane)
   cerr<<"create plane failed!"<<endl;

PxShape* shape = plane->createShape(PxPlaneGeometry(), *mMaterial);
if (!shape)
   cerr<<"create shape failed!"<<endl;
gScene->addActor(*plane); 

We are repeating the same steps as we did in the last tutorial. We first initialize the PhysX library and its extensions. Next we create the scene object and then we create a static ground plane rigidbody.

//2) Create cube  
PxReal density = 1.0f;
PxTransform transform(PxVec3(0.0f, 5.0, 0.0f), PxQuat::createIdentity());
PxVec3 dimensions(0.5,0.5,0.5);
PxBoxGeometry geometry(dimensions);    
for(int i=0;i<10;i++) {
 transform.p  = PxVec3(0.0f,5.0f+5*i,0.0f);
PxRigidDynamic *actor = PxCreateDynamic(*gPhysicsSDK, transform, geometry, *mMaterial, density);
 if (!actor)
   cerr<<"create actor failed!"<<endl;
 actor->setAngularDamping(0.75);
 actor->setLinearVelocity(PxVec3(0,0,0)); 
 gScene->addActor(*actor);
 boxes.push_back(actor);
}
}

In the above lines, we loop 10 times. We generate a new y position using the loop variable and then assign this position to the global pose of the current actor. In the previous PhysX release, we would create a new actor and give it the same descriptor. Now we have to create a new actor with new transform. Next we call the addActor function to create a new object for us.

Rendering of multiple boxes
In PhysX3, the rendering of objects has greatly been simplified. Since at the time of creation of our rigid bodies, we stored them into a vector. We use that vector for rendering. The RenderActors function and the other related functions are implemented as follows,
void RenderActors()  { 
  // Render all the actors in the scene 
  for(int i=0;i<boxes.size();i++ ) {
    DrawActor(boxes[i]);
  }
} 
void DrawBox(PxShape* pShape) {
  PxTransform pT = PxShapeExt::getGlobalPose(*pShape);
  PxBoxGeometry bg;
  pShape->getBoxGeometry(bg);
  PxMat33 m = PxMat33Legacy(pT.q );
  float mat[16];
  getColumnMajor(m,pT.p, mat);
  glPushMatrix(); 
     glMultMatrixf(mat);
  glutSolidCube(bg.halfExtents.x*2);
  glPopMatrix(); 
}
void DrawShape(PxShape* shape)  { 
  PxGeometryType::Enum type = shape->getGeometryType();
  switch(type) 
  {          
     case PxGeometryType::eBOX:
 DrawBox(shape);
 break;
  } 
} 

void DrawActor(PxRigidActor* actor)  {  
  PxU32 nShapes = actor->getNbShapes(); 
  PxShape** shapes=new PxShape*[nShapes];
  actor->getShapes(shapes, nShapes);     
  while (nShapes--) 
  { 
     DrawShape(shapes[nShapes]); 
  } 
  delete [] shapes;
} 

The only difference between this RenderActor function and the one in the previous
tutorial is that this function loops over all of the rigid bodies. That's it. The rest of the code remains the same since it will loop through all of the actors and determine their types to call the appropriate draw function as detailed in the last tutorial.

Running the code gives us the following output.
PhysX3.1 Multiple Boxes

Source code of this tutorial

Friday, May 27, 2011

PhysX3: A simple bouncing box

In this tutorial, I will show you how to create a simple box at a specific position and let it bounce under influence of gravity. We will be adding to the code base from the previous tutorials. We first create the PhysX3 sdk object and store it into a global pointer as given in the previous tutorial. For this tutorial, the following headers and libs are needed.

#include <iostream>
#include <GL/freeglut.h>
#include < PxPhysicsAPI.h>
#include < PxExtensionsAPI.h>
#include < PxDefaultErrorCallback.h>
#include < PxDefaultAllocator.h>
#include < PxDefaultSimulationFilterShader.h>
#include < PxDefaultCpuDispatcher.h>
#include < PxShapeExt.h>
#include < PxMat33Legacy.h>
#include < PxSimpleFactory.h>

using namespace std;

#pragma comment(lib, "PhysX3_x86.lib")
#pragma comment(lib, "PxTask.lib")
#pragma comment(lib, "Foundation.lib")
#pragma comment(lib, "PhysX3Extensions.lib")
#pragma comment(lib, "GeomUtils.lib")

As you can see, now we have to add a lot of headers this is because a lot of parameters which were given by default in the previous PhysX versions have to be given explicitly.


const int WINDOW_WIDTH=1024,
WINDOW_HEIGHT=768;

static PxPhysics* gPhysicsSDK = NULL;
static PxDefaultErrorCallback gDefaultErrorCallback;
static PxDefaultAllocator gDefaultAllocatorCallback;
static PxSimulationFilterShader gDefaultFilterShader=PxDefaultSimulationFilterShader;

PxScene* gScene = NULL;
PxReal myTimestep = 1.0f/60.0f;
PxRigidActor *box;

In the above lines, we store the variables for screen size, the global physx sdk pointer, scene pointer and the box rigid body pointer. In PhysX3, we no more need to provide the shape desc for objects since now only the geometry has to be specified using the available classes as we will see in a minute.


gPhysicsSDK = PxCreatePhysics(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback, PxTolerancesScale() );
if(gPhysicsSDK == NULL) {
cerr<<"Error creating PhysX3 device."<<endl;
cerr<<"Exiting..."<<endl;
exit(1);
}

if(!PxInitExtensions(*gPhysicsSDK))
cerr<< "PxInitExtensions failed!" <<endl;



In the above lines, we call the CreatePhysX function.Now in PhysX3, we need to provide the allocator and the error callback. We pass in the default handlers provided by the PhysX3 sdk. Once we have a valid PhysX object, we initialize the extensions. This is required so that the other extensions are setup properly.


//Create the scene
PxSceneDesc sceneDesc(gPhysicsSDK->getTolerancesScale());
sceneDesc.gravity=PxVec3(0.0f, -9.8f, 0.0f);
if(!sceneDesc.cpuDispatcher) {
PxDefaultCpuDispatcher* mCpuDispatcher = PxDefaultCpuDispatcherCreate(1);
if(!mCpuDispatcher)
cerr<<"PxDefaultCpuDispatcherCreate failed!"<<endl;
sceneDesc.cpuDispatcher = mCpuDispatcher;
}
if(!sceneDesc.filterShader)
sceneDesc.filterShader = gDefaultFilterShader;

gScene = gPhysicsSDK->createScene(sceneDesc);
if (!gScene)
cerr<<"createScene failed!"<<endl;
gScene->setVisualizationParameter(PxVisualizationParameter::eSCALE, 1.0);
gScene->setVisualizationParameter(PxVisualizationParameter::eCOLLISION_SHAPES, 1.0f);

In the above lines, the scene object is created and the parameters for the simulation are passed in as was in the previous physX versions. In this case, we ask PhysX to set up the global scene gravity to 9.8 m/s^2 The -ve sign is to make it point downwards.


PxMaterial* mMaterial = gPhysicsSDK->createMaterial(0.5,0.5,0.5);



In the above lines, we set the default material's physical properties like static and dynamic friction and the coefficient of restitution. In PhysX3, the default materials are not accessed by index now we need to give an a new object.
Creating actors

//Create actors
//1) Create ground plane
PxReal d = 0.0f;
PxTransform pose = PxTransform(PxVec3(0.0f, 0, 0.0f),PxQuat(PxHalfPi, PxVec3(0.0f, 0.0f, 1.0f)));
PxRigidStatic* plane = gPhysicsSDK->createRigidStatic(pose);
if (!plane)
cerr<<"create plane failed!"<<endl;
PxShape* shape = plane->createShape(PxPlaneGeometry(), *mMaterial);
if (!shape)
cerr<<"create shape failed!"<<endl;
gScene->addActor(*plane);

//2) Create cube
PxReal density = 1.0f;
PxTransform transform(PxVec3(0.0f, 10.0f, 0.0f), PxQuat::createIdentity());
PxVec3 dimensions(0.5,0.5,0.5);
PxBoxGeometry geometry(dimensions);

PxRigidDynamic *actor = PxCreateDynamic(*gPhysicsSDK, transform, geometry, *mMaterial, density);
actor->setAngularDamping(0.75);
actor->setLinearVelocity(PxVec3(0,0,0));
if (!actor)
cerr<<"create actor failed!"<<endl;
gScene->addActor(*actor);

box = actor;
}

In the above lines, we create two actors for the ground plane and the box. For each of these actors, we first set their transform. In PhysX3 the transforms are now given as quaternions. We then create the PxRigid[Static/Dynamic] object by calling appropriate function to create a static/dynamic object. Next, the shape of the object is specified and then the actor is added to the scene. For box, the box geometry is specified here. We use this geometry object by storing the actor reference into a global variable.

Handling PhysX stepping loop
Once the actor stuff is done, the next thing we need to handle is the PhysX loop. This will allow the simulation to step ahead in time. We will implement an asynchronous loop which can be done using the following lines of code.

void StepPhysX()
{
gScene->simulate(myTimestep);

//...perform useful work here using previous frame's state data
while(!gScene->fetchResults() )
{
// do something useful
}
}

These lines were copied directly from the documentation so rather than commenting anything on these, I would ask you to go and read the asynchronous loop section in the PhysX documentation. We will call this function once from our display function.

Rendering of Actors
The next step is to render the actors. To make easier for use to work with PhysX, I have modularized the code into functions. First, the RenderActors() function is implemented as follows,

void RenderActors()
{
// Render all the actors in the scene
DrawActor(box);
}

Nothing fancy here, we just call the DrawActor function passing it the box actor reference. The DrawActor function is implemented as follows,

 
void DrawActor(PxRigidActor* actor)
{
PxU32 nShapes = actor->getNbShapes();
PxShape** shapes=new PxShape*[nShapes];

actor->getShapes(shapes, nShapes);
while (nShapes--)
{
DrawShape(shapes[nShapes]);
}
delete [] shapes;
}

It looks a lot like the previous PhysX version DrawActor function. It basically ask the actor for the number of shapes it has and then calls the DrawShapes function with the shape parameter. The DrawShape function is implemented as follows,


void DrawShape(PxShape* shape)
{
PxGeometryType::Enum type = shape->getGeometryType();
switch(type)
{
case PxGeometryType::eBOX:
DrawBox(shape);
break;
}
}

This function first identifies the type of the shape and then uses a switch case to call the appropriate Draw function. For our case, we check for the Box object and then call the DrawBox function passing it the shape parameter. The DrawBox function is implemented as follows,


void DrawBox(PxShape* pShape) {
PxTransform pT = PxShapeExt::getGlobalPose(*pShape);
PxBoxGeometry bg;
pShape->getBoxGeometry(bg);
PxMat33 m = PxMat33Legacy(pT.q );
float mat[16];
getColumnMajor(m,pT.p, mat);
glPushMatrix();
glMultMatrixf(mat);
glutSolidCube(bg.halfExtents.x*2);
glPopMatrix();
}

The DrawBox function gets the current Global pose (basically the shapes tranform matrix) and then converts it into a column major form (so that we can pass this matrix to OpenGL). Next, the currnet transformation matrix is stored (glPushMatrix) and then the box's matrix is multiplied to the current matrix. Then, we draw the box's geometry (using the glutSolidCube function) and finally revert the old transformation back by calling glPopMatrix.

The Display Function
Now after these function definitions, the display function becomes this,

void Display() {
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//setup the view transformation using
//gluLookAt(...);

//Update PhysX
if (gScene)
{
StepPhysX();
}

RenderActors();

glutSwapBuffers();
}


That's it. Attached is the complete source code for this tutorial. Here is the snapshot of the application.
PhysX3.1 Simple Box

Source code for this tutorial

PhysX3: Getting started

There has been a major revamp of the PhysX API from version 3. I will try to convert all of the existing tutorials into PhysX3 so here I go with the first getting started tutorial.
Visual studio2008 project include directories
To ensure that you can follow smoothly along with me in the rest of the tutorials, make sure that the visual studio project directories contain the following directories in the include path. (This option is accessible through Tools->Options->Projects & Solutions->VC++ Directories. Here YOUR_PHYSX_PATH is where the PhysX3 folder is stored on your harddisk.)
YOUR_PHYSX_PATH\SDKs\PhysXAPI
YOUR_PHYSX_PATH\SDKs\PhysXAPI\foundation
YOUR_PHYSX_PATH\SDKs\PhysXAPI\extensions
YOUR_PHYSX_PATH\SDKs\PhysXAPI\common
YOUR_PHYSX_PATH\SDKs\PhysXAPI\pxtask\include
YOUR_PHYSX_PATH\Samples\SampleFramework\framework\include

Lib path
This path is added in the lib paths.
YOUR_PHYSX_PATH\SDKs\lib\win32

Getting started with NVIDIA PhysX3
We need to include the headers first.

#include <iostream>
#include <gl/freeglut.h>
#include <pxphysicsapi.h>
#include <pxdefaulterrorcallback.h>
#include <pxdefaultallocator.h>

using namespace std;

#pragma comment(lib, "PhysX3_x86.lib")
#pragma comment(lib, "Foundation")
#pragma comment(lib, "PhysX3Extensions.lib")


The PhysX header is now PxPhysicsAPI.h. This header is needed for PhysX. The rest are for c++ output/input stuff and freeglut API stuff. I like to programmatically add the linker libraries. For this basic startup demo, we need PhysX3_x86.lib/dll, Foundation.lib/dll, PhysX3Extensions.lib/dll so we link to them.

const int WINDOW_WIDTH=1024,
WINDOW_HEIGHT=768;

static PxPhysics* gPhysicsSDK = NULL;
static PxDefaultErrorCallback gDefaultErrorCallback;
static PxDefaultAllocator gDefaultAllocatorCallback;

IN the above lines, we setup the window dimensions. Then we store the PhysX object pointer. In the previous sdk, only first parameter was needed now all of the parameters are needed. These include the allocator and error callback handlers. The sdk provides default handlers so we use them.


void InitializePhysX() {
gPhysicsSDK = PxCreatePhysics(PX_PHYSICS_VERSION, gDefaultAllocatorCallback, gDefaultErrorCallback, PxTolerancesScale() );
if(gPhysicsSDK == NULL) {
cerr<<"Error creating PhysX device."<<endl;
cerr<<"Exiting..."<<endl;
exit(1);
}
}
void ShutdownPhysX() {
gPhysicsSDK->release();
}

Like before, we call the PxCreatePhysics function and pass it all the parameters. If the call succeeds, we get the object otherwise we prompt an error and exit. For release, we need to call the release function of the sdk object reference.

Thats it. The code should not give u any errors. To make sure everything is fine and there are no problems, copy PhysX3_x86.dll to the current solution directory. Hope you will enjoy the rest of the tutorials.
Source code

Saturday, April 30, 2011

PhysX Basics Tutorial: Joint Basics



In this tutorial, we will see how to create a simple distance joint. We will reuse the picking code in this tutorial to make things a bit more interesting. So without any further ado, lets get started. We will create two boxes one of which will be a static object. The other box will be manipulated by the mouse hence it will be dynamic.
Creating the boxes
The dynamic box
We simply call the box descriptor as discussed in the past tutorials. Nothing new here.

NxBodyDesc bodyDesc;
bodyDesc.angularDamping = 0.75f;
bodyDesc.linearVelocity = NxVec3(0,0,0);

NxBoxShapeDesc boxDesc;
size_t box_size = 1;
boxDesc.dimensions = NxVec3(box_size/2.0f, box_size/2.0f, box_size/2.0f);

actorDesc2.shapes.pushBack(&boxDesc);
actorDesc2.body = &bodyDesc;
actorDesc2.density = 1.0f;
actorDesc2.globalPose.t = NxVec3(0.0f,3.0f,0.0f);

NxActor* dynamicBox = gScene->createActor(actorDesc2);
dynamicBox->userData= (void*)box_size;


The static box
For static box, we simply create the actor as before and then raise the body flag to be NX_BF_FROZEN.

//create another box which is static
actorDesc2.globalPose.t = NxVec3(0.0f,5.0f,0.0f);

NxActor* staticBox = gScene->createActor(actorDesc2);
staticBox->userData= (void*)box_size;
staticBox->raiseBodyFlag(NX_BF_FROZEN);


Creating joint
For creating a very basic distance joint, we need to fill in the descriptor called
NxDistanceJointDesc. The first things we will give it are the actors that the joint links.

//create a joint
NxDistanceJointDesc desc;
desc.actor[0] = dynamicBox;
desc.actor[1] = staticBox;

For this, we store the references returned from createActor function as shown in the previous section. Next, we specify the different properties of the joint descriptor.
The max/minDistance denote the limits of stretch/compression for this joint respectively.

desc.maxDistance = 2.0f;
desc.minDistance = 1.0f;

The damper determines how damped the springiness of the spring is. A high value dampens the spring and vice verse for spring value.

desc.spring.damper = 1.0f;
desc.spring.spring = 200.0f;

The next two lines are very important. The first setsup the desc's flags. This controls whether the min, max limit of the distance joint, and the spring in the distance joint is enabled. If you dont add these flags, there will be no limit and no springiness to the joint. Likewise the jointFlags are also important. If u want that the actors connected to the distance joint collide, you must pass the NX_JF_COLLISION_ENABLED flag to the jointFlags descriptor. Finally, the spring is created as any other object that we have covered in the past tutorials.

desc.flags |= NX_DJF_MIN_DISTANCE_ENABLED | NX_DJF_MAX_DISTANCE_ENABLED | NX_DJF_SPRING_ENABLED;
desc.jointFlags |= NX_JF_COLLISION_ENABLED;
gScene->createJoint(desc);


Rendering of the distance joint
For rendering of the distance joint, we do a fairly simple thing by creating a global array for 2 NxVec3 types. When we are about to draw the box actors, we store their current positions in the global array so the new DrawCube function is this,

//Stored globally
NxVec3 pos[2]; //for storing the two end points of spring

void DrawBox(NxShape* pShape, size_t size) {
static int count=0;
pos[(count++)%2] = pShape->getGlobalPosition();
NxMat34 pose = pShape->getGlobalPose();
float mat[16];
pose.getColumnMajor44(mat);
glPushMatrix();
glMultMatrixf(mat);
glutSolidCube(size);
glPopMatrix();
}

Next, in the render function, we draw the line between the two positions just stored.

glColor3f(gMouseJoint!=NULL,gMouseJoint==NULL,gMouseJoint==NULL);
//Draw the spring
glBegin(GL_LINES);
glVertex3f(pos[0].x, pos[0].y, pos[0].z);
glVertex3f(pos[1].x, pos[1].y, pos[1].z);
glEnd();


That's it we have a simple distance joint between two boxes. Here is the snapshot from this application.

PhysX Basics

Source code of this tutorial

Thursday, April 28, 2011

PhysX Basics Tutorial: Using the Visual Debugger



In this tutorial, we will see how to connect our client application to the visual debugger. Usually, when you start the visual debugger, it will try to connect to an application. If there is no application connecting to it, it will do nothing.

How to enable remote debugging in your application
On the client side (your application) after you have created the sdk object call this line of code.

gPhysicsSDK->getFoundationSDK().getRemoteDebugger()->connect ("localhost", 5425);

The first parameter of the connect function is the ip address (for local debugging, you can use localhost (127.0.0.1)), the second parameter is the port where the connection will be made.

Demo run
We will now try to see the debugger in action. First, run the visual debugger. Then run your application. You should see all of your objects in the visual debugger. The active objects are green and the inactive (sleep) objects are yellow. This can turn out to be an invaluable tool when we are working on a fairly large project.

That's it for this demo. There is no source code for this tutorial. Just use any of the existing codes and add in the code snippet given earlier and see it in action.
Here is a snapshot of a debugging session.

Using PhysX Visual Debugger

We will look at how to create joints in the next tutorial.

PhysX Basics Tutorial: Picking



In this tutorial, we will use the scene of multiple boxes from the last tutorial. This tutorial assumes that you have successfully understood the basics of how to create an actor using the scene object. If not, u may want to review the previous tutorials as a refresher. Ok so now lets get started. There are a lot of things similar between this and the previous tutorial.

General picking
We will first look at how picking works in general. The user picks on a point on the window. The 2D point coordinates are converted to a 3d point. Then, a ray is generated. The origin and direction of the ray are first calculated by unprojecting the clicked point at different depths. The same point coordinates are used but with two depths (z=0 and z=1) for the near hit point and the far hit point respectively. Once we have constructed the ray, the scene is asked to find an intersecting actor. If the ray has intersected with any actor, a dynamic spring is created between the intersected actor and a sphere at the intersection point. In the mouse motion funciton, depending on whether the actor has been intersected the intersected actor is manipulated.

Picking in PhysX
We define two new functions ViewProject and ViewUnProject as follows,

void ViewProject(NxVec3 &v, int &xi, int &yi, float &depth)
{
GLdouble winX, winY, winZ;
gluProject((GLdouble) v.x, (GLdouble) v.y, (GLdouble) v.z, modelMatrix, projMatrix, viewPort, &winX, &winY, &winZ);
xi = (int)winX; yi = viewPort[3] - (int)winY - 1; depth = (float)winZ;
}
void ViewUnProject(int xi, int yi, float depth, NxVec3 &v)
{
yi = viewPort[3] - yi - 1;
GLdouble wx, wy, wz;
gluUnProject((GLdouble) xi, (GLdouble) yi, (GLdouble) depth,
modelMatrix, projMatrix, viewPort, &wx, &wy, &wz);
v.set((NxReal)wx, (NxReal)wy, (NxReal)wz);
}

The above functions simply call the glu[Un]Project function. Nothing fancy here. Both of these functions need the viewport, modelview and projection matrices so we store these matrices globally. We obtain the viewport values and projection matrix when they are setup (in the resize handler) as shown below.

void OnReshape(int nw, int nh) {
glViewport(0,0,nw, nh);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (GLfloat)nw / (GLfloat)nh, 0.1f, 1000.0f);
glGetIntegerv(GL_VIEWPORT, viewPort);
glGetDoublev(GL_PROJECTION_MATRIX, projMatrix);
glMatrixMode(GL_MODELVIEW);
}

Similarly, we obtain the modelview matrix in the render function just after the viewing transformation is set.

glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
//setting up modelview matrix
glTranslatef(0,0,dist);
glRotatef(rX,1,0,0);
glRotatef(rY,0,1,0);
glGetDoublev(GL_MODELVIEW_MATRIX, modelMatrix);
...
//rest of display function

So now we have our matrices. We now come on the Pick function. This function takes an x, y screen coordinate, cast a ray from into the scene and returns true if there is an intersection. It also stores a sphere object at the hit point, stores reference to the intersected actor and also store a spring between the hitpoint sphere and the actor. This function is defined as follows,


bool PickActor(int x, int y)
{
ReleaseHelpers();

We first release all previous helpers (the spring and the last intersection sphere.


NxRay ray;
ViewUnProject(x,y,0.0f, ray.orig);
ViewUnProject(x,y,1.0f, ray.dir);
ray.dir -= ray.orig; ray.dir.normalize();

The above lines create a ray as given in the previous paragraph.


NxRaycastHit hit;
NxShape* closestShape = gScene->raycastClosestShape(ray, NX_ALL_SHAPES, hit);
if (!closestShape) return false;
if (!closestShape->getActor().isDynamic()) return false;

The above lines is where the ray is cast to find the closest actor. If there is none, we return false.


int hitx, hity;
ViewProject(hit.worldImpact, hitx, hity, gMouseDepth);
gMouseSphere = CreateSphere(hit.worldImpact, 0.1f, 1.0f);

gMouseSphere->raiseBodyFlag(NX_BF_KINEMATIC);
gMouseSphere->raiseActorFlag(NX_AF_DISABLE_COLLISION);

The above lines project the hit point back to get the world space position. This is done so that the picking cursor (sphere) could be drawn at the intersection point.
The sphere's body flag is raised to kinematic since it will be attached to an actor(see next few lines). The collisions are also disabled since we donot want our cursor to intersect with any geometry.



NxDistanceJointDesc desc;
gSelectedActor = &closestShape->getActor();
gSelectedActor->wakeUp();

desc.actor[0] = gMouseSphere;
desc.actor[1] = gSelectedActor;

These lines create a descriptor for a joint having one end point, our sphere cursor and the other end point our intersected actor.


gMouseSphere->getGlobalPose().multiplyByInverseRT(hit.worldImpact, desc.localAnchor[0]);
gSelectedActor->getGlobalPose().multiplyByInverseRT(hit.worldImpact, desc.localAnchor[1]);

The above lines modify the transformation of the intersected actor based on the hit point.


desc.maxDistance = 0.0f;
desc.minDistance = 0.0f;
desc.spring.damper = 1.0f;
desc.spring.spring = 200.0f;
desc.flags |= NX_DJF_MAX_DISTANCE_ENABLED | NX_DJF_SPRING_ENABLED;
NxJoint* joint = gScene->createJoint(desc);
gMouseJoint = (NxDistanceJoint*)joint->is(NX_JOINT_DISTANCE);
return true;
}

Finally, the descriptor parameters are filled in and a joint is created. Note that on every mouse click, the old cursor (sphere) and joint are released and a new pair is created. The ReleaseHelpers function is defined as follows,

void ReleaseHelpers()
{
if (gMouseJoint)
gScene->releaseJoint(*gMouseJoint);
gMouseJoint = NULL;
if (gMouseSphere)
gScene->releaseActor(*gMouseSphere);
gMouseSphere = NULL;
}

Nothing fancy here either. We just release the created objects (the sphere cursor and the joint).

That's it. You need to call the pick function in the mouse function and handle the drag event. Enjoy this snapshot from the demo.

PhysX Picking

Source code of this tutorial

Wednesday, April 27, 2011

PhysX Basics Tutorial: Multiple Bouncing Box



In this tutorial, we will add multiple boxes to the scene. This tutorial assumes that you have successfully understood the basics of how to create an actor using the scene object. If not, u may want to review the previous tutorials as a refresher. Ok so now lets get started. There are a lot of things similar between this and the previous tutorial on the simple box. In fact, the only thing changed when we need to add multiple boxes is the InitializePhysX function. This function is given as follows,


void InitializePhysX() {
gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
if(gPhysicsSDK == NULL) {
cerr<<"Error creating PhysX device."<<endl;
cerr<<"Exiting..."<<endl;
exit(1);
}
//Create the scene
NxSceneDesc sceneDesc;
sceneDesc.gravity.set(0.0f, -9.8f, 0.0f);

gScene = gPhysicsSDK->createScene(sceneDesc);

NxMaterial* defaultMaterial = gScene->getMaterialFromIndex(0);
defaultMaterial->setRestitution(0.5);
defaultMaterial->setStaticFriction(0.5);
defaultMaterial->setDynamicFriction(0.5);

gScene->setTiming(myTimestep / 4.0f, 4, NX_TIMESTEP_FIXED);


//Create actors
//1) Create ground plane
NxPlaneShapeDesc planeDesc;
NxActorDesc actorDesc, actorDesc2;

actorDesc.shapes.pushBack(&planeDesc);
gScene->createActor(actorDesc);

//2) Create cube
NxBodyDesc bodyDesc;
bodyDesc.angularDamping = 0.75f;
bodyDesc.linearVelocity = NxVec3(0,0,0);

NxBoxShapeDesc boxDesc;
size_t box_size = 1;
boxDesc.dimensions = NxVec3(box_size/2.0f, box_size/2.0f, box_size/2.0f);

actorDesc2.shapes.pushBack(&boxDesc);
actorDesc2.body = &bodyDesc;
actorDesc2.density = 1.0f;

We are repeating the same steps as we did in the last tutorial. The only thing that we need to do in case when we need multiple objects of the same type is that we need to create new actors using the scene object. All of this reuse the same actor descriptor object.


for(int i=0;i<10;i++) {
actorDesc2.globalPose.t = NxVec3(0.0f,5.0f+5*i,0.0f);
gScene->createActor(actorDesc2)
}
}

In the above lines, we loop 10 times. We generate a new y position using the loop variable and then assign this position to the global pose of the actor descriptor. Next we call the createActor function passing it the modified descriptor to create a new object for us.

That's it. The rest of the code remains the same since it will loop through all of the actors and determine their types to call the appropriate draw function as detailed in the last tutorial.

Running the code gives us the following output.
PhysX Multiple Bouncing Boxes

Source code of this tutorial

PhysX Basics Tutorial: A Simple Bouncing Box


In this tutorial, I will show you how to create a simple box at a specific position and let it bounce under influence of gravity. We will be adding to the code base from the previous tutorials. We first create the PhysX sdk object and store it into a global pointer like this,
#include <iostream>

#include <GL/freeglut.h>

#include <NxPhysics.h>



#pragma comment(lib, "PhysXLoader.lib")



NxPhysicsSDK* gPhysicsSDK = NULL;

NxScene* gScene = NULL;

NxActor* groundPlane; 

NxActor* box; 



NxReal myTimestep = 1.0f/60.0f;



void InitializePhysX() {

   gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);

   if(gPhysicsSDK == NULL) {

      cerr<<"Error creating PhysX device."<<endl;

      cerr<<"Exiting..."<<endl;

      exit(1);

   }

In the above lines, we just store pointers to the PhysX sdk object, the scene object and two actors (our ground plane and the box) and the timeStep value for stepping the PhysX simulation.

   //Create the scene

   NxSceneDesc sceneDesc;

   sceneDesc.gravity.set(0.0f, -9.8f, 0.0f); 

   gScene = gPhysicsSDK->createScene(sceneDesc);



In PhysX any physics object you want to make, you need to fill a relevant descriptor and then pass that descriptor to the sdk function (through the PhysX sdk pointer) responsible for creating the object for you. In this case, we ask PhysX to set up the global scene gravity to 9.8 m/s^2 The -ve sign is to make it point downwards.

   NxMaterial* defaultMaterial = gScene->getMaterialFromIndex(0);

   defaultMaterial->setRestitution(0.5);

   defaultMaterial->setStaticFriction(0.5);

   defaultMaterial->setDynamicFriction(0.5);



   gScene->setTiming(myTimestep / 4.0f, 4, NX_TIMESTEP_FIXED);

In the above lines, we set the default material's physical properties like static and dynamic friction and the coefficient of restitution. Next, we set the update timing for the PhysX sdk. We ask the sdk to use a fix time stepping. For the simple demo like this, fixed time steps should suffice.
Creating actors
   //Create actors 

   //1) Create ground plane

   NxPlaneShapeDesc planeDesc;

   NxActorDesc actorDesc, actorDesc2;

   actorDesc.shapes.pushBack(&planeDesc);

   gScene->createActor(actorDesc);



   //2) Create cube  

   NxBodyDesc bodyDesc;

   bodyDesc.angularDamping = 0.75f;

   bodyDesc.linearVelocity = NxVec3(0,0,0);

   NxBoxShapeDesc boxDesc;

   boxDesc.dimensions = NxVec3(0.5, 0.5, 0.5);

   actorDesc2.shapes.pushBack(&boxDesc);

   actorDesc2.body   = &bodyDesc;

   actorDesc2.density  = 1.0f;

   actorDesc2.globalPose.t  = NxVec3(0,10,0);

   gScene->createActor(actorDesc2);

}

In the above lines, we create two actors for the ground plane and the box. For each of these actors, their descriptors are filled first to allow us to adjust the parameters. For the ground plane, the default parameters create a ground plane at origin and a positive Y normal direction. Once created, the actor descriptor is given to the scene's createActor function. Next, the same steps are taken for the box. In case of box however the body descriptot is first filled to store the box's linear velocity and angular damping. Then the box's shape descriptor is filled to fill its dimensions. This shape is then adde to the actors shapes list. Next, the actor descriptor sets the body, density and the initial position (globalPose.t). Finally, the createActor function is invoked again. Thats it, we have successfully added the two actors to the PhysX engine.

Handling PhysX stepping loop
Once the actor stuff is done, the next thing we need to handle is the PhysX loop. This will allow the simulation to step ahead in time. We will implement an asynchronous loop which can be done using the following lines of code.
void StepPhysX() 

{ 

   gScene->simulate(myTimestep);        

   gScene->flushStream();        

   //...perform useful work here using previous frame's state data        

   while(!gScene->fetchResults(NX_RIGID_BODY_FINISHED, false) )     

   {

      // do something useful        

   }

} 

These lines were copied directly from the documentation so rather than commenting anything on these, I would ask you to go and read the asynchronous loop section in the PhysX documentation. We will call this function once from our display function.

Rendering of Actors
The next step is to render the actors. To make easier for use to work with PhysX, I have modularized the code into functions. First, the RenderActors() function is implemented as follows,
void RenderActors() 

{ 

    // Render all the actors in the scene 

    int nbActors = gScene->getNbActors(); 

    NxActor** actors = gScene->getActors(); 

    while (nbActors--) 

    { 

        NxActor* actor = *actors++; 

        DrawActor(actor); 

    } 

} 

Nothing fancy here, we first query the scene for the total number of actors it contains. Then, we loop through each actor and draw it by calling the DrawActor function. The DrawActor function is implemented as follows,

 

void DrawActor(NxActor* actor) 

{ 

    NxShape* const* shapes = actor->getShapes(); 

    NxU32 nShapes = actor->getNbShapes(); 

     

    while (nShapes--) 

    { 

        DrawShape(shapes[nShapes]); 

    } 

} 

It looks a lot like the previous function doesn't it. It basically ask the actor for the number of shapes it has and then calls the DrawShapes function with the shape parameter. The DrawShape function is implemented as follows,

void DrawShape(NxShape* shape) 

{ 

   int type = shape->getType();

   switch(type) 

   {          

      case NX_SHAPE_BOX:

         DrawBox(shape);

      break;

   } 

} 

This function first identifies the type of the shape and then uses a switch case to call the appropriate Draw function. For our case, we check for the Box object and then call the DrawBox function passing it the shape parameter. THe DrawBox function is implemented as follows,

void DrawBox(NxShape* pShape) {

   NxMat34 pose = pShape->getGlobalPose(); 

   float mat[16];

   pose.getColumnMajor44(mat);

   glPushMatrix(); 

      glMultMatrixf(mat);

      glutSolidCube(1);

   glPopMatrix(); 

}

The DrawBox function gets the current Global pose (basically the shapes tranform matrix) and then converts it into a column major form (so that we can pass this matrix to OpenGL). Next, the currnet transformation matrix is stored (glPushMatrix) and then the box's matrix is multiplied to the current matrix. Then, we draw the box's geometry (using the glutSolitCube function) and finally revert the old transformation back by calling glPopMatrix.

The Display Function
Now after these function definitions, the display function becomes this,
void Display() {

   glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

   glLoadIdentity();

   //setup the view transformation using 

   //gluLookAt(...);



   //Update PhysX 

   if (gScene) 

   { 

       StepPhysX(); 

   }   



   RenderActors();



   glutSwapBuffers();

}


That's it. Attached is the complete source code for this tutorial. Here is the snapshot of the application.
PhysX Simple Box

Source code for this tutorial

Tuesday, April 26, 2011

PhysX Basics Tutorial: Using GLUT with PhysX



This tutorial is on how to setup freeglut with NVIDIA PhysX sdk.


#include <iostream>
#include <GL/freeglut.h>
#include <NxPhysics.h>

using namespace std;

#pragma comment(lib, "PhysXLoader.lib")

const int WINDOW_WIDTH=1024,
WINDOW_HEIGHT=768;

static NxPhysicsSDK* gPhysicsSDK = NULL;

In the above lines, we first include the required headers. Then the requried linker library is linked programmatically. Next we setup the variables for the screen size and a global pointer to the PhysX sdk. This is done so that PhysX is conveniently accessible throughout the code.


void InitializePhysX() {
gPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION);
if(gPhysicsSDK == NULL) {
cerr<<"Error creating PhysX device."<<endl;
cerr<<"Exiting..."<<endl;
exit(1);
}
}
void ShutdownPhysX() {
NxReleasePhysicsSDK(gPhysicsSDK);
}

These two functions were discussed in the previous tutorial so nothing new here. For the NXCreatePhysicsSDK function, the other parameters are ignored.


void InitGL() {
}

void OnReshape(int nw, int nh) {
glViewport(0,0,nw, nh);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60, (GLfloat)nw / (GLfloat)nh, 0.1f, 100.0f);
glMatrixMode(GL_MODELVIEW);
}

void OnRender() {
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
glutSwapBuffers();
}

void OnShutdown() {
ShutdownPhysX();
}
void main(int argc, char** argv) {
atexit(OnShutdown);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT);
glutCreateWindow("GLUT PhysX Demo");

glutDisplayFunc(OnRender);
glutReshapeFunc(OnReshape);

InitGL();
InitializePhysX();

glutMainLoop();
}

These lines setup a glut window with double buffer support. It also hooks up two functions for resize handling and display. Thats it. The glut window is now setup with PhysX. The next tutorial will discuss how to add a basic cube that falls due to gravity into a glut window. Source codes are here

PhysX Basics Tutorial: Getting started with NVIDIA PhysX



I went to see the power of the NVIDIA PhysX sdk. So I downloaded the sdk from the PhysX developer site. While the sdk contains a lot of demos, for a beginner like me it was quite tedious to get started. I initially started with the documentation and I must say it is pretty good at explaining the API. So my next step was to look at the internet to find out if there are any basic tutorials. Fortunately, I came across Swiftless Tutorials (http://www.swiftless.com/misctuts/physxtuts.html) on AGEIA PhysX (before acquired by NVIDIA, AGEIA owned this sdk). These were very helpful for me in understanding how to get up and running with NVIDIA PhysX sdk. So I will try to fill the gap by doing basic PhysX tutorials.

These tutorials are based on the latest NVIDIA PhysX sdk version 2.8.4. This sdk does not ask u for installing the system software. Thus its your responsibilty to handle the dlls required. Which dlls u need I will explain in a minute. I will use freeglut in this tutorial series.

Getting started with NVIDIA PhysX
We need to include the headers first.

#include <iostream >
#include <nxphysics.h >
using namespace std;
#pragma comment(lib, "PhysXLoader.lib")

The last header NxPhysics.h is the header needed for PhysX. The rest are for c++ output/input stuff. I like to programmatically add the linker libraries. For this basic startup demo, we only need the PhysxLoader.lib/dll so we link to it.
void main() {

NxSDKCreateError whatError;
NxPhysicsSDK* pPhysicsSDK = NxCreatePhysicsSDK(NX_PHYSICS_SDK_VERSION,0,0, NxPhysicsSDKDesc(), &whatError);
if(pPhysicsSDK) {
NxReleasePhysicsSDK(pPhysicsSDK);
} else {
cerr << "Cannot create PhysX device." << endl;
cerr << "Reason: " << whatError;
}


Thats it. If u try to compile and run the code, the pPhysicsSDK pointer will be NULL and the error code will be NXCE_PHYSX_NOT_FOUND. The reason for this is because the required dlls are needed to be copied to the current solution folder. These dlls are PhysXLoader.dll and PhsyXCore.dll. That's it you have the helloworld PhysX program.

Next, we will look at how to hook glut with PhysX in the next tutorial.
Hope you will enjoy the rest of the tutorials. Source codes are here

Wednesday, April 6, 2011

ARB_transform_feedback2

I could not find enough demos on how to use the new ARB transform feedback2 extension. Basically it goes like this,
1) You need to call
 
glGenTransformFeedbacks(1, &tfID);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfID);

like any other function in OpenGL.

2) You specify the buffer and the shader varyings.
 
glBindBufferBase( GL_TRANSFORM_FEEDBACK_BUFFER, 0, tfvbo ); glTransformFeedbackVaryings( pg, 1, attr, GL_INTERLEAVED_ATTRIBS); //(my cards does not support the EXT function


3) In the render function u don’t call glDraw[*] functions instead u call
 
glDrawTransformFeedback(GL_POINTS, tfID);

The buffer binding is taken from the tfID transform feedback buffer.
Thats it. The new way simplifies the handling of buffers.
Attached is the full source code.

Source Code
Binary (Requires freeglut and glew)
Visual Studio 2008 sln (Requires freeglut and glew)

Download solution from Google Docs

Thursday, February 24, 2011

Sunday, February 20, 2011

Implementing histogram pyramid

Just recently, I wanted to implement the histogram pyramid datastructure as detailed here and here however I could not figure it out immediately how to go about it. Fortunately, I was able to find this website. Even though this website was a good starting point however it also left the gaps to be filled in by the readers themselves. Then, I looked into a GPL library HPMC) which made it easier for me to understnad how the histogram pyramid is actually implemented although the code is well written the shader stuff was a bit difficult for me to get hold of. So I went forward to implement the original technique from scratch on my own so here it is. I hope that the discussion here is useful for others. Here is a snapshot of what you would get in the end.
Histogram Pyramid

If you are able to produce something interesting out of this, do let me know I would love to see what you come up with. So here are the missing details.

The histogram pyramid starts with first generating a 2D texture out of your geometry. The first thing needed is generating a series of FBOs with multiple attacments that would act as storage for our histogram pyramid levels. We do so by first generating a series of FBOs with different attachments as follows,

 
vector fboIDs;
GLuint histopyramid_texID;
int size = 2048;
int max_level = (int)(log(size)/log(2));
void InitFBOs() {
glGenTextures(1, &histopyramid_texID);
glBindTexture( GL_TEXTURE_2D, histopyramid_texID);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, max_level);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA32F, size, size, 0, GL_RGBA, GL_FLOAT, NULL );
glGenerateMipmap( GL_TEXTURE_2D );

fboIDs.resize(max_level+1 );
glGenFramebuffers( static_cast( fboIDs.size() ), &fboIDs[0] );
for( GLuint m=0; m< fboIDs.size(); m++) {
glBindFramebuffer( GL_DRAW_FRAMEBUFFER,fboIDs[m] );
glFramebufferTexture2D( GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, histopyramid_texID, m );
if( !checkFBOStatus( __FILE__, __LINE__ ) ) {
cerr << "OpenGL error: Framebuffer for HP level " << m << " incomplete." << endl;
exit(EXIT_FAILURE);
}
}
glBindFramebuffer( GL_DRAW_FRAMEBUFFER,0 );
}

After setting up the fbo, we attach it to allow offscreen rendering and clear it.
Note that we need to setup the MAX mipmap level for directing the output to the correct mipmap level.

 
glBindTexture( GL_TEXTURE_2D, histopyramid_texID );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fboIDs[0] );
glClear(GL_COLOR_BUFFER_BIT);


Next is the slicing of the 3D geometry. We can do so by using the glOrtho function as follows.

 
int tileX = 16, tileY=16;
int w = size/tileX;
int h = size/tileY;
float teapot_size = 0.5;
float t_size_2 = teapot_size*2;
float clip_d = -t_size_2;
int x=0, y=0;
float dZ = (2*abs(clip_d))/(tileX*tileY);
for(int j=0;j< tileY;j++) {
x=0;
for(int i=0;i< tileX;i++) {
glLoadIdentity();
glOrtho(-t_size_2,t_size_2,-t_size_2,t_size_2,clip_d, clip_d+dZ);
glViewport( x, y, w, h);
glutSolidTeapot(teapot_size);
clip_d+=dZ;
x+=w;
}
y+=h;
}


This gives us something like this image


So now we have our geometry rendered to the base (0) level of the histogram pyramid. The original paper on building point clouds using histogram pyramid used descriminator to determine the active cells. We do this by using alpha test on the output during build process of the histogram pyramid (see the next code snippet). Now we need to build the histogram pyramid. We do so by using a reduction fragment shader and invoke it on a fullscreen quad. For each histogram pyramid level, we bind a new fbo and render the fullscreen quad. Thus, each successive level is a reduced version of its predecessor. This is achieved as follows,

 
base_shader.Use();
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fboIDs[0] );
glViewport( 0, 0, size, size );
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_GREATER, 0.1f);
RenderFullscreenQuad();
glDisable(GL_ALPHA_TEST);
if( max_level < 1 ) {
return true;
}
reduction_shader.Use();
glBindTexture( GL_TEXTURE_2D, histopyramid_texID );
glUniform2f( reduction_shader_floor("delta"), -0.5f/size,0.5f/size );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fboIDs[1] );
glViewport( 0, 0, size/2, size/2 );
RenderFullscreenQuad();
if( max_level < 2 ) {
return true;
}
for(GLsizei m=2; m<=max_level; m++) {
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, m-1 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, m-1 );

glUniform2f(reduction_shader("delta"),-0.5f/(1<<(max_level+1-m)),0.5f/(1<<(max_level+1-m)) );

glBindFramebuffer( GL_DRAW_FRAMEBUFFER, fboIDs[m] );
glViewport( 0, 0, 1<<(max_level-m), 1<<(max_level-m) );
RenderFullscreenQuad();
}

reduction_shader.UnUse();



The base level shader is simply outputting the color from the histogram pyramid. The alpha test rejects all the zero entries and we are only left with the non-zero data.
The reduction shader I use is this,

 
uniform sampler2D histopyramid;
uniform vec2 delta;
void
main()
{
gl_FragColor = vec4(
dot( vec4(1.0), ( texture2D( histopyramid, gl_TexCoord[0].xy+delta.xx ) ) ),
dot( vec4(1.0), ( texture2D( histopyramid, gl_TexCoord[0].xy+delta.yx ) ) ),
dot( vec4(1.0), ( texture2D( histopyramid, gl_TexCoord[0].xy+delta.xy ) ) ),
dot( vec4(1.0), ( texture2D( histopyramid, gl_TexCoord[0].xy+delta.yy ) ) )
);
}



Obtaining total vertices


To see how many data items (points in our case) we have, we lookup the top element of the histogram pyramid. We do so by using a PBO, attach it to the histogram top level and then call glGetTexImage function as follows,

 
glBindBuffer( GL_PIXEL_PACK_BUFFER,histoPBOID );
glBindTexture( GL_TEXTURE_2D, histopyramid_texID );
glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAX_LEVEL, max_level);
glGetTexImage( GL_TEXTURE_2D, max_level,GL_RGBA, GL_FLOAT, NULL );


Next, we call the glBufferSubData function to extract the total vertices as follows,

 
float data[4];
glGetBufferSubData( GL_PIXEL_PACK_BUFFER,0, sizeof(GLfloat)*4, &data[0] );
totalVertices = static_cast( floorf(data[0]) + floorf(data[1]) + floorf(data[2]) + data(mem[3]) );
glBindBuffer( GL_PIXEL_PACK_BUFFER, 0 );


Rendering point cloud
For rendering of points, we first bind a temp VBO containing indices incremented linearly. The temp VBO is setup at the initialization as follows,

 

enumerate_vbo_n = 3*1000;
glGenBuffers( 1, &enumVBOID);
glBindBuffer( GL_ARRAY_BUFFER, enumVBOID);
glBufferData( GL_ARRAY_BUFFER, 3*sizeof(GLfloat)* enumerate_vbo_n,NULL,GL_STATIC_DRAW );
GLfloat* ptr = reinterpret_cast( glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY ) );
for(int i=0; i< enumerate_vbo_n; i++) {
*ptr++ = static_cast( i );
*ptr++ = 0.0f;
*ptr++ = 0.0f;
}
glUnmapBuffer( GL_ARRAY_BUFFER );


We could also have used the gl_VertexID builtin attribute to accesss the vertex ID which is used to index into the histogram pyramid. We bind this VBO and then call the glDrawArrays function as follows,

 

glBindBuffer( GL_ARRAY_BUFFER, enumVBOID );
glVertexPointer( 3, GL_FLOAT, 0, NULL );
glEnableClientState( GL_VERTEX_ARRAY );

user_shader.Use();

GLsizei N = totalVertices;
for(GLsizei i=0; i< N; i+= enumerate_vbo_n) {
glUniform1f( user_shader("key_offset"), static_cast( i ) );
glDrawArrays( GL_POINTS, 0, min( N-i, enumerate_vbo_n ) );
}
user_shader.UnUse();


The user shader accepts the incoming vertex stream and converts it into a 3d position. This vertex and fragment shaders are given below.

 

uniform sampler2D histopyramid;
uniform float key_offset;
uniform int max_level;
uniform float TILE_X,
TILE_Y,
TOTAL;

#define FUNC_X TILE_X/2.0
#define FUNC_Y TILE_Y/2.0
void
getVertexPos( out vec3 p )
{
float key_ix = gl_Vertex.x + key_offset;
vec2 texpos = vec2(0.5);
vec4 delta_x = vec4( -0.5, 0.5, -0.5, 0.25 );
vec4 delta_y = vec4( 0.0, -0.5, 0.0, 0.25 );
vec4 sums,hist,mask;
for(int i=max_level; i>0; i--) {
vec4 sums = texture2DLod( histopyramid, texpos, float(i) );
vec4 hist = sums;
hist.w += hist.z;
hist.zw += hist.yy;
hist.yzw += hist.xxx;
vec4 mask = vec4( lessThan( vec4(key_ix), hist ) );
texpos += vec2( dot( mask, delta_x ), dot( mask, delta_y ) );
key_ix -= dot( sums.xyz, vec3(1.0)-mask.xyz );
delta_x *= 0.5;
delta_y *= 0.5;
}
vec4 raw = texture2DLod( histopyramid, texpos, 0.0 );
sums = floor(raw);
hist = sums;
hist.w += hist.z;
hist.zw += hist.yy;
hist.yzw += hist.xxx;
mask = vec4( lessThan( vec4(key_ix), hist ) );
float nib = dot(vec4(mask), vec4(-1.0,-1.0,-1.0, 3.0));
texpos += vec2( dot( mask, delta_x ), dot( mask, delta_y ) );
key_ix -= dot( sums.xyz, vec3(1.0)-mask.xyz );
float val = fract( dot( raw, vec4(equal(vec4(nib),vec4(0,1,2,3))) ) );

vec2 foo = vec2(TILE_X,TILE_Y)*texpos;
vec2 tp = vec2( (2.0*TILE_X)/FUNC_X, (2.0*TILE_Y)/FUNC_Y ) * fract(foo);
float slice = dot( vec2(1.0, TILE_Y), floor(foo));

p = vec3(tp, slice)/vec3(1.0,1.0,TOTAL);

}

void main()
{
vec3 p;
getVertexPos( p);
gl_Position = gl_ModelViewProjectionMatrix * vec4( p, 1.0 );
//debug
gl_FrontColor = vec4(p,1);
//gl_FrontColor = gl_Color ;
}


The interesting bit is happening in the getVertexPos function. First the delta values for moving to the next cell are calculated.

 

float key_ix = gl_Vertex.x + key_offset;
vec2 texpos = vec2(0.5);
vec4 delta_x = vec4( -0.5, 0.5, -0.5, 0.25 );
vec4 delta_y = vec4( 0.0, -0.5, 0.0, 0.25 );


Then the traversal loop is initiated. This loop runs log_2(size) that is the total levels in the histogram pyramid. Since we are using 4 channels for each entry of the histogram pyramid, we do a partial sum by first looking up the value at the current histogram pyramid level. The swizzle part shown below calcualtes the end ranges for each child node.

 

for(int i=max_level; i>0; i--) {
vec4 sums = texture2DLod( histopyramid, texpos, float(i) );
vec4 hist = sums;
hist.w += hist.z;
hist.zw += hist.yy;
hist.yzw += hist.xxx;


Next, based on the current key_index, the mask is calculated to see whether the current key_index is less than the current sum at the current histogram pyramid level. This mask is used to calculate the texture lookup position and the new key_index is upated accordingly. After updating the key_index and texture position, the delta values are updated for the next level of the histogram pyramid.

 

vec4 mask = vec4( lessThan( vec4(key_ix), hist ) );
texpos += vec2( dot( mask, delta_x ), dot( mask, delta_y ) );
key_ix -= dot( sums.xyz, vec3(1.0)-mask.xyz );
delta_x *= 0.5;
delta_y *= 0.5;
}


After the traversal loop ends, we are already at the base level of the histogram pyramid. We find the raw value at the texture lookup position again calculating the sum and the end ranges as earlier. Then the mask is calculated and the texture lookup position and the key index are updated. The actual value is then calculated.

 

vec4 raw = texture2DLod( histopyramid, texpos, 0.0 );
sums = floor(raw);
hist = sums;
hist.w += hist.z;
hist.zw += hist.yy;
hist.yzw += hist.xxx;
mask = vec4( lessThan( vec4(key_ix), hist ) );
float nib = dot(vec4(mask), vec4(-1.0,-1.0,-1.0, 3.0));
texpos += vec2( dot( mask, delta_x ), dot( mask, delta_y ) );
key_ix -= dot( sums.xyz, vec3(1.0)-mask.xyz );
float val = fract( dot( raw, vec4(equal(vec4(nib),vec4(0,1,2,3))) ) );


Finally, the 3D position of the vertex is calculated by multiplying the texture position with the tile size. The Z value is approximated using the Y tiling values.

 

vec2 foo = vec2(TILE_X,TILE_Y)*texpos;
vec2 tp = vec2( (2.0*TILE_X)/FUNC_X, (2.0*TILE_Y)/FUNC_Y ) * fract(foo);
float slice = dot( vec2(1.0, TILE_Y), floor(foo));


Lastly, the 3D coordinate is calculated as follows,

 
p = vec3(tp, slice)/vec3(1.0,1.0,TOTAL);


This position is then rendered, giving us the following output.
Histogram Pyramid
The performance of the histogram pyramid is pretty fast. If u find anything interesting, do drop me an email.

Happy OpenGL coding.

Popular Posts

Copyright (C) 2011 - Movania Muhammad Mobeen. Awesome Inc. theme. Powered by Blogger.