Extract vertex data from an FBX file? - opengl

I'm trying to extract vertex and UV map information from a FBX file created with 3ds max 2010.
All i could get from the file are good vertex and polygon index data but wrong UV maps.
Can someone point me in a good direction or give me a tutorial?

Note that when you load Normals for a object that is perfectly smooth they index differently then when not smooth.
Here is a link to some code I have made to load a FBX file into system memory... thought it might help You want to look at "MedelProcess_Mesh.cpp" btw to answer some questions you might have. Hope this helps, remember I have no animation support in there.
SIMPLE ANSWER::
For UVs.
int uvIndex1 = mesh->GetTextureUVIndex(polyIndex, 0);
int uvIndex2 = mesh->GetTextureUVIndex(polyIndex, 1);
int uvIndex3 = mesh->GetTextureUVIndex(polyIndex, 2);
KFbxVector2 uv1 = uv->GetAt(uvIndex1);
KFbxVector2 uv2 = uv->GetAt(uvIndex2);
KFbxVector2 uv3 = uv->GetAt(uvIndex3);
For Verts.
int vertexCount = mesh->GetControlPointsCount();
KFbxVector4* vertexArray = mesh->GetControlPoints();

Related

Skeletal animation: distorted mesh for fbx file but not dae file?

I am having a very weird trouble using Assimp to load and do skeletal animation. I am using two models to test my code, and both models are loaded correctly with Assimp Viewer so there should be no errors with them themselves. However, when I load these two models with my code, only 1 works correctly.
Obviously, this one does not work. The animation of the neck of the chicken works as expected, but the legs are distorted.
This one works perfectly.
The only differences I can think of are that the first model is an fbx file while the second is a dae file and that the first one has multiple meshes, which requires me to transform them back to the same root space if I want the static model to load correctly, while the second one only has one mesh that is already at origin in root space. The meshes I have to transform back to the same space, unsurprisingly, are those that contains legs of the chicken.
I am actually not using Assimp's mOffsetMatrix but calculating my own inverseBindTransform. I assume I calculate them correctly because 1 of my models works. Below is an overview of my matrix multiplication:
modelView * toWorldMatrix * desiredPoseMatrix * inverseBindTransform * meshToWorldMat * position
meshToWorldMat is the transform that brings mesh space back to world space. (toWorldMatrix * desiredPoseMatrix) is just the result of the keyframe interpolation multiplied with its parentMatrix.
What is wrong with my approach?
Update: I also discover that some meshes of the distorted fbx model share the same bone, though I'm not sure if this is significant.
I used the following transformation for each bone in skeleton:
math::Matrix4F Bone::getTransform(const NodePtr& meshNode) const
{
math::Matrix4F fullCurrentMesh = meshNode->getWorldTransformation()
* meshNode->getLocalInitTransformation(ETransformation::Geometry);
math::Matrix4F fullInitMesh = meshNode->getWorldInitTransformation()
* meshNode->getLocalInitTransformation(ETransformation::Geometry);
math::Matrix4F relPose0 = (m_node->getWorldInitTransformation() * m_bindPoseBone).getInverse()
* fullInitMesh;
math::Matrix4F relPoseInv = fullCurrentMesh.getInverse() * m_node->getWorldTransformation();
return relPoseInv * relPose0;
}
All "init" matrices are calculated in timestamp = 0, "local" matrices are data from "fbx" file, m_bindPoseBone is bind pose for this bone (also from "fbx")

Clip Unstructured grid and keep arrays data

