Help to translate shadertoy 2d fast clouds to defold

I found pretty looking clouds at shadertoy, but unable to convert it to defold.

Clouds shader

Missing iChanel0, iGlobalTime, iResolution, iMouse, iGlobalTime.

Please help with it. And if you can point to manual/code with GLSL to defold shader translation tips.

Thank you.

Here is shader program in WebGL (fragment, I presume)

//SETTINGS//
const float timeScale = 10.0;
const float cloudScale = 0.5;
const float skyCover = 0.6; //overwritten by mouse x drag
const float softness = 0.2;
const float brightness = 1.0;
const int noiseOctaves = 8;
const float curlStrain = 3.0;
//SETTINGS//

float saturate(float num)
{
return clamp(num,0.0,1.0);
}

float noise(vec2 uv)
{
return texture2D(iChannel0,uv).r;
}

vec2 rotate(vec2 uv)
{
uv = uv + noise(uv*0.2)*0.005;
float rot = curlStrain;
float sinRot=sin(rot);
float cosRot=cos(rot);
mat2 rotMat = mat2(cosRot,-sinRot,sinRot,cosRot);
return uv * rotMat;
}

float fbm (vec2 uv)
{
float rot = 1.57;
float sinRot=sin(rot);
float cosRot=cos(rot);
float f = 0.0;
float total = 0.0;
float mul = 0.5;
mat2 rotMat = mat2(cosRot,-sinRot,sinRot,cosRot);

for(int i = 0;i < noiseOctaves;i++)
{
    f += noise(uv+iGlobalTime*0.00015*timeScale*(1.0-mul))*mul;
    total += mul;
    uv *= 3.0;
    uv=rotate(uv);
    mul *= 0.5;
}
return f/total;

}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 screenUv = fragCoord.xy/iResolution.xy;
vec2 uv = fragCoord.xy/(40000.0*cloudScale);

float mouseXAffect = (iMouse.x/iResolution.x);

float cover = mouseXAffect*1.1+0.1;
if( iMouse.z<=0.0001 ) cover = 0.5;

float bright = brightness*(1.8-cover);

float color1 = fbm(uv-0.5+iGlobalTime*0.00004*timeScale);
float color2 = fbm(uv-10.5+iGlobalTime*0.00002*timeScale);

float clouds1 = smoothstep(1.0-cover,min((1.0-cover)+softness*2.0,1.0),color1);
float clouds2 = smoothstep(1.0-cover,min((1.0-cover)+softness,1.0),color2);

float cloudsFormComb = saturate(clouds1+clouds2);

vec4 skyCol = vec4(0.6,0.8,1.0,1.0);
float cloudCol = saturate(saturate(1.0-pow(color1,1.0)*0.2)*bright);
vec4 clouds1Color = vec4(cloudCol,cloudCol,cloudCol,1.0);
vec4 clouds2Color = mix(clouds1Color,skyCol,0.25);
vec4 cloudColComb = mix(clouds1Color,clouds2Color,saturate(clouds2-clouds1));

fragColor = mix(skyCol,cloudColComb,cloudsFormComb);
}

Defold already uses GLSL.

The missing values are Shadertoy specific data which you will have to send yourself to the shader program. You can do this via go.set after adding the fields to the associated material.

https://www.shadertoy.com/howto

Make a copy of sprite.material and sprite.fp from the builtins you can define the missing in the fragment program file and in the material file.

For example, you could adapt the iGlobalTime to

local global_time = global_time or 0

function update(self, dt)
    global_time = global_time + dt
    go.set("#sprite", "global_time", vmath.vector4(global_time, 0, 0, 0))
end

This would update the material property global_time to the total ms since the script started. Then you could use it in the shader program like

varying mediump vec4 position;
varying mediump vec2 var_texcoord0;

uniform lowp sampler2D DIFFUSE_TEXTURE;
uniform lowp vec4 tint;

uniform lowp vec4 global_time;


void main()
{

	gl_FragColor = vec4(var_texcoord0.xy,0.5+0.5*sin(global_time.x),1.0) * texture2D(DIFFUSE_TEXTURE, var_texcoord0.xy) ;	
}

And edit your material

name: "sprite"
tags: "tile"
vertex_program: "/main/materials/sprite.vp"
fragment_program: "/main/materials/sprite.fp"
vertex_constants {
  name: "view_proj"
  type: CONSTANT_TYPE_VIEWPROJ
}
vertex_constants {
  name: "world"
  type: CONSTANT_TYPE_WORLD
}
fragment_constants {
  name: "tint"
  type: CONSTANT_TYPE_USER
  value {
    x: 1.0
    y: 1.0
    z: 1.0
    w: 1.0
  }
}
fragment_constants {
  name: "global_time"
  type: CONSTANT_TYPE_USER
  value {
    x: 3.0
  }
}

If you were to use this with a sprite it would produce this https://www.bookofdefold.com/examples/ShaderExample/index.html

Try to adapt the shader program more based on this understanding. If you get stuck post and we’ll nudge you in the right direction.

6 Likes

Thank you very much for thorough answer. I like to see professional to contact with.

Now I can try test shaders and make some cool effects in games.

Best regards to you.

Live long and prosper :slight_smile:

4 Likes

Tip I forgot to mention when working with shader code is to do Rebuild and Launch instead of Build and Launch in order to make sure the files update properly.

Thank you. This is very good tip. You save me from frustration when build.

I modified shader but it does not show anything. Can you help to specify sampler2d as noise texture.

Noise texture loaded and atlas is set.

Right now we are limited in ability to load extra external textures (sadly). It is a feature that has been requested. By default, the only one you are given access to from the project is DIFFUSE_TEXTURE of the associated sprite. You do have options with adapting this shader still.

A. Generate the data of the noise on the fly, there are many different noise styles you could use

B. Store the noise texture in an array in the fragment program source - for a black and white noise texture you can keep it simple, but for other textures you’ll want to store more information. There are a number of ways to go about packing and using data like this.

C. Set the sprite to noise texture and then use the DIFFUSE_TEXTURE instead of iChannel0

Thank you, this is great source you showed to me. I will use it as procedural generation.

Good to see what kind of FX is available with Defold.

Ported the shader to Defold:

9 Likes

Noyce work, @GerodruS. :+1:

Works fine on Mac OS, but on iPhone 7 Plus is terrible slow :frowning:

Cool! Thank you for sharing!

Yep, on old PCs too.
It’s straight port without almost any optimizations.
Fast clouds are not so fast (:
Maybe, I’ll do something, but if you have any suggestions - you’re welcome!

1 Like

Neat!

As for performance, the old optimisation trick still stand, the fastest code is the code that doesn’t have to run! :slight_smile:

In this case, that means moving calculations from fragment shader to the vertex shader, or perhaps as uniforms. See my answer to this forum post for a more hands on look at what I’m referring to.

2 Likes

Thank you for generous offer. It will help me a lot.