Starting out with Shaders

Hi all -

I’ve looked through the forum and documentation for information about using Shaders in Processing - but the results have been pretty mixed.

Examples from the Book of Shaders and Shadertoy don’t seem to play very nice with Processing, out-of-the-box.

The online tutorial - “Processing Shader Examples” - is 10 years old and relies on a library, GLGraphics, that is also about 10 years old. Are these tools still maintained and part of the Processing workflow?

Essentially, I’m just looking for a few basic examples/tutorials to get started with shaders in Processing, if anyone has any suggestions…

Also, I’m starting to become a little unclear about the advantages of Javascript vs. P5.JS vs. Python implementations of Processing, if anyone wanted to weigh in on the relationship of those to learning general shader processes.

Thanks!

If you just want to use fragment shaders such as in Shadertoy, it’s pretty simple.

PShader fragShader;

void setup() {
  size( 800, 800, P2D );
  fragShader = loadShader( "frag.glsl" );
}

void draw() {
  fragShader.set( "time", frameCount / 60.0 );
  shader( fragShader );
  rect( 0, 0, width, height );
}

Then, in your sketch directory, make a subdirectory called data and in it put frag.glsl with your shader code:

#ifdef GL_ES
precision highp float;
precision mediump int;
#endif

uniform vec2 resolution;
uniform float time;

void main() {
   vec2 uv = (2.*gl_FragCoord.xy - resolution) / resolution.y;
   vec3 col = vec3( 0.1, 0.3, 0.5 );
   if( length( uv ) < 0.5 + 0.3*sin( time ) ) {
       col = vec3( 1. );
   }
   gl_FragColor = vec4( col, 1. );
}

Processing sends in the “resolution” uniform automatically, but you’ll pass in “time” and any other inputs you want. For mouse or keyboard inputs, just use Processing’s functions and pass in whatever data values you need.

Debugging of shaders can be very tedious, so make small changes and test frequently to catch your errors as early as you can.

Thanks! This is definitely helpful to get some perspective.
I’m curious about this debugging process, though - with a slightly more complex bit of code, I run into a number of “undeclared identifier” errors.

///modificado por jorge2017a2
//referencia
//https://www.shadertoy.com/view/ltGSWz

#define distfar 6.0
#define iterations 5.0

float maxcomp(vec3 p) {
    return max(p.x,max(p.y,p.z));
}

float sdBox( vec3 p, vec3 b )
{
  vec3  di = abs(p) - b;
  float mc = maxcomp(di);
  return min(mc,length(max(di,0.0)));
}

float sdBox2D(vec2 p, vec2 b) {
	vec2  di = abs(p) - b;
    float mc = max(di.x,di.y);
    return min(mc,length(max(di,0.0)));
}

float sdCross( in vec3 p )
{
  float da = sdBox2D(p.xy,vec2(1.0));
  float db = sdBox2D(p.yz,vec2(1.0));
  float dc = sdBox2D(p.zx,vec2(1.0));
  return min(da,min(db,dc));
}

#define MENGER_ITERATIONS	2

vec4 mapFractal(in vec3 p)
{	
    p.xz = mod(p.xz + 4.0, 2.0) -1.0;
    //p.y = mod(p.y + 1.0, 2.0) - 1.0;
	
    float d = sdBox(p,vec3(1.0));
    vec4 res = vec4(d, 1.0, 0.01, 0.0);
	
    //float s = 1.5;
    float s = 2.5;
    
    for(int i = 0; i < MENGER_ITERATIONS; ++i)
    {	 
       
        s = pow(2.0,float(i));
        vec3 a = mod(p * s, 2.0) - 1.0;
        s *= 11.0;
        //vec3 r = abs(1.0 - 4.0 * abs(a));
        vec3 r = abs(1.0 - 5.0 * abs(a));
        
        float da = max(r.x, r.y);
        float db = max(r.y, r.z);
        float dc = max(r.z, r.x);
        float c = (min(da, min(db, dc)) - 0.85) / s;
        

        if(c > d)
        {
            d = c;
            res = vec4(d, min(res.y, 0.2 * da * db * dc), 0.0, 1.0);
        }
    }
    
    return res;
}


