Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

3d models of SL Avatars / 3d painting

Babette Ultsch
Registered User
Join date: 26 Mar 2007
Posts: 15
04-02-2007 18:57
HI,

i am new to all this.
I have already tried to make clothing
with the templates in *.psd format.
But in several cases it would be much better to use
a 3d paint program to create textures like deep paint
or body paint.
Does anyone knows a source of avatar meshes
with SL-compatible UVW- layout in the known formats
like *obj, *.3ds or whatever?

thank you,
Babette
Chosen Few
Alpha Channel Slave
Join date: 16 Jan 2004
Posts: 7,496
04-02-2007 19:29
Go to the Downloads section of this site. You'll find the avatar models available in OBJ and Poser formats.
_____________________
.

Land now available for rent in Indigo. Low rates. Quiet, low-lag mainland sim with good neighbors. IM me in-world if you're interested.
Babette Ultsch
Registered User
Join date: 26 Mar 2007
Posts: 15
04-03-2007 04:19
thank you very much :-)
Tiffy McMillan
Registered User
Join date: 1 Apr 2007
Posts: 2
04-03-2007 06:06
Hi,

sorry I'm still struggling with this ... where can I find the download section?

A link would be great.

Thanks
Tiffy
Chip Midnight
ate my baby!
Join date: 1 May 2003
Posts: 10,231
04-03-2007 07:07
http://secondlife.com/community/avatar.php
_____________________

My other hobby:
www.live365.com/stations/chip_midnight
Chosen Few
Alpha Channel Slave
Join date: 16 Jan 2004
Posts: 7,496
04-03-2007 09:28
Chip kindly provided the direct link to the avatar models for you, but just so you know, the more generic "download section" I was talking about is simply www.secondlife.com/download. On that page, you'll find links to every downloadable resource Linden Lab provides for SL. Toward the bottom of the page, you'll see a link called "Avatar Files".
_____________________
.

Land now available for rent in Indigo. Low rates. Quiet, low-lag mainland sim with good neighbors. IM me in-world if you're interested.
Tiffy McMillan
Registered User
Join date: 1 Apr 2007
Posts: 2
04-04-2007 01:45
thanks a lot

... found them actually 10 minutes after my post :)
Zee Pixel
Registered User
Join date: 14 Feb 2006
Posts: 99
But those avatar models don't mach in world
04-04-2007 19:04
The meshes on the download models don't match SL. I'm having a hell of a time trying to paint geometric shapes on shirts and it looks like ass in on the download models. So I have to resort to upload preview to see if I have it right and give up on the tools that use the downloadable models.
Chip Midnight
ate my baby!
Join date: 1 May 2003
Posts: 10,231
04-04-2007 19:16
They match perfectly, Zee. The important thing to remember is that they represent the default shapes. Things will look different on other shapes, and some of the morph targets at the extremes have slightly altered UV mapping to help minimize stretching. For example the stomach size slider, set to max, morphs the av to UVs slightly different than those with the slider in the middle. The morph targets have never been released though, so we have no way of seeing those altered UVs. Geometric patterns in general are difficult to make look good across a wide range of shapes, but if it looks good on the obj in your 3d paint program or previewer, it should look the same on an av of the same gender with the default shape.
_____________________

My other hobby:
www.live365.com/stations/chip_midnight
Zee Pixel
Registered User
Join date: 14 Feb 2006
Posts: 99
No, they don't and...
04-04-2007 20:11
here's what I'm talking about. When I do shirt with an intense pattern, it uploads and looks great. But we built a transformation tool that maps cloth simulations on to clothing designs and tried to use the UV Map from the old V1.1 templates that you can't download anymore (the reverted to an older template that is missing that layer) for perfect alignment and it's hosed now. It used to work a year ago but LL "fixed" it apparently at some point. Now the tool outputs incorrectly transformed UVs on the output. It's a shame that they didn't update this data in the public space when they fixed in the engine...

