我写了一个简单的片段着色器,它渲染了一个mandelbrot集。我在c中使用和使用glsl的opengl进行此操作。
#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,0时我得到这个结果。
如您所见,该组的左侧未在四边形上呈现。
c值来自顶点着色器,所以我假设它在x和y轴上都是-1到1,并在它们之间进行插值。
我的问题是:
我想如果我能理解如何放大该组,我可以弄清楚如何放大特定部分,但我不确定。
编辑,确保我的代码
的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我能够解决我遇到的问题,现在我正在添加Mandelbrot集的一些镜头。
答案 0 :(得分:2)
c值来自顶点着色器,所以我假设它在x和y轴上都是-1到1,并在它们之间进行插值。
这是正确的。
1)如何将图像置于四边形中心?我不太确定。
您只需要缩小1.5倍并将其居中放在-0.5上。 Mandelbrot集的有趣部分在实轴上从大约-2延伸到1,在虚轴上从-i延伸到i:
2)我怎么能说放大mandelbrot上的一些内容并跟进,让我说我想放大一下该组的特定部分? 2B)假设我点击屏幕并在NDC中获得位置?
放回你之前版本中的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像素块的平均值等),它可能看起来会更好。 / p>
如果你放大到最远,你将会遇到GPU使用的浮点数精度的极限。