尝试使用GLSL像素着色器制作mandelbrot集,但在分支时遇到麻烦

问题描述 投票:1回答:1

我正在尝试对GLSL中设置的mandelbrot进行编码。但这似乎是由于GLSL内部分支的限制所致,无法正常工作。这是我的代码:

passthrough.vsh:

attribute vec4 a_color;
attribute vec3 a_position;
attribute vec2 a_texCoord0;

uniform mat4 u_projTrans;
varying vec4 v_color;
varying vec2 v_texCoord0;

void main() {
    v_color = a_color;
    v_texCoord0 = a_texCoord0;
    gl_Position = u_projTrans * vec4(a_position, 1);
}

mandelbrot.fsh:

varying vec4 v_color;
varying vec2 v_texCoord0;

uniform sampler2D u_sampler2D;

uniform int u_width;
uniform int u_height;

uniform float u_realCenter;
uniform float u_imagCenter;

uniform float u_realSpan;
uniform float u_imagSpan;

int maxIterations = 255;

float rand(vec2 c0);

vec2 squareComplex(vec2 z);
vec2 coordToComplexNumber(vec2 coord);

float getRed(int stability);
float getGreen(int stability);
float getBlue(int stability);

void main()
{
    vec2 c = coordToComplexNumber(gl_FragCoord.xy);
    vec2 z = vec2(0, 0);

    int stability = 0;
    int attempts = 0;

    for (int i = 0; i < maxIterations && z.x * z.x + z.y * z.y < 4.0; i++) {
        z = squareComplex(z) + c;
        stability = stability + 1;
    }

    gl_FragColor = vec4(getRed(stability), getGreen(stability), getBlue(stability), 1);
}

vec2 squareComplex(vec2 z)
{
    return vec2(z.x * z.x - z.y * z.y, 2.0 * z.x * z.y);
}

vec2 coordToComplexNumber(vec2 coord)
{
    float lowestReal = u_realCenter - u_realSpan / 2.0;
    float lowestImag = u_imagCenter - u_imagSpan / 2.0;

    float portionX = coord.x / float(u_width);
    float portionY = coord.y / float(u_height);

    float mappedX = lowestReal + portionX * u_realSpan;
    float mappedY = lowestImag + portionY * u_imagSpan;

    return vec2(mappedX, mappedY);
}

float getRed(int stability)
{
    return float(stability) / float(maxIterations) * 255.0;
}

float getGreen(int stability)
{
    return mod(float(stability), float(maxIterations)) * 255.0;
}

float getBlue(int stability)
{
    return 0.0;
}

问题似乎在这里发生:

for (int i = 0; i < maxIterations && z.x * z.x + z.y * z.y <= 4.0; i++) {
    z = squareComplex(z) + c;
    stability = stability + 1;
}

使用下面的代码进行测试表明,此循环每次只运行1次迭代,然后退出。

gl_FragColor = vec4(stability == 1 ? 1 : 0, 0, 0, 1);

最终将所有内容都涂成红色。

我还尝试在循环内使用break语句,而不是在for循环条件内使用&& z.x * z.x + z.y * z.y <= 4.0,如下所示:

if (z.x * z.x + z.y * z.y > 4.0) break;

这似乎总是错误的。因此总是退出。我已经了解了GLSL中分支的限制。因此这可能是这两种情况的原因,但是我不知道如何在不分支的情况下在GLSL中编码Mandelbrot集,我找不到任何解决方案,也找不到在GLSL中使分支工作的方法。

[我在Linux上的Intel HD笔记本电脑,Windows上的NVidia笔记本电脑和Samsung Galaxy S9上测试了此代码,但它们在其中任何一个上均不起作用。

此代码正在Java LibGDX中实现。

也许与该错误有关:

LwjglGraphics: created OpenGL 3.2+ core profile (GLES 3.0) context. This is experimental!

这是从我的DesktopLauncherCode:

package mypackagename.desktop

import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
import mypackagename.Mandelbrot;

public class DesktopLauncher {
    public static void main (String[] arg) {
        LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
        config.vSyncEnabled = true;
        config.useGL30 = true;
        config.title = "GLSL Shaders";
        config.width = 1280;
        config.height = 720;
        new LwjglApplication(new Mandelbrot(), config);
    }
}

这是我的主要代码:

package mypackagename;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;

public class Mandelbrot extends ApplicationAdapter {

    private SpriteBatch batch;
    private ShaderProgram shader;

    private Texture texture;

    @Override
    public void create () {
        batch = new SpriteBatch();

        ShaderProgram.pedantic = false;
        shader = new ShaderProgram(
                Gdx.files.internal("shaders/mandelbrot3.vsh"),
                Gdx.files.internal("shaders/mandelbrot3.fsh")
        );
        System.out.println(shader.isCompiled() ? "shader compiled, yay" : shader.getLog());
        batch.setShader(shader);

        shader.setUniformf("u_realCenter", 0);
        shader.setUniformf("u_imagCenter", 0);
        shader.setUniformf("u_realSpan", 6);
        shader.setUniformf("u_imagSpan", 6);
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.begin();
        batch.draw(texture, 0, 0);
        batch.end();
    }

    @Override
    public void dispose () {
        batch.dispose();
        shader.dispose();
    }

    @Override
    public void resize(int width, int height) {
        super.resize(width, height);
        texture = new Texture(getPixmapRectangle(width, height, Color.BLUE));
        shader.setUniformi("u_width", width);
        shader.setUniformi("u_height", height);
    }

    public static Pixmap getPixmapRectangle(int width, int height, Color color) {
        Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
        pixmap.setColor(color);
        pixmap.fillRectangle(0, 0, pixmap.getWidth(), pixmap.getHeight());
        return pixmap;
    }
}
glsl shader fragment-shader mandelbrot
1个回答
0
投票

在OpenGL ES 2.0中,for循环有几个限制。参见OpenGL ES Shading Language 1.00 Specification - Appendix A: Limitations for ES 2.0

4控制流程[...]支持for循环,但具有以下限制:[...]条件具有形式

loop_index relational_operator constant_expression  

其中relational_operator为以下之一:>> = <<= ==或!=

导致片段着色器无法成功编译。

但是可以在break循环中使用for语句。例如:

void main()
{
    // [...]

    for (int i = 0; i < maxIterations; i++) {
        if (z.x * z.x + z.y * z.y >= 4.0)
            break;
        z = squareComplex(z) + c;
        stability = stability + 1;
    }

    // [...]
}
© www.soinside.com 2019 - 2024. All rights reserved.