I'm trying to clip a vtkUnstructuredGrid using vtkClipDataSet. The problem is that after I clip, the resulting vtkUnstructuredGrid doesn't have the point/cells data (the arrays).
This is my code:
vtkSmartPointer<vtkUnstructuredGrid> model = reader->GetOutput();
// this shows that model has one point data array called "Displacements" (vectorial of 3 components)
model->Print(std::cout);
// Plane to cut it
vtkSmartPointer<vtkPlane> plane = vtkSmartPointer<vtkPlane>::New();
plane->SetOrigin(0.0,0.0,0.0); plane->SetNormal(1,0,0);
// Clip data
vtkSmartPointer<vtkClipDataSet> clipDataSet = vtkSmartPointer<vtkClipDataSet>::New();
clipDataSet->SetClipFunction(plane);
clipDataSet->SetInputConnection(model->GetProducerPort());
clipDataSet->InsideOutOn();
clipDataSet->GenerateClippedOutputOn();
//PROBLEM HERE. The print shows that there aren't any arrays on the output data
clipDataSet->GetOutput()->Print(std::cout);
I need the output grid to have the arrays, because I would like to display the values on the resulting grid.
For example, if the data are are scalars, I would like to display isovalues on the cutted mesh. If the data is vectorial, I would like to deform the mesh (warp) in the direction of the data vectors.
Here I have an example on ParaView of what I would like to do. The solid is the original mesh and the wireframe mesh is the deformed one.
I'm using VTK 5.10 under C++ (Windows 8.1 64 bits, if that helps).
Thank you!
PS: I tried asking this on the VTKusers list, but I got no answer.
Ok I found the error after the comment of user lib. I was missing the call to update after I set the inputconnection.
Thank you all.
// Clip data
vtkSmartPointer<vtkClipDataSet> clipDataSet = vtkSmartPointer<vtkClipDataSet>::New();
clipDataSet->SetClipFunction(plane);
clipDataSet->SetInputConnection(model->GetProducerPort());
clipDataSet->InsideOutOn();
clipDataSet->GenerateClippedOutputOn();
clipDataSet->Update(); // THIS is the solution

Creating a Grayscale image in Visual C++ from a float array

I have an array of grayscale pixel values (floats as a fraction of 1) that I need to display, and then possibly save. The values just came from computations, so I have no libraries currently installed or anything. I've been trying to figure out the CImage libraries, but can't make much sense of what I need to do to visualize this data. Any help would be appreciated!
Thank you.
One possible approach which I've used with some success is to take D3DX's texture functions to create a Direct3D texture and fill it. There is some overhead in starting up D3D, but it provides you with multi-thread-able texture creation and built-in-ish viewing, as well as saving to files without much more fuss.
If you're not interested in using D3D(X), some of the specifics here won't be useful, but the generator should help figure out how to output data for any other library.
For example, assuming an existing D3D9 device pDevice and a noise generator (or other texture data source) pGen:
IDirect3DTexture9 * pTexture = nullptr;
D3DXCreateTexture(pDevice, 255, 255, 0, 0, D3DFMT_R8G8B8, D3DPOOL_DEFAULT, &pTexture);
D3DXFillTexture(pTexture, &texFill, pGen);
D3DXSaveTexture("texture.png", D3DXIFF_PNG, pTexture, NULL);
The generator function:
VOID WINAPI texFill(
D3DXVECTOR4* pOut,
CONST D3DXVECTOR2* pTexCoord,
CONST D3DXVECTOR2* pTexelSize,
LPVOID pData,
) {
// For a prefilled array:
float * pArray = (float *)pData;
float initial = pArray[(pTexCoord->y*255)+pTexCoord->x];
// For a generator object:
Generator * pGen = (Generator*)pData; // passed in as the third param to fill
float initial = pGen->GetPixel(pTexCoord->x, pTexCoord->y);
pOut->x = pOut->y = pOut->z = (initial * 255);
pOut->w = 255; // set alpha to opaque
}
D3DXCreateTexture: http://msdn.microsoft.com/en-us/library/windows/desktop/bb172800%28v=vs.85%29.aspx
D3DXFillTexture: http://msdn.microsoft.com/en-us/library/windows/desktop/bb172833(v=vs.85).aspx
D3DXSaveTextureToFile: http://msdn.microsoft.com/en-us/library/windows/desktop/bb205433(v=vs.85).aspx
Corresponding functions are available for volume/3D textures. As they are already set up for D3D, you can simply render the texture to a flat quad to view, or use as a source in whatever graphical application you may want.
So long as your generator is thread-safe, you can run the create/fill/save in one thread per texture, and generate multiple slices or frames simultaneously.
I found that the best solution for this problem was to use the SFML library (www.sfml-dev.org). Very simple to use, but must be compiled from source if you want to use it with VS2010.
You can use the PNM image format without any libraries whatsoever. (The format itself is trivial). However it's pretty archaic and you'll have to have an image viewer that supports it. IvanView, for example, supports it on Windows.

openGL Creating texture atlas at run time?

So I've set up my framework in a neat little system to wrap SDL, openGL and box2D all together for a 2D game.
Now how it works is that I create an object of "GameObject" class, specify a "source PNG", and then it automatically creates an openGL texture and a box2d body of the same dimensions.
Now I am worried about if I start needing to render many different textures on screen.
Is it possible to load in all my sprite sheets at run time, and then group them all together into one texture? If so, how? And what would be a good way to implement it (so that I wouldn't have to manually be specifying any parameters or anything).
The reason I want to do it at run time and not pre-done is so that I can easily load together all (or most) of the tiles, enemies etc.. of a certain level into this one texture, because every level won't have the same enemies. It'd also make the whole creating art process easier.
There are likely some libraries that already exist for creating texture atlases (optimal packing is a nontrivial problem) and converting old texture coordinates to the new ones.
However, if you want to do it yourself, you probably would do something like this:
Load all textures from disk (your "source PNG") and retrieve the raw pixel data buffer,
If necessary, convert all source textures into the same pixel format,
Create a new texture big enough to hold all the existing textures, along with a corresponding buffer to hold the pixel data
"Blit" the pixel data from the source images into the new buffer at a given offset (see below)
Create a texture as normal using the new buffer's data.
While doing this, determine the mapping from "old" texture coordinates into the "new" texture coordinates (should be a simple matter of recording the offsets for each element of the texture atlas and doing a quick transform). It would probably also be pretty easy to do it inside a pixel shader, but some profiling would be required to see if the overhead of passing the extra parameters is worth it.
Obviously you also want to check to make sure you are not doing something silly like loading the same texture into the atlas twice, but that's a concern that's outside this procedure.
To "blit" (copy) from the source image to the target image you'd do something like this (assuming you're copying a 128x128 texture into a 512x512 atlas texture, starting at (128, 0) on the target):
unsigned char* source = new unsigned char[ 128 * 128 * 4 ]; // in reality, comes from your texture loader
unsigned char* target = new unsigned char[ 512 * 512 * 4 ];
int targetX = 128;
int targetY = 0;
for(int sourceY = 0; sourceY < 128; ++sourceY) {
for(int sourceX = 0; sourceX < 128; ++sourceX) {
int from = (sourceY * 128 * 4) + (sourceX * 4); // 4 bytes per pixel (assuming RGBA)
int to = ((targetY + sourceY) * 512 * 4) + ((targetX + sourceX) * 4); // same format as source
for(int channel = 0; channel < 4; ++channel) {
target[to + channel] = source[from + channel];
}
}
}
This is a very simple brute force implementation: there are much faster, more succinct and more clever ways to copy an array, but the idea is that you are basically copying the contents of the source texture into the target texture at a given X and Y offset. In the end, you will have created a new texture which contains the old textures in it.
If the indexing math doesn't make sense to you, think about how a 2D array is actually indexed inside a 1D space (such as computer memory).
Please forgive any bugs. This isn't production code but instead something I wrote without checking if it compiles or runs.
Since you're using SDL, I should mention that it has a nice function that might be able to help you: SDL_BlitSurface. You can create an SDL_Surface entirely within SDL and simply use SDL_BlitSurface to copy your source surfaces into it, then convert the atlas surface into a GL texture.
It will take care of all the math, and can also do a format conversion for you on the fly.

