Plasma

This is a Shadertoy example. Because of the way this docs are built, its housed in a minimal Indigo project for built purposes, but the shader code isn't run because it's incompatible with Indigo, so all you get is a black screen.

This example is a port of 'Plasma' by Jolle, and you can view it here: https://www.shadertoy.com/view/XsVSDz

The GLSL Output

This is the shadertoy compatible GLSL code that Ultraviolet manufactures, note that this shader is in two parts, Buffer A and Image:

Buffer A

const float pi=3.1415927;
void mainImage(out vec4 fragColor,in vec2 fragCoord){
  float i=fragCoord.x/iResolution.x;
  vec3 t=(iTime+iMouse.y)/vec3(63.0,78.0,45.0);
  vec3 cs=cos(((i*pi)*2.0)+((vec3(0.0,1.0,-0.5))*pi)+t);
  fragColor=vec4(0.5+(0.5*cs),1.0);
}

Image

const vec2 vp=vec2(320.0,200.0);
void mainImage(out vec4 fragColor,in vec2 fragCoord){
  float t=(iTime*10.0)+iMouse.x;
  vec2 uv=fragCoord.xy/iResolution.xy;
  vec2 p0=(uv-0.5)*vp;
  vec2 hvp=vp*0.5;
  vec2 p1d=((vec2(cos(t/98.0),sin(t/178.0)))*hvp)-p0;
  vec2 p2d=((vec2(sin((-t)/124.0),cos((-t)/104.0)))*hvp)-p0;
  vec2 p3d=((vec2(cos((-t)/165.0),cos(t/45.0)))*hvp)-p0;
  float sum=0.25+(0.5*(cos(length(p1d)/30.0))+(cos(length(p2d)/20.0))+(sin(length(p3d)/25.0))*(sin(p3d.x/20.0))*(sin(p3d.y/15.0)));
  fragColor=texture(iChannel0,vec2(fract(sum),0.0));
}

Ultraviolet Shadertoy code

Reminder: The live demo will not work, below is the Shadertoy compatible code.

Unlike the default example, this example produces two shaders: 1. A shader that produces a buffer (bufferA) 2. A shader that produces the final image (image)

If you were to render Bufffer A, you'd see that it produces a noise image, which is then used as a reference source in order to produce the final plasma effect.

object ShaderToyExample:

  inline def bufferA =
    Shader[ShaderToyEnv, Unit] { env =>
      @const val pi: Float = 3.1415926435f

      def mainImage(fragColor: vec4, fragCoord: vec2): vec4 =
        val i: Float = fragCoord.x / env.iResolution.x
        val t: vec3  = (env.iTime + env.iMouse.y) / vec3(63.0f, 78.0f, 45.0f)
        val cs: vec3 = cos(i * pi * 2.0f + vec3(0.0f, 1.0f, -0.5f) * pi + t)

        vec4(0.5f + 0.5f * cs, 1.0f)
    }

  inline def image =
    Shader[ShaderToyEnv, Unit] { env =>
      @const val vp: vec2 = vec2(320.0, 200.0)

      def mainImage(fragColor: vec4, fragCoord: vec2): vec4 =
        val t: Float  = env.iTime * 10.0f + env.iMouse.x
        val uv: vec2  = fragCoord.xy / env.iResolution.xy
        val p0: vec2  = (uv - 0.5f) * vp
        val hvp: vec2 = vp * 0.5f
        val p1d: vec2 = vec2(cos(t / 98.0f), sin(t / 178.0f)) * hvp - p0
        val p2d: vec2 = vec2(sin(-t / 124.0f), cos(-t / 104.0f)) * hvp - p0
        val p3d: vec2 = vec2(cos(-t / 165.0f), cos(t / 45.0f)) * hvp - p0
        val sum: Float = 0.25f + 0.5f * (cos(length(p1d) / 30.0f) +
          cos(length(p2d) / 20.0f) +
          sin(length(p3d) / 25.0f) * sin(p3d.x / 20.0f) * sin(p3d.y / 15.0f))

        texture2D(env.iChannel0, vec2(fract(sum), 0))
    }

Then to get the code for the two shaders as a String so that we might print or output them somewhere, we can do the following:

object Output:

  val bufferACode: String =
    ShaderToyExample.bufferA.toGLSL[ShaderToy].toOutput.code

  val imageCode: String =
    ShaderToyExample.image.toGLSL[ShaderToy].toOutput.code