I'm writing a GLSL shader for raymarching, and I want to implement an orbit camera. For that, I check when the user left clicks to save the current coordinates, and change the angles of the camera depending on what direction the mouse moves. However, the variable in which I store the mouse position when the first click happens always contains the mouse current position. Trying to debug the problem, I found out that the first if
from main
is always reached, so the screen is black while the mouse is clicked:
// Camera control
vec2 cameraAng = vec2(0.5, 0.5);
bool isDragging = false;
vec2 startDraggingPos = vec2(-1);
// ···
void mainImage(out vec4 c, vec2 p)
{
vec2 uv = (gl_FragCoord.xy - 0.5*iResolution.xy) / iResolution.y;
vec2 mouseUV = vec2(0.5);
mouseUV = iMouse.xy/iResolution.xy; // [0,1]
if(iMouse.z > 0.0 && (iMouse.x > 0.0 || iMouse.y > 0.0) && !isDragging){
isDragging = true;
startDraggingPos = mouseUV;
// == Debug ==
c = vec4(0.0,0.0, 0.0,1.0);
return;
}
else if(iMouse.z < 0.0 || (iMouse.x <= 0.0 || iMouse.y <= 0.0)){
isDragging = false;
}
if(isDragging){
vec2 inc = (mouseUV - startDraggingPos) * 10.0;
cameraAng += inc;
}
// ···
}
It looks like the isDragging
variable is being reset all the time, but I can't figure out a solution. Here is the link to the full Shadertoy page: Shadertoy.
Thanks.
Your code seems to be written on the assumption that shader invocations have some preserved global state.
They do not.
The start of main
in a shader works exactly like the start of main
in your C++ program. All of your C++ global variables are initialized per their initializers before main
, then main
executes. That's what program execution means. It's just that in shaders, this happens for every vertex/fragment/etc independently, because every separate invocation of a shader is considered a separate execution of the program.
Because that's what it is.
Your shader should not be deciding whether or not dragging is happening. Your non-shader code should tell it that dragging is happening. Since you're using ShaderToy (and therefore, you don't control any non-shader code), you're going to have to use the information it provides to deduce whether dragging is happening. And this cannot be preserved across shader invocations (well, it maybe could depending on if ShaderToy supports image load/store, but that's well out of scope here). So whatever that deduction is, it must be executed continuously.