Write a exporter
From Virtools Wiki
Contents |
Write a exporter (*.nmo file)
I will try to explain howto create a standalone exporter to export file/s to Virtools *.nmo filetype. Please note that this page will only explain the basic things you need to do to create a *.nmo file. You will need to write your own specific code for the application you wish to export from (eg. Houdini, Maya, 3DMax etc).
Note! There is a fully functional sample in the Virtools directory on howto create a standalone application for Virtools. This page will try to explain some of the features you need to perform to make it work. If you want to add more functionality, rather than exists on this page, you should either check out the forum or the standalone example from Virtoools.
See $virtools root$\Sdk\Samples\Runtime\Standalone Player (where $root$ is where you have installed Virtools) for more information.
The code in this example, is probably not compilable. Please rewrite yourself, to make it work.
Setup your Visual Studio 2003
You need to setup your Visual Studio so you will be able to compile your standalone. The setup can be different from computer to computer, so below is the basic setup that I have used. Note that $virtools root$ means the root folder where you have installed Virtools (ex. C:\Program Files\Virtools 4.0).
Property pages:
- Linker->Input->Additional Dependencies: Here you need to add the basic libs to make your project work:
CK2.lib VxMath.lib ge2Virtools.lib
- Linker->General->Additional Library Directories: Here you a link to the Windows SDK libs:
"$virtools root$\Sdk\Lib\Win32\Release"
- C/C++ ->General->Additional Include Directories: Add a link to the include folder in your Virtools:
"$virtools root$\Sdk\Includes"
Remember to include the headerfiles you need in your own header. These includes are the basic ones, and you might need to add other ones.
#include "CKAll.h" #include "Ge2Virtools.h"
Now Visual Studio is (hopefully) ready for coding!
Access Virtools engine
When creating a standalone exporter, you need to access the Virtools engine. This must be the first call to the virtools you need to do, otherwise you wont be able to access any virtools data.
CKStartUp()
This function will return CK_OK if successfull.
If this function doesnt return CK_OK, then something is wrong, and you should make sure the function exits alltogether.
Create Pluginmanager and parse plugins
Your standalone application might need to be able to access certain plugins. This is done by first creating a pointer to the pluginmanager and then let the pluginmanager to parse all the plugins you have declared and then it will automaticly load the plugins it might need during the application lifetime.
Create the pluginpointer:
CKPluginManager *ThePluginManager = CKGetPluginManager();
Create a char to store the path to our plugin folder
char PluginPath[250];
Get the plugin path
VxGetModuleFileName(NULL, VirtoolsPath, MAX_LENGTH); CKPathSplitter PathSplitt(VirtoolsPath); sprintf(PluginPath, "%s%s%s", PathSplitt.GetDrive(), PathSplitt.GetDir(), "Plugins");
Parse the plugins, and they will be unloaded until the engine needs them
ThePluginManager->ParsePlugins(PluginPath);
And that is basicly all we need to do to parse our DLL files!
NOTE!
I have personally stored the DLL files in folders in the same path as the final standalone file exists.
I dont know if this is the "right" way to do it.
Create Virtools exportspecific pointers
Next step is to create a Virtools Context pointer.
This pointer is used all the way through the application and must be valid to make it work.
The creation function is called as above:
CKContext *m_pVirtoolsContext = NULL; CKCreateContext(&m_pVirtoolsContext, 0, 0)
This function should return CK_OK if successfull.
Export2Virtools *m_pExportVirtools = NULL; m_pExportVirtools = new Export2Virtools(m_pVirtoolsContext, FALSE);
You must declare the context pointer before creating this one. This function doesnt have a specific return value, so make sure the context pointer is valid.
For more information of the inparameters for these functions, please read in the Virtools documentation.
Export data and load into Virtools structs
Now when we have setup all the needed functions to be able to communicate with Virtools, we need to export the data from the exporting application and into Virtools specific structs.
First we need to create a temporary mesh where we can store our data in.
We will create a VirtoolsTransitionMesh, with help from the Export2Virtools variable we created earlier.
VirtoolsTransitionMesh VirtoolsTempMesh(m_pExportVirtools);
We will use this variable to store all the vertices, faces, normals and other information. This will later be generated when we have filled it with the necessary information.
Now, all 3D applications have their own special way to store their information, so I will not add that part to this page. But I will show each function that virtool uses and try to explain how they work.
Export vertices
to add all vertices from a object, you use our previously created pointer (VirtoolsTransitionMesh) and use the "AddPosition" function.
VirtoolsTempMesh.AddPosition(VxVector);
This function is simply using a VxVector as inparameter. Which should store the x,y and z for each specific point from the object. Loop through all available vertices and add them one by one to the VirtoolsTransitionMesh.
Export Faces
Same thing goes with exporting the faces for our object.
The AddFace function can look little more confusing, since it doesnt really say what it want.
You can use one of the following:
AddFace(int index1, int index2, int index3, CKMaterial *m); AddFace(int *indices, int indexcount, CKMaterial *m);
The first one takes in three different indexes. Which means three points that makes the face itself. The second one takes in a int pointer instead of the three sepeare points as the first one. This simply means that instead of using ex. index[1], index[2], index[3] you just use index as a inparameter, and state that index contains 3 indices.
Both functions has a third option if this current face has a material. If you dont have a material or dont want to use one, just set NULL for the CKMaterial inparameter.
Export Normals
Exporting normals works the same way as exporting vertices. The function looks like this:
VirtoolsTempMesh.AddNormal(VxVector);
- Export Texture coordinates (UV)
Exporting texture coordinates are as simple as above normals. The function looks like this:
VirtoolsTempMesh.AddUv(VxUV);
The inparameter 'VxUV' is a variable with a .u and a .v variable. The UV coordinates that comes from the 3D application could be a vector or a float3 variable. If that is the case, just take the two first variables, and put the first one into .u and the second one into .v and you should be fine.
Virtools' texture coordinates are upside down. So to avoid getting your texture to look incorrect inside Virtools you will need
to "turn" the texture coordinates.
VxUV TempUV; // The u-axis doesnt need to be turned TempUV.u = TextureCoordinate.x; //The v-axis needs to be turned TempUV.v = 1.0f - TextureCoordinate.y;
By adding '1.0f -' before the texture coordinate will turn it for you. You must do this with every UV coordinates!
Now you have setup the UVs, but you need to setup the UV indices aswell. This can be most easily done when loading your faces to the Virtools file, but you can in theory load them whenever you want.
AddUVFace(int index1, int index2, int index3,int channel = 0);
This function sets up the UV faces for you. Basicly this function needs to know the face index.
Remember that a face consists of three points to make a face. So each point in that face, is a index value that this function needs.
So easiest is to do it like this:
int FaceIndex = 0;
for(int i = 0; i < NumberOfFaces; i++, FaceIndex += 3)
{
// Add face function
AddFace(pFaceArray, VertexCount, NULL);
// Add UV face function
pVirtoolsTempMesh->AddUVFace(FaceIndex, FaceIndex + 1, FaceIndex + 2);
}
This pseudo code shows that you just add a ascending number to each point you have loaded in. And since the face has three points, you put in 1,2,3 and then jump three points, and next time you add 4,5,6 etc until you have loaded all your faces.
Export materials
I personally, havent exported any materials to virtools. What I did instead, is to add a empty Virtools material to each object instead. If you want to add one material to a object you just go through the following code:
// Create a material CKMaterial *pMaterial = (CKMaterial *)VirtoolsContext.CreateObject(CKCID_MATERIAL, "Material"); // Set the material for the whole face for(int i = 0; i < TransitionMesh->m_Faces.Size(); i++) TransitionMesh.SetFaceMaterial(i, pMaterial);
This will apply one material for the whole face size (all faces). It is possible to add several materials to your Virtools file. All you need to do is let the Virtools material know which faces this specific material should use.
Export texture
You don't export a texture in the general sense as you export faces, vertices etc. What you need to do, is to get the filepath to the texture file. When you have the file you would need to load it into the Virtools file. But first you need to create a Virtools texture file:
CKTexture *pVirtoolsTexture = (CKTexture *)m_pVirtoolsContext->CreateObject(CKCID_TEXTURE, TextureName);
This returns a texture pointer which we will use:
pVirtoolsTexture->LoadImage(TextuePath);
This function returns TRUE if successfull. If the function returns FALSE, there could be couple of reasons.
- The filepath is incorrect. Check the address once more and make sure its valid
- The filetype is not supported. Change to a supported filetype. Virtools only supports the basic ones (jpg, bmp, tga...). You can add your own filetype support by creating a dll file for that specific filetype
- The filetype dll file is not included into the plugin folder. You would need to add 'ImageReader.dll' and 'JpgLoader.dll' to the plugin folder to get the basic filetypes. (see above).
If the function was successfull, we have a texture saved into that texture pointer. So now it must be assigned to a material which will display the texture. If the texture is not assigned to a material, it will still exist in the file, just not used until assigned:
pVirtoolsMaterial->SetTexture(pVirtoolsTexture);
Export Keyframe Animation
Exporting keyframe animation is really straightforward. But you must export the animation after you have created your Virtools 3dEntity.
First you need to create the objectanimation class where you will store the animation.
CKObjectAnimation *pVirtoolsAnimation = Export2Virtools::AddObjectAnimation(Ck3DEntity *EntityWithAnimation, const char *pName);
Now when you have the animation pointer, you will just simply have to add each individual keyframe to the pointer, along with the time of the animation.
CKObjectAnimation::AddPositionKey(float TimeStep, VxVector *pos); CKObjectAnimation::AddRotationKey(float TimeStep, VxQuaternion *rot); CKObjectAnimation::AddScaleKey(float TimeStep, VxVector *scale);
Virtools will calculate automaticly the interpolation between the different keyframes.
Generate Virtoolsdata
After adding all the data you needed into the TransitionMesh, you will need to generate all the data
so you can use it with virtools to create our object!
VirtoolsTempMesh.GenerateVirtoolsData()
The function actually creates an array for the vertices and the faces in Virtools. It will return TRUE if it was successfull. If false, that means that some of your input data (vertices, faces...) are either stored incorrectly or maybe invalid.
Create Virtools file
Now when you have filled the TempMesh file above, we need to create the nmo file itself.
Add3dObject
This function will create a Virtools 3D entity. Usually this function doesnt return anything (returns void), but since we will need a pointer to the created entity, we will make it return a entity pointer to us.
CK3dEntity *pEntity = (CK3dEntity *)ExportVirtools.Add3dObject("The objects entity name here");
AddMesh
No we have a enttity, which Virtools will recognize inside the dev application. But the entity is empty. So we need to create a mesh with all the data that we have previously created. To do this we need to add a mesh!
We use our generated Mesh information from our temp Mesh structure we have created, and we give the mesh a name. This function returns a pointer to our newly created mesh.
CKMesh *pMesh = ExportVirtools.AddMesh(&VirtoolsTempMesh, "The objects Mesh name here");
SetCurrentMesh
Now when we now have a pointer to our mesh, we must tell our 3DEntity which mesh it will contain. We send in the mesh pointer to the Entity. Basicly when looking at the 3DEntity, it points to a mesh.
pEntity->SetCurrentMesh(pMesh);
CreateCKObjectArray
Now we have a 3DEntity that we can see in Virtools (or we will be able to see it), and the entity has a mesh filled with data. Now we need to store all this into an Array, so Virtools will load all our data. So first we create the Array, and then we generate the array!
CKObjectArray *pVirtoolsObjectsArray; pVirtoolsObjectsArray = CreateCKObjectArray(); //Generate the array ExportVirtools.GenerateObjects(m_pVirtoolsObjectsArray, false, false);
Now, we must fill our array with information. So we send in our 3DEntity pointer into the Array.
Everything that is added to this array will be saved to the final nmo file.
pVirtoolsObjectsArray->InsertFront(pEntity);
CreateCKFile
So now when we have our data stored into our Array, we must create the final file, to where we will save all this information we have created. This pointer will do all our saving needs later on. Make sure that the function returns a valid pointer.
CKFile *pFinalFile = m_pVirtoolsContext->CreateCKFile();
Save session
Now everything is setup to start the save session. Now we need to tell Virtools where to save it and what to save. Then virtools will create a file automaticly and we will be done!
Start a save session with virtools:
pFinalFile->StartSave("char to where we want to save the file");
Tell virtools what we want to save, here we want to save our array we created.
You could probably also just add single objects, one at the time, instead of using a array.
But this way it stores alot more time and space. So I recommend to use a array for this.
pFinalFile->SaveObjects(m_pVirtoolsObjectsArray);
And when we have saved our object, just close the save session.
pFinalFile->EndSave();
Virtools cleanup
And that is it! Now a virtools file is created where you specified.
What we should do now, is just clean up the virtools variables.
You might want to clear out all local variables you have created aswell.
//Clear the context VirtoolsContext.ClearAll() //Close the context CKCloseContext(m_pVirtoolsContext); //And finally, close the Virtools engine CKShutdown();
Important to know when releasing virtoolsdata is that you should close the virtools engine last.
