|
|

楼主 |
发表于 2007-8-21 08:01:00
|
显示全部楼层
Re: Re:救命:简单地形渲染时的一个问题
snhun: Re:救命:简单地形渲染时的一个问题
1.图片太小,看不清细节。
2.没有渲染部分的代码。
所以,很难判断。
//源代码:
#include <windows.h>
#include <stdio.h>
#include <gl/gl.h>
#include <gl/glut.h>
#include <gl/glaux.h>
#include <time.h>
#pragma comment(lib, "glaux.lib")
#define SIZE 128
#define TILE_SIZE 5
struct HEIGHT_REGION
{
int low_height;
int optimal_height;
int high_height;
};
//|----|----|----|----|----|
class CTerrain
{
private:
UCHAR heightmap[SIZE * SIZE];
float smooth_filter;
HEIGHT_REGION regions[4];
GLuint texture;
private:
void FilterBand(float *band, int stride, int count, float filter);
void Smooth(float *heightmap);
public:
CTerrain()
{
}
~CTerrain()
{
}
int Initialize();
int GenerateFaultFormation(int num_iterations, float height, float height_reducer);
int GenerateMidPoint(float height, float height_reducer);
void Render();
void GenTexture();
void Output()
{
for (int i=0; i<SIZE/4; i++)
for (int j=0; j<SIZE/4; j++)
printf("%3d ", heightmap[i*SIZE + j]);
}
};
int CTerrain::Initialize()
{
int i, j;
smooth_filter = 0.3f;
for (i=0; i<SIZE; i++)
for (j=0; j<SIZE; j++)
{
heightmap[i * SIZE + j] = 0;
}
//初始化高度区域
int half_height_range = 255 / 4;
for (int i=0; i<4; i++)
{
regions.low_height = i * half_height_range;
regions.optimal_height = regions.low_height + half_height_range;
regions.high_height = regions.optimal_height + half_height_range;
printf("region %d : %d, %d, %d\n",i, regions.low_height, regions.optimal_height, regions.high_height);
}
return 1;
}
void CTerrain::FilterBand(float *band, int stride, int count, float filter)
{
float v = band[0];
int j = stride;
for (int i = 1; i < count; i++)
{
band[j] = filter * v + (1 - filter) * band[j];
v = band[j];
j += stride;
}
}
void CTerrain::Smooth(float *heightmap)
{
int i;
for (i=0; i<SIZE; i++)
FilterBand(&heightmap[i * SIZE], 1, SIZE, smooth_filter);
for (i=0; i<SIZE; i++)
FilterBand(&heightmap[i * SIZE + SIZE -1], -1, SIZE, smooth_filter);
for (i=0; i<SIZE; i++)
FilterBand(&heightmap, SIZE, SIZE, smooth_filter);
for (i=0; i<SIZE; i++)
FilterBand(&heightmap[(SIZE-1) * SIZE + i], -SIZE, SIZE, smooth_filter);
}
int CTerrain::GenerateFaultFormation(int num_iterations, float height, float height_reducer)
{
int curr_iteration = 0;
int x1, z1, x2, z2;
int dir_x1, dir_z1, dir_x2, dir_z2;
int i, j;
float *temp_buffer = new float[SIZE * SIZE];
for (i=0; i<SIZE*SIZE; i++)
temp_buffer = 0.0f;
for (; curr_iteration < num_iterations; curr_iteration++)
{
do
{
x1 = rand()%SIZE;
z1 = rand()%SIZE;
x2 = rand()%SIZE;
z2 = rand()%SIZE;
}while (x1 == x2 && z1 == z2);
dir_x1 = x2 - x1;
dir_z1 = z2 - z1;
for (i=0; i<SIZE; i++)
for (j=0; j<SIZE; j++)
{
dir_x2 = j - x1;
dir_z2 = i - z1;
if (dir_x1 * dir_z2 - dir_z1 * dir_x2 > 0)
temp_buffer[i*SIZE + j] += height;
}
height *= height_reducer;
Smooth(temp_buffer); //在这里平滑
}
//filter to 0~255
float max_height, min_height, height_range;
max_height = min_height = temp_buffer[0];
for (i=0; i<SIZE * SIZE; i++)
{
if (temp_buffer > max_height)
max_height = temp_buffer;
else
if (temp_buffer < min_height)
min_height = temp_buffer;
}
height_range = max_height - min_height;
for (i=0; i<SIZE * SIZE; i++)
{
heightmap = (UCHAR)((temp_buffer - min_height) * 255.0f / height_range);
}
delete[] temp_buffer;
return 1;
}
int CTerrain::GenerateMidPoint(float height, float height_reducer)
{
int i, j, index;
int rect_size = SIZE;
float *temp_buffer = new float[SIZE * SIZE];
for (i=0; i<SIZE*SIZE; i++)
temp_buffer = 0.0f;
while (rect_size > 0)
{
for (i=0; i<SIZE; i+=rect_size)
for (j=0; j<SIZE; j+=rect_size)
{
index = i * rect_size * SIZE + j * rect_size;
if (index > 0 && index < SIZE * SIZE)
temp_buffer[index] = (temp_buffer[index-rect_size] + temp_buffer[index+rect_size] + temp_buffer[index - SIZE*rect_size] + temp_buffer[index+SIZE*rect_size]) * 0.25 - height + rand()%((int)(height*2.0f));
}
Smooth(temp_buffer);
height *= height_reducer;
rect_size /= 2;
}
float max_height, min_height, height_range;
max_height = min_height = temp_buffer[0];
for (i=0; i<SIZE * SIZE; i++)
{
if (temp_buffer > max_height)
max_height = temp_buffer;
else
if (temp_buffer < min_height)
min_height = temp_buffer;
}
height_range = max_height - min_height;
for (i=0; i<SIZE * SIZE; i++)
{
heightmap = (UCHAR)((temp_buffer - min_height) * 255.0f / height_range);
}
delete[] temp_buffer;
return 1;
}
void CTerrain::Render()
{
glPushMatrix();
glTranslatef(-SIZE*TILE_SIZE*0.5f, 0, -SIZE*TILE_SIZE*0.5f);
int i, j;
UCHAR color;
glColor3f(1.0f, 1.0f, 1.0f);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
for (i=0; i<SIZE-1; i++)
{
glBegin(GL_TRIANGLE_STRIP);
for (j=0; j<SIZE-1; j++)
{
color = heightmap[i * SIZE + j];
// glColor3ub(color, color, color);
glTexCoord2f((float)j / (float)SIZE, (float)i / (float)SIZE);
glVertex3f(j * TILE_SIZE, color, i * TILE_SIZE);
color = heightmap[i * SIZE + j + SIZE];
// glColor3ub(color, color, color);
glTexCoord2f((float)j / (float)SIZE, (float)(i+1) / (float)SIZE);
glVertex3f(j * TILE_SIZE, color, i * TILE_SIZE + TILE_SIZE);
}
glEnd();
}
glPopMatrix();
}
void CTerrain::GenTexture()
{
float u_ratio, v_ratio;
AUX_RGBImageRec *image[4];
image[0] = auxDIBImageLoad("lowestTile.bmp");
image[1] = auxDIBImageLoad("lowTile.bmp");
image[2] = auxDIBImageLoad("highTile.bmp");
image[3] = auxDIBImageLoad("highestTile.bmp");
int i, j, curr_tile, index;
int height;
float presence;
UCHAR data[SIZE * SIZE * 3] = {0};
float half_height = 255.0f / 4.0f;
for (i=0; i<SIZE; i++)
for (j=0; j<SIZE; j++)
{
index = i * SIZE + j;
height = heightmap[index];
for (curr_tile=0; curr_tile < 4; curr_tile++)
{
if (height > regions[curr_tile].low_height && height < regions[curr_tile].high_height)
{
if (height < regions[curr_tile].optimal_height)
presence = (float)(height - regions[curr_tile].low_height) / half_height;
else
presence = (float)(regions[curr_tile].high_height - height) / half_height;
data[index * 3 + 0] += image[curr_tile]->data[index * 3 + 0] * presence;
data[index * 3 + 1] += image[curr_tile]->data[index * 3 + 1] * presence;
data[index * 3 + 2] += image[curr_tile]->data[index * 3 + 2] * presence;
// printf("(%2d, %2d, %2d, %2d, %.2f) ", regions[curr_tile].low_height, regions[curr_tile].optimal_height, regions[curr_tile].high_height, height, presence);
}
}
// printf("(%3d %3d %3d)", data[index * 3 + 0], data[index * 3 + 1], data[index * 3 + 2]);
}
for (curr_tile = 0; curr_tile < 4; curr_tile ++)
{
if (image[curr_tile]->data)
free(image[curr_tile]->data);
}
//gen texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
}
//main.cpp
CTerrain terrain;
void init()
{
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glEnable(GL_DEPTH_TEST);
glClearDepth(1.0f);
glDepthFunc(GL_LEQUAL);
// glEnable(GL_CULL_FACE);
glDisable(GL_CULL_FACE);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
glShadeModel(GL_SMOOTH);
srand(time(NULL));
terrain.Initialize();
terrain.GenerateFaultFormation(32, 128, 0.95f);
// terrain.GenerateMidPoint(64, 0.9f);
terrain.GenTexture();
// terrain.Output();
}
void reshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(90, 1.0f, 0.0f, 1000.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0.0f, 400.0f, 500.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f);
}
void display()
{
int time_counter = GetTickCount();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static float rot = 0.0f;
rot += 5.0f;
if (rot > 360.0f)
rot -= 360.0f;
glPushMatrix();
glRotatef(rot, 0.0f, 1.0f, 0.0f);
terrain.Render();
glPopMatrix();
glutSwapBuffers();
while (GetTickCount() - time_counter < 33);
glutPostRedisplay();
}
void keyboard(int key, int mousex, int mousey)
{
switch (key)
{
case GLUT_KEY_UP:
terrain.GenerateFaultFormation(32, 128, 0.9f);
break;
}
}
void main()
{
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutCreateWindow("Frac terrain generation");
glutReshapeFunc(reshape);
glutDisplayFunc(display);
glutSpecialFunc(keyboard);
init();
glutMainLoop();
}
|
|