lib3ds 2.0 example 2
cheungmine
2009-2-14
在上一個例子中,展示了基本的lib3ds2.0的使用方法。在本例中,對上面的代碼稍作修改。這樣,無論3ds檔案是否有相機或燈光,都可以顯示了。
思路就是,如果3ds檔案沒有相機,我們就增加4個相機。如果沒有燈光,就增加3個OmniLight。
上面的代碼參考了文章:
《利用lib3ds和OpenGL實現3ds檔案的讀取和顯示---白改朝》---電腦編程技巧與維護2008.7
例子player.c代碼使用了glut32。(下篇文章,我會轉到Windows上實現這個代碼。不使用glut庫。)
本例仍然沒有使用貼圖。希望我的下個例子能把貼圖做出來。
好了,代碼全部貼在下面了。需要的庫仍然可以在網上找到,就不廢話了。
///////////////////////////////////////////////////////////////////////////////<br />// player2.c<br />//<br />// 2009-2-14<br />//<br />// 作者:cheungmine<br />//<br />// 參考:<br />//<br />// http://www.lib3ds.org/lib3ds-1.2.0/examples/player.c<br />//<br />// 目錄結構:<br />//<br />// lib/lib3ds_2.0/src/<br />//debug/lib3ds20d.lib lib3ds20d.dll<br />// release/lib3ds20.lib lib3ds20.dll<br />//<br />// lib/lib3ds_2.0/<br />// glut_test/player.c<br />//<br />// lib/win_opengl32/<br />// inc/gl.h glu.h glut.h<br />// lib/opengl32.lib glu32.lib glut32.lib<br />// bin/opengl32.dll glu32.dll glut32.dll<br />//<br />///////////////////////////////////////////////////////////////////////////////<br />// 記憶體流失檢測<br />// 在需要檢測的地方放置語句:<br />// _CrtDumpMemoryLeaks();<br />// 以下3句的次序不能改變<br />#define _CRTDBG_MAP_ALLOC<br />#include<stdlib.h><br />#include<crtdbg.h></p><p>#include<stdio.h><br />#include<string.h><br />#include<math.h><br />#include<assert.h></p><p>#include <windows.h></p><p>// 使用 USE_SGI_OPENGL 可能在某些機器上運行 wglMakeCurrent 系列函數返回失敗的結果<br />#define GLUT_NO_LIB_PRAGMA</p><p>// #define USE_SGI_OPENGL<br />#ifdef USE_SGI_OPENGL<br />#include "../../sgi-opengl2-sdk/include/gl/gl.h"<br />#include "../../sgi-opengl2-sdk/include/gl/glu.h"<br />#include "../../sgi-opengl2-sdk/include/gl/glut.h"</p><p>#pragma comment(lib, "../../sgi-opengl2-sdk/lib/opengl.lib")<br />#pragma comment(lib, "../../sgi-opengl2-sdk/lib/glu.lib")<br />#pragma comment(lib, "../../sgi-opengl2-sdk/lib/glut.lib")<br />#else<br />#include "../../win-opengl32/inc/GL.h"<br />#include "../../win-opengl32/inc/GLU.h"</p><p>#pragma comment(lib, "../../win-opengl32/lib/OPENGL32.lib")<br />#pragma comment(lib, "../../win-opengl32/lib/GLU32.lib")</p><p>#include "../../win-opengl32/inc/GLUT.h"<br />#pragma comment(lib, "../../win-opengl32/lib/glut32.lib")<br />#endif</p><p>//<br />// lib3ds<br />//<br />#include "../src/lib3ds.h"</p><p>#ifdef _DEBUG<br /># pragma comment(lib, "../src/debug/lib3ds20d.lib")<br />#else<br /># pragma comment(lib, "../src/release/lib3ds20.lib")<br />#endif</p><p>static const char* filename="E://GU2005//LIB//lib3ds_2.0//data//Bf109G6//Bf109G6.3ds";<br />//E://3DS//Spacecraft//Spacecraft.3ds";</p><p>//"E://GU2005//LIB//lib3ds_2.0//data//abom.3ds";<br />//"E:/3DS/House/house.3ds";<br />static Lib3dsFile *model=0;</p><p>static const char* camera=0;<br />static float current_frame=0.0;</p><p>static int gl_width;<br />static int gl_height;</p><p>static int camera_menu_id=0;<br />static int halt=0;</p><p>#ifndef MAX<br /># define MAX(x,y) ((x)>(y)?(x):(y))<br />#endif</p><p>static void camera_menu(int value)<br />{<br />Lib3dsCamera *c=0;<br />int i;</p><p>for( i=0; i<value; i++ ){<br />if (i==model->ncameras)<br />return;<br />c = model->cameras[i];<br />}<br />if (c)<br />camera=c->name;<br />}</p><p>static void render_node(Lib3dsNode *node)<br />{<br />Lib3dsNode*p;<br />Lib3dsMesh*mesh;<br />Lib3dsFace*face;<br />Lib3dsMaterial *mat;<br />Lib3dsMeshInstanceNode *meshData;</p><p>Lib3dsVector*norm_verts;<br />Lib3dsVector*norm_faces;</p><p>int i;<br />unsignedfi;<br />floatM[4][4];</p><p>assert(model);</p><p>// 遞迴<br />for (p=node->childs; p!=0; p=p->next){<br />render_node(p);<br />}</p><p>if (node->type==LIB3DS_NODE_MESH_INSTANCE)<br />{<br />if (strcmp(node->name,"$$$DUMMY")==0) {<br />return;<br />}</p><p>if (!node->user_id)<br />{<br />mesh = lib3ds_file_mesh_for_node(model, node);<br />assert(mesh);<br />if (!mesh) {<br />return;<br />}</p><p>node->user_id = glGenLists(1);<br />glNewList(node->user_id, GL_COMPILE);</p><p>norm_verts = (Lib3dsVector*) malloc(3*sizeof(Lib3dsVector)*mesh->nfaces);<br />norm_faces = (Lib3dsVector*) malloc(sizeof(Lib3dsVector)*mesh->nfaces);</p><p>lib3ds_matrix_copy(M, mesh->matrix);<br />lib3ds_matrix_inv(M);<br />glMultMatrixf(&M[0][0]);</p><p>lib3ds_mesh_calculate_face_normals(mesh, (float (*)[3])norm_faces);<br />lib3ds_mesh_calculate_vertex_normals(mesh, (float (*)[3])norm_verts);</p><p>for (fi=0; fi<mesh->nfaces; ++fi) {<br />face = &(mesh->faces[fi]);<br />mat = 0;</p><p>if (face->material>=0 && face->material<model->nmaterials)<br />mat=model->materials[face->material];</p><p>if (mat)<br />{<br />// 使用材質<br />float s = pow(2, 10.0*mat->shininess);<br />if (s>128.0) s = 128.0f;</p><p>glMaterialfv(GL_FRONT, GL_AMBIENT, mat->ambient);<br />glMaterialfv(GL_FRONT, GL_DIFFUSE, mat->diffuse);<br />glMaterialfv(GL_FRONT, GL_SPECULAR, mat->specular);<br />glMaterialf(GL_FRONT, GL_SHININESS, s);<br />}<br />else {<br />// 使用貼圖<br />float a[]={0.2, 0.2, 0.2, 1.0};<br />float d[]={0.8, 0.8, 0.8, 1.0};<br />float s[]={0.0, 0.0, 0.0, 1.0};<br />glMaterialfv(GL_FRONT, GL_AMBIENT, a);<br />glMaterialfv(GL_FRONT, GL_DIFFUSE, d);<br />glMaterialfv(GL_FRONT, GL_SPECULAR, s);<br />}</p><p>// Draw tri-face<br />glBegin(GL_TRIANGLES);</p><p>glNormal3fv(norm_faces[fi].v);// face normal</p><p>for (i=0; i<3; ++i) {<br />glNormal3fv(norm_verts[3*fi+i].v);// vertex normal<br />glVertex3fv(mesh->vertices[face->index[i]]);<br />}</p><p>glEnd();<br />}</p><p>free(norm_faces);<br />free(norm_verts);</p><p>glEndList();<br />}</p><p>if (node->user_id) {<br />glPushMatrix();<br />meshData = (Lib3dsMeshInstanceNode*) node;</p><p>glMultMatrixf(&node->matrix[0][0]);<br />glTranslatef(-meshData->pivot[0], -meshData->pivot[1], -meshData->pivot[2]);<br />glCallList(node->user_id);</p><p>// glutSolidSphere(50.0, 20,20);<br />glPopMatrix();<br />}<br />}<br />}</p><p>static void display(void)<br />{<br />int i, li;</p><p>Lib3dsNode *nodC, *nodT, *nod;<br />Lib3dsCameraNode *camNode;<br />Lib3dsTargetNode *tgtNode;<br />float M[4][4];</p><p>GLfloat a[] = {0.0f, 0.0f, 0.0f, 1.0f};<br />GLfloat c[] = {1.0f, 1.0f, 1.0f, 1.0f};<br />GLfloat p[] = {0.0f, 0.0f, 0.0f, 1.0f};</p><p>Lib3dsLight *l;</p><p>glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);</p><p>if (!model) {<br />exit(1);<br />}</p><p>nodC=lib3ds_file_node_by_name(model, camera, LIB3DS_NODE_CAMERA);<br />nodT=lib3ds_file_node_by_name(model, camera, LIB3DS_NODE_CAMERA_TARGET);</p><p>if (!nodC || !nodT) {<br />assert(0 && "Camera or Target not found!");<br />exit(1);<br />}</p><p>camNode = (Lib3dsCameraNode*) nodC;<br />tgtNode = (Lib3dsTargetNode*) nodT;</p><p>glMatrixMode(GL_PROJECTION);<br />glLoadIdentity();<br />gluPerspective( camNode->fov, gl_width/gl_height, 0.1f, 6000.0);<br />glMatrixMode(GL_MODELVIEW);<br />glLoadIdentity();<br />glRotatef(-90, 1.0, 0,0);</p><p>li=GL_LIGHT0;</p><p>for (i=0; i<model->nlights; i++)<br />{<br />l = model->lights[i];<br />glEnable(li);</p><p>glLightfv(li, GL_AMBIENT, a);<br />glLightfv(li, GL_DIFFUSE, c);<br />glLightfv(li, GL_SPECULAR, c);// p?</p><p>p[0] = l->position[0];<br />p[1] = l->position[1];<br />p[2] = l->position[2];<br />glLightfv(li, GL_POSITION, p);</p><p>if (!l->spot_light) {<br />continue;<br />}</p><p>p[0] = l->target[0] - l->position[0];<br />p[1] = l->target[1] - l->position[1];<br />p[2] = l->target[2] - l->position[2]; </p><p>glLightfv(li, GL_SPOT_DIRECTION, p);</p><p>++li;<br />}</p><p>lib3ds_matrix_camera(M, camNode->pos, tgtNode->pos, camNode->roll);</p><p>glMultMatrixf(&M[0][0]);</p><p>for (nod=model->nodes; nod!=0; nod=nod->next) {<br />render_node(nod);<br />}</p><p>if (!halt) {<br />current_frame+=1.0;</p><p>if (current_frame>model->frames) {<br />current_frame=0;<br />}</p><p>lib3ds_file_eval(model, current_frame);</p><p>glutSwapBuffers();<br />glutPostRedisplay();<br />}<br />}</p><p>// 增加預設的相機和目標<br />static add_default_cameras (Lib3dsFile *model, Lib3dsBBox *bbox, float sizes[], float center[])<br />{<br />int index=0;<br />Lib3dsCamera *cam;<br />Lib3dsCameraNode *nodCam;</p><p>Lib3dsTargetNode *nodTgt;</p><p>// Camera_X<br />cam = lib3ds_camera_new ("Camera_X");<br />assert(cam);<br />memcpy(cam->target, center, sizeof(Lib3dsVector));<br />memcpy(cam->position, center, sizeof(Lib3dsVector));<br />cam->position[0] = bbox->bmax[0] + 1.5*MAX(sizes[1],sizes[2]);<br />cam->near_range = (cam->position[0] - bbox->bmax[0])/2;<br />cam->far_range = (cam->position[0] - bbox->bmin[0])*2;<br />lib3ds_file_insert_camera(model, cam, index++);<br />nodCam = lib3ds_node_new_camera(cam);<br />assert(nodCam);<br />lib3ds_file_append_node(model, (Lib3dsNode*)nodCam, 0);</p><p>nodTgt = lib3ds_node_new_camera_target(cam);<br />assert(nodTgt);<br />lib3ds_file_append_node(model, (Lib3dsNode*)nodTgt, 0);</p><p>// Camera_Y<br />cam = lib3ds_camera_new ("Camera_Y");<br />assert(cam);<br />memcpy(cam->target, center, sizeof(Lib3dsVector));<br />memcpy(cam->position, center, sizeof(Lib3dsVector));<br />cam->position[1] = bbox->bmin[1] - 1.5*MAX(sizes[0],sizes[2]);<br />cam->near_range = (bbox->bmin[1]-cam->position[1])/2;<br />cam->far_range = (bbox->bmax[1]-cam->position[1])*2;<br />lib3ds_file_insert_camera(model, cam, index++);<br />nodCam = lib3ds_node_new_camera(cam);<br />assert(nodCam);<br />lib3ds_file_append_node(model, (Lib3dsNode*)nodCam, 0);</p><p>nodTgt = lib3ds_node_new_camera_target(cam);<br />assert(nodTgt);<br />lib3ds_file_append_node(model, (Lib3dsNode*)nodTgt, 0);</p><p>// Camera_Z<br />cam = lib3ds_camera_new ("Camera_Z");<br />assert(cam);<br />memcpy(cam->target, center, sizeof(Lib3dsVector));<br />memcpy(cam->position, center, sizeof(Lib3dsVector));<br />cam->position[2] = bbox->bmax[2] + 1.5*MAX(sizes[0],sizes[1]);<br />cam->near_range = (cam->position[2]-bbox->bmax[2])/2;<br />cam->far_range = (cam->position[2]-bbox->bmin[2])*2;<br />lib3ds_file_insert_camera(model, cam, index++);<br />nodCam = lib3ds_node_new_camera(cam);<br />assert(nodCam);<br />lib3ds_file_append_node(model, (Lib3dsNode*)nodCam, 0);</p><p>nodTgt = lib3ds_node_new_camera_target(cam);<br />assert(nodTgt);<br />lib3ds_file_append_node(model, (Lib3dsNode*)nodTgt, 0);</p><p>// Camera_ISO<br />cam = lib3ds_camera_new ("Camera_ISO");<br />assert(cam);<br />memcpy(cam->target, center, sizeof(Lib3dsVector));<br />cam->position[0] = bbox->bmax[0] + 0.75f*sizes[3];<br />cam->position[1] = bbox->bmin[1] - 0.75f*sizes[3];<br />cam->position[2] = bbox->bmax[2] + 0.75f*sizes[3];<br />cam->near_range = (cam->position[0]-bbox->bmax[0])/2;<br />cam->far_range = (cam->position[0]-bbox->bmin[0])*3;<br />lib3ds_file_insert_camera(model, cam, index++);<br />nodCam = lib3ds_node_new_camera(cam);<br />assert(nodCam);<br />lib3ds_file_append_node(model, (Lib3dsNode*)nodCam, 0);</p><p>nodTgt = lib3ds_node_new_camera_target(cam);<br />assert(nodTgt);<br />lib3ds_file_append_node(model, (Lib3dsNode*)nodTgt, 0);<br />}</p><p>// 增加預設的燈光<br />static void add_default_lights (Lib3dsFile *model, Lib3dsBBox *bbox, float sizes[], float center[])<br />{<br />int index=0;<br />Lib3dsOmnilightNode *omniNode;<br />Lib3dsLight*light;</p><p>// light0<br />light = lib3ds_light_new("light0");<br />assert(light);</p><p>light->spot_light = 0;<br />light->see_cone = 0;<br />light->color[0]=light->color[1]=light->color[2]=0.6f;<br />light->position[0]=center[0]+sizes[3]*0.75;<br />light->position[1]=center[1]-sizes[3]*1;<br />light->position[2]=center[2]+sizes[3]*1.5;<br />light->outer_range = 100;<br />light->inner_range = 10;<br />light->multiplier=1;</p><p>lib3ds_file_insert_light(model, light, index++);<br />omniNode = lib3ds_node_new_omnilight(light);<br />assert(omniNode);<br />lib3ds_file_append_node(model, (Lib3dsNode*)omniNode, 0);</p><p>// light1<br />light = lib3ds_light_new("light1");<br />assert(light);</p><p>light->spot_light = 0;<br />light->see_cone = 0;<br />light->color[0]=light->color[1]=light->color[2]=0.3f;<br />light->position[0]=center[0]-sizes[3];<br />light->position[1]=center[1]-sizes[3];<br />light->position[2]=center[2]+sizes[3]*0.75;<br />light->outer_range = 100;<br />light->inner_range = 10;<br />light->multiplier=1;</p><p>lib3ds_file_insert_light(model, light, index++);<br />omniNode = lib3ds_node_new_omnilight(light);<br />assert(omniNode);<br />lib3ds_file_append_node(model, (Lib3dsNode*)omniNode, 0);</p><p>// light2<br />light = lib3ds_light_new("light2");<br />assert(light);</p><p>light->spot_light = 0;<br />light->see_cone = 0;<br />light->color[0]=light->color[1]=light->color[2]=0.3f;<br />light->position[0]=center[0];<br />light->position[1]=center[1]+sizes[3];<br />light->position[2]=center[2]+sizes[3];<br />light->outer_range = 100;<br />light->inner_range = 10;<br />light->multiplier=1;</p><p>lib3ds_file_insert_light(model, light, index++);<br />omniNode = lib3ds_node_new_omnilight(light);<br />assert(omniNode);<br />lib3ds_file_append_node(model, (Lib3dsNode*)omniNode, 0);<br />}</p><p>static void init(void)<br />{<br />int i;<br />float sizes[4];// 模型尺寸座標<br />float center[3];// 模型目標中心座標<br />Lib3dsBBox bbox;// 模型範圍</p><p>glClearColor(0, 0, 0, 1.0);// 背景色<br />glShadeModel(GL_SMOOTH);<br />glEnable(GL_LIGHTING);<br />glEnable(GL_LIGHT0);<br />glDisable(GL_LIGHT1);<br />glDepthFunc(GL_LEQUAL);<br />glEnable(GL_DEPTH_TEST);<br />glEnable(GL_CULL_FACE);<br />glCullFace(GL_BACK);<br />//glDisable(GL_NORMALIZE);<br />//glPolygonOffset(1.0, 2);</p><p>// 開啟模型檔案,讀入模型資料並關閉檔案控制代碼<br />model=lib3ds_file_open(filename);<br />if (!model) {<br />printf("***ERROR*** Loading 3DS file failed.");<br />exit(1);<br />}</p><p>// 讀模數型的包圍盒<br />lib3ds_file_bounding_box_of_nodes (model, 1, 0, 0, bbox.bmin, bbox.bmax, 0);<br />for (i=0; i<3; i++) {<br />sizes[i] = bbox.bmax[i]-bbox.bmin[i];<br />center[i]= (bbox.bmax[i]+bbox.bmin[i])/2;<br />}<br />sizes[3] = MAX(sizes[0],sizes[1]); sizes[3] = MAX(sizes[3],sizes[2]);</p><p>if (!model->cameras) {<br />// 如果3ds Max製作的情境中沒有燈光、相機,就人為地在模型空間的四個角各加入一個<br />add_default_cameras (model, &bbox, sizes, center);<br />add_default_lights (model, &bbox, sizes, center);<br />}</p><p>if (!camera) {<br />camera = model->cameras[0]->name;<br />}</p><p>camera_menu_id = glutCreateMenu(camera_menu);</p><p>for (i=0; i<model->ncameras; i++){<br />glutAddMenuEntry(model->cameras[i]->name, i);<br />}</p><p>glutAttachMenu(0);</p><p>lib3ds_file_eval(model, 0);<br />}</p><p>static void reshape (int nWidth, int nHeight)<br />{<br />gl_width = nWidth;<br />gl_height = (nHeight==0?1:nHeight);<br />glViewport(0, 0, gl_width, gl_height);<br />}</p><p>static void keyboard(unsigned char key, int x, int y)<br />{<br />switch (key) {<br />case 27:<br />exit(0);<br />break;<br />case 'h':<br />halt=!halt;<br />glutPostRedisplay();<br />break;<br />}<br />}</p><p>int main(int argc, char** argv)<br />{<br />glutInit(&argc, argv);</p><p>glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);<br />glutInitWindowSize(640, 480);<br />glutInitWindowPosition(100, 100);<br />glutCreateWindow(argv[0]);</p><p>init();</p><p>glutDisplayFunc(display);<br />glutReshapeFunc(reshape);<br />glutKeyboardFunc(keyboard);<br />glutMainLoop();</p><p>/* Memory leaks detecting */<br />_CrtDumpMemoryLeaks();</p><p>return(0);<br />}
我選了幾個3ds檔案測試,結果如下: