|
|
最简单的地形实现方法:
我是一个OPENGL初学者,最近使用画三角形的方法(GL_TRIANGLE)实现了一个简单地形的构造.效果比较差.与初学者一起分享.
#include "math.h"
#define W 100 //地图X方向上正方形的个数(两个相邻的三角形组成一个正方形)
#define L 100 //地图Z方向上正方形的个数
#define dis 4.0f //正方形的边长
GLuint ground;
//用来加载纹理图片
GLuint LoadGLTexture(char* filename)
{
GLuint intexture=0;
AUX_RGBImageRec *pic = NULL;
pic = auxDIBImageLoad(filename);
if(pic == NULL)
return false;
glGenTextures(1,&intexture);
glBindTexture (GL_TEXTURE_2D,intexture);
gluBuild2DMipmaps(GL_TEXTURE_2D,4, pic->sizeX,
pic->sizeY,GL_RGB,GL_UNSIGNED_BYTE,pic->data);
free(pic->data);
free(pic);
return intexture;
}
struct PIXEL//顶点结构
{
float x;
float y;
float z;
};
PIXEL map[W][L];
//初始化地形的每个顶点坐标
VOID InitMap()
{
ground=LoadGLTexture("bb.bmp");//加载纹理图片,可自己选择一个24bit的正方形bmp图片
for(int x=0;x<W;x++)
for(int z=0;z<L;z++)
{
map[x][z].x=dis*(float)x;
map[x][z].z=dis*(float)z;
map[x][z].y=rand()%200*0.01f;//顶点的高度随机产生,范围在0.0f---2.0f之间
}
}
//该函数计算由p1,p2,p3三个点组成的三角形面的法向量
float* CNormal(PIXEL p1,PIXEL p2,PIXEL p3)
{
PIXEL v1,v2 IXEL n;
float normal[4];
v1.x=p2.x-p1.x;
v1.y=p2.y-p1.y;
v1.z=p2.z-p1.z;
v2.x=p3.x-p1.x;
v2.y=p3.y-p1.y;
v2.z=p3.z-p1.z;
n.x=v1.y*v2.z-v1.z*v2.y;
n.y=v1.z*v2.x-v1.x*v2.z;
n.z=v1.x*v2.y-v1.y*v2.x;
double l=sqrt(n.x*n.x+n.y*n.y+n.z*n.z);
if(l!=0.0)
{
n.x=n.x/l;
n.y=n.y/l;
n.z=n.z/l;
}
else
{
n.x=0.0;
n.y=0.0;
n.z=1.0;
}
normal[0]=-n.x;
normal[1]=-n.y;
normal[2]=-n.z;
normal[3]=0.0f;
return normal;
}
//渲染地形
void Draw()
{
PIXEL p1,p2,p3;
float* n;
glBindTexture(GL_TEXTURE_2D,ground);
glBegin(GL_TRIANGLES);
for(int x=0;x<W-1;x++)
for(int z=0;z<L-1;z++)
{
//设置三角形A的法向
p1.x=map[x][z].x;
p1.y=map[x][z].y;
p1.z=map[x][z].z;
p2.x=map[x+1][z].x;
p2.y=map[x+1][z].y;
p2.z=map[x+1][z].z;
p3.x=map[x][z+1].x;
p3.y=map[x][z+1].y;
p3.z=map[x][z+1].z;
n=CNormal(p1,p2,p3);
glNormal3fv(n);
//绘制三角形A
glTexCoord2f(0.0f, 0.0f);
glVertex3f(map[x][z].x,map[x][z].y,map[x][z].z);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(map[x+1][z].x,map[x+1][z].y,map[x+1][z].z);
glTexCoord2f(0.0f, 1.0f);
glVertex3f(map[x][z+1].x,map[x][z+1].y,map[x][z+1].z);
//设置三角形B的法向
p1.x=map[x][z+1].x;
p1.y=map[x][z+1].y;
p1.z=map[x][z+1].z;
p2.x=map[x+1][z].x;
p2.y=map[x+1][z].y;
p2.z=map[x+1][z].z;
p3.x=map[x+1][z+1].x;
p3.y=map[x+1][z+1].y;
p3.z=map[x+1][z+1].z;
n=CNormal(p1,p2,p3);
glNormal3fv(n);
//绘制三角形B
glTexCoord2f(0.0f, 1.0f);
glVertex3f(map[x][z+1].x,map[x][z+1].y,map[x][z+1].z);
glTexCoord2f(1.0f, 0.0f);
glVertex3f(map[x+1][z].x,map[x+1][z].y,map[x+1][z].z);
glTexCoord2f(1.0f, 1.0f);
glVertex3f(map[x+1][z+1].x,map[x+1][z+1].y,map[x+1][z+1].z);
}
//三角形A和B是相邻的两个三角形,它们组成了一个正方形.该地形就是由100*100个这样的正方形组成的.
glEnd();
}
说明:
InitMap()函数在OPENGL程序的初始化函数(一般名为Init().)调用.以初始化地形坐标.
Draw()在OPENGL的渲染函数(一般名为Render().)里调用.
由于CNormal()计算了每个三角面的法向,所以可以打开并设置光照,效果会很明显.
该代码在Nehe教程的OPENGL应用程序框架里运行后效果如下图:
|
-
|