Oh well.
Chip Midnight
ate my baby!
Join date: 1 May 2003
Posts: 10,231
04-04-2007 22:31
To my knowledge the UV maps have only changed twice. Once was when the chest area was altered a bit to make t-shirts a bit easier, and once when the male "package" slider was added. That caused all pants and underwear to become crotchless. I don't remember when the t-shirt alteration happened. I think it was in beta. The crotch fix was introduced in 1.1. The alternate template sets by both myself and Robin Sojourner are derived directly from the downloadable obj files and are very accurate for the current UVs.
_____________________

My other hobby:
www.live365.com/stations/chip_midnight
Zora Spoonhammer
Registered User
Join date: 29 Jan 2006
Posts: 23
getting the morph data
04-05-2007 09:56
Correct, Chip.

I've been talking with Zee, and it's exactly those texture morph targets you're talking about that are making the procedurals not match... the male AV that is included as an OBJ has the position morphs applied, but not the UV morphs. If you remap the female model then bake to texture, everything works as expected, but it doesn't work for the male model, doh. ...Naturally, if you start with the female model and ignore the male entirely, even if you are making "male" textures, everything works great as textures for both are interchangable.

Incidentally, the morph data is available in the character files on disk. I wrote this quick importer (below) for AC3D when I was trying to figure out what was up with UVs last night. It just loads the geometry, but if you're interested in the morph targets I commented the areas in the script where you can add that.

llmimport.cpp:

/*-------------------------------------------------------------------------

created on: 4/4/2007

This plug-in for AC3D imports the LLM model files found in your
\SecondLife\character folder. It imports geometry and UV maps,
but does not load child LODs.

This will allow you to view the character data in AC3D, where it
can be modified or happily exported to many other formats.

The source code is based heavily on the SL viewer source, but
does not need the viewer or any of the Linden libraries to run.
You will need the AC3D SDK library and header files to
compile the plug-in.

This program really is a dirty hack written in no time at all, so
while it seemed to do the job just fine for me, honestly I'm not
responsible if this eats your computer. :-)

Enjoy!!

Zora

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Portions copyright Linden Research, Inc. Released under GPL 2.0:

*
* Copyright (c) 2001-2007, Linden Research, Inc.
*
* The source code in this file ("Source Code";) is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL";), unless you have obtained a separate licensing agreement
* ("Other License";), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlife.com/developers/opensource/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at http://secondlife.com/developers/opensource/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.

---------------------------------------------------------------------------*/


/*-------------------------------------------------------------------------
Includes and Pragmas
---------------------------------------------------------------------------*/
#include "ac_plugin.h"
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>
#include <float.h>

/*---------------------------------------------------------------------------
Definitions
---------------------------------------------------------------------------*/
#ifdef WIN32
#define LL_WINDOWS 1
#define LL_LITTLE_ENDIAN
#endif

#define HEADER_ASCII "Linden Mesh 1.0"
#define HEADER_BINARY "Linden Binary Mesh 1.0"

typedef signed char S8;
typedef unsigned char U8;
typedef signed short S16;
typedef unsigned short U16;
typedef signed int S32;
typedef unsigned int U32;

#if LL_WINDOWS
// Windows wchar_t is 16-bit
typedef U32 llwchar;
#else
typedef wchar_t llwchar;
#endif

#if LL_WINDOWS
typedef signed __int64 S64;
// probably should be 'hyper' or similiar
#define S64L(a) (a)
typedef unsigned __int64 U64;
#define U64L(a) (a)
#else
typedef long long int S64;
typedef long long unsigned int U64;
#if LL_DARWIN || LL_LINUX
#define S64L(a) (a##LL)
#define U64L(a) (a##ULL)
#endif
#endif

typedef float F32;
typedef double F64;

typedef S32 BOOL;
typedef U8 KEY;
typedef U32 MASK;
typedef U32 TPACKETID;

// Use #define instead of consts to avoid conversion headaches
#define S8_MAX (SCHAR_MAX)
#define U8_MAX (UCHAR_MAX)
#define S16_MAX (SHRT_MAX)
#define U16_MAX (USHRT_MAX)
#define S32_MAX (INT_MAX)
#define U32_MAX (UINT_MAX)
#define F32_MAX (FLT_MAX)
#define F64_MAX (DBL_MAX)

#define S8_MIN (SCHAR_MIN)
#define U8_MIN (0)
#define S16_MIN (SHRT_MIN)
#define U16_MIN (0)
#define S32_MIN (INT_MIN)
#define U32_MIN (0)
#define F32_MIN (FLT_MIN)
#define F64_MIN (DBL_MIN)


#ifndef TRUE
#define TRUE (1)
#endif

#ifndef FALSE
#define FALSE (0)
#endif

#ifndef NULL
#define NULL (0)
#endif

typedef U8 LLPCode;

#if LL_LINUX && __GNUC__ <= 2
typedef int intptr_t;
#endif

static const U32 LENGTHOFVECTOR3 = 3;
typedef struct LLVector3
{
F32 mV[LENGTHOFVECTOR3];
} _LLVector3;

static const U32 LENGTHOFVECTOR2 = 2;
typedef struct LLVector2
{
F32 mV[LENGTHOFVECTOR2];
} _LLVector2;

typedef S32 LLPolyFace[3];


/*---------------------------------------------------------------------------
Endian Swizzle from llEndianSwizzle.h
---------------------------------------------------------------------------*/

#ifdef LL_LITTLE_ENDIAN
// little endian is native for most things.
inline void llendianswizzle(void *,int,int)
{
// Nothing to do
}
#endif

#ifdef LL_BIG_ENDIAN
// big endian requires a bit of work.
inline void llendianswizzle(void *p,int typesize, int count)
{
int i;
switch(typesize)
{
case 2:
{
U16 temp;
for(i=count ;i!=0 ;i--)
{
temp = ((U16*)p)[0];
((U16*)p)[0] = ((temp >> 8) & 0x000000FF) | ((temp << 8) & 0x0000FF00);
p = (void*)(((U16*)p) + 1);
}
}
break;

case 4:
{
U32 temp;
for(i=count; i!=0; i--)
{
temp = ((U32*)p)[0];
((U32*)p)[0] =
((temp >> 24) & 0x000000FF) |
((temp >> 8) & 0x0000FF00) |
((temp << 8) & 0x00FF0000) |
((temp << 24) & 0xFF000000);
p = (void*)(((U32*)p) + 1);
}
}
break;
}

}
#endif

// Use this when working with a single integral value you want swizzled

#define llendianswizzleone(x) llendianswizzle(&;(x), sizeof(x), 1)


