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