当前位置: 首页 > 知识库问答 >
问题:

在OpenGL中利用等离子体分形生成地形

阎俊英
2023-03-14

我想用等离子体分形生成随机地形。我在网上浏览,想找到一个解决方案,可以帮助我在我的特殊问题,但没有找到任何东西。事实上,我生成了简单的等离子体分形,它看起来像这样:

下面是分形的图片:

分形是不完美的,因为有看到的正方形,但我的老师接受。生成这种分形的算法是,给定一个输入正方形,我通过在每一个正方形边的中间插入四个点,然后在中心插入一个点,将它分割成更小的正方形,从而创建4个新的正方形。每一个新生成的顶点都有其颜色值,它是一个范围为[0,255]的浮点,该浮点使用特殊的公式进行计数。我现在有一个任务,使用这个分形生成随机地形,并且知道每个点的高度与计数的颜色值成正比。我的问题是,我试图用生成的方块角坐标来绘制四边形,但我的四边形并不相连(有些地方,两个四边形边缘的高度如此不同,以至于它们之间出现了一个间隙)。

下面是我的地形图:

下面是我生成这个地形的代码:

#include <iostream>
#include "glut\glut.h"
#include <stdlib.h>
#include <vector>
#include <algorithm>
#include <fstream>

int window_width = 600, window_height = 600;
typedef float point2d[2]; 
struct vertex;
struct square;
std::vector<square> sq; // generated squares

// represents the vertex in 2 D 
struct vertex
{
    point2d pos;
    float c;
};

// represents square in 2D
struct square
{
    square() {}
    square(vertex x, vertex y, vertex z, vertex w) : a(x), b(y), c(z), d(w)
    {
        this->x = abs(y.pos[0] - x.pos[0]);
    }
    vertex a, b, c, d;
    float x; // length of the side of the square
};
// deklaracje funkcji glut:
void display_scene();
void reshape(GLsizei width, GLsizei height);
void key_pressed(unsigned char key, int x, int y);

// helper function used when counting color of
// newly generated verticle (point)
float W(float x)
{
    return (-1.0 / window_width)*x + (float)(1.0 / 2.0);
}

// the same as above but for middle point 
float Wc(float x)
{
    return ((-1.0 / 1200.0f)*x + (float)(1.0 / 2.0)) / 2;
}

// converts value of range [0.0, 255.0] to 
// the numeber of range [0.0, 1.0]
float rgb_to_float(float rgb)
{
    return (1.0f / 255.0f) * rgb;
}

// gets color for a vertex based on the newly created 
// square's side length x
float get_color(float c1, float c2, float x)
{
    int c_prim = (rand() % 256); // draw any number of range [0, 255]
    float w = W(x); // count helper function for given side length
    return (1 - 2 * w) * c_prim + c1*w + c2 * w; // color is the result of such equation
}

// similarly for the center point 
float get_middle_color(float c1, float c2, float c3, float c4, float x)
{
    int c_prim = rand() % 256;
    float w = Wc(x);

    return (1 - 4 * w)*c_prim + w*c1 + w*c2 + w*c3 + w*c4;
}

// each time the function is invoked five new points 
// are counted by which the current square is divided
// so that 4 new squares are created. Four points are
// in the middle length of the side of the square that is
// currently processed and the fifth is in the center of it
// and that brings 4 new squares. The action is repeated for 
// each square in the input vector sq. 
std::vector<square> divide_square(std::vector<square> sq)
{
    vertex c12, c23, c34, c41, cc; // newly generated points
    std::vector<square> new_squares; // newly created squares go there
    float x = sq[0].x / 2; // length of new squares is half of the length of the original one
    // for each square in input vector do the dividing operation
    for (int i = 0; i < sq.size(); i++)
    {
        // initializing new vertices on the sides of old square
        c12.pos[0] = sq[i].a.pos[0] + x; c12.pos[1] = sq[i].a.pos[1];
        c23.pos[0] = sq[i].b.pos[0]; c23.pos[1] = sq[i].b.pos[1] + x;
        c34.pos[0] = sq[i].d.pos[0] + x; c34.pos[1] = sq[i].d.pos[1];
        c41.pos[0] = sq[i].a.pos[0]; c41.pos[1] = sq[i].a.pos[1] + x;
        // ... and the center one:
        cc.pos[0] = c12.pos[0]; cc.pos[1] = c23.pos[1];
        // counting color based on above formulas
        c12.c = get_color(sq[i].a.c, sq[i].b.c, x); c23.c = get_color(sq[i].b.c, sq[i].c.c, x);
        c34.c = get_color(sq[i].c.c, sq[i].d.c, x); c41.c = get_color(sq[i].a.c, sq[i].d.c, x);
        cc.c = get_middle_color(sq[i].a.c, sq[i].b.c, sq[i].c.c, sq[i].d.c, x);
        // generating and adding four newly generated squares to the container of squares for further processing 
        square s1(sq[i].a, c12, cc, c41);
        square s2(c12, sq[i].b, c23, cc);
        square s3(cc, c23, sq[i].c, c34);
        square s4(c41, cc, c34, sq[i].d);
        new_squares.push_back(s1); new_squares.push_back(s2);
        new_squares.push_back(s3); new_squares.push_back(s4);
    }
    return new_squares;
}

// dynamic two-dimensional array representing matrix for storing all
// generated squares (this array should be ordered 
// in such way that each row "i" contains 256 squares
// which A vertex has Y coordinate equal to "i"
// for instance Map[3][0] should represent the first
// square which has A corner vertex coordinates like (0, 3)
square **Map = new square*[256];

// performing the dividing mechanism and filling up the 
// Map matrix
void foo()
{
    vertex a, b, c, d; // vertices of the entering square of size 256x256
    a.pos[0] = 0.0f; a.pos[1] = 0.0f;
    b.pos[0] = 256.0f; b.pos[1] = 0.0f;
    c.pos[0] = 256.0f; c.pos[1] = 256.0f;
    d.pos[0] = 0.0f; d.pos[1] = 256.0f;
    a.c = 0.5f; b.c = 0.5f; c.c = 0.5f; d.c = 0.5f;
    sq.push_back(square(a, b, c, d)); // adding it as the first the square to the container
    // while generated smaller squares have the x length more than 1.0 divide them on smaller ones
    while (sq[0].x > 1.0f)
    {
        sq = divide_square(sq);
    }
    int tempor = 0; // helper for iterating columns of Map matrix
    float curr_y; // represent the y-coordinate of left-upper square corner (A)
    for (int j = 0; j < 256; j++)
    {
        Map[j] = new square[256]; // new row of 256 squares is initialized
        // search all squares for finding those which left-upper corner (A)
        // y-coordinate is equal to the row numer
        for (int i = 0; i < sq.size(); i++)
        {
            curr_y = sq[i].a.pos[1];
            if (curr_y == j)
            {
                Map[j][tempor++] = sq[i];
            }
        }
        tempor = 0; // setting to first column again
    }
}

// helper global variables to set some properties
// for drawing and transforming which can be set
// by pressing some keys (they are set in key_pressed
// function)
double rot = 10.0; // rotation angle;
int rows = 1; // the variable to iterate rows of Map matrix
int columns = 10; // the variable to iterate columns of Map matrix

void key_pressed(unsigned char key, int x, int y)
{
    if (key == '>')
        glRotated(rot, 1.0, 1.0, 1.0);
    if (key == 'z')
        rows++;
    if (key == 'x')
        rows--;
    if (key == 't')
        glTranslated(-1.0, 0.0, 0.0); // translating to the left
    if (key == 's')
        columns += 40;
    display_scene();
}
int main()
{
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB); // inicjalizacja bufora ramki: podwójne buforowanie, RGB
    glutInitWindowSize(window_width, window_height);
    glutCreateWindow("Terrain");

    glutDisplayFunc(display_scene); // przekazanie wskaźnika do funkcji wywoływanej przez GLUT przy wyświetlaniu
    glutReshapeFunc(reshape); // jw. ale przy zmianie wielkości okna
    glutKeyboardFunc(key_pressed);
    // invoking function to generate squares.
    foo();
    glutMainLoop();

    return 0;
}


