OpenGL ES可以自己绘制你所需要的图片,也可以直接加载一些3ds文件或者.x文件。将定点坐标、纹理坐标、法向量等转换成数组,并通过ES里的方法如:glDrawElements()、glDrawArray()等将模型显示。这里,我自己写了个类可以完成3ds文件的加载与显示,对于.x文件的显示则要简单点。在后面会给出方法。。。以下是代码:
如有失误,请更正。。。谢谢
/*
* ThreeDS.h
*
* Created on: 2009-10-30
* Author: yuyanya
*/
#ifndef _THREEDS_H
#define _THREEDS_H
#include <e32def.h>
#include <GLES/gl.h>
#include <e32cmn.h>
#include <e32Base.h>
#include <EIKDEF.H>
#include <f32file.h>
#include <EIKENV.H>
#include <coemain.h>
#include <e32std.h>
#include <math.h>
#include <fbs.h>
#include <d3ds_bmp.mbg>
#include <s32file.h>
#define PRIMARY 0x4D4D // 基本块(Primary Chunk),位于文件的开始
// 主块(Main Chunks)
#define OBJECTINFO 0x3D3D // 网格对象的版本号
#define VERSION 0x0002 // .3ds文件的版本
#define EDITKEYFRAME 0xB000 // 所有关键帧信息的头部
// 对象的次级定义(包括对象的材质和对象)
#define MATERIAL 0xAFFF // 保存纹理信息
#define OBJECT 0x4000 // 保存对象的面、顶点等信息
// 材质的次级定义
#define MATNAME 0xA000 // 保存材质名称
#define MATDIFFUSE 0xA020 // 对象/材质的颜色
#define MATMAP 0xA200 // 新材质的头部
#define MATMAPFILE 0xA300 // 保存纹理的文件名
#define OBJ_MESH 0x4100 // 新的网格对象
#define MAX_TEXTURES 100 // 最大的纹理数目
// OBJ_MESH的次级定义
#define OBJ_VERTICES 0x4110 // 对象顶点
#define OBJ_FACES 0x4120 // 对象的面
#define OBJ_MATERIAL 0x4130 // 对象的材质
#define OBJ_UV 0x4140 // 对象的UV纹理坐标
#define Mag(Normal) (sqrt(Normal.x*Normal.x + Normal.y*Normal.y + Normal.z*Normal.z))
class CVector3
{
public:
TReal32 x;
TReal32 y;
TReal32 z;
};
class CVector2
{
public:
TReal32 x;
TReal32 y;
};
struct tFace
{
TInt vertIndex[3];
TInt coordIndex[3];
};
//材质信息
struct tMatInfo
{
TBuf8<255> strName; //纹理名称
TBuf8<255> strFile; //如果存在纹理映射,则表示纹理文件名称
TInt texureId;
TBuf8<3> color;
TReal uTile;
TReal vTile;
TReal uOffset;
TReal vOffset;
};
struct t3DObject
{
TInt numOfVerts;
TInt numOfFaces;
TInt numOfTexVertex;
TInt materialId;
TBool bHasTexture; // 是否具有纹理映射
TBuf8<255> strName; // 对象的名称
CVector3 *pVerts; // 对象的顶点
CVector3 *pNormals; // 对象的法向量
CVector2 *pTexVerts; // 纹理UV坐标
tFace *pFaces; // 对象的面信息
};
struct t3DModel //模型信息结构体
{ int numOfObjects; // 模型中对象的数目
int numOfMaterials; // 模型中材质的数目
RPointerArray<tMatInfo>pMaterials; // 材质链表信息
RPointerArray<t3DObject> pObject; // 模型中对象链表信息
};
struct tChunk //保存块信息的结构
{ TUint16 ID; // 块的ID
TUint length; // 块的长度
TUint bytesRead; // 需要读的块数据的字节数
};
class CLoad3DS// CLoad3DS类处理所有的装入代码
{
public:
RFs fs;
//RFs mFs;
static CLoad3DS* NewL();
static CLoad3DS* NewLC();
private:
CLoad3DS(); // 初始化数据成员
void ConstructL();
virtual ~CLoad3DS();
public:
void show3ds(int j0,float tx,float ty,float tz,float size);//显示3ds模型
void Init(TFileName filename,int j);
private:
TBool Import3DS(t3DModel *pModel, TFileName aFileName);// 装入3ds文件到模型结构中
void CreateTextureL(TUint textureArray[], const TDesC& strFileName, TInt textureID);// 从文件中创建纹理
int GetString(TDes8& tBuf); // 读一个字符串
void ReadChunk(tChunk *); // 读下一个块
void ReadNextChunk(t3DModel *aModel, tChunk *); // 读下一个块
void ReadNextObjChunk(t3DModel *aModel,t3DObject *aObject,tChunk *);// 读下一个对象块
void ReadNextMatChunk(t3DModel *aModel, tChunk *); // 读下一个材质块
void ReadColor(tMatInfo *aMaterial, tChunk *aChunk);// 读对象颜色的RGB值
void ReadVertices(t3DObject *aObject, tChunk *); // 读对象的顶点
void ReadVertexIndices(t3DObject *aObject,tChunk *aPreChunk);// 读对象的面信息
void ReadUVCoordinates(t3DObject *aObject,tChunk *);// 读对象的纹理坐标
void ReadObjMat(t3DModel *aModel,t3DObject *aObject,tChunk *aPreChunk);// 读赋予对象的材质名称
void ComputeNormals(t3DModel *aModel); // 计算对象顶点的法向量
void CleanUp(); // 关闭文件,释放内存空间
//RFileReadStream mRs;
RFile mFile; // 文件指针
tChunk *mCurrentChunk;
tChunk *mTempChunk;
};
#endif
/*
* ThreeDS.cpp
*
* Created on: 2009-10-30
* Author: yuyanya
*/
#include "ThreeDS.h"
#include <AknUtils.h>
TUint g_Texture[MAX_TEXTURES] =
{
0
};
t3DModel g_3DModel[10];
TBool g_bLighting = ETrue;
CLoad3DS* CLoad3DS::NewL()
{
CLoad3DS* self = CLoad3DS::NewLC();
CleanupStack::Pop(self);
return self;
}
CLoad3DS* CLoad3DS::NewLC()
{
CLoad3DS* self = new (ELeave) CLoad3DS;
CleanupStack::PushL(self);
self->ConstructL();
return self;
}
CLoad3DS::CLoad3DS()
{
//
}
void CLoad3DS::ConstructL()
{
fs = CCoeEnv::Static()->FsSession();
//mFs = CCoeEnv::Static()->FsSession();
mCurrentChunk = new (ELeave) tChunk; // 初始化并为当前的块分配空间
mTempChunk = new (ELeave) tChunk; // 初始化一个临时块并分配空间
}
CLoad3DS::~CLoad3DS()
{
fs.Close();
//mFs.Close();
delete mCurrentChunk; // 释放当前块
delete mTempChunk; // 释放临时块
}
TBool CLoad3DS::Import3DS(t3DModel *aModel, TFileName aFileName) // 装入3ds文件到模型结构中
{
User::LeaveIfError(mFile.Open(fs, aFileName, EFileStream));
//User::LeaveIfError(mRs.Open(mFs,aFileName,EFileRead));
ReadChunk(mCurrentChunk);
if (mCurrentChunk->ID != PRIMARY)
{
RDebug::Print(_L("Unable to load PRIMARY chuck from file:%S/n"),aFileName);
return false;
}
// 现在开始读入数据,ReadNextChunk()是一个递归函数
// 通过调用下面的递归函数,将对象读出
ReadNextChunk(aModel, mCurrentChunk);
// 在读完整个3ds文件之后,计算顶点的法线
ComputeNormals(aModel);
return TRUE;
}
void CLoad3DS::Init(TFileName filename, TInt j)
{
TBuf<255> temp;
if (!Import3DS(&g_3DModel[j], filename))
RDebug::Print(_L("Load file failed"));
for (TInt i = 0; i < g_3DModel[j].numOfMaterials; i++)
{
if (g_3DModel[j].pMaterials[i]->strFile.Length() > 0)
{
temp.Copy(g_3DModel[j].pMaterials[j]->strFile);
CreateTextureL(g_Texture, temp, i);
}
g_3DModel[j].pMaterials[i]->texureId = i;
}
}
void CLoad3DS::CreateTextureL(TUint textureArray[], const TDesC& strFileName,
TInt textureID) //从文件中创建纹理
{
if (strFileName.Length() < 0)
return;
//CFbsBitmap* pBitmap = new (ELeave) CFbsBitmap;
CFbsBitmap* pBitmap;
_LIT(KFileName,"system//apps//graphics//d3ds_bmp.mbm");
TFileName fileName(KFileName);
//User::LeaveIfError(CompleteWithAppPath(fileName));
//CleanupStack::PushL(pBitmap);
//pBitmap = iEikonEnv->CreateBitmapL(strFileName,EMbmD3ds_bmpCar_dealers1);
pBitmap = CEikonEnv::Static()->CreateBitmapL(fileName,EMbmD3ds_bmpFace);
//User::LeaveIfError(pBitmap->Load(strFileName,EMbmD3ds_bmpCar_dealers1/*the resource ID*/,ETrue)); //TODO: May be error
glGenTextures(1, &textureArray[textureID]);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glBindTexture(GL_TEXTURE_2D, textureArray[textureID]);
glTexImage2D(GL_TEXTURE_2D, 0, 3, pBitmap->SizeInPixels().iWidth,
pBitmap->SizeInPixels().iHeight, 0, GL_RGB, GL_UNSIGNED_BYTE,
pBitmap->DataAddress());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,
GL_LINEAR_MIPMAP_LINEAR);
if (pBitmap)
{
delete pBitmap;
}
CleanupStack::PopAndDestroy(pBitmap);
}
void CLoad3DS::show3ds(int j0, float tx, float ty, float tz, float size)
{
glPushMatrix();
glDisable(GL_TEXTURE_2D);
glTranslatef(tx, ty, tz);
glScalef(size, size, size);
glRotatef(90, 0, 1.0f, 0);
for (TInt i = 0; i < g_3DModel[j0].numOfObjects; i++)
{
t3DObject* pObject = g_3DModel[j0].pObject[i];
if (pObject->bHasTexture)
{
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,g_Texture[pObject->materialId]);
}
else
glDisable(GL_TEXTURE_2D);
glColor4f(255, 255, 255, 255);
for (TInt j = 0; j < pObject->numOfFaces; j++)
{
for (TInt tex = 0; tex < 3; tex++)
{
TInt index = pObject->pFaces[j].vertIndex[tex];
glNormal3f(pObject->pNormals[index].x,
pObject->pNormals[index].y, pObject->pNormals[index].z); //设置法向量
if (pObject->bHasTexture)
{
if (pObject->pTexVerts)
{
GLubyte texCoord[2];
texCoord[0] = pObject->pTexVerts[index].x;
texCoord[1] = pObject->pTexVerts[index].y;
glTexCoordPointer(2, GL_FLOAT,0, texCoord); //创建纹理
}
}
else
{
if (pObject->materialId >= 0)
{
GLubyte colors[4];
colors[0]
= g_3DModel[j0].pMaterials[pObject->materialId]->color[0];
colors[1]
= g_3DModel[j0].pMaterials[pObject->materialId]->color[1];
colors[2]
= g_3DModel[j0].pMaterials[pObject->materialId]->color[2];
colors[3] = 255;
glColorPointer(4, GL_UNSIGNED_BYTE, 0, colors);
}
}
GLubyte triangles[3];
triangles[0] = pObject->pVerts[index].x;
triangles[1] = pObject->pVerts[index].y;
triangles[2] = pObject->pVerts[index].z;
glDrawElements(GL_TRIANGLES, 1, GL_UNSIGNED_BYTE, triangles);
}
}
}
glEnable(GL_TEXTURE_2D);
glPopMatrix();
}
void CLoad3DS::CleanUp()
{
fs.Close();
delete mCurrentChunk; // 释放当前块
delete mTempChunk; // 释放临时块
}
void CLoad3DS::ReadChunk(tChunk *aChunk)
{
TBuf8<20> tempID;
tempID.Zero();
TBuf8<20> tempLength;
tempLength.Zero();
User::LeaveIfError(mFile.Read(tempID, 2));
aChunk->bytesRead = tempID.Size();
aChunk->ID = tempID[1];
aChunk->ID = aChunk->ID<<8;
aChunk->ID = aChunk->ID + tempID[0];
// aChunk->ID = (tempID[1]&0xFFFF<<8) | tempID[0] & 0xFFFF; //Convert the TBuf8 to TUint16
User::LeaveIfError(mFile.Read(tempLength, 4));
aChunk->bytesRead += tempLength.Size();
aChunk->length = tempLength[3] << 24 | tempLength[2] << 16 | tempLength[1]
<< 8 | tempLength[0] & 0xFFFFFFFF;
}
void CLoad3DS::ReadNextChunk(t3DModel* aModel, tChunk* aPreChunk)
{
t3DObject* newObject = new (ELeave) t3DObject;
tMatInfo* newTexture = new (ELeave) tMatInfo;
TUint version = 0;
HBufC8* buffer1 = HBufC8::NewL(1024);
mCurrentChunk = new tChunk;
TBuf8<10> tempVersion;
while (aPreChunk->bytesRead < aPreChunk->length)
{
ReadChunk(mCurrentChunk);
switch (mCurrentChunk->ID)
{
case VERSION:
tempVersion.Zero();
User::LeaveIfError(mFile.Read(tempVersion,
mCurrentChunk->length - mCurrentChunk->bytesRead));
mCurrentChunk->bytesRead += tempVersion.Size();
version = tempVersion[3] << 24 | tempVersion[2] << 16
| tempVersion[1] << 8 | tempVersion[0] & 0xFFFFFFFF;
if (version > 0x03)
RDebug::Print(
_L("This 3DS file is over version 3 so it may load incorrectly"));
break;
case OBJECTINFO:
tempVersion.Zero();
ReadChunk(mTempChunk);
User::LeaveIfError(mFile.Read(tempVersion, mTempChunk->length
- mTempChunk->bytesRead));
mTempChunk->bytesRead += tempVersion.Size();
version = tempVersion[3] << 24 | tempVersion[2] << 16
| tempVersion[1] << 8 | tempVersion[0] & 0xFFFFFFFF;
mCurrentChunk->bytesRead += mTempChunk->bytesRead;
ReadNextChunk(aModel, mCurrentChunk);
break;
case MATERIAL:
aModel->numOfMaterials++;
aModel->pMaterials.Append(newTexture);
ReadNextMatChunk(aModel, mCurrentChunk);
break;
case OBJECT:
aModel->numOfObjects++;
aModel->pObject.Append(newObject);
mCurrentChunk->bytesRead += GetString(
aModel->pObject[aModel->numOfObjects - 1]->strName);
ReadNextObjChunk(aModel, aModel->pObject[aModel->numOfObjects
- 1], mCurrentChunk);
break;
case EDITKEYFRAME:
TInt temp = mCurrentChunk->length - mCurrentChunk->bytesRead;
TPtr8 temp1 = buffer1->Des();
User::LeaveIfError(mFile.Read(temp1, temp));
mCurrentChunk->bytesRead += temp;
break;
default:
TInt tmplength = mCurrentChunk->length
- mCurrentChunk->bytesRead;
TPtr8 temp2 = buffer1->Des();
User::LeaveIfError(mFile.Read(temp2, tmplength));
mCurrentChunk->bytesRead += tmplength;
break;
}
aPreChunk->bytesRead += mCurrentChunk->bytesRead;
}
delete mCurrentChunk;
mCurrentChunk = aPreChunk;
delete buffer1;
buffer1 = NULL;
}
int CLoad3DS::GetString(TDes8& tBuf)
{
TInt index;
TBuf8<255> buf;
TBuf8<1> buf1;
buf1.Append('/0');
do
{
buf.Zero();
mFile.Read(buf, 1);
tBuf.Append(buf);
}
while (buf[0] != '/0');
index = tBuf.Find(buf1) + 1;
return index;
}
void CLoad3DS::ReadNextObjChunk(t3DModel *aModel, t3DObject *aObject,
tChunk *aPreChunk)
{
TInt i = 0;
HBufC8* buf = HBufC8::NewL(102400);
TPtr8 ptr = buf->Des();
mCurrentChunk = new tChunk;
while (aPreChunk->bytesRead < aPreChunk->length)
{
ReadChunk(mCurrentChunk);
switch (mCurrentChunk->ID)
{
case OBJ_MESH:
ReadNextObjChunk(aModel, aObject, mCurrentChunk);
break;
case OBJ_VERTICES:
ReadVertices(aObject, mCurrentChunk);
break;
case OBJ_FACES:
ReadVertexIndices(aObject, mCurrentChunk);
break;
case OBJ_MATERIAL:
ReadObjMat(aModel, aObject, mCurrentChunk);
break;
case OBJ_UV:
ReadUVCoordinates(aObject, mCurrentChunk);
break;
default:
User::LeaveIfError(mFile.Read(ptr, mCurrentChunk->length
- mCurrentChunk->bytesRead));
mCurrentChunk->bytesRead += mCurrentChunk->length - mCurrentChunk->bytesRead;
ptr.Zero();
break;
}
aPreChunk->bytesRead += mCurrentChunk->bytesRead;
}
delete mCurrentChunk;
mCurrentChunk = aPreChunk;
delete buf;
buf = NULL;
}
void CLoad3DS::ReadNextMatChunk(t3DModel *aModel, tChunk *aPreChunk)
{
TInt i = 0;
HBufC8* buf = HBufC8::NewL(12000);
TPtr8 ptr = buf->Des();
mCurrentChunk = new tChunk;
while (aPreChunk->bytesRead < aPreChunk->length)
{
ReadChunk(mCurrentChunk);
switch (mCurrentChunk->ID)
{
case MATNAME: //如果是材质名称
User::LeaveIfError(
mFile.Read(aModel->pMaterials[aModel->numOfMaterials
- 1]->strName, mCurrentChunk->length
- mCurrentChunk->bytesRead)); //读入材质名称
mCurrentChunk->bytesRead
+= aModel->pMaterials[aModel->numOfMaterials - 1]->strName.Size();
break;
case MATDIFFUSE: //对象的RGB颜色
ReadColor(aModel->pMaterials[aModel->numOfMaterials - 1],
mCurrentChunk);
break;
case MATMAP: //纹理信息的头部
ReadNextMatChunk(aModel, mCurrentChunk); //进入下一个材质块信息
break;
case MATMAPFILE: // 读入材质的文件名称
User::LeaveIfError(
mFile.Read(aModel->pMaterials[aModel->numOfMaterials
- 1]->strFile, mCurrentChunk->length
- mCurrentChunk->bytesRead));
mCurrentChunk->bytesRead
+= aModel->pMaterials[aModel->numOfMaterials - 1]->strFile.Size();
break;
default:
User::LeaveIfError(mFile.Read(ptr, mCurrentChunk->length - mCurrentChunk->bytesRead)); // 掠过不需要读入的块
mCurrentChunk->bytesRead += mCurrentChunk->length - mCurrentChunk->bytesRead;
break;
}
aPreChunk->bytesRead += mCurrentChunk->bytesRead;
}
delete mCurrentChunk;
mCurrentChunk = aPreChunk; // 删除当前块,并将当前块设置为前面的块
delete buf;
buf = NULL;
}
void CLoad3DS::ReadColor(tMatInfo *aMaterial, tChunk *aChunk) //读入RGB颜色
{
ReadChunk(mTempChunk);
User::LeaveIfError(mFile.Read(aMaterial->color, mTempChunk->length
- mTempChunk->bytesRead));
mTempChunk->bytesRead += aMaterial->color.Size();
aChunk->bytesRead += mTempChunk->bytesRead;
}
void CLoad3DS::ReadVertexIndices(t3DObject *aObject, tChunk *aPreChunk) //读入顶点索引
{
TUint16 index = 0; // 用于读入当前面的索引
TBuf8<255> bufIndex;
TBuf8<10> num;
User::LeaveIfError(mFile.Read(num, 2)); // 读入该对象中面的数目
aPreChunk->bytesRead += num.Size();
aObject->numOfFaces = ((num[1] & 0xFFFFFF) << 8) | num[0]& 0xFFFFFFFF;
aObject->pFaces = new tFace[aObject->numOfFaces];
memset(aObject->pFaces, 0, sizeof(tFace) * aObject->numOfFaces); // 分配所有面的存储空间,并初始化结构
for (TInt i = 0; i < aObject->numOfFaces; i++)
{
for (TInt j = 0; j < 4; j++) // 遍历对象中所有的面
{
User::LeaveIfError(mFile.Read(bufIndex, sizeof(index))); // 读入当前面的第一个点
aPreChunk->bytesRead += bufIndex.Size();
// index = ((bufIndex[3] & 0xFFFFFFFF) << 24)
// | ((bufIndex[2] & 0xFFFFFFFF) << 16) | ((bufIndex[1]
// & 0xFFFFFFFF) << 8) | (bufIndex[0] & 0xFFFFFFFF);
index = bufIndex[1]&0xFFFF<<8|bufIndex[0]&0xFFFF;
if (j < 3)
{
aObject->pFaces[i].vertIndex[j] = index;
}
}
}
}
void CLoad3DS::ReadUVCoordinates(t3DObject *aObject, tChunk *aPreChunk) // 读对象的纹理坐标
{
TBuf8<10> texNum;
TBuf8<255> texVert;
HBufC8* buf = HBufC8::NewL(30000);
TPtr8 ptr = buf->Des();
TInt preValue;
TInt tempNum;
TInt structNum;
User::LeaveIfError(mFile.Read(texNum, 2)); //读UV坐标的数量
aPreChunk->bytesRead += texNum.Size();
aObject->numOfTexVertex = ((texNum[1] & 0xFFFFFF) << 8) | texNum[0]& 0xFFFFFFFF;
aObject->pTexVerts = new CVector2[aObject->numOfTexVertex]; //分配保存UV坐标的空间
User::LeaveIfError(mFile.Read(ptr, aPreChunk->length
- aPreChunk->bytesRead)); //读入纹理坐标
preValue = aPreChunk->length - aPreChunk->bytesRead - 1;
tempNum = (aPreChunk->length - aPreChunk->bytesRead) / 4; //记录有多少个值
structNum = tempNum / 3; //记录有多少组顶点
for (TInt i = 1; i < structNum; i++) //对顶点赋值
{
aObject->pTexVerts[i].y = ((ptr[preValue--] & 0xFFFFFFFF) << 24)
| ((ptr[preValue--] & 0xFFFFFFFF) << 16) | ((ptr[preValue--]
& 0xFFFFFFFF) << 8) | (ptr[preValue--] & 0xFFFFFFFF);
aObject->pTexVerts[i].x = ((ptr[preValue--] & 0xFFFFFFFF) << 24)
| ((ptr[preValue--] & 0xFFFFFFFF) << 16) | ((ptr[preValue--]
& 0xFFFFFFFF) << 8) | (ptr[preValue--] & 0xFFFFFFFF);
}
aPreChunk->bytesRead += ptr.Size();
delete buf;
buf = NULL;
}
void CLoad3DS::ReadVertices(t3DObject *aObject, tChunk *aPreChunk) //读对象的顶点
{
TBuf8<10> vertNum;
HBufC8 *vert = HBufC8::NewL(30000);
TPtr8 ptr = vert->Des();
TInt structNum;
TInt preValue = 0;
TInt tempNum;
User::LeaveIfError(mFile.Read(vertNum, 2)); //读入顶点的数目
aPreChunk->bytesRead += vertNum.Size();
aObject->numOfVerts = ((vertNum[1] & 0xFFFFFF) << 8) | vertNum[0]
& 0xFFFFFFFF;
aObject->pVerts = new (ELeave) CVector3[aObject->numOfVerts];
memset(aObject->pVerts, 0, sizeof(CVector3) * aObject->numOfVerts); //为存储顶点分配空间并初始化
User::LeaveIfError(
mFile.Read(ptr, aPreChunk->length - aPreChunk->bytesRead));
tempNum = (aPreChunk->length - aPreChunk->bytesRead) / 4; //记录有多少个值
TInt temp = aPreChunk->length - aPreChunk->bytesRead - 1;
structNum = tempNum / 3; //记录有多少组顶点
aPreChunk->bytesRead += ptr.Size();
for (TInt i = 0; i < structNum; i++) //对顶点赋值
{
aObject->pVerts[i].z = ((ptr[temp--] & 0xFFFFFFFF) << 24)
| ((ptr[temp--] & 0xFFFFFFFF) << 16) | ((ptr[temp--]
& 0xFFFFFFFF) << 8) | (ptr[temp--] & 0xFFFFFFFF);
aObject->pVerts[i].y = ((ptr[temp--] & 0xFFFFFFFF) << 24)
| ((ptr[temp--] & 0xFFFFFFFF) << 16) | ((ptr[temp--]
& 0xFFFFFFFF) << 8) | (ptr[temp--] & 0xFFFFFFFF);
aObject->pVerts[i].x = ((ptr[temp--] & 0xFFFFFFFF) << 24)
| ((ptr[temp--] & 0xFFFFFFFF) << 16) | ((ptr[temp--]
& 0xFFFFFFFF) << 8) | (ptr[temp--] & 0xFFFFFFFF);
}
for (TInt i = 0; i < aObject->numOfVerts; i++) //将y轴和z轴交换并对z轴反向
{
TReal fTempY = aObject->pVerts[i].z;
aObject->pVerts[i].y = aObject->pVerts[i].z;
aObject->pVerts[i].z = -fTempY;
}
delete vert;
vert = NULL;
}
void CLoad3DS::ReadObjMat(t3DModel *aModel, t3DObject *aObject,
tChunk *aPreChunk) //读入对象的材质名称
{
TBuf8<255> strMaterial; //保存对象的材质名称
HBufC8* buf = HBufC8::NewL(12000);
TPtr8 ptr = buf->Des(); //读入不需要的错误
aPreChunk->bytesRead += GetString(strMaterial); // 材质或者是颜色,或者是对象的纹理,也可能保存了象明亮度、发光度等信息。
// 下面读入赋予当前对象的材质名称
for (TInt i = 0; i < aModel->numOfMaterials; i++)
{
if (strMaterial==(aModel->pMaterials[i]->strName)) //如果读入的纹理与当前的纹理名称匹配
{
aObject->materialId = i;
if (aModel->pMaterials[i]->strFile.Length() > 0) // 判断是否是纹理映射,如果strFile是一个长度大于1的字符串,则是纹理
{
aObject->bHasTexture = ETrue;
}
break;
}
else
{
aObject->materialId = -1; //如果该对象没有材质,则设置materialId为-1
}
}
User::LeaveIfError(
mFile.Read(ptr, aPreChunk->length - aPreChunk->bytesRead));
aPreChunk->bytesRead += aPreChunk->length - aPreChunk->bytesRead;
delete buf;
buf = NULL;
}
CVector3 Vector(CVector3 vPoint1, CVector3 vPoint2) //求两点决定的矢量
{
CVector3 vVector;
vVector.x = vPoint1.x - vPoint2.x;
vVector.y = vPoint1.y - vPoint2.y;
vVector.z = vPoint1.z - vPoint2.z;
return vVector;
}
CVector3 AddVector(CVector3 vVector1, CVector3 vVector2) //两个矢量相加
{
CVector3 vResult;
vResult.x = vVector2.x + vVector1.x;
vResult.y = vVector2.y + vVector1.y;
vResult.z = vVector2.z + vVector1.z;
return vResult;
}
CVector3 DivideVectorByScaler(CVector3 vVector1, TReal Scaler) //处理矢量的缩放
{
CVector3 vResult;
vResult.x = vVector1.x / Scaler;
vResult.y = vVector1.y / Scaler;
vResult.z = vVector1.z / Scaler;
return vResult;
}
CVector3 Cross(CVector3 vVector1, CVector3 vVector2) //返回两个矢量的叉积
{
CVector3 vCross;
vCross.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y));
vCross.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z));
vCross.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x));
return vCross;
}
CVector3 Normalize(CVector3 vNormal) // 规范化矢量
{
double Magnitude;
Magnitude = Mag(vNormal); // 获得矢量的长度
vNormal.x /= (float) Magnitude;
vNormal.y /= (float) Magnitude;
vNormal.z /= (float) Magnitude;
return vNormal;
}
void CLoad3DS::ComputeNormals(t3DModel *aModel) //计算对象的法向量
{
CVector3 vVector1, vVector2, vNormal, vPloy[3];
if (aModel->numOfObjects <= 0) //模型中没有对象就返回
return;
for (TInt index = 0; index < aModel->numOfObjects; index++)
{
t3DObject *pObject = aModel->pObject[index]; //获得当前的对象
CVector3 *pNormals = new CVector3[pObject->numOfFaces]; //分配存储空间
CVector3 *pTempNormals = new CVector3[pObject->numOfFaces];
pObject->pNormals = new CVector3[pObject->numOfVerts];
for (TInt i = 0; i < pObject->numOfFaces; i++)
{
vPloy[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]];
vPloy[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]];
vPloy[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]];
vVector1 = Vector(vPloy[0], vPloy[2]); //获得多边形的矢量
vVector2 = Vector(vPloy[2], vPloy[1]); //获得多边形的第二个矢量
vNormal = Cross(vVector1, vVector2); //获得两个矢量的叉积
pTempNormals[i] = vNormal; //保存非规范化向量
vNormal = Normalize(vNormal); //规范化获得的叉积
pNormals[i] = vNormal; //将法向量添加到法向量列表
}
CVector3 vSum =
{
0.0, 0.0, 0.0
};
CVector3 vZero = vSum;
TInt shared = 0;
for (TInt i = 0; i < pObject->numOfVerts; i++)
{
for (TInt j = 0; j < pObject->numOfFaces; j++) //遍历所有三角形面
{
if (pObject->pFaces[j].vertIndex[0] == i
|| pObject->pFaces[j].vertIndex[1] == i
|| pObject->pFaces[j].vertIndex[2] == i)
{
vSum = AddVector(vSum, pTempNormals[j]);
shared++;
}
}
pObject->pNormals[i] = DivideVectorByScaler(vSum, TReal(-shared));
pObject->pNormals[i] = Normalize(pObject->pNormals[i]);
vSum = vZero;
shared = 0;
}
delete pTempNormals;
delete pNormals;
}
}