/*---------------------------------------------------------------------------
Import the Model File

Parameters: char *fileName - file name to load

Returns: <nothing>
---------------------------------------------------------------------------*/
ACObject *llmimport_load(char *fileName)
{
ACObject *pModel; // new model object
FILE *fp; // input file
long lColor; // surface color
Vertex *pNewVertex; // new vertex
Surface *pNewSurface; // new surface

// open the file
display_message("Importing model...";);
fp = fopen(fileName, "rb";);
if ( fp == NULL ) {
message_dialog("Could not open file %s.", fileName);
return NULL;
}

// create a new object
pModel = new_object(OBJECT_NORMAL);
if ( pModel == NULL ) {
message_dialog("Could not create AC3D object.";);
fclose(fp);
return NULL;
}
object_set_name(pModel, "llm mesh";);
lColor = rgb_to_index(rgb_floats_to_long(1.0f, 1.0f, 1.0f));

//
// The following section borrows heavily from llpolymesh.cpp
// in the Second Life viewer source code, copyright Linden Research, Inc.
// Licensed under GPL 2.0.
//
// Modifications primarily include changes involving generating the
// geometry in AC3D. LODs, morphs and other unsupported features are ignored.
//

//-------------------------------------------------------------------------
// Polymesh members
//-------------------------------------------------------------------------

// transform data
//LLVector3 mPosition;
//LLQuaternion mRotation; // LC: these don't need stored, they are entered directly into AC3D instead
//LLVector3 mScale;

// vertex data
S32 mNumVertices;
LLVector3 *mBaseCoords;
LLVector3 *mBaseNormals;
LLVector3 *mBaseBinormals;
LLVector2 *mTexCoords;
LLVector2 *mDetailTexCoords;
F32 *mWeights;

BOOL mHasWeights;
BOOL mHasDetailTexCoords;

// face data
S32 mNumFaces;
LLPolyFace *mFaces;

//
// LC: joint and morph targets not supported at this time
//

/*
// face set data
U32 mNumJointNames;
std::string* mJointNames;

// morph targets
typedef LLLinkedList<LLPolyMorphData> LLPolyMorphDataList;
LLPolyMorphDataList mMorphData;

std::map<S32, S32> mSharedVerts;

LLPolyMeshSharedData* mReferenceData;
S32 mLastIndexOffset;
*/

// Temporarily...
// Triangle indices
U32 mNumTriangleIndices;
U32 *mTriangleIndices;

//-------------------------------------------------------------------------
// Default values
//-------------------------------------------------------------------------
BOOL bIsLOD = FALSE;

mNumVertices = 0;
mBaseCoords = NULL;
mBaseNormals = NULL;
mBaseBinormals = NULL;
mTexCoords = NULL;
mDetailTexCoords = NULL;
mWeights = NULL;
mHasWeights = FALSE;
mHasDetailTexCoords = FALSE;

mNumFaces = 0;
mFaces = NULL;

mTriangleIndices = NULL;
mNumTriangleIndices = 0;

//-------------------------------------------------------------------------
// Read the first chunk
//-------------------------------------------------------------------------
char header[128];
fread(header, sizeof(char), 128, fp);

//-------------------------------------------------------------------------
// Check for proper binary header
//-------------------------------------------------------------------------
BOOL bStatus = FALSE;
if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 )
{

//----------------------------------------------------------------
// File Header (seek past it)
//----------------------------------------------------------------
fseek(fp, 24, SEEK_SET);

//----------------------------------------------------------------
// HasWeights
//----------------------------------------------------------------
U8 hasWeights;
size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
if (numRead != 1)
{
message_dialog("can't read HasWeights flag from %s", fileName);
}
if (! bIsLOD )
{
mHasWeights = (hasWeights==0) ? FALSE : TRUE;
}

//----------------------------------------------------------------
// HasDetailTexCoords
//----------------------------------------------------------------
U8 hasDetailTexCoords;
numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
if (numRead != 1)
{
message_dialog("can't read HasDetailTexCoords flag from %s", fileName);
}

//----------------------------------------------------------------
// Position
//----------------------------------------------------------------
LLVector3 position;
numRead = fread(position.mV, sizeof(float), 3, fp);
llendianswizzle(position.mV, sizeof(float), 3);
if (numRead != 3)
{
message_dialog("can't read Position from %s", fileName);
}

//
// LC: replaced LL position with ac3d equivalent
//

//setPosition( position );

Point3 pos;
pos.x = position.mV[0];
pos.y = position.mV[1];
pos.z = position.mV[2];
translate_object_abs(pModel, &pos);

//----------------------------------------------------------------
// Rotation
//----------------------------------------------------------------
LLVector3 rotationAngles;
numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
llendianswizzle(rotationAngles.mV, sizeof(float), 3);
if (numRead != 3)
{
message_dialog("can't read RotationAngles from %s", fileName);
}

U8 rotationOrder;
numRead = fread(&rotationOrder, sizeof(U8), 1, fp);

if (numRead != 1)
{
message_dialog("can't read RotationOrder from %s", fileName);
}

rotationOrder = 0;

//
// LC: replaced LL rotation with ac3d equivalent
//

//setRotation( mayaQ( rotationAngles.mV[0],
// rotationAngles.mV[1],
// rotationAngles.mV[2],
// (LLQuaternion::Order)rotationOrder ) );

set_global_matrix_rotate(rotationAngles.mV[0], rotationAngles.mV[1], rotationAngles.mV[2]);
rotate_object(pModel);


//----------------------------------------------------------------
// Scale
//----------------------------------------------------------------
LLVector3 scale;
numRead = fread(scale.mV, sizeof(float), 3, fp);
llendianswizzle(scale.mV, sizeof(float), 3);
if (numRead != 3)
{
message_dialog("can't read Scale from %s", fileName);
}

//
// LC: replaced LL scale with ac3d equivalent
//

//setScale( scale );

object_scale(pModel, scale.mV[0], scale.mV[1], scale.mV[2]);

//-------------------------------------------------------------------------
// Release any existing mesh geometry
//-------------------------------------------------------------------------

//
// LC: nothing to free in this case, original was a class method
//

//freeMeshData();

U16 numVertices = 0;

//----------------------------------------------------------------
// NumVertices
//----------------------------------------------------------------
if (! bIsLOD )
{
numRead = fread(&numVertices, sizeof(U16), 1, fp);
llendianswizzle(&numVertices, sizeof(U16), 1);
if (numRead != 1)
{
message_dialog("can't read NumVertices from %s", fileName);
}

//
// LC: perform allocate inline
//

//allocateVertexData( numVertices );

U32 i;
mBaseCoords = new LLVector3[ numVertices ];
mBaseNormals = new LLVector3[ numVertices ];
mBaseBinormals = new LLVector3[ numVertices ];
mTexCoords = new LLVector2[ numVertices ];
mDetailTexCoords = new LLVector2[ numVertices ];
mWeights = new F32[ numVertices ];
for (i = 0; i < numVertices; i++)
{
mWeights = 0.f;
}
mNumVertices = numVertices;


//----------------------------------------------------------------
// Coords
//----------------------------------------------------------------
numRead = fread(mBaseCoords, 3*sizeof(float), numVertices, fp);
llendianswizzle(mBaseCoords, sizeof(float), 3*numVertices);
if (numRead != numVertices)
{
message_dialog("can't read Coordinates from %s", fileName);
}

//----------------------------------------------------------------
// Normals
//----------------------------------------------------------------
numRead = fread(mBaseNormals, 3*sizeof(float), numVertices, fp);
llendianswizzle(mBaseNormals, sizeof(float), 3*numVertices);
if (numRead != numVertices)
{
message_dialog("can't read Normals from %s", fileName);
}

//----------------------------------------------------------------
// Binormals
//----------------------------------------------------------------
numRead = fread(mBaseBinormals, 3*sizeof(float), numVertices, fp);
llendianswizzle(mBaseBinormals, sizeof(float), 3*numVertices);
if (numRead != numVertices)
{
message_dialog("can't read Binormals from %s", fileName);
}


//----------------------------------------------------------------
// TexCoords
//----------------------------------------------------------------
numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
if (numRead != numVertices)
{
message_dialog("can't read TexCoords from %s", fileName);
}

//----------------------------------------------------------------
// DetailTexCoords
//----------------------------------------------------------------
if (mHasDetailTexCoords)
{
numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
if (numRead != numVertices)
{
message_dialog("can't read DetailTexCoords from %s", fileName);
}
}

//----------------------------------------------------------------
// Weights
//----------------------------------------------------------------
if (mHasWeights)
{
numRead = fread(mWeights, sizeof(float), numVertices, fp);
llendianswizzle(mWeights, sizeof(float), numVertices);
if (numRead != numVertices)
{
message_dialog("can't read Weights from %s", fileName);
}
}
}

//----------------------------------------------------------------
// NumFaces
//----------------------------------------------------------------
U16 numFaces;
numRead = fread(&numFaces, sizeof(U16), 1, fp);
llendianswizzle(&numFaces, sizeof(U16), 1);
if (numRead != 1)
{
message_dialog("can't read NumFaces from %s", fileName);
}

//
// LC: perform allocate inline
//

// allocateFaceData( numFaces );

mFaces = new LLPolyFace[ numFaces ];
mNumFaces = numFaces;
mNumTriangleIndices = mNumFaces * 3;


//----------------------------------------------------------------
// Faces
//----------------------------------------------------------------
U32 i;
U32 numTris = 0;
for (i = 0; i < numFaces; i++)
{
S16 face[3];
numRead = fread(face, sizeof(U16), 3, fp);
llendianswizzle(face, sizeof(U16), 3);
if (numRead != 3)
{
message_dialog("can't read Face[%d] from ", i, fileName);
}

//
// LC: asserts do nothing in an AC3D plugin. All exceptions are trapped.
//
//if (mReferenceData)
//{
// llassert(face[0] < mReferenceData->mNumVertices);
// llassert(face[1] < mReferenceData->mNumVertices);
// llassert(face[2] < mReferenceData->mNumVertices);
//}

if ( bIsLOD )
{
// store largest index in case of LODs
for (S32 j = 0; j < 3; j++)
{
if (face[j] > mNumVertices - 1)
{
mNumVertices = face[j] + 1;
}
}
}
mFaces[0] = face[0];
mFaces[1] = face[1];
mFaces[2] = face[2];

//
// LC: this section was commented out in the original source. it is retained for reference.
//

// S32 j;
// for(j = 0; j < 3; j++)
// {
// LLDynamicArray<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
// if (!face_list)
// {
// face_list = new LLDynamicArray<S32>;
// mVertFaceMap.addData(face[j], face_list);
// }
// face_list->put(i);
// }

numTris++;
}

//
// LC: remainder commented out; skin weights and morphs are not supported at this time
// as AC3D doesn't really utilize them anyway.
//
// However, if you really want the morph data, the procedure for loading it is pretty much
// the same as above... see llpolymesh.cpp to copy-and-paste the needed functions.
//
// Dennis at supercoldmilk.com has some plug-ins that add limited morph target editting to
// AC3D, mostly targeted at creating morphs for Poser. You could probably use those to
// schlep the data to poser using ac3d as a simple conversion utility.
//

/*
//----------------------------------------------------------------
// NumSkinJoints
//----------------------------------------------------------------
if (! bIsLOD )
{
U16 numSkinJoints = 0;
if ( mHasWeights )
{
numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
llendianswizzle(&numSkinJoints, sizeof(U16), 1);
if (numRead != 1)
{
llerrs << "can't read NumSkinJoints from " << fileName << llendl;
}
allocateJointNames( numSkinJoints );
}

//----------------------------------------------------------------
// SkinJoints
//----------------------------------------------------------------
for (i=0; i < numSkinJoints; i++)
{
char jointName[64];
numRead = fread(jointName, sizeof(jointName), 1, fp);
if (numRead != 1)
{
llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl;
}

std::string *jn = &mJointNames;
*jn = jointName;
}

//-------------------------------------------------------------------------
// look for morph section
//-------------------------------------------------------------------------
char morphName[64];
while(fread(&morphName, sizeof(char), 64, fp) == 64)
{
if (!strcmp(morphName, "End Morphs";))
{
// we reached the end of the morphs
break;
}
LLPolyMorphData* morph_data = new LLPolyMorphData(morphName);

BOOL result = morph_data->loadBinary(fp, this);

if (!result)
{
delete morph_data;
continue;
}

mMorphData.addData(morph_data);
}

S32 numRemaps;
if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
{
llendianswizzle(&numRemaps, sizeof(S32), 1);
for (S32 i = 0; i < numRemaps; i++)
{
S32 remapSrc;
S32 remapDst;
if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
{
llerrs << "can't read source vertex in vertex remap data" << llendl;
break;
}
if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
{
llerrs << "can't read destination vertex in vertex remap data" << llendl;
break;
}
llendianswizzle(&remapSrc, sizeof(S32), 1);
llendianswizzle(&remapDst, sizeof(S32), 1);

mSharedVerts[remapSrc] = remapDst;
}
}
}
*/

bStatus = TRUE;
}
else
{
message_dialog("invalid mesh file header: %s", fileName);
bStatus = FALSE;
}

