0
点赞
收藏
分享

微信扫一扫

lib3ds 2.0 example 2


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库。)

    本例仍然没有使用贴图。希望我的下个例子能把贴图做出来。

    好了,代码全部贴在下面了。需要的库仍然可以在网上找到,就不废话了。

///
// 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();

/* Memory leaks detecting */
_CrtDumpMemoryLeaks();

return(0);
}

 

我选了几个3ds文件测试,结果如下:

 

 

lib3ds 2.0 example 2_file

 

 

 

 

举报

相关推荐

0 条评论