Я пытаюсь закодировать набор Мандельброта в GLSL. Но это может показаться из-за ограничений ветвления внутри GLSL, это не работает должным образом. Вот мой код:
passthrough.v sh:
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.f sh:
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;
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;
}
Тестирование с использованием следующего кода показывает, что этот l oop запускает только 1 итерацию и затем завершается каждый раз.
gl_FragColor = vec4(stability == 1 ? 1 : 0, 0, 0, 1);
, что приводит к окрашиванию всего красного.
Я также пытался использовать оператор break внутри l oop вместо использования && z.x * z.x + z.y * z.y <= 4.0
внутри условия for l oop, например:
if (z.x * z.x + z.y * z.y > 4.0) break;
Это, кажется, не работает должным образом , Я читал об ограничениях в ветвлении в GLSL. Так что это может быть причиной в обоих случаях, но я не знаю, как кодировать множество Мандельброта в GLSL без ветвления, и я не могу найти никакого решения для этого, а также не могу найти способ заставить ветвление работать в GLSL .
Я тестировал этот код на ноутбуке Intel HD на Linux, ноутбуке NVidia на Windows и на 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;
}
}