fclose( fp );

// check for successful read
if ( ! bStatus ) {
message_dialog("%s is not a valid model file.", fileName);

if ( mBaseCoords != NULL ) delete [] mBaseCoords;
if ( mBaseNormals != NULL ) delete [] mBaseNormals;
if ( mBaseBinormals != NULL ) delete [] mBaseBinormals;
if ( mTexCoords != NULL ) delete [] mTexCoords;
if ( mDetailTexCoords != NULL ) delete [] mDetailTexCoords;
if ( mWeights != NULL ) delete [] mWeights;
if ( mFaces != NULL ) delete [] mFaces;

return NULL;
}

// create the object
int intCurrentFace = 0;
while ( intCurrentFace < mNumFaces ) {

pNewSurface = new_surface();

int intCurrentVertex = 0;
do {
int intVertexIndex = mFaces[intCurrentFace][intCurrentVertex];

pNewVertex = new_vertex();
pNewVertex->x = mBaseCoords[intVertexIndex].mV[1];
pNewVertex->y = mBaseCoords[intVertexIndex].mV[2];
pNewVertex->z = mBaseCoords[intVertexIndex].mV[0];
object_add_vertex(pModel, pNewVertex);
surface_add_vertex_head(pNewSurface, pNewVertex, mTexCoords[intVertexIndex].mV[0], mTexCoords[intVertexIndex].mV[1]);

++intCurrentVertex;
} while (intCurrentVertex < 3);

surface_set_col(pNewSurface, 1);
surface_set_shading(pNewSurface, true);
object_add_surface_head(pModel, pNewSurface);

++intCurrentFace;
}

