Map processing sketch coordinates to shader .frag coordinates

Hi, everyone,

Since I am a beginer with shaders, I’m stuck in this very basic matter. I would like to generate a shader image output in the exact point where the mouse is, as a first step in the project I am currently in.
I exactly don’t know the proper way to normalize the coordinates according to different sketch sizes (horizontal or vertical) and therefore use them to map my mouse coordinates.

I post here some code example that is not actually working :

That’s my normalizing function:

if (width>height) {
    screenSz=new PVector((float(width)/float(height)), 1.0);
  } else if (height>width) {
    screenSz=new PVector(1.0, (float(height)/float(width)));
  } else {
    screenSz=new PVector(1.0, 1.0);
 }

and that’s the mapping one:

PVector convertPos(PVector _pv, PVector _pvScreen) {
  return new PVector(map(_pv.x, 0, width, 0, _pvScreen.x), map(_pv.y, height, 0, 0, _pvScreen.y));
}

The actual problems with this code is that, in my shader, the image generated goes inverse (upDown) to the mouseY position, and in any axis covers the whole of the screen.

Any help will be very, very appreciated. I hope this problem could be useful for future shader newbies like me. Thanks a lot.

1 Like

Replying to my own question: Actually, I can say that the following code is performing well in a simplified version. This way, I know that my problems come from another part of the code.
Here I post the whole working code, that may be useful to someone. Thanks a lot.

Here, the processing code:

PShader shader;
int numShad=0;
String strFile,file;
PVector screenSz,posPV=new PVector();
float[] _pos =new float[2];

void setup(){
  size(1024, 768, P2D);
  hint(DISABLE_OPTIMIZED_STROKE);
  screenSz=screenCenter();
  loadShadi(file,strFile,numShad,screenSz);
  _pos[0] = 0; 
  _pos[1] = 0;
}

void draw(){
  
  posPV.set(convertPos(new PVector(mouseX,mouseY),screenSz));
  _pos[0] = posPV.x; 
  _pos[1] = posPV.y; 
  shader.set("pos",_pos);
  rect(0,0,width,height);
}

PVector screenCenter(){
  PVector _screenSz;
  if (width>height) {
    _screenSz=new PVector((float(width)/float(height)), 1.0);
  } else if (height>width) {
    _screenSz=new PVector(1.0, (float(height)/float(width)));
  } else _screenSz=new PVector(1.0, 1.0);
  
  
  return new PVector((_screenSz.x), (_screenSz.y));
}


void keyPressed(){
  if(key=='l')loadShadi(file,strFile,numShad,screenSz);
}

void loadShadi( String _file,String _strFile,int _numShad,PVector _scrCenter) {
  _strFile=str(_numShad);
  if (_strFile.length()<2)_strFile=str(0)+_strFile;
  _file="../data/shad_"+(_strFile)+".frag";
  
  shader = loadShader( _file );
  shader(shader);
  shader.set("size", (float)width, (float)height);
  shader.set("pos",_pos);
  shader.set("u_resolution", float(width), float(height));
  shader.set("screenCenterX", _scrCenter.x);  
  shader.set("screenCenterY", _scrCenter.y);   
  shader.set("width_", width*1.);  
  shader.set("height_", height*1.);  
} 

PVector convertPos(PVector _pv, PVector _pvS) {
  return new PVector(map(_pv.x, 0, width, 0, _pvS.x), map(_pv.y, height, 0, 0, _pvS.y));
}


and here the fragment shader code, moving a white ellipse extracted from “the book of shaders” by Patricio Gonzalez Vivo:

#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
uniform vec2 size;
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
uniform float screenCenterX;
uniform float screenCenterY;
uniform float width_;
uniform float height_;
uniform float[2] pos;

float circle(in vec2 _st, in float _radius, in vec2 _center){
    vec2 dist = _st-vec2(_center.x,_center.y);

    float _st1=_radius-(_radius*0.01);
    float _st2=_radius+(_radius*0.01);
    return 1.-smoothstep(_st1,_st2,dot(dist,dist)*4.0);
}
void main(){
	vec2 st = gl_FragCoord.xy/min(u_resolution.x,u_resolution.y);
	vec3 _finalColor=vec3(0.);

	vec2 _pos =vec2(pos[0],pos[1]);
	float _c=circle(st,0.1,_pos);

	gl_FragColor = vec4(vec3(_c),1.);

}
2 Likes

Thanks for sharing your solution!

Just to be clear, is your problem solved now as marked, or do you need additional help?

Hi, @jeremydouglass. Yes, this concrete problem is solved. Thanks a lot.

1 Like

Hi! Here’s an even simpler version that draws a circle using a shader at the mouse position:

// sketch.pde
PShader shader;

void setup() {
  size(400, 800, P2D);
  loadShadi();
}
void draw() {  
  // note the vertical flip
  shader.set("u_mouse", (float) mouseX, (float) (height-mouseY));
  rect(0, 0, width, height);
}
void keyPressed() {
  if (key=='l') {
    loadShadi();
  }
}
void loadShadi() {
  shader = loadShader("ColorFrag.glsl");
  shader(shader);
  shader.set("u_resolution", (float) width, (float) height);
}
// ColorFrag.glsl
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;

float circle(in vec2 _st, in float _radius, in vec2 _center) {
    return 1. - smoothstep(
        _radius * 0.99, 
        _radius * 1.01, length(_st - _center));
}

void main() {
  vec2 screenPos = gl_FragCoord.xy / u_resolution.y;
  vec2 circlePos = u_mouse / u_resolution.y;

  float gray = circle(screenPos, 0.1, circlePos);

  gl_FragColor = vec4(vec3(gray), 1.);
}

:slight_smile:

3 Likes

Thanks, Abe! You are true, that’s even simpler and more elegant.