2015-11-23 2 views
1

Я хочу создать случайный ландшафт с использованием фрактала плазмы. Я просматривал Интернет, чтобы найти решение, которое может помочь мне в моей конкретной проблеме, но ничего не нашел. На самом деле я создал простой плазменный фрактал, который выглядит следующим образом:Ландшафт, генерирующий плазменный фрактал в OpenGL

Вот картина фрактала:

fractal http://i65.tinypic.com/2qa8lyo.jpg

Фрактал не является совершенным, потому что видели квадратики, но принял мой учитель. Алгоритм генерации такого фрактала заключался в том, что с учетом входного квадрата я делил его на меньшие, вставив четыре точки в середину каждой квадратной стороны, а затем одну точку в центре, что привело к созданию 4 новых квадратов. Каждая вновь созданная вершина имела значение цвета, которое является поплавком диапазона [0, 255], которое подсчитывалось с использованием специальной формулы. Теперь у меня есть задача создать случайный ландшафт, используя этот фрактал, и зная, что высота каждой точки пропорциональна подсчитанному значению цвета. Моя проблема заключается в том, что я пытаюсь рисовать квадратики с использованием сгенерированных координат углов квадратов, но мои квадранты не связаны (есть места, где два квадроцикла на разных высотах, между ними возникает промежуток).

Вот картина моей местности:

terrain 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, поэтому я решил привести весь код. Я хотел бы знать, как преодолеть проблему с отключенными (сломанными) квадроциклами. Любая помощь была оценена :)

+1

Я думаю, что проблема заключается в том, что когда вы подразделяете два соседних квадрата, вы создаете две новые (и по-разному) вершины в одной и той же точке, по одному для каждого из квадратов, которые вы разделили. Вам нужно будет найти способ, чтобы каждый край делился только один раз. (Я не думаю, что вам нужно использовать явную структуру «квадрат», поскольку углы квадратов подразумеваются длиной края, но я не закодировал плазму буквально десятилетиями, а моя память туманна ...) – molbdnilo

+0

Я проверил, и я не создаю ни одной вершины дважды, так как я генерирую эти пять пунктов один раз, а затем создаю четыре квадрата, используя их, чтобы на самом деле не было возможности дублировать точки. Поправьте меня, если я ошибаюсь. – Rafichu

+0

и что вы будете делать, когда вы их разделите? – Alnitak

ответ

1

Ваш «квадратный» класс не является идеальной моделью для расчета высот в этой сетке, потому что каждый раз, когда вы подразделяете вас, вы заканчиваете модификацию точек, разделяемых соседними квадратами, а также, возможно, и родительским квадрат.

По крайней мере, ваши квадраты содержат ссылки (или указатели) на вершины и разделяют эти ссылки между соседними квадратами.

Затем, когда вы меняете какую-либо вершину, тогда все квадраты, которые делят ее, автоматически получат обновленные координаты.

+0

Я думал что я назначаю вершины по значению, потому что я не храню указатели и не храню ссылки, но могу ошибаться, потому что я привык к стилю C# или Java «присвоение по значению». Я понял, что я перекрывал свои созданные точки новыми. – Rafichu

Смежные вопросы