游戏开发论坛

 找回密码
 立即注册
搜索
查看: 5823|回复: 9

最简单的地形实现方法

[复制链接]

9

主题

29

帖子

35

积分

注册会员

Rank: 2

积分
35
发表于 2005-8-7 13:57:00 | 显示全部楼层 |阅读模式
最简单的地形实现方法:

我是一个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,v2IXEL 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应用程序框架里运行后效果如下图:



sf_20058713572.jpg

44

主题

248

帖子

274

积分

中级会员

Rank: 3Rank: 3

积分
274
发表于 2005-8-7 22:56:00 | 显示全部楼层

Re:最简单的地形实现方法

不慢么

9

主题

29

帖子

35

积分

注册会员

Rank: 2

积分
35
 楼主| 发表于 2005-8-8 08:40:00 | 显示全部楼层

Re:最简单的地形实现方法

20000个三角形时速度还好,超过45000个时速度下降的厉害.的确地形过渡很尖,如何过渡的光滑一点.perlin noise是什么方法.想问一下如何判断可见区和非可见区以便裁减.

44

主题

248

帖子

274

积分

中级会员

Rank: 3Rank: 3

积分
274
发表于 2005-8-9 11:00:00 | 显示全部楼层

Re:最简单的地形实现方法

四个相邻的小方块的法线取平均值,可以平滑一些

6

主题

116

帖子

116

积分

注册会员

Rank: 2

积分
116
发表于 2005-8-9 18:27:00 | 显示全部楼层

Re:最简单的地形实现方法

我想学D3D

197

主题

1041

帖子

1104

积分

金牌会员

Rank: 6Rank: 6

积分
1104
QQ
发表于 2005-8-11 03:13:00 | 显示全部楼层

Re: Re:最简单的地形实现方法

azureyes: Re:最简单的地形实现方法

perlin noise 就是photoshop中生成"分层云彩"的算法.

http://www.azure.com.cn/article.asp?i...


黑白云层的地形算法~用在editor之类里面或许有用~~拿来生成random地图用~~如果是realtime的游戏系统~~还是做个地形扫描光栅最实在~



Re:最简单的地形实现方法



四个相邻的小方块的法线取平均值,可以平滑一些

感觉平滑只取周围四相邻是不够的~这样会过于平凡的使用if等等语句~~if过于平凡会影响性能~光栅稍描是最理想的平滑算法~

9

主题

29

帖子

35

积分

注册会员

Rank: 2

积分
35
 楼主| 发表于 2005-8-11 15:20:00 | 显示全部楼层

Re:最简单的地形实现方法

发现不用perlin noise随便找个位图读每点的像素的RGB,然后将R+B+G作为地形高度也可.我可以尽量将位图颜色过渡做的平缓些,出来的地形还是尖锐.

int GetPixelHeight(HWND hWnd,HDC hdc,int X,int Y)  //返回位图上点(X,Y)的R+G+B值
{


int size;
BYTE* p;
struct TYPE
{
int r;
int g;
int b;
};

TYPE data[64][64];
HDC hdcMem;
HBITMAP hBitmap;
BITMAP bitmap;

hdc=GetDC(hWnd);
hdcMem = CreateCompatibleDC (hdc) ;
hBitmap =(HBITMAP):oadImage(NULL,"cc.bmp",IMAGE_BITMAP,64,64,LR_LOADFROMFILE);//读一个位图文件
GetObject(hBitmap, sizeof (BITMAP),&bitmap) ;
SelectObject (hdcMem, hBitmap) ;

size=bitmap.bmHeight*bitmap.bmWidthBytes;
p=(BYTE*)GlobalAlloc(GPTR,size);
GetBitmapBits(hBitmap,size,(LPVOID*)p);


for(int x=0;x<bitmap.bmWidth;x++)
for(int y=0;y<bitmap.bmHeight;y++)
{
data[x][y].b=(int)p[x*bitmap.bmBitsPixel/8+y*bitmap.bmWidthBytes];
data[x][y].g=(int)p[x*bitmap.bmBitsPixel/8+y*bitmap.bmWidthBytes+1];
data[x][y].r=(int)p[x*bitmap.bmBitsPixel/8+y*bitmap.bmWidthBytes+2];
}

int a,b,c;
a=data[X][Y].b;
b=data[X][Y].r;
c=data[X][Y].g;

ReleaseDC(hWnd,hdcMem);
DeleteObject(hBitmap);
return a+b+c;

}

