I'm trying to load a PhysX 3.3 heightmap and render it with OpenGL using glm and glfw, but so far it doesn't seem to be working. I'm basing my code on the PhysX samples, and am also using FreeImage to load the heightmap texture (which is a .TGA, the same one that comes with the PhysX Particles sample).

Here's the code where I load the texture into a PhysX heightmap, everything based on the PhysX Particles sample and the FreeImage manual:

PxVec3* heightfieldVertexes;
PxU32* heightfieldIndices;    
heightfield:addHeightfield("particles_heightmap.tga", -10.0f, 2.0f, 2.0f, 0.3f, physicsSimulator->getInstance().createMaterial(0.9f, 0.9f, 0.001f), heightfieldVertexes, heightfieldIndices);

void PhysicsSimulator::addHeightfield(char* heightfieldTexturePath, PxReal thickness, PxReal xScale, PxReal yScale, PxReal zScale, PxMaterial *material, PxVec3*& vertices, PxU32*& indices)

    // check the file signature and deduce its format
    fif = FreeImage_GetFileType(heightfieldTexturePath);

    if (fif == FIF_UNKNOWN) // No signature? Try to guess the file format from the file extension
        fif = FreeImage_GetFIFFromFilename(heightfieldTexturePath);

    if ((fif == FIF_UNKNOWN) || !FreeImage_FIFSupportsReading(fif))
        cerr << "Heightfield map texture could not be loaded!" << endl;


    FIBITMAP *heightfieldTexture = FreeImage_Load(fif, heightfieldTexturePath);

        cerr << "Heightfield map texture contains invalid data!" << endl;


    PxU16 nbColumns = PxU16(FreeImage_GetWidth(heightfieldTexture));
    PxU16 nbRows = PxU16(FreeImage_GetHeight(heightfieldTexture));
    PxHeightFieldDesc heightfieldDesc;
    heightfieldDesc.nbColumns = nbColumns;
    heightfieldDesc.nbRows = nbRows;
    PxU32* samplesData = (PxU32*)malloc(sizeof(PxU32) * (nbColumns * nbRows));
    heightfieldDesc.samples.data = samplesData;
    heightfieldDesc.samples.stride = sizeof(PxU32);
    heightfieldDesc.convexEdgeThreshold = 0;
    PxU8* currentByte = (PxU8*)heightfieldDesc.samples.data;
    PxU32 texturePitch = PxU32(FreeImage_GetPitch(heightfieldTexture));
    PxU8* loaderPtr = (PxU8*)FreeImage_GetBits(heightfieldTexture);
    vertices = (PxVec3*)malloc(sizeof(PxVec3) * (nbColumns * nbRows));
    PxReal* UVs = (PxReal*)malloc(sizeof(PxReal) * ((nbColumns * nbRows * 2)));

    for(PxU32 row = 0; row < nbRows; row++)
        PxU8* pixel = (PxU8*)loaderPtr;
        for(PxU32 column = 0; column < nbColumns; column++)
            PxHeightFieldSample* currentSample = (PxHeightFieldSample*)currentByte;
            currentSample->height = pixel[FI_RGBA_BLUE];
            vertices[row * nbColumns + column] = PxVec3(PxReal(row) * xScale, PxReal(currentSample->height * zScale), PxReal(column) * yScale);
            UVs[2 * (row * nbColumns + column)] = (PxReal(row) / PxReal(nbRows)) * 7.0f;
            UVs[2 * (row * nbColumns + column) + 1] = (PxReal(column) / PxReal(nbColumns)) * 7.0f;
            currentSample->materialIndex0 = 0;
            currentSample->materialIndex1 = 0;
            currentByte += heightfieldDesc.samples.stride;
            pixel += 3;
        loaderPtr += texturePitch;

    // free alocated memory for heightfield texture

    PxHeightField* heightfield = mPhysics->createHeightField(heightfieldDesc);
    // free alocated memory for heightfield samples description
    // create shape for heightfield
    PxTransform pose(PxVec3(-((PxReal)nbRows * yScale) / 2.0f, 0.0f, -((PxReal)nbColumns * xScale) / 2.0f), PxQuat(PxIdentity));
    PxRigidActor* hf = mPhysics->createRigidStatic(pose);
    PxShape* shape = hf->createShape(PxHeightFieldGeometry(heightfield, PxMeshGeometryFlags(), zScale, xScale, yScale), *material);
    shape->setFlag(PxShapeFlag::ePARTICLE_DRAIN, false);
    shape->setFlag(PxShapeFlag::eSIMULATION_SHAPE, true);
    // add actor to the scene
    // create indices and UVs
    indices = (PxU32*)malloc(sizeof(PxU32) * (nbColumns - 1) * (nbRows - 1) * 3 * 2);
    for(int i = 0; i < (nbColumns - 1); ++i)
        for(int j = 0; j < (nbRows - 1); ++j)
            // first triangle
            indices[6 * (i * (nbRows - 1) + j) + 0] = (i + 1) * nbRows + j;
            indices[6 * (i * (nbRows - 1) + j) + 1] = i * nbRows + j;
            indices[6 * (i * (nbRows - 1) + j) + 2] = i * nbRows + j + 1;
            // second triangle
            indices[6 * (i * (nbRows - 1) + j) + 3] = (i + 1) * nbRows + j + 1;
            indices[6 * (i * (nbRows - 1) + j) + 4] = (i + 1) * nbRows + j;
            indices[6 * (i * (nbRows - 1) + j) + 5] = i * nbRows + j + 1;

And here is the code where I try to render it, which is located on glfw main loop (some parts of the code where omitted for simplicity):

GLFWwindow* window;

int width, height;

mat4 viewMatrix;
mat4 projectionMatrix;


glfwGetFramebufferSize(window, &width, &height);
glViewport(0, 0, width, height);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
viewMatrix = lookAt(eye, center, up);;
projectionMatrix = perspective(fovy, width/(float)height, near, far);

GLuint vao;
glGenVertexArrays( 1, &vao );
glBindVertexArray( vao );

GLuint buffer;
glGenBuffers( 1, &buffer );
glBindBuffer( GL_ARRAY_BUFFER, buffer );
glBufferData( GL_ARRAY_BUFFER, sizeof(heightfieldVertexes), NULL, GL_STATIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(heightfieldVertexes), heightfieldVertexes);

GLuint program = InitShader("heightfieldVertexShader.vert", "heightfieldFragmentShader.frag");

GLuint vPosition = glGetAttribLocation( program, "vPosition" );
glEnableVertexAttribArray( vPosition );
glVertexAttribPointer( vPosition, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );

GLuint Model = glGetUniformLocation( program, "Model" );
glUniformMatrix4fv( Model, 1, GL_FALSE, modelMatrix.front());

GLuint View = glGetUniformLocation( program, "View" );
glUniformMatrix4fv( View, 1, GL_FALSE, value_ptr(viewMatrix) );

GLuint Projection = glGetUniformLocation( program, "Projection" );
glUniformMatrix4fv( Projection, 1, GL_FALSE, value_ptr(projectionMatrix) );

glDrawElements( GL_TRIANGLE_STRIP, sizeof(heightfieldIndices)/sizeof(PxU32), GL_UNSIGNED_INT, heightfieldIndices );


Lastly, here are the GLSL shader codes. First for the vertex shader:

#version 430

in vec3 vPosition;

out vec4 color;

uniform mat4 Model;
uniform mat4 View;
uniform mat4 Projection;

void main()
    mat4 ModelViewProjection = Projection * View * Model;

    gl_Position = ModelViewProjection * vec4(vPosition, 1.0);

    color = vec4(1.0, 0.0, 0.0, 1.0);

EDIT: I'm trying to render the heightmap in red just to check if it is ok.

And the fragment shader:

#version 430

in vec4 color;

out vec4 fColor; // fragment's final color

void main()
    fColor = color;

The results of the rendering don't show anything from the heightmap.

As it is today it's far from optimized, but the initial idea is to make it work, and after that make it fast. I think that the view and projection matrix are correct, since I can create and render a box and a plane that interact with each other with PhysX, and they seem to be right. The model matrixes are created by PhysX itself and so I'm assuming that it is correct (and it seems correct in the other actors on the scene).

Unfortunatelly my current computer is not compatible with the more recent versions of OpenGL, so I'm programming this project while I'm on college, but came home today and thought that it may be that I'm trying to pass pointers to a PxVec3 and PxU32 arrays to GLSL shaders, but I don't really know if they are meant to this... As I said, I'm also using glm, and in the case of the vec3 and vec4 array types (from glm) everything works fine. Can this be the error or I'm wrong and the PhysX types are compatible with GLSL?

Other thing that I though is that maybe it's being rendered, but on some place that my camera isn't looking at. If this is the case, is there any way that I can figure where the heightmap is being drawn?

  • \$\begingroup\$ Have you checked if the height map is being loaded correctly (using PVD)? \$\endgroup\$ – UnholySheep Oct 21 '14 at 9:37
  • \$\begingroup\$ Also on a side note I would advise you to stop using C-style casts and malloc in C++ code - use C++ new and casts, it will help you find some hard to spot mistakes and bugs \$\endgroup\$ – UnholySheep Oct 21 '14 at 9:39
  • \$\begingroup\$ @UnholySheep no, I'm not using PVD... thanks for pointing it out, I'll check it the next time I go to college and will report back. And also thanks for the C++ advise. \$\endgroup\$ – Liordino Neto Oct 21 '14 at 12:40
  • \$\begingroup\$ @UnholySheep I just tried to use PVD, made the code to connect my application to it, but when I open PVD it shows the "Failed to start Pvd console" message on the log, along with "The system cannot find the file specified. (Exception from HRESULT: 0x80070002)", and there's nothing on the log. Couldn't find anything online about this error specifically on PVD, but tried to deactivate the Windows firewall and reinstall PVD, which didn't solve it. Do you know what it can be? Thanks! \$\endgroup\$ – Liordino Neto Oct 22 '14 at 23:52
  • \$\begingroup\$ Tried it again in a different computer and got the same errors. \$\endgroup\$ – Liordino Neto Oct 23 '14 at 14:49

As pointed out by @UnholySheep, I was linking the normal PhysX libraries, but the CHECKED versions of them must be linked for the PhysX Visual Debugger to work, and all the "error" messages that show up are perfectly normal when the PVD can't connect, which was the case.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.