📄 lesson2.cpp
字号:
// 下面的函数读入对象的材质名称
void CLoad3DS::ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk)
{
char strMaterial[255] = {0}; // 用来保存对象的材质名称
int buffer[50000] = {0}; // 用来读入不需要的数据
// 材质或者是颜色,或者是对象的纹理,也可能保存了象明亮度、发光度等信息。
// 下面读入赋予当前对象的材质名称
pPreviousChunk->bytesRead += GetString(strMaterial);
// 遍历所有的纹理
for(int i = 0; i < pModel->numOfMaterials; i++)
{
//如果读入的纹理与当前的纹理名称匹配
if(strcmp(strMaterial, pModel->pMaterials[i].strName) == 0)
{
// 设置材质ID
pObject->materialID = i;
// 判断是否是纹理映射,如果strFile是一个长度大于1的字符串,则是纹理
if(strlen(pModel->pMaterials[i].strFile) > 0) {
//载入纹理
BuildTexture(pModel->pMaterials[i].strFile, pModel->texture[pObject->materialID]);
// 设置对象的纹理映射标志
pObject->bHasTexture = true;
}
break;
}
else
{
// 如果该对象没有材质,则设置ID为-1
pObject->materialID = -1;
}
}
pPreviousChunk->bytesRead += fread(buffer, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
}
// 下面的这些函数主要用来计算顶点的法向量,顶点的法向量主要用来计算光照
// 下面的宏定义计算一个矢量的长度
#define Mag(Normal) (sqrt(Normal.x*Normal.x + Normal.y*Normal.y + Normal.z*Normal.z))
// 下面的函数求两点决定的矢量
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, float 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 *pModel)
{
CVector3 vVector1, vVector2, vNormal, vPoly[3];
// 如果模型中没有对象,则返回
if(pModel->numOfObjects <= 0)
return;
// 遍历模型中所有的对象
for(int index = 0; index < pModel->numOfObjects; index++)
{
// 获得当前的对象
t3DObject *pObject = &(pModel->pObject[index]);
// 分配需要的存储空间
CVector3 *pNormals = new CVector3 [pObject->numOfFaces];
CVector3 *pTempNormals = new CVector3 [pObject->numOfFaces];
pObject->pNormals = new CVector3 [pObject->numOfVerts];
// 遍历对象的所有面
for(int i=0; i < pObject->numOfFaces; i++)
{
vPoly[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]];
vPoly[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]];
vPoly[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]];
// 计算面的法向量
vVector1 = Vector(vPoly[0], vPoly[2]); // 获得多边形的矢量
vVector2 = Vector(vPoly[2], vPoly[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;
int shared=0;
// 遍历所有的顶点
for (i = 0; i < pObject->numOfVerts; i++)
{
for (int 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, float(-shared));
// 规范化最后的顶点法向
pObject->pNormals[i] = Normalize(pObject->pNormals[i]);
vSum = vZero;
shared = 0;
}
// 释放存储空间,开始下一个对象
delete [] pTempNormals;
delete [] pNormals;
}
}
HDC hDC=NULL; // Private GDI Device Context
HGLRC hRC=NULL; // Permanent Rendering Context
HWND hWnd=NULL; // Holds Our Window Handle
HINSTANCE hInstance; // Holds The Instance Of The Application
bool keys[256]; // Array Used For The Keyboard Routine
bool active=TRUE; // Window Active Flag Set To TRUE By Default
bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default
t3DModel CarModel;
void DrawModel(t3DModel& Model)
{
// 遍历模型中所有的对象
for(int i = 0; i < Model.numOfObjects; i++)
{
// 如果对象的大小小于0,则退出
if(Model.pObject.size() <= 0) break;
// 获得当前显示的对象
t3DObject *pObject = &Model.pObject[i];
// 判断该对象是否有纹理映射
if(pObject->bHasTexture) {
// 打开纹理映射
glEnable(GL_TEXTURE_2D);
glColor3ub(255, 255, 255);
glBindTexture(GL_TEXTURE_2D, Model.texture[pObject->materialID]);
} else {
// 关闭纹理映射
glDisable(GL_TEXTURE_2D);
glColor3ub(255, 255, 255);
}
// 开始以g_ViewMode模式绘制
glBegin(GL_TRIANGLES);
// 遍历所有的面
for(int j = 0; j < pObject->numOfFaces; j++)
{
// 遍历三角形的所有点
for(int whichVertex = 0; whichVertex < 3; whichVertex++)
{
// 获得面对每个点的索引
int index = pObject->pFaces[j].vertIndex[whichVertex];
// 给出法向量
glNormal3f(pObject->pNormals[ index ].x, pObject->pNormals[ index ].y, pObject->pNormals[ index ].z);
// 如果对象具有纹理
if(pObject->bHasTexture) {
// 确定是否有UVW纹理坐标
if(pObject->pTexVerts) {
glTexCoord2f(pObject->pTexVerts[ index ].x, pObject->pTexVerts[ index ].y);
}
} else {
if(Model.pMaterials.size() && pObject->materialID >= 0)
{
BYTE *pColor = Model.pMaterials[pObject->materialID].color;
glColor3ub(pColor[0], pColor[1], pColor[2]);
}
}
glVertex3f(pObject->pVerts[ index ].x, pObject->pVerts[ index ].y, pObject->pVerts[ index ].z);
}
}
glEnd(); // 绘制结束
}
}
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
{
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
// Calculate The Aspect Ratio Of The Window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,6000.0f);
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // Enables Depth Testing
glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
CLoad3DS *loader=NULL;
loader=new(CLoad3DS);
loader->Import3DS(&CarModel, "Bf109G6.3DS");
GLfloat LightAmbient[]= { 0.8f, 0.8f, 0.8f, 1.0f };
GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat LightPosition[]= { 0.0f, 0.0f, -500.0f, 1.0f };
glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);
glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);
glEnable(GL_LIGHT1);
glEnable(GL_LIGHTING);
delete loader;
return TRUE; // Initialization Went OK
}
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glLoadIdentity(); // Reset The Current Modelview Matrix
gluLookAt(0, 0, -10, 0, 0, 0, 0, 1, 0);
static float ax=0.0f;
static float ay=0.0f;
static float az=0.0f;
glPushMatrix();
glRotatef(ax, 1.0f, 0.0f, 0.0f);
glRotatef(ay, 0.0f, 1.0f, 0.0f);
glRotatef(az, 0.0f, 0.0f, 1.0f);
DrawModel(CarModel);
glPopMatrix();
ax+=1.0f;
ay+=0.50f;
az+=1.10f;
return TRUE; // Keep Going
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -