Hi,
I’m currently working on a GLSL Reaction Diffusion project using Three.js, and I’ve been using this code as a reference. I’ve successfully updated the code to run on the latest Three.js version and made several other modifications.
My main challenges are:
-
How can I ensure that the diffusion only occurs within the confines of a specific shape or texture when the “Only inside” checkbox is checked? I want to prevent it from spreading outside. Also to be able to create many different patterns.
-
Is it possible to make the resulting effect transparent so that I can save a PNG image of it with a transparent background?
-
I’ve implemented scaling for the diffusion inside the fragment.glsl file, but I’m wondering if there’s a better or more efficient way to achieve this effect?
Ultimately, my goal is to have control over whether the diffusion occurs strictly within a defined shape (texture) or if it can extend beyond when the “Only inside” checkbox is unchecked.
You can access the project on CodeSandbox through this link: CodeSandbox Link.
All improvements are welcome!
fragment.glsl
My main fragment shader looks like this:
uniform int time;
uniform vec2 resolution;
uniform sampler2D start;
uniform sampler2D uTexture;
uniform float uScale;
uniform vec2 mouse;
uniform bool allowMouse;
vec2 pos;
vec2 texColor;
vec2 offset;
uniform float dA;
uniform float dB;
uniform float kill;
uniform float feed;
uniform float dT;
vec2 getLaplace() {
// My scaling method
vec2 offset = vec2( 1.0 ) / resolution * (uScale - 0.1);
vec2 up = pos + vec2( 0.0, -offset.y );
vec2 down = pos + vec2( 0.0, offset.y );
vec2 left = pos + vec2( -offset.x, 0.0 );
vec2 right = pos + vec2( offset.x, 0.0 );
vec2 center = texture2D( uTexture, pos ).rg;
vec2 colUp = texture2D( uTexture, up ).rg;
vec2 colDown = texture2D( uTexture, down ).rg;
vec2 colLeft = texture2D( uTexture, left ).rg;
vec2 colRight = texture2D( uTexture, right ).rg;
return colUp + colDown + colLeft + colRight - 4.0 * center;
}
void main( void ) {
vec2 uv = gl_FragCoord.xy / resolution;
pos = gl_FragCoord.xy / resolution;
vec2 color;
if( time == 1 ) {
color = vec2( 1.0, step( 0.1, texture2D( start, uv ).g ) * 0.3 );
} else {
vec2 texColor = texture2D( uTexture, uv ).rg;
offset = vec2( 1.0 ) / resolution;
float a = texColor.r;
float b = texColor.g;
// Mouse interaction
if(allowMouse && mouse.x > 5.0 && mouse.x < resolution.x - 5.0 && mouse.y > 5.0 && mouse.y < resolution.y - 5.0 ) {
float diff = length( gl_FragCoord.xy - mouse );
if( diff < 8.0 ) b = ( 1.0 - smoothstep( 1.0, 8.0, diff ) ) * 0.3;
}
vec2 laplace = getLaplace();
// Gray-Scott Model Equations
float red = (dA * laplace.r) - (a * b * b) + feed * (1.0 - a);
float green = (dB * laplace.g) + (a * b * b) - (kill + feed) * b;
color = texColor + vec2(red, green) * dT;
}
gl_FragColor = vec4(color, 0.0, 1.0);
}
color_fragment.glsl
uniform vec2 resolution;
uniform sampler2D uTexture;
uniform vec3 color1;
uniform vec3 color2;
uniform float uScale;
void main( void ){
vec2 uv = gl_FragCoord.xy / resolution * vec2( 0.5 );
vec3 color = mix(color1, color2, min(texture2D(uTexture, uv).g * 2.0, 1.0));
color = step( 0.5, color );
gl_FragColor = vec4(color, 1.0);
}
vertex.glsl
varying vec2 vUv;
uniform vec2 resolution;
void main(){
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
Any guidance or suggestions would be greatly appreciated!