Complex gradient loop

And playing with the program and I am hallucinating with results. I have obtained this amazing gradient that you can see here:

colorMode( HSB, 360,100,100 );

color c = color( random(1,360), 100, 100 );


But sometimes the result is dirtier because the colors of the points art not as closer and organized in the colour wheel:

So how could I relate these points to follow the order of colors in colour wheel, from hue 1 to 360 in HSB color mode? Imagine that randoms colors are 22,45,154, 263,302 and 313, how could I distribute them like this: point 1(22), point 2(45), point 3(154), point 4(263), point 5(302), point 6(313)?

1 Like

In initControlPoints(), you could change it to:

  for( int i=0; i<N; i++ ) {
    float ang = TAU*i/N;
    int x = (int)((0.5 + 0.4*cos(ang)) * 65536);
    int y = (int)((0.5 + 0.4*sin(ang)) * 65536);
    color c = color( 360.0*i/N, 100, 100 );
    inputs.pixels[ i ] = (x << 16) | y;
    inputs.pixels[ i+N ] = c;
  }

If you want some randomness, you would want to randomly generate and store N hue values in an array, sort it, and read them out in order when filling the input.pixels.

  float[] hues = new float[N];
  for( int i=0; i<N; i++ ) hues[i] = random(360);
  hues = sort( hues );
  for( int i=0; i<N; i++ ) {
    float ang = TAU*i/N;
    float r = random( 0.2, 0.5 );
    int x = (int)((0.5 + r*cos(ang)) * 65536);
    int y = (int)((0.5 + r*sin(ang)) * 65536);
    color c = color( hues[i], 100, 100 );
    inputs.pixels[ i ] = (x << 16) | y;
    inputs.pixels[ i+N ] = c;
  }
1 Like

Hi

Complex but easy

void setup () {
size (600,600);
colorMode(HSB);
}
void draw(){
for(int i= 600; i >0; i=i -1) {
  stroke((i/2) + (mouseX/2), 300,300);
rect(0,0,i ,i);
}
}

well, no I am trying to change

size( 1200, 1600, P3D );

and I receive this message:

“The sketch has been resized from 1200x1600 to 1200x1055 by the operating system.
This happened outside Processing, and may be a limitation of the OS or window manager.”

how could make this image bigger in windows?

1 Like

You can keep size() so it fits on your screen, but, in my code above, you can set the size of the grad PGraphics to be as large as you want.

So

void setup() {
  size( 600, 800, P3D );
  colorMode( HSB, 1, 1, 1, 1 );
  grad = createGraphics( width*2, height*2, P3D );
  gradShader = new PShader( this, gradVert, gradFrag );
  initControlPoints();
  gradShader.set( "strength", strength );
  gradShader.set( "bOklab", bOklab );
  noLoop();
}

and in draw(), change image() to image( grad, 0, 0, width, height ); and where I have save( fileName ); change it to grad.save( fileName ); so it saves the PGraphics image rather than the screen image.

1 Like

And what If I wanted to choose coordinates and colors of the control points? How could I use, for example, these values?

float x1 = 525;
float y1 = 150;
float x2 = 990;
float y2 = 500;
float x3 = 550;
float y3 = 925;
float x4 = 275;
float y4 = 725;
float x5 = 500;
float y5 = 125;
float x6 = 250;
float y6 = 200;


color a = color(179,100,100);
color b = color(68, 100,100);
color c = color(303, 100,100);
color d = color(299, 100,100);
color e = color(276, 100,100);
color f = color(193, 100,100);
1 Like

Put them in an array and read from the array in the loop to fill the inputs texture. For instance if you have the coordinates in x[] and y[] and the colors in c[], then you would use:

  for( int i=0; i<N; i++ ) {
    int x = (int)(65536 * x[i] / grad.width);
    int y = (int)(65536 * y[i] / grad.height);
    inputs.pixels[ i ] = (x << 16) | y;
    inputs.pixels[ i+N ] = c[i];
  }
2 Likes

like this?

float[] positions =  new float [12];
float [x1] = 525;
float [y1] = 150;
float [x2] = 990;
float [y2] = 500;
float [x3] = 550;
float [y3] = 925;
float [x4] = 275;
float [y4] = 725;
float [x5] = 500;
float [y5] = 125;
float [x6] = 250;
float [y6] = 200;

color[] colors = new color [];
color [a] = color(179,100,100);
color [b] = color(68, 100,100);
color [c] = color(303, 100,100);
color [d] = color(299, 100,100);
color [e] = color(276, 100,100);
color [f] = color(193, 100,100);




More like this. It’s easier to make a 2D array of floats for the positions. I wouldn’t name an array color since that’s already a Processing function name – could be confusing.

1 Like

Hi

Thanks! And do I receive this message? “NullPointerException” for this line

inputs.pixels[ i ] = (x << 16) | y;
PImage inputs;
PGraphics grad;
PShader gradShader;

int N = 9;
float strength = 1.;
boolean bShowPoints = true;
boolean bSaveFrame = false;

void setup() {
  size( 750, 1000, P3D );
  //fullScreen( P3D, SPAN );
  colorMode( HSB, 360,100,100 );
  grad = createGraphics( width, height, P3D );
  gradShader = new PShader( this, gradVert, gradFrag );
  initControlPoints();
  gradShader.set( "strength", strength );
  noLoop();
}

