New version of the My3D tools for the Irrlicht released!!!
New version of the My3D tools for the Irrlicht released!!!
Intro:
This tools allow you to exporting lightmapped scene from 3DMAX directly into Irrlicht.
Read more about this tool in this thread
http://irrlicht.sourceforge.net/phpBB2/ ... &start=150
New features in My3D v.3:
- lightmaps integration in my3d file - very, very easy to use exporter
(now you don't need to converting images into 'jpg' format and to copy them into 'Lightmaps' directory);
- two methods of compression of the embedded lightmap data
(simple compression and RLE compression);
- 16 bit and 24 bit format of the embedded lightmap data;
(for 16bit more effective to use simple compression, for 24and - RLE compression);
- lightmaps as standalone image files also possible
(but i don't use it any more in my project);
- GUI interface for the exporter;
- transparent materials support.
The My3D tools:
1) My3D Plugin (source and binary included);
http://zdimitor.nm.ru/MY3DPlugin.zip
1) My3D Example (loader for the Irrlicht and test scene included).
http://zdimitor.nm.ru/MY3DExample.zip
Usage:
1) Create lightmapped scene in 3DSMAX;
2) Use My3D plugin to export it into *.my3d file;
3) Load scene into Irrlicht with this class
(CMy3DMeshLoader included in My3D Example);
4) Enjoy!
SceenShoot (My3D Example with Irrlicht 0.7.1):
P.S.:
I test it only with 3DSMAX5, if you want to use it with MAX6, you must recompe my3d plugin with maxsdk6.
This tools allow you to exporting lightmapped scene from 3DMAX directly into Irrlicht.
Read more about this tool in this thread
http://irrlicht.sourceforge.net/phpBB2/ ... &start=150
New features in My3D v.3:
- lightmaps integration in my3d file - very, very easy to use exporter
(now you don't need to converting images into 'jpg' format and to copy them into 'Lightmaps' directory);
- two methods of compression of the embedded lightmap data
(simple compression and RLE compression);
- 16 bit and 24 bit format of the embedded lightmap data;
(for 16bit more effective to use simple compression, for 24and - RLE compression);
- lightmaps as standalone image files also possible
(but i don't use it any more in my project);
- GUI interface for the exporter;
- transparent materials support.
The My3D tools:
1) My3D Plugin (source and binary included);
http://zdimitor.nm.ru/MY3DPlugin.zip
1) My3D Example (loader for the Irrlicht and test scene included).
http://zdimitor.nm.ru/MY3DExample.zip
Usage:
1) Create lightmapped scene in 3DSMAX;
2) Use My3D plugin to export it into *.my3d file;
3) Load scene into Irrlicht with this class
(CMy3DMeshLoader included in My3D Example);
4) Enjoy!
SceenShoot (My3D Example with Irrlicht 0.7.1):
P.S.:
I test it only with 3DSMAX5, if you want to use it with MAX6, you must recompe my3d plugin with maxsdk6.
Already found how to download the files!!!
mirrored here:
http://www.danielpatton.com/afecelis/Zd ... xample.zip
http://www.danielpatton.com/afecelis/Zd ... Plugin.zip
thnx Dimitri!!!
mirrored here:
http://www.danielpatton.com/afecelis/Zd ... xample.zip
http://www.danielpatton.com/afecelis/Zd ... Plugin.zip
thnx Dimitri!!!
Hi to all!
Last night i made some improvements to the CMY3DMeshLoade, in the createMesh function.
Here the source.
You can just copy/paste it into you project.
After this patch you'll have more pleasure to work with transparen materials.
Last night i made some improvements to the CMY3DMeshLoade, in the createMesh function.
Here the source.
You can just copy/paste it into you project.
After this patch you'll have more pleasure to work with transparen materials.
Code: Select all
//--------------------------------------------------------------------------------
IAnimatedMesh* CMY3DMeshFileLoader::createMesh(
io::IReadFile* file
)
{
core::stringc file_name = file->getFileName();
// working directory (from wich we loadinfd the scene)
core::extractFilePath((c8*)file_name.c_str(), (c8*)WorkDir, 255);
core::stringc msg="";
msg="Loading scene from ";
msg.append(file_name);
logger->log(msg.c_str(), ELL_INFORMATION);
// read file into memory
file->seek(0);
u16 id;
c8 name[256];
SMyFileHeader fileHeader;
file->read(&fileHeader, sizeof(SMyFileHeader));
if (fileHeader.MyId!=MY_ID || fileHeader.Ver!=MY_VER)
{ logger->log("Bad MY3D file header, loading failed!", ELL_ERROR);
return 0;
}
file->read(&id, sizeof(id));
if (id!=MY_SCENE_HEADER_ID)
{ logger->log("Can not find MY_SCENE_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
SMySceneHeader sceneHeader;
file->read(&sceneHeader, sizeof(SMySceneHeader));
SceneBackgrColor = video::SColor(
sceneHeader.BackgrColor.R, sceneHeader.BackgrColor.G,
sceneHeader.BackgrColor.B, sceneHeader.BackgrColor.A
);
SceneAmbientColor = video::SColor(
sceneHeader.AmbientColor.R, sceneHeader.AmbientColor.G,
sceneHeader.AmbientColor.B, sceneHeader.AmbientColor.A
);
file->read(&id, sizeof(id));
if (id!=MY_MAT_LIST_ID)
{ logger->log("Can not find MY_MAT_LIST_ID, loading failed!", ELL_ERROR);
return 0;
}
// loading materials and textures
logger->log("Loading materials and textures...", ELL_INFORMATION);
file->read(&id, sizeof(id));
for (int m=0; m<sceneHeader.MaterialCount; m++)
{ if (id!=MY_MAT_HEADER_ID)
{ logger->log("Can not find MY_MAT_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
SMyMaterialEntry me;
// read material header
SMyMaterialHeader materialHeader;
file->read(&materialHeader, sizeof(SMyMaterialHeader));
me.Header = materialHeader;
// read next identificator
file->read(&id, sizeof(id));
static int LightMapIndex=0;
bool GetLightMap=false, GetMainMap=false;
for (int t=0; t<materialHeader.TextureCount; t++)
{
if (id==MY_TEX_FNAME_ID)
file->read(name, 256);
else
{
file->read(&id, sizeof(id));
if (id!=MY_TEXDATA_HEADER_ID)
{ logger->log("Can not find MY_TEXDATA_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
SMyTexDataHeader texDataHeader;
file->read(&texDataHeader, sizeof(SMyTexDataHeader));
core::strcpy(texDataHeader.Name, name);
char LightMapName[255];
sprintf(LightMapName,"My3D.Lightmap.%d",++LightMapIndex);
core::stringc pixFormatStr;
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
{
pixFormatStr = "24bit,";
}
else if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_16)
{
pixFormatStr = "16bit,";
}
else
{
msg="Unknown format of image data (";
msg.append(LightMapName);
msg.append("), loading failed!");
logger->log(msg.c_str(), ELL_ERROR);
return 0;
}
core::stringc comprStr ="";
if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_NONE_ID)
// none compressed image data
{
comprStr = " without compression";
}
else if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_RLE_ID)
// RLE compressed image data
{
comprStr = " RLE compression";
}
else if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_SIMPLE_ID)
// simple compressed image data
{
comprStr = " simple compression";
}
else
{
logger->log("Unknown method of compression image data, loading failed!", ELL_ERROR);
return 0;
}
c8 resStr[255];
sprintf(resStr, " %dx%d,", texDataHeader.Width, texDataHeader.Height);
msg = "Creating lightmap ";
msg.append(LightMapName);
msg.append(" (");
msg.append(pixFormatStr); msg.append(resStr); msg.append(comprStr);
msg.append(")...");
logger->log(msg.c_str(), ELL_INFORMATION);
s32 num_pixels = texDataHeader.Width*texDataHeader.Height;
void* data = 0;
if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_NONE_ID)
// none compressed image data
{
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
{ data = (void*) new SMyPixelColor24[num_pixels];
file->read(data, sizeof(SMyPixelColor24)*num_pixels);
}
else
{ data = (void*) new SMyPixelColor16[num_pixels];
file->read(data, sizeof(SMyPixelColor16)*num_pixels);
}
}
else if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_RLE_ID)
{
// read RLE header identificator
file->read(&id, sizeof(id));
if (id!=MY_TEXDATA_RLE_HEADER_ID)
{ logger->log("Can not find MY_TEXDATA_RLE_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
// read RLE header
SMyRLEHeader rleHeader;
file->read(&rleHeader, sizeof(SMyRLEHeader));
//allocate memory for input and output buffers
void *input_buffer = (void*) new unsigned char[rleHeader.nEncodedBytes];
void *output_buffer = (void*) new unsigned char[rleHeader.nDecodedBytes];
// read encoded data
file->read(input_buffer, rleHeader.nEncodedBytes);
// decode data
data = (void*) new unsigned char[rleHeader.nDecodedBytes];
s32 decodedBytes = core::rle_decode(
(unsigned char*)input_buffer, rleHeader.nEncodedBytes,
(unsigned char*)output_buffer, rleHeader.nDecodedBytes
);
if (decodedBytes!=(s32)rleHeader.nDecodedBytes)
{ logger->log("Error extracting data from RLE compression, loading failed!", ELL_ERROR);
return 0;
}
// free input buffer
delete []input_buffer;
// here decoded data
data = output_buffer;
}
else if (texDataHeader.ComprMode==MY_TEXDATA_COMPR_SIMPLE_ID)
// simple compressed image data
{
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
data = (void*) new SMyPixelColor24[num_pixels];
else
data = (void*) new SMyPixelColor16[num_pixels];
u32 nReadedPixels =0, nToRead =0;
while (true)
{
file->read(&nToRead, sizeof(nToRead));
if ((s32)(nReadedPixels+nToRead)>(s32)num_pixels) break;
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
{ SMyPixelColor24 col24;
file->read(&col24, sizeof(SMyPixelColor24));
for (u32 p=0; p<nToRead; p++)
{ ((SMyPixelColor24*)data)[nReadedPixels+p] =
SMyPixelColor24(col24.r, col24.g, col24.b);
}
}
else
{ SMyPixelColor16 col16;
file->read(&col16, sizeof(SMyPixelColor16));
for (u32 p=0; p<nToRead; p++)
{ ((SMyPixelColor16*)data)[nReadedPixels+p].argb = col16.argb;
}
}
nReadedPixels+=nToRead;
if ((s32)nReadedPixels>=(s32)num_pixels) break;
}
if ((s32)nReadedPixels!=(s32)num_pixels)
{
logger->log("Image data seems to be corrupted, loading failed!", ELL_ERROR);
return 0;
}
}
//! Creates a software image from a byte array.
video::IImage* light_img = 0;
if (texDataHeader.PixelFormat == MY_PIXEL_FORMAT_24)
// 24 bit lightmap format
{
light_img = Driver->createImageFromData(
video::ECF_R8G8B8,
core::dimension2d<s32>(texDataHeader.Width, texDataHeader.Height),
data
);
}else
// 16 bit lightmap format
{
light_img = Driver->createImageFromData(
video::ECF_A1R5G5B5,
core::dimension2d<s32>(texDataHeader.Width, texDataHeader.Height),
data
);
}
me.LigtmapTex = Driver->addTexture(LightMapName, light_img);
//light_img->drop();
GetLightMap=true;
}
core::stringc Name = name;
int pos2 = Name.findLast('.');
core::stringc LightingMapStr = "LightingMap";
int ls = LightingMapStr.size();
core::stringc sub = Name.subString((s32)core::fmax((f32)0, (f32)(pos2 - ls)), ls);
core::stringc texFName = WorkDir;
if (sub == LightingMapStr && !GetLightMap)
{
texFName.append("Lightmaps/");
texFName.append(Name);
me.LigtmapFileName = texFName;
if (texFName!="null")
me.LigtmapTex = Driver->getTexture(texFName.c_str());
GetLightMap = true;
}
else if (!GetMainMap && !GetLightMap )
{
texFName.append(Name);
me.DiffuseTexFileName = texFName;
if (texFName!="null")
me.DiffuseTex = Driver->getTexture(texFName.c_str());
GetMainMap = true;
}
file->read(&id, sizeof(id));
}
MaterialEntry.push_back(me);
}
// loading meshes
if (Mesh) Mesh->drop();
Mesh = new SMesh();
logger->log("Loading meshes...", ELL_INFORMATION);
if (id!=MY_MESH_LIST_ID)
{ logger->log("Can not find MY_MESH_LIST_ID, loading failed!", ELL_ERROR);
return 0;
}
file->read(&id, sizeof(id));
for (s32 mesh_id=0; mesh_id<sceneHeader.MeshCount; mesh_id++)
{
//----------------------------------------------------------------
// Warning!!! In some cases MY3D exporter uncorrectly calculates
// MeshCount (it's a problem, has to be solved) thats why
// i added this code line
if (id!=MY_MESH_HEADER_ID) break;
//----------------------------------------------------------------
if (id!=MY_MESH_HEADER_ID)
{ logger->log("Can not find MY_MESH_HEADER_ID, loading failed!", ELL_ERROR);
return 0;
}
SMyMeshHeader meshHeader;
file->read(&meshHeader, sizeof(SMyMeshHeader));
msg = " ";
msg.append(meshHeader.Name);
logger->log(msg.c_str(), ELL_INFORMATION);
core::array <SMyVertex> Vertex;
core::array <SMyFace> Face;
core::array <SMyTVertex> TVertex1, TVertex2;
core::array <SMyFace> TFace1, TFace2;
s32 vertsNum=0;
s32 facesNum=0;
// verticies
file->read(&id, sizeof(id));
if (id!=MY_VERTS_ID)
{ logger->log("Can not find MY_VERTS_ID, loading failed!", ELL_ERROR);
return 0;
}
file->read(&vertsNum, sizeof(vertsNum));
Vertex.reallocate(vertsNum);
file->read(Vertex.pointer(), sizeof(SMyVertex)*vertsNum);
Vertex.set_used(vertsNum);
// faces
file->read(&id, sizeof(id));
if (id!=MY_FACES_ID)
{ logger->log("Can not find MY_FACES_ID, loading failed!", ELL_ERROR);
return 0;
}
file->read(&facesNum, sizeof(facesNum));
Face.reallocate(facesNum);
file->read(Face.pointer(), sizeof(SMyFace)*facesNum);
Face.set_used(facesNum);
SMyMaterialEntry* matEnt = getMaterialEntryByIndex(meshHeader.MatIndex);
if (!matEnt)
{ msg="Can not find material, attached to mesh ";
msg.append(meshHeader.Name);
msg=", loading failed!";
logger->log(msg.c_str(), ELL_ERROR);
return 0;
}
// reading texture channels
for (s32 tex=0; tex<(s32)meshHeader.TChannelCnt; tex++)
// Max 2 texture channels allowed (but in format .my3d can be more)
{ s32 tVertsNum=0, tFacesNum=0;
// reading texture coords
file->read(&id, sizeof(id));
if (id!=MY_TVERTS_ID)
{ msg="Can not find MY_TVERTS_ID (";
msg.append(tex);
msg.append("texture channel), loading failed!");
logger->log(msg.c_str(), ELL_ERROR);
return 0;
}
file->read(&tVertsNum, sizeof(tVertsNum));
if (tex==0)
// 1st texture channel
{ TVertex1.reallocate(tVertsNum);
file->read(TVertex1.pointer(), sizeof(SMyTVertex)*tVertsNum);
TVertex1.set_used(tVertsNum);
}
else if (tex==1)
// 2nd texture channel
{ TVertex2.reallocate(tVertsNum);
file->read(TVertex2.pointer(), sizeof(SMyTVertex)*tVertsNum);
TVertex2.set_used(tVertsNum);
}
else
// skip other texture channels
{ u32 pos = file->getPos();
file->seek(pos+sizeof(SMyTVertex)*tVertsNum);
}
// reading texture faces
file->read(&id, sizeof(id));
if (id!=MY_TFACES_ID)
{ msg="Can not find MY_TFACES_ID (";
msg.append(tex);
msg.append("texture channel), loading failed!");
logger->log(msg.c_str(), ELL_ERROR);
return 0;
}
file->read(&tFacesNum, sizeof(tFacesNum));
if (tex==0)
// 1st texture channel
{ TFace1.reallocate(tFacesNum);
file->read(TFace1.pointer(), sizeof(SMyFace)*tFacesNum);
TFace1.set_used(tFacesNum);
}
else if (tex==1)
// 2nd texture channel
{ TFace2.reallocate(tFacesNum);
file->read(TFace2.pointer(), sizeof(SMyFace)*tFacesNum);
TFace2.set_used(tFacesNum);
}
else
// skip other texture channels
{ u32 pos = file->getPos();
file->seek(pos+sizeof(SMyFace)*tFacesNum);
}
}
// creating geometry for the mesh
SMeshBufferLightMap* buffer = new SMeshBufferLightMap();
buffer->Material.MaterialType = video::EMT_LIGHTMAP_M2; // EMT_LIGHTMAP_M4 also possible
buffer->Material.Wireframe = false;
buffer->Material.Lighting = false;
buffer->Material.BilinearFilter = true;
if (matEnt)
{
buffer->Material.Texture1 = matEnt->DiffuseTex;
buffer->Material.Texture2 = matEnt->LigtmapTex;
}
if (!buffer->Material.Texture2)
{
buffer->Material.MaterialType = video::EMT_SOLID;
}
if (matEnt && matEnt->Header.Trasparency!=0)
{
buffer->Material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
}
int vert_ind=0;
video::S3DVertex2TCoords currentVertex;
for (int f=0; f<facesNum; f++)
{
if (matEnt)
{
video::SColor color(
matEnt->Header.DiffuseColor.A, matEnt->Header.DiffuseColor.R,
matEnt->Header.DiffuseColor.G, matEnt->Header.DiffuseColor.B
);
currentVertex.Color = color.getInterpolated(video::SColor(0,0,0,0), 1-matEnt->Header.Trasparency);
}
else
{
currentVertex.Color = video::SColor(255,255,255,255);
}
currentVertex.Pos.X = Vertex[Face[f].C].Coord.X;
currentVertex.Pos.Y = Vertex[Face[f].C].Coord.Y;
currentVertex.Pos.Z = Vertex[Face[f].C].Coord.Z;
if (meshHeader.TChannelCnt>0)
{ currentVertex.TCoords.X = TVertex1[TFace1[f].C].TCoord.X;
currentVertex.TCoords.Y = TVertex1[TFace1[f].C].TCoord.Y;
}
if (meshHeader.TChannelCnt>1)
{ currentVertex.TCoords2.X = TVertex2[TFace2[f].C].TCoord.X;
currentVertex.TCoords2.Y = TVertex2[TFace2[f].C].TCoord.Y;
}
buffer->Indices.push_back(vert_ind);
buffer->Vertices.push_back(currentVertex);
vert_ind++;
currentVertex.Pos.X = Vertex[Face[f].B].Coord.X;
currentVertex.Pos.Y = Vertex[Face[f].B].Coord.Y;
currentVertex.Pos.Z = Vertex[Face[f].B].Coord.Z;
if (meshHeader.TChannelCnt>0)
{ currentVertex.TCoords.X = TVertex1[TFace1[f].B].TCoord.X;
currentVertex.TCoords.Y = TVertex1[TFace1[f].B].TCoord.Y;
}
if (meshHeader.TChannelCnt>1)
{ currentVertex.TCoords2.X = TVertex2[TFace2[f].B].TCoord.X;
currentVertex.TCoords2.Y = TVertex2[TFace2[f].B].TCoord.Y;
}
buffer->Indices.push_back(vert_ind);
buffer->Vertices.push_back(currentVertex);
vert_ind++;
currentVertex.Pos.X = Vertex[Face[f].A].Coord.X;
currentVertex.Pos.Y = Vertex[Face[f].A].Coord.Y;
currentVertex.Pos.Z = Vertex[Face[f].A].Coord.Z;
if (meshHeader.TChannelCnt>0)
{ currentVertex.TCoords.X = TVertex1[TFace1[f].A].TCoord.X;
currentVertex.TCoords.Y = TVertex1[TFace1[f].A].TCoord.Y;
}
if (meshHeader.TChannelCnt>1)
{ currentVertex.TCoords2.X = TVertex2[TFace2[f].A].TCoord.X;
currentVertex.TCoords2.Y = TVertex2[TFace2[f].A].TCoord.Y;
}
buffer->Indices.push_back(vert_ind);
buffer->Vertices.push_back(currentVertex);
vert_ind++;
}
if (buffer->Material.MaterialType == video::EMT_TRANSPARENT_VERTEX_ALPHA)
{
buffer->Material.BackfaceCulling = false;
SMesh* transparentMesh = new SMesh();
transparentMesh->addMeshBuffer(buffer);
SAnimatedMesh* transpSAM = new SAnimatedMesh();
// you have to add this type in IAnimatedMesh.h
//transpSAM->Type = EAMT_MY3D;
transpSAM->addMesh(transparentMesh);
transpSAM->recalculateBoundingBox();
transparentMesh->drop();
transparentMesh = 0;
if (SceneManager)
{ SceneManager -> addOctTreeSceneNode(
((IAnimatedMesh*)transpSAM)->getMesh(0)
);
}
transpSAM->drop();
}
else
Mesh->addMeshBuffer(buffer);
buffer->drop();
file->read(&id, sizeof(id));
}
if (id==MY_FILE_END_ID)
logger->log("Loading OK", ELL_INFORMATION);
else
logger->log("Loading finished, but can not find MY_FILE_END_ID token.", ELL_WARNING);
SAnimatedMesh* am = new SAnimatedMesh();
// you have to add this type in IAnimatedMesh.h
//am->Type = EAMT_MY3D;
am->addMesh(Mesh);
am->recalculateBoundingBox();
Mesh->drop();
Mesh = 0;
msg="Scene successfully loaded from";
msg.append(file_name);
logger->log(msg.c_str(), ELL_INFORMATION);
return am;
}
I have updated My3DExample with new patch!
http://zdimitor.nm.ru/MY3DExample.zip
@afecelis mirror it please.
Good luck friends!
http://zdimitor.nm.ru/MY3DExample.zip
@afecelis mirror it please.
Good luck friends!
I've compiled ZDimotor's plugin for max6.
Here is the link:
http://etcaptor.f2g.net/public/my3dmax6.zip
Here is the link:
http://etcaptor.f2g.net/public/my3dmax6.zip
done!
same DL link. thnx for the update!
http://www.danielpatton.com/afecelis/Zd ... xample.zip
@etcaptor: I'll try to compile a max6 version and upload it for testing purposes
same DL link. thnx for the update!
http://www.danielpatton.com/afecelis/Zd ... xample.zip
@etcaptor: I'll try to compile a max6 version and upload it for testing purposes
-
- Posts: 44
- Joined: Mon Mar 29, 2004 7:46 pm
- Location: New Jersey
- Contact:
@Tyn: you need Max's render-to-texture feature to use lightmaps attached to Zdimitor's My3d format. Gmax (max4) lacks of it; it even lacks of an internal renderer (you have to render thru Yafray) so I don't think there's a chance for it.
@etcaptor: thnx for the max6 version. About source compiling; it compiled with no problem in My office computer, but at home I'm getting errors, so I'm beginning to think it's one of my system vbles. screwing up the compilation process.
cheers guys!
ps. I uploaded a very brief video showing the potential of the format here:
http://www.danielpatton.com/afecelis/files/simple.zip
@etcaptor: thnx for the max6 version. About source compiling; it compiled with no problem in My office computer, but at home I'm getting errors, so I'm beginning to think it's one of my system vbles. screwing up the compilation process.
cheers guys!
ps. I uploaded a very brief video showing the potential of the format here:
http://www.danielpatton.com/afecelis/files/simple.zip