// free memory
if ( mBaseCoords != NULL ) delete [] mBaseCoords;
if ( mBaseNormals != NULL ) delete [] mBaseNormals;
if ( mBaseBinormals != NULL ) delete [] mBaseBinormals;
if ( mTexCoords != NULL ) delete [] mTexCoords;
if ( mDetailTexCoords != NULL ) delete [] mDetailTexCoords;
if ( mWeights != NULL ) delete [] mWeights;
if ( mFaces != NULL ) delete [] mFaces;

// display status
display_message("Import successful.";);
set_progress_bar(0);
redraw_all();

// check if model was created
if ( pModel == NULL ) {
message_dialog("Error creating model from filename %s.", fileName);
return NULL;
}

// calculate normals
object_calc_normals(pModel);

// return object
return pModel;
}


/*---------------------------------------------------------------------------
Called on Plugin Initialization, Required by AC3D

Parameters: plug in initialization data, unused

Returns: 0 for success, -1 if failed
---------------------------------------------------------------------------*/
AC3D_PLUGIN_FUNC int AC3DPluginInit(AC3DPluginInitData *d)
{
// add importer
ac_register_file_importer("LLMImporter", ".llm", "Linden Labs Model", llmimport_load, "LLM Importer";);

// return success
return 0;
}


/*---------------------------------------------------------------------------
Called on Plugin Exit, Required by AC3D

Parameters: <none>

Returns: 0 for success, -1 if failed
---------------------------------------------------------------------------*/
AC3D_PLUGIN_FUNC int AC3DPluginExit()
{
// return success
return 0;
}


/*---------------------------------------------------------------------------
Returns Author Information, Required by AC3D

Parameters: <none>

Returns: static string containing version and author information
---------------------------------------------------------------------------*/
AC3D_PLUGIN_FUNC char *AC3DPluginAbout()
{
return ("LLM Model Import - Version 1.0";);
}
Chip Midnight
ate my baby!
Join date: 1 May 2003
Posts: 10,231
04-05-2007 11:04
From: Zora Spoonhammer
if you start with the female model and ignore the male entirely, even if you are making "male" textures, everything works great as textures for both are interchangable.


Interesting. I hadn't really considered that, but the way I set up my av models in max takes that into account completely by accident, hehe. I set up a scene for texture baking and painting with Ghostpainter. I thought it would be handy to set up a single figure that I could morph from female to male. I ran into a problem with that though because the vertex order is completely different between the two dowloadable objs. In order to get a working morph that didn't twist itself into a pretzel, I just copied the female av and manually snapped all its vertices to the male model to get the correct shape while maintaining the same vertex order. I was then able to use that as the morph target without any problems and baking for male or female work just fine. Trying to incorporate the other morph targets and their unique UVs would be a ton of work.
_____________________

My other hobby:
www.live365.com/stations/chip_midnight