void initControlPoints() {
    float[][] pos = {
  { 525, 150 }, { 990, 500 }, { 550, 925 },
  { 275, 725 }, { 500, 125 }, { 250, 200 }
};
color[] cols = { 
  color( 179, 100, 100 ), color( 68, 100, 100 ), color( 303, 100, 100 ),
  color( 299, 100, 100 ), color( 276, 100, 100 ), color( 193, 100, 100 )
};

  for( int i=0; i<N; i++ ) {
    int x = (int)(65536 * pos[i][0] / grad.width);
    int y = (int)(65536 * pos[i][1] / grad.height);
    inputs.pixels[ i ] = (x << 16) | y;
    inputs.pixels[ i+N ] = cols[i];
  }
  //inputs = createImage( N, 2, ARGB );
  //inputs.loadPixels();
  //float[] hues = new float[N];
  // for( int i=0; i<N; i++ ) hues[i] = random(360);
  //hues = sort( hues );
  //for( int i=0; i<N; i++ ) {
  //float ang = TAU*i/N;
  // float r = random( 0.2, 0.5 );
    // int x = (int)((0.5 + r*cos(ang)) * 65536);
    // int y = (int)((0.5 + r*sin(ang)) * 65536);
    //color c = color( hues[i], 100, 100 );
    //inputs.pixels[ i ] = (x << 16) | y;
    //inputs.pixels[ i+N ] = c;
  //}
 //inputs.updatePixels();
 //gradShader.set( "inputs", inputs );
 //gradShader.set( "N", N );
}

void draw() {
  gradShader.set( "bShowPoints", bShowPoints );
  grad.beginDraw();
  grad.noStroke();
  grad.shader( gradShader );
  grad.rect( 0, 0, grad.width, grad.height );
  grad.resetShader();
  grad.endDraw();
  image( grad, 0, 0 );
  if( bShowPoints ) 
    text( str(N)+"    "+str(strength), 8, 16 );
  if( bSaveFrame ) {
    String fileName = getClass().getSimpleName() + "-" +
      nf(year(),4) + "-" + nf(month(),2) + "-" + nf(day(),2) + "-" +
      nf(hour(),2) + "-" + nf(minute(),2) + "-" + nf(second(),2) + ".TIFF";
    save( fileName );
    println( "saved " + fileName );
    bSaveFrame = false;
  }
}

void keyPressed() {
  if( keyCode == ENTER ) initControlPoints();
  else if( keyCode == DOWN ) { 
    strength /= 1.1;    
    gradShader.set( "strength", strength );
  }
  else if( keyCode == UP ) { 
    strength *= 1.1;    
    gradShader.set( "strength", strength );
  }
  else if( keyCode == LEFT ) { N = max(N-1, 1);  initControlPoints(); }
  else if( keyCode == RIGHT ) { N++;  initControlPoints(); }
  else if( key == ' ' ) bShowPoints = !bShowPoints;
  else if( key == '+' ) bSaveFrame = true;
  redraw();
}


String[] gradVert = {"""
#version 330
uniform mat4 transformMatrix;
in vec4 position;
void main() {
  gl_Position = transformMatrix * position;
}
"""};


String[] gradFrag = {"""
#version 330
precision highp float;
uniform vec2 resolution;
uniform sampler2D inputs;
uniform int N;
uniform bool bShowPoints;
uniform float strength;
out vec4 fragColor;

void main() {
  float aspect = resolution.x/resolution.y;
  vec2 uv = gl_FragCoord.xy / resolution.y;
  vec3 col = vec3(0.);
  float totw = 0.;
  for( int i=0; i<N; i++ ) {
    vec4 posData = texelFetch( inputs, ivec2( i, 0 ), 0 ) * 255.0;
    float x = (posData.a * 256 + posData.r)*aspect;
    float y = posData.g * 256 + posData.b;
    vec2 pos = vec2( x, y ) / 65536.0;
    vec3 c = texelFetch( inputs, ivec2( i, 1 ), 0 ).rgb;
    float d = length( uv - pos );
    float w = exp( -d*d*N*strength );
    if( w > 0 ) {
      col += c * w;
      totw += w;
    }
  }
  if( totw > 0. ) col /= totw;

  if( bShowPoints ) {
    for( int i=0; i<N; i++ ) {
      vec4 posData = texelFetch( inputs, ivec2( i, 0 ), 0 ) * 255.0;
      float x = (posData.a * 256 + posData.r)*aspect;
      float y = posData.g * 256 + posData.b;
      vec2 pos = vec2( x, y ) / 65536.0;
      vec3 c = texelFetch( inputs, ivec2( i, 1 ), 0 ).rgb;
      float d = length( uv - pos );
      if( d < 0.01 ) col = vec3(1.);
      if( d < 0.007 ) col = c;
    }
  }

  fragColor = vec4( col, 1. );
}
"""};

You have to keep the rest of the code that creates the PImage. And because you have 6 points, you have to set N to 6 at the top or can set it to N = pos.length; after creating the pos array as I did in the code below.

void initControlPoints() {
float[][] pos = {
  { 525, 150 }, { 990, 500 }, { 550, 925 },
  { 275, 725 }, { 500, 125 }, { 250, 200 }
};
color[] cols = { 
  color( 179, 100, 100 ), color( 68, 100, 100 ), color( 303, 100, 100 ),
  color( 299, 100, 100 ), color( 276, 100, 100 ), color( 193, 100, 100 )
};

  N = pos.length;
  inputs = createImage( N, 2, ARGB );
  inputs.loadPixels();
  for( int i=0; i<N; i++ ) {
    int x = (int)(65536 * pos[i][0] / grad.width);
    int y = (int)(65536 * pos[i][1] / grad.height);
    inputs.pixels[ i ] = (x << 16) | y;
    inputs.pixels[ i+N ] = cols[i];
  }
  inputs.updatePixels();
  gradShader.set( "inputs", inputs );
  gradShader.set( "N", N );
}