void display_scene(){
    // setting background color
    glClearColor(0.4f, 0.4f, 0.4f, 1.0);
    // clearing buffer to draw new image
    glClear(GL_COLOR_BUFFER_BIT);
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < columns; j++)
        {
            // drawing quads in 3D where X and Z coordinates are just like
            // the square A, B, C or D vertices X and Y coordinates and 
            // the Y coordinate (height) depends on the color of the vertex
            // (the darker color the lower height)
            glBegin(GL_QUADS);
            float col = rgb_to_float(Map[i][j].a.c); 
            // color may be to brigth (for instance 0.0019) so some
            // scalling is done 
            if (col < 0.1)
                col *= 10;
            glColor3f(col, col, col); // seting color for drawing the verticle
            glVertex3f(Map[i][j].a.pos[0], col * 10, Map[i][j].a.pos[1]);
            col = rgb_to_float(Map[i][j].b.c);
            if (col < 0.1)
                col *= 10;
            glColor3f(col, col, col);
            glVertex3f(Map[i][j].b.pos[0], col*10, Map[i][j].b.pos[1]);
            col = rgb_to_float(Map[i][j].c.c);
            if (col < 0.1)
                col *= 10;
            glColor3f(col, col, col);
            glVertex3f(Map[i][j].c.pos[0], col*10, Map[i][j].c.pos[1]);
            col = rgb_to_float(Map[i][j].d.c);
            if (col < 0.1)
                col *= 10;
            glColor3f(col, col, col);
            glVertex3f(Map[i][j].d.pos[0], col*10, Map[i][j].d.pos[1]);
            glEnd();
        }
    }
    glFlush(); // powyższe polecenia zostaną przesłąne do sterownika karty graficznej (lepsza wydajność, bo naraz podaje się wszystkie dane, a nie każdą daną po kolei, co zajmowałoby więcej czasu)
    glutSwapBuffers();
}

void reshape(GLsizei width, GLsizei height){
    if (height == 0) // omitting diving by zero in counting AspectRatio
        height = 1;
    // setting view port the same as window size
    glViewport(0, 0, width, height);
    // switching to projection matrix for setting proper view aspects
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    GLfloat AspectRatio = (GLfloat)width / (GLfloat)height;
    if (width <= height)
        glOrtho(-7.5, 7.5, -7.5 / AspectRatio, 7.5 / AspectRatio, 10.0, -10.0);
    else
        glOrtho(-7.5*AspectRatio, 7.5*AspectRatio, -7.5, 7.5, 10.0, -10.0);
    // switching to modelview matrix to enable performing transformations on 
    // the image such as translating, rotating etc.
    glMatrixMode(GL_MODELVIEW);                                
    glLoadIdentity();
}

我想知道如何克服问题与断开(坏)的四线。

共有1个答案

宋康安
2023-03-14

您的“Square”类不是计算该网格中高度的理想模型,因为每次细分时都要修改相邻方块共享的点,也可能是父方块共享的点。

至少,让您的方块包含对顶点的引用(或指针),并在相邻的方块之间共享这些引用。

然后,当你修改任何顶点时,所有共享它的方块将自动获得更新的坐标。

 类似资料:
  • 问题内容: 目的:使用指定的参数调用外部应用程序,然后退出脚本。 以下脚本无法正常工作: 尝试过的事情:-不分离。提前谢谢了 问题答案: 从node.js文档中: 默认情况下,父级将等待分离的子级退出。为防止父级等待给定的子级,请使用child.unref()方法,并且父级的事件循环将其引用计数中不包括该子级。 使用detached选项启动长时间运行的进程时,除非该进程提供了未连接到父级的stdi

  • 我正在编写一个可视化洞穴的OpenGL程序,所以当我可视化地表地形时,我希望它是透明的,这样你就可以看到下面的洞穴了。我假设我可以将来自数字高程模型的数据归一化为一个网格,该网格以规则的间距对准x/z轴,并将每个网格单元格渲染为两个三角形。使用对齐的网格,我可以避免在应用画家的算法时进行排序的成本(以确保适当的透明度效果);相反,我可以逐行呈现单元格,从最远的行和每行最远的单元格开始。 这一切都很

  • 我想做一个简单的2D地形,只有几个颠簸和高度变化: 我想过只是用随机数来描述某个顶点的高度,但我看不出我怎么能从这个做一个网格。我正在寻找一种方法来找到地形的顶点和索引缓冲区。 我如何做到这一点?

  • 问题内容: 我正在使用ionic框架为android平台生成apk。 运行后,将生成android-debug.apk。如何生成更小,更快的非调试apk? 问题答案: 这是我的android发布shell脚本 IFY

  • 我使用离子框架生成apkAndroid平台。 运行后,将进行Android调试。生成apk。如何生成更小更快的非调试apk?