Управление увеличением масштаба набора Мандельброта
Я написал простой фрагментный шейдер, который отображает множество Мандельброта. Я делаю это в c и с opengl, используя glsl.
#version 330 core
in vec2 fCoord; //position.x position.y which is -1 to 1 on both axis
uniform int maxIterations;
uniform sampler1D mandiTexture;
out vec4 color;
void main()
{
vec2 c, z;
c.x = fCoord.x;
c.y = fCoord.y;
int i;
z = vec2(0.0f, 0.0f);
for(i=0; i<maxIterations; i++) {
float x = (z.x * z.x - z.y * z.y) + c.x;
float y = (z.y * z.x + z.x * z.y) + c.y;
if((x * x + y * y) > 4.0) break;
z.x = x;
z.y = y;
}
vec4 tcolor;
if (i == maxIterations)
{
tcolor = vec4(0.0f, 0.0f, 0.0f, 1.0f);
}
else
{
tcolor = texture(mandiTexture, float(i) / float(maxIterations));
}
color = tcolor;
}
я заметил, что, играя с начальным значением z, я получаю разные результаты, но в основном они выходят за пределы моего квадрата. С z как 0, я получаю этот результат.
как вы можете видеть, левая сторона набора не отображается на четырехугольнике.
Значение c исходит из вершинного шейдера, поэтому я предполагаю, что оно идет от -1 до 1 по осям x и y и интерполируется между ними.
Мои вопросы:
- 1) Как я могу центрировать изображение на квадроцикле? Я не совсем уверен в этом.
- 2) Как я могу сказать увеличить масштаб набора Мандельброта и продолжить, скажем, я хочу увеличить конкретную часть набора?
- 2B) Допустим, я нажимаю на экран и получаю позицию в НДЦ?
- 3) Если я установлю свои максимальные итерации выше, набор, похоже, станет действительно неровным, это нормальное поведение?
Я думаю, что если я смогу понять, как увеличить масштаб устройства, я смогу понять, как увеличить конкретную часть, но я не уверен.
редактировать, убедившись, что мой код
main.c
int maxIterations = 70;
int iterAmount = 1;
char* vshad, *fshad;
GLuint verticesBuffer, colorBuffer, vao, texCoordBuffer, indicesBuffer;
GLuint mandiTextureID, sp;
mat4_s vm, pm, opm, tm;
GLint viewMat = -1;
GLint projMat = -1;
GLint modelMat = -1;
GLint mandiTexture = -1;
GLint maxIterLoc = -1;
void initShaders(void)
{
char* vertexShaderSource = getResource("vert.shad");
char* fragmentShaderSource = getResource("frag.shad");
vshad = readFile(vertexShaderSource);
fshad = readFile(fragmentShaderSource);
free(vertexShaderSource);
free(fragmentShaderSource);
}
int run_game()
{
current_utc_time(&start_time);
while(game_running)
{
current_utc_time(¤t_time);
double frameTime = (diff(start_time,current_time).tv_sec + diff(start_time,current_time).tv_nsec) * .00000001;
//printf("float time: %0.8f\n",frameTime);
if ( frameTime > 0.25 )
{
frameTime = 0.25;
}
current_utc_time(&start_time);
current_time = start_time;
accumulator += frameTime;
while ( accumulator >= dt )
{
accumulator -= dt;
t += dt;
//printf("fixed update dt: %0.8f\n",dt);
}
//render_state = currentState * alpha + previousState * ( 1.0 - alpha );
const double alpha = accumulator / dt;
render();
if(game_running < 1) { break; }
while (SDL_PollEvent(&event))
{
switch (event.type) {
case SDL_QUIT:
game_running = -1;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
{
case SDLK_ESCAPE:
game_running = -1;
break;
}
break;
}
}
}
return -1;
}
int main(int argc, char const *argv[]) {
initShaders();
mat4_identity(&vm);
vec3_s eye = {0, 0, 0};
vec3_s center = {0, 0, -1};
vec3_s up = {0, 1, 0};
mat4_lookAt(&vm, &eye, ¢er, &up);
mat4_identity(&opm);
mat4_ortho(&opm, 0, 200, 0, 200, 1, 100);
mat4_identity(&tm);
mat4_scalex(&tm, &tm, 100, 100, 0);
mat4_translatex(&tm, &tm, 100.0f, 100.0f, -20);
SDL_Surface* mandiSurface = loadPNG(getResource("mandi.png"));
if(!mandiSurface) {
printf("IMG_Load: %s\n", IMG_GetError());
// handle error
}
GLenum Mode1 = GL_RGB;
if(4 == mandiSurface->format->BytesPerPixel)
{
Mode1 = GL_RGBA;
printf("mode change");
}
sp = getShaderProgram(vshad, fshad);
r = newRenderable2d();
glGenVertexArrays(1, &vao);
glGenBuffers(1, &verticesBuffer);
glGenBuffers(1, &colorBuffer);
glGenBuffers(1, &indicesBuffer);
glGenBuffers(1, &texCoordBuffer);
glBindVertexArray(vao); //bind vertex array buffer
glBindBuffer(GL_ARRAY_BUFFER, verticesBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(r->vertices), r->vertices, GL_STATIC_DRAW);
//bind n setup indices
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(r->indices), r->indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind indices
//bind n setup colors
glBindBuffer(GL_ARRAY_BUFFER, colorBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(r->colors), r->colors, GL_STATIC_DRAW);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(1);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind colors
//bind n setup texture coords
glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(r->texCoords), r->texCoords, GL_STATIC_DRAW);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), (GLvoid*)0);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind texture coords
glBindVertexArray(0); //unbind vertex array buffer
//mandi 1d texture
glGenTextures(1, &mandiTextureID);
glBindTexture(GL_TEXTURE_1D, mandiTextureID);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage1D(GL_TEXTURE_1D, 0, Mode1, mandiSurface->w, 0, Mode1, GL_UNSIGNED_BYTE, mandiSurface->pixels);
glBindTexture(GL_TEXTURE_1D, 0);
free(mandiSurface);
while(run_game() >= 0);
free(r);
IMG_Quit();
SDL_GL_DeleteContext(maincontext);
SDL_DestroyWindow(window);
return 0;
}
void render()
{
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
glUseProgram(sp);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_1D, mandiTextureID);//mandiTexture
mandiTexture = getUniformLocation(sp, "mandiTexture");
glUniform1i(mandiTexture, 0);
glBindVertexArray(verticesBuffer);
viewMat = getUniformLocation(sp, "viewMat");
modelMat = getUniformLocation(sp, "modelMat");
projMat = getUniformLocation(sp, "projMat");
maxIterLoc = getUniformLocation(sp, "maxIterations");
glUniformMatrix4fv(viewMat, 1, GL_FALSE, vm.m);
glUniformMatrix4fv(projMat, 1, GL_FALSE, opm.m);
glUniformMatrix4fv(modelMat, 1, GL_FALSE, tm.m);
glUniform1i(maxIterLoc, maxIterations);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
SDL_GL_SwapWindow(window);
}
int init_sdl(int width, int height, char* title, double fps)
{
if (SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
SDL_Log("sdl failed to init");
SDL_Quit();
return -1;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
window = SDL_CreateWindow(title, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, width, height, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
if(window == NULL)
{
SDL_Log("sdl failed to create window");
SDL_Quit();
return -1;
}
maincontext = SDL_GL_CreateContext(window);
if(maincontext == NULL)
{
SDL_Log("sdl failed to create opengl context");
SDL_Quit();
return -1;
}
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
SDL_GL_SetSwapInterval(1);
return 1;
}
вершинный шейдер
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec3 icolor;
layout (location = 2) in vec2 vTexCoord;
uniform mat4 modelMat;
uniform mat4 viewMat;
uniform mat4 projMat;
out vec4 fcolor;
out vec2 fTexCoord;
out vec2 fCoord;
void main()
{
gl_Position = projMat * viewMat * modelMat * vec4(position, 1.0);
fCoord = vec2(position);
fTexCoord = vTexCoord;
fcolor = vec4(icolor, 1.0f);
}
Благодаря @samgak я смог решить проблемы, которые у меня были, и теперь я добавляю несколько снимков из набора Мандельброта.
1 ответ
Значение c исходит из вершинного шейдера, поэтому я предполагаю, что оно идет от -1 до 1 по осям x и y и интерполируется между ними.
Правильно.
1) Как я могу центрировать изображение на квадроцикле? Я не совсем уверен в этом.
Вам просто нужно уменьшить масштаб в 1,5 раза и отцентрировать его на -0,5. Интересные части множества Мандельброта простираются примерно от -2 до 1 на действительной оси и от -i до i на воображаемой оси:
2) Как я могу сказать увеличить некоторые из набора Мандельброта и продолжить, скажем, я хочу увеличить конкретную часть набора? 2B) Допустим, я нажимаю на экран и получаю позицию в НДЦ?
Верните 2 формы, которые были у вас в предыдущей версии:
uniform vec2 center;
uniform float scale;
Объявите переменные для хранения этих значений в вашем коде C и установите их с помощью glUniform2f
а также glUniform1f
, Для центрирования набора начальные значения должны быть -0,5, 0,0 для центра и 1,5 для шкалы (большие значения уменьшаются). Затем в своем фрагментном шейдере просто примените их следующим образом:
c = (fCoord * scale) + center;
Чтобы щелкнуть по экрану и увеличить конкретное местоположение, поверните местоположение мыши в значение от -1,-1 до 1,1 в зависимости от его положения на экране, затем примените к нему приведенное выше уравнение, чтобы найти местоположение, на котором вы щелкнули, Установите это как новый центр и умножьте масштаб на значение меньше 1, чтобы увеличить заданную величину.
3) Если я установлю свои максимальные итерации выше, набор, похоже, станет действительно неровным, это нормальное поведение?
Скриншот, который вы разместили, выглядит нормально. Вероятно, это выглядело бы лучше, если бы вы реализовали некоторую мультисэмплирование в своем фрагментном шейдере (например, вычислите несколько значений в цикле и сложите их вместе, чтобы каждый пиксель фактически представлял собой среднее значение для блока пикселей 2x2 или 4x4 и т. Д.).
Если вы увеличите масштаб в конце концов, вы попадете в пределы точности чисел с плавающей запятой, используемых графическим процессором.