Friday, August 14, 2015

Building GLEW and GLFW libraries for static linking in Visual Studio

It seems the prebuilt binaries for GLEW and GLFW are not really suitable for static linking when using static (i.e. the non-DLL versions) of the VC++ runtime libraries.

Here's a short how-to for compiling GLEW and GLFW for this usage scenario:

1.) Building GLEW

  • download and extract GLEW source code package from http://glew.sourceforge.net/
  • goto /build/vc10 (or vc12)
  • open glew.sln
  • select desired build configuration (debug or release)
  • select glew_static project
  • set C/C++ Code Generation options for glew_static project: Select correct runtime library
  • Build project
  • Result: glew32s(d).lib
2.) Building GLFW
  • download and extract GLFW source code package from http://www.glfw.org/download.html
  • download and extract CMake win .zip from http://www.cmake.org/download/
  • run CMake GUI (i.e. bin/cmake-gui.exe)
  • select GLFW source root directory
  • choose output directory ("Where to build the binaries"), can be same as above
  • click "Configure"
  • select compiler
  • deselect "USE_MSVC_RUNTIME_LIBRARY_DLL" option
  • make sure "BUILD_SHARED_LIBS" is also disabled
  • click "Configure" again
  • click "Generate"
  • open generated GLFW.sln (located in output directory as specified above)
  • select desired build configuration (debug or release)
  • set C/C++ Code Generation options for glfw project: Select correct runtime library
  • Build project
  • Result: glfw3.lib


Monday, March 31, 2014

NVScene demo released

I participated in the PC demo competition at NVScene.

You can download the demo here.


Please keep in mind this is basically a one-man production. I'm quite satisfied with how the final demo turned out, given the limited amount of time I had to work on it.

My NVidia GTC / NVScene slides and session video

Here are the slides and video of my presentation mentioned in the previous post:

Slides (PDF)
Video (ustream)

Unfortunately, it seems something went wrong during recording, the first 6:28 are audio-only, but then video also appears..

Monday, March 17, 2014

Speaking at NVidia GPU Tech Conference / NVScene 2014

I'll give a talk at NVScene in San Francisco on Thursday 27th:

Demo Engine Tricks of the Trade (2:00 pm, Session S4819)


The presentation will cover tips to improve design workflows, increase rendering performance and how to simplify graphics engine code.

Friday, October 18, 2013

Fixing RenderMonkey Installer Fatal Error

Here is a workaround if your installation of RenderMonkey fails with "Fatal Error: Installation ended prematurely":
Open a command prompt, go to the directory where the RenderMonkey .msi file is located and type:

msiexec /qr /i RenderMonkey.2008-12-17-v1.82.322.msi

Thursday, October 10, 2013

FBX SDK Tips

Here are some little tips based on my current experience with the FBX SDK (2014.1):

Linker problems

If you get linker errors (e.g. related to ClassId when using the GetSrcObject or FindMember functions) make sure you link to "libfbxsdk-md.lib" instead of "libfbxsdk.lib".

Node Transformations

Regarding computation of node transformation matrices you need to realize that there are two different formulas used depending on whether the current file is a Maya scene or comes from 3dsmax.
Make sure you read the relevant section in the FBX SDK Programmer's Guide -> Nodes and the Scene Graph -> FBX Nodes -> "Computing Transformation Matrices" (http://docs.autodesk.com/FBX/2014/ENU/FBX-SDK-Documentation/).


The first step is to get the local node transformation. There are several ways to do this:

Option 1:
FbxMatrix matTransform = pNode->GetScene()->GetEvaluator()->GetNodeLocalTransform(pNode);

Option 2:
FbxVector4 translation = pNode->EvaluateLocalTranslation();
FbxVector4 rotation = pNode->EvaluateLocalRotation();
FbxVector4 scale = pNode->EvaluateLocalScaling();
 
FbxMatrix matTransform( translation, rotation, scale );
   
Option 3:
FbxVector4 translation = pNode->LclTranslation.Get();
FbxVector4 rotation    = pNode->LclRotation.Get();
FbxVector4 scale       = pNode->LclScaling.Get();   
FbxMatrix matTransform( translation, rotation, scale );


The next step is to get the geometric transform (assuming 3dsmax is used):

FbxVector4 T = pNode->GetGeometricTranslation (FbxNode::eSourcePivot);
FbxVector4 R = pNode->GetGeometricRotation(FbxNode::eSourcePivot);
FbxVector4 S = pNode->GetGeometricScaling(FbxNode::eSourcePivot);
FbxMatrix matGeometricOffset(T, R, S);


Then we apply the mentioned formula for 3dsmax:

FbxMatrix nodeMatrix = parentMatrix * matTransform;
FbxMatrix worldMatrix = nodeMatrix * matGeometricOffset;


The resulting matrix should then be converted to the conventions of the 3D API you are using (GL/D3D/etc.)

Getting all AnimStacks of the current Scene

The FBX SDK in many cases provides several different ways to retrieve the same information, which can be a bit confusing at times.
To iterate over all AnimStacks in the scene you can use

    for(int i=0; i < m_pImporter->GetAnimStackCount(); i++)
    {

        FbxAnimStack* pAnimStack =  m_pScene->GetSrcObject(i);
        // ...
    }

Or alternatively:

    for(int i=0; i < m_pImporter->GetAnimStackCount(); i++)
    {
        FbxTakeInfo* takeInfo = m_pImporter->GetTakeInfo(i);
        FbxString takeName = takeInfo->mName;


        FbxAnimStack* pAnimStack = m_pScene->FindMember((const char*)takeName);
        // ...
    }

But as said, there are even more ways of doing the same thing...

Friday, July 13, 2012

Open Asset Import Library (AssImp) is great!

I can only recommend you to try it out, it has a very simple and well structured API and supports many different formats, including COLLADA.
You don't even need to compile the whole thing, just download the package from sourceforge, add the include path and dynamically link to the provided DLL (you will only need to import aiImportFile, aiReleaseImport and some of the material getter functions).
I use AssImp in my little converter tool to translate COLLADA files to a custom binary format.

Here is a small snippet to dump simple meshes (separate binary files for vertex attributes and indices):

(some helper code first)
class ExportFile {
public:
    FILE* f;
 
    ExportFile(const char* filename) { f = fopen(filename, "wb"); }
    ~ExportFile() { fclose(f); }
    inline void writeU32(uint32 value) { fwrite(&value, 1, sizeof(uint32), f); }
    inline void write(void* data, size_t length) { fwrite(data, 1, length, f); }
 // etc.
};

void writeArray(const char* filename, unsigned int count, size_t stride, void* data)
{
    ExportFile f(filename);
    f.writeU32(count);
    f.write(data, count*stride);
}
Here's the export function:
void exportMesh(aiMesh* mesh)
{
    std::string meshName = meshNodeNames[mesh];

 // vertex arrays
    writeArray((meshName + std::string(".vtx")).c_str(), mesh->mNumVertices,
               sizeof(aiVector3D), mesh->mVertices);
    writeArray((meshName + std::string(".nrm")).c_str(), mesh->mNumVertices, 
                sizeof(aiVector3D), mesh->mNormals);

    if (mesh->mTangents) {
        writeArray((meshName + std::string(".tan")).c_str(), mesh->mNumVertices, 
                   sizeof(aiVector3D), mesh->mTangents);
    }
 
    // texcoords
    char uvFilename[256];
    int numUVs = 0;
    for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++)
    {
        if (mesh->mTextureCoords[i]) {
            numUVs++;
            unsigned int numComps = mesh->mNumUVComponents[i];
            aiVector3D* uvw_array = mesh->mTextureCoords[i];
            float* tex = new float[numComps * mesh->mNumVertices];

            for (unsigned int v=0; v < mesh->mNumVertices; v++) {
                if (numComps >= 1) tex[v*numComps+0] = uvw_array[v].x;
                if (numComps >= 2) tex[v*numComps+1] = uvw_array[v].y;
                if (numComps >= 3) tex[v*numComps+2] = uvw_array[v].z;
            }

            sprintf(uvFilename, "%s.uv%d", meshName.c_str(), i);
            writeArray(uvFilename, mesh->mNumVertices, sizeof(float)*numComps, tex);

            delete[] tex;
        }
    }

    // indices
    size_t idxCount = mesh->mNumFaces*3;
    assert(idxCount <= 65536);

    uint16* indices = new uint16[idxCount];
    for (unsigned int i=0; i < mesh->mNumFaces; i++) {
        assert(mesh->mFaces[i].mNumIndices == 3);
        indices[i*3+0] = mesh->mFaces[i].mIndices[0];
        indices[i*3+1] = mesh->mFaces[i].mIndices[1];
        indices[i*3+2] = mesh->mFaces[i].mIndices[2];
    }
    writeArray((meshName + std::string(".idx")).c_str(), idxCount, sizeof(uint16), indices);

    delete[] indices;
}