vec2 map1(vec3 p) 
{
    float d = sdBox(p,vec3(1.0));
    
    for (float i = 0.0; i < iterations; i++) {

        float scale = pow(2.0,i);
        vec3 q = mod(scale*p,2.0)-1.0;
        q = 1.0-abs(q);
        float c = sdCross(q*3.0)/(scale*3.0);
        d = max(d,-c),1.0;
        
        p += scale/3.0;
		
    }
    
    return vec2(d,1.0);
    
}




vec2 map(vec3  p)
{

   float t=mod(iTime,10.0); 
   float t1=mod(t,4.0);
   float t2=mod(t,3.0);
   float d1;
   if (t1<t2)
    d1=mapFractal(p).x;
   else
    d1=map1(p).x;
   
   return vec2(d1,1.0);
    
}

/*
*/

vec3 calcnormal(vec3 p) {
    vec2 e = vec2(0.0001, 0.0);
    vec3 n;
    n.x = map(p+e.xyy).x - map(p-e.xyy).x;
    n.y = map(p+e.yxy).x - map(p-e.yxy).x;
    n.z = map(p+e.yyx).x - map(p-e.yyx).x;
    return  normalize(n);
}

float softshadow (vec3 ro, vec3 rd) {
    float res = 1.0;
    float t = 0.001;
    for (float i = 0.0; i < 1000.0; i++) {
        if (t>distfar) break;
        vec2 h = map(ro + t*rd);
        if (h.x < 0.0001) return 0.0;
        res = min(res, 64.0*h.x/t);
        t += h.x;
    }
    return res;
}

vec3 trace(vec3 ro, vec3 rd) {
    float t = 0.0;
    for (float i = 0.0; i < 1000.0; i++) {
        if (t > distfar) break;
        vec2 d = map(ro + rd*t);
        if (d.x < 0.0001) return vec3(t, d.y, i);
        t += d.x;
    }
    return vec3(0.0);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	vec2 uv = fragCoord.xy / iResolution.xy * 2.0 - 1.0;
    uv.x *= iResolution.x/iResolution.y;
    
    vec3 ro = vec3(0.0,0.0,1.5);
    vec3 rd = normalize(vec3(uv,-1.5));
    
    float theta = sin(iTime/2.0);
    mat2 rot = mat2(cos(theta),sin(theta),-sin(theta),cos(theta));
    ro.yz *= rot;
    rd.yz *= rot;
    theta = iTime/3.0;
    rot = mat2(cos(theta),sin(theta),-sin(theta),cos(theta));
    ro.xz *= rot;
    rd.xz *= rot;
    
    vec3 t = trace(ro, rd);
    
    vec3 col = vec3(0.8);
    
    if (t.y > 0.5) {
        
        vec3 pos = ro + rd*t.x;
        vec3 lig = normalize(vec3(0.6,1.0,0.8));
        vec3 nor = calcnormal(pos);
        float refRange = 0.2;
        
        float occ = 1.0/(1.0+t.z/15.0);
        float sha = softshadow(pos, lig);
        float dif = max(0.0, dot(nor,lig));
        float sky = 0.5+0.5*nor.y;
        float ind = max(0.0, dot(nor,vec3(-1.0,-0.2,-1.0)*lig));
        float ref = max(1.0-refRange,dot(-nor,rd))-1.0+refRange;
        
        col = vec3(0.8,1.0,1.2)*dif*pow(vec3(sha),vec3(1.0,1.2,1.5));
        col += vec3(0.2,0.3,0.4)*ind*occ;
        col += vec3(0.2,0.2,0.3)*sky*occ;
        col += pow(ref,2.0)*4.0*occ;
        
        col = pow(col,vec3(0.4545));
        
    }
    
	fragColor = vec4(col,1.0);
}

Produces the following errors:

RuntimeException: Cannot compile fragment shader:
ERROR: 0:100: Use of undeclared identifier 'iTime'
ERROR: 0:101: Use of undeclared identifier 't'
ERROR: 0:102: Use of undeclared identifier 't'
ERROR: 0:104: Use of undeclared identifier 't1'
ERROR: 0:104: Use of undeclared identifier 't2'
ERROR: 0:151: Use of undeclared identifier 'iResolution'
ERROR: 0:152: Use of undeclared identifier 'uv'
ERROR: 0:152: Use of undeclared identifier 'iResolution'
ERROR: 0:152: Use of undeclared identifier 'iResolution'
ERROR: 0:155: Use of undeclared identifier 'uv'
ERROR: 0:157: Use of undeclared identifier 'iTime'
ERROR: 0:158: Use of undeclared identifier 'theta'
ERROR: 0:158: Use of undeclared identifier 'theta'
ERROR: 0:158: Use of undeclared identifier 'theta'
ERROR: 0:158: Use of undeclared identifier 'theta'
ERROR: 0:159: Use of undeclared identifier 'rot'
ERROR: 0:160: Use of undeclared identifier 'rd'
ERROR: 0:160: Use of undeclared identifier 'rot'
ERROR: 0:161: Use of undeclared identifier 'theta'
ERROR: 0:161: Use of undeclared identifier 'iTime'
ERROR: 0:162: Use of undeclared identifier 'rot'
ERROR: 0:162: Use of undeclared identifier 'theta'
ERROR: 0:162: Use of undeclared identifier 'theta'
ERROR: 0:162: Use of undeclared identifier 'theta'
ERROR: 0:162: Use of undeclared identifier 'theta'
ERROR: 0:163: Use of undeclared identifier 'rot'
ERROR: 0:164: Use of undeclared identifier 'rd'
ERROR: 0:164: Use of undeclared identifier 'rot'
ERROR: 0:166: Use of undeclared identifier 'rd'
ERROR: 0:170: Use of undeclared identifier 't'
ERROR: 0:172: Use of undeclared identifier 'rd'
ERROR: 0:172: Use of undeclared identifier 't'
ERROR: 0:174: Use of undeclared identifier 'pos'
ERROR: 0:177: Use of undeclared identifier 't'
ERROR: 0:178: Use of undeclared identifier 'pos'
ERROR: 0:179: Use of undeclared identifier 'nor'
ERROR: 0:180: Use of undeclared identifier 'nor'
ERROR: 0:181: Use of undeclared identifier 'nor'
ERROR: 0:182: Use of undeclared identifier 'nor'
ERROR: 0:182: Use of undeclared identifier 'rd'
ERROR: 0:184: Use of undeclared identifier 'dif'
ERROR: 0:184: Use of undeclared identifier 'sha'
ERROR: 0:185: Use of undeclared identifier 'ind'
ERROR: 0:185: Use of undeclared identifier 'occ'
ERROR: 0:186: Use of undeclared identifier 'sky'
ERROR: 0:186: Use of undeclared identifier 'occ'
ERROR: 0:187: Use of undeclared identifier 'ref'
ERROR: 0:187: Use of undeclared identifier 'occ'

Right. You’re starting too complex at first. Start with the simplest shaders and work up in complexity as you understand how to work with Processing.

From my example, I pass in time in the variable “time”. If you prefer, rename it “iTime” both in the Processing code and as the uniform variable in the shader to match your example. Likewise, Processing passes in the resolution as “resolution”. You could use a #define to rename it:

#define iResolution resolution

at the top of your shader code or just use “resolution” instead of “iResolution” in the code below.

The other errors probably stem from those two missing variables.