簡體   English   中英

在OpenGL中使用等離子分形生成地形

[英]Terrain generating using plasma fractal in OpenGL

我想使用等離子分形生成隨機地形。 我正在瀏覽Internet,以找到可以對我的特定問題有所幫助的解決方案,但沒有發現任何問題。 實際上,我生成了簡單的等離子體分形,如下所示:

這是分形的圖片:

分形http://i65.tinypic.com/2qa8lyo.jpg

分形並不完美,因為存在正方形,但被我的老師接受。 生成這種分形的算法是,給定一個輸入正方形,我通過在每個正方形邊的中間插入四個點,然后在中心插入一個點,將其划分為較小的正方形,從而創建4個新正方形。 每個新生成的頂點都有其顏色值,該顏色值是范圍為[0,255]的浮點,使用特殊公式對其進行計數。 我現在有一個任務可以使用此分形生成隨機地形,並且知道每個點的高度與所計算的顏色值成正比。 我的問題是,我嘗試使用生成的角點坐標繪制四邊形,但四邊形未連接(在某些地方,兩個四邊形邊緣的高度不同,因此它們之間會出現間隙)。

這是我的地形圖片:

地形http://i64.tinypic.com/kt7pi.jpg

這是我生成此地形的代碼:

#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();
}

很抱歉,我插入了全部代碼,但是該錯誤可能隱藏在opengl參數配置中,因此我決定帶上全部代碼。 我想知道如何解決四邊形斷開(斷開)的問題。 任何幫助表示贊賞:)

您的“正方形”類不是用於計算此網格中高度的理想模型,因為每次細分時,最終都會修改相鄰正方形甚至父正方形可能共享的點。

至少,讓正方形包含頂點的引用 (或指針),並在相鄰正方形之間共享這些引用。

然后,當您修改任何頂點時,所有共享該正方形的正方形都會自動獲取更新的坐標。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM