Saturday 29 April 2023

Android GLES - Flame shader

I'm quite starter of using GLES 2.0 on Android and I am trying to create a Flame-shaped shader using GLSL. I tried applying the shader from the following link: https://www.shadertoy.com/view/MdKfDh

However, the result I got is not satisfactory.

Flame Shader

The image I created looks like the flames are flowing diagonally and the shape is too stretched vertically, while the flame shader on "shadertoy" gives the impression of flames bursting out. The glsl fragment code I wrote is like this:

precision mediump float;

#define timeScale           iTime * 1.0
#define fireMovement        vec2(-0.01, -0.5)
#define distortionMovement  vec2(-0.01, -0.3)
#define normalStrength      40.0
#define distortionStrength  0.1

uniform vec2 screenSize;
uniform float progress;

// #define DEBUG_NORMAL

/** NOISE **/
float rand(vec2 co) {
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

vec2 hash( vec2 p ) {
    p = vec2( dot(p,vec2(127.1,311.7)),
    dot(p,vec2(269.5,183.3)) );

    return -1.0 + 2.0*fract(sin(p)*43758.5453123);
}

float noise( in vec2 p ) {
    const float K1 = 0.366025404; // (sqrt(3)-1)/2;
    const float K2 = 0.211324865; // (3-sqrt(3))/6;

    vec2 i = floor( p + (p.x+p.y)*K1 );

    vec2 a = p - i + (i.x+i.y)*K2;
    vec2 o = step(a.yx,a.xy);
    vec2 b = a - o + K2;
    vec2 c = a - 1.0 + 2.0*K2;

    vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 );

    vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0)));

    return dot( n, vec3(70.0) );
}

float fbm ( in vec2 p ) {
    float f = 0.0;
    mat2 m = mat2( 1.6,  1.2, -1.2,  1.6 );
    f  = 0.5000*noise(p); p = m*p;
    f += 0.2500*noise(p); p = m*p;
    f += 0.1250*noise(p); p = m*p;
    f += 0.0625*noise(p); p = m*p;
    f = 0.5 + 0.5 * f;
    return f;
}

/** DISTORTION **/
vec3 bumpMap(vec2 uv, vec2 resolution) {
    vec2 s = 1. / resolution;
    float p =  fbm(uv);
    float h1 = fbm(uv + s * vec2(1., 0));
    float v1 = fbm(uv + s * vec2(0, 1.));

    vec2 xy = (p - vec2(h1, v1)) * normalStrength;
    return vec3(xy + .5, 1.);
}

vec3 constructCampfire(vec2 resolution, vec2 normalized, float time) {
    vec3 normal = bumpMap(normalized * vec2(1.0, 0.3) + distortionMovement * time, resolution);

    vec2 displacement = clamp((normal.xy - .5) * distortionStrength, -1., 1.);
    normalized += displacement;

    vec2 uvT = (normalized * vec2(1.0, 0.5)) + time * fireMovement;
    float n = pow(fbm(8.0 * uvT), 1.0);

    float gradient = pow(1.0 - normalized.y, 2.0) * 5.;
    float finalNoise = n * gradient;
    return finalNoise * vec3(2.*n, 2.*n*n*n, n*n*n*n);
}

void main() {
    vec2 resolution = screenSize;
    vec2 normalized = gl_FragCoord.xy / resolution;
    vec3 campfire = constructCampfire(resolution, normalized, progress);
    gl_FragColor = vec4(campfire, 1.0);
}

As you can see, the GLSL code I wrote is very similar to the code in "shadertoy". The difference is, I pass in the screenSize(pixels) and progress(float seconds) from the Android side. For your information, the code above is fragment shader, and I've already adjust vertex shader using gl_Position for entire screen. I am not sure why the result is not what I expected.

Also, I have another problem where after about 10 seconds, the image becomes pixelated and gradually turns into a square flame.

Pixelated Flame shader

It seems to be a problem when the progress value becomes too large, but I am not sure of the reason, and don't know how to fix it.

If anyone knows the cause and solution to these issues, I would greatly appreciate your response. Thank you.



from Android GLES - Flame shader

No comments:

Post a Comment