9

主题

29

帖子

35

积分

注册会员

Rank: 2

积分
35
 楼主| 发表于 2005-8-12 09:50:00 | 显示全部楼层

Re: 最简单的地形实现方法

谢谢了,我用你的perlin noise实现的地形很平滑,但速度有点慢,75Hz的刷新下帧速为30.如何提高速度呢.下面是附图.

sf_200581294930.jpg

9

主题

29

帖子

35

积分

注册会员

Rank: 2

积分
35
 楼主| 发表于 2005-8-13 01:17:00 | 显示全部楼层

Re:最简单的地形实现方法

研究了你的代码,总结了一下perlin noise产生地形高度的几个函数:



float persistence = 0.45f;
int Number_Of_Octaves = 3;


//一个噪声发生器
float Noise1(int x, int y)
{
  x = x % 25;
  y = y % 25;
  int n = x + y * 57;
  n = (n<<13) ^ n;
  return ( 1.0f - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
}

//一个光滑噪声发生器
float SmoothNoise_1(int x, int y)
{
    float corners = ( Noise1(x-1, y-1)+Noise1(x+1, y-1)+Noise1(x-1, y+1)+Noise1(x+1, y+1) ) / 16.0f;
    float sides   = ( Noise1(x-1, y)  +Noise1(x+1, y)  +Noise1(x, y-1)  +Noise1(x, y+1) ) /  8.0f;
    float center  =  Noise1(x, y) / 4.0f;
    return corners + sides + center;
}

//插值函数
float Cosine_Interpolate(float a, float b, float x)
{
        double ft = x * 3.1415927;
        double f = (1 - cos(ft)) * 0.5f;

        return  (float)(a*(1-f) + b*f);

}



//插值噪声发生器
float InterpolatedNoise_1(float x, float y)
{

      int integer_X    = int(x);
      float fractional_X = x - integer_X;

      int integer_Y    = int(y);
      float fractional_Y = y - integer_Y;

      float v1 = SmoothNoise_1(integer_X,     integer_Y);
      float v2 = SmoothNoise_1(integer_X + 1, integer_Y);
      float v3 = SmoothNoise_1(integer_X,     integer_Y + 1);
      float v4 = SmoothNoise_1(integer_X + 1, integer_Y + 1);

      float i1 = Cosine_Interpolate(v1 , v2 , fractional_X);
      float i2 = Cosine_Interpolate(v3 , v4 , fractional_X);

      return Cosine_Interpolate(i1 , i2 , fractional_Y);
}


//最终的PERLIN NOISE
float PerlinNoise_2D(float x, float y)
{
      float total = 0.0f;
      float p = persistence;
      int n = Number_Of_Octaves - 1;

      for(int i=0;i<=n;i++)
          {
          float frequency = (float)pow((float)2,i);
          float amplitude = (float)pow(p,i);

          total = total + InterpolatedNoise_1(x * frequency, y * frequency) * amplitude;
      }

      return total;
}


地形高度用float PerlinNoise_2D(float x, float y)来产生即可实现平滑过渡.


//初始化地形的每个顶点坐标
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=PerlinNoise_2D(x,z);
}

}
另外测试了一下,我的程序里影响帧速的不是大量的数学运算也不是光照及贴图,而是渲染三角形的函数glVertex3f();发现该函数主导了帧速.求如何能提高渲染三角形的速度.

2

主题

85

帖子

85

积分

注册会员

Rank: 2

积分
85
发表于 2005-8-13 20:28:00 | 显示全部楼层

Re:最简单的地形实现方法

LOD algorithm is required if you want to gain a acceptable fps.

you can refer to my geomorphing based CLOD algorithm, which eliminates bumpping out problem in traditional LOD algorithms.

http://blog.gameres.com/upload/sf_2005423124451.rar
this is the original version (built with d3d9 debug runtime because of my carelessness) and  will have documents added if i have time.

sorry i have some problem with the browser which would crash if i ever tried to type chinese.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-12-27 10:17

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表