obtain wrong RGB during creating dynamic texture in OGRE

Hi I have problem while I am trying to create dynamic texture to assign as a background in my ogre window. I want to assign values dynamicly for an each pixel of texture and then I use this texture as a background.
I use this code to create dynamic texture.
Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual("BackgroundTex", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 800, 600, 0, Ogre::PF_R8G8B8, Ogre:: TU_DYNAMIC);
Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create("BackgroundMat",Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
material->getTechnique(0)->getPass(0)->createTextureUnitState("BackgroundTex");
material->getTechnique(0)->getPass(0)->setSceneBlending(Ogre::SBT_TRANSPARENT_COLOUR);
Ogre::Rectangle2D* rect = new Ogre::Rectangle2D(true);
rect->setCorners(-1.0, 1.0, 1.0, -1.0);
rect->setRenderQueueGroup(Ogre::RENDER_QUEUE_BACKGROUND);
rect->setBoundingBox(Ogre::AxisAlignedBox(-100000.0 * Ogre::Vector3::UNIT_SCALE, 100000.0 * Ogre::Vector3::UNIT_SCALE));
Ogre::SceneNode* node = sceneManager->getRootSceneNode()->createChildSceneNode("BackgroundMat");
node->attachObject(rect);
node->setVisible(true);
rect->setMaterial("BackgroundMat");
Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer();
pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock();
Ogre::uint8* pDest = static_cast<Ogre::uint8*>(pixelBox.data);
for(size_t i=0; i < 600; i++)
{
for(size_t j=0; j < 800; j++)
{
*pDest++ = 0;
*pDest++ = 0;
*pDest++ = 255;
}
}
pixelBuffer->unlock();
in this piece of code I assign blue ( R:0 G:0 B:255 ) for each value. I expect to obtain full of blue window but instead of blue background I obtain this background that seen in the picture.
Instead of blue background, in the texture that I obtain there are 3 different color types and they are always repeat sequently. Blue pixels are true but the other 2 color would be blue as well. I cant find reason that cause this problem. What can I do? What is a wrong part?
According to Christopher's comment:
I have no experience with Ogre3D, but can it be that it actually gives you the image data as RGBA (or BGRA, or ARGB) instead of just RGB. So you miss an additional pDest++ (or maybe *pDest++ = 255) and therefore in the first loop interation you get blue, then green, then red and then blue again, ..., which would somehow coincide with your shown image.
EDIT: In your comment you say (if I understood correctly) that you get a completely red image when you add an additional ++pDest in the loop. This at least tells us that you indeed get a 4-component image from Ogre3D, since we now are not out of sync with the colors anymore and have only a single color. But since this color is red, it seems Ogre3D gives you the image data as BGRA. So just set the first component to 255 instead of the third (and of course keep this additional ++pDest in there).
You may have specified the texture as PF_R8G8B8, but it seems Ogre3D has some freedom regarding the layout of the image data in the buffer and actually the graphics driver also has some freedom regarding the memory layout of the textures and often a 32-bit RGBA or BGRA image has some advantages over 24-bit RGB.
It may also depend what underlying graphics API (D3D or GL) is used by Ogre3D and which is the standard there. In GL for example you cannot map texture memory directly and need to use a PBO for this, whose memory layout can in turn be chosen different from the texture. I don't know about D3D, but I think D3D especially likes BGRA layout.
EDIT: You can also check pixelBox.format to see what format the data has.
I had met the same problem like this.
The texture you have created was in the format of Ogre::PF_R8G8B8, but the actual hardwarebuffer Ogre is using is still Ogre::PF_R8G8B8A8, which means it's 4 bits rather than 3 bits.
You can add another line in your loop:
pDest++;