So, I have a circle in glsl that is supposed to be drawn around the mouse. The resulting circle is drawn in the wrong location.
I'm drawing the circle by taking the step of the distance from st and the vector2 of the uniform mouse.
I have no Idea why this is happening.
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;
float pct = 0.0;
vec2 brightness = vec2(0.0);
pct = step(distance(st,vec2(u_mouse/100.0)),0.5);
vec3 color = vec3(0.);
color = vec3(pct);
brightness = vec2(1.0);
gl_FragColor = vec4(color,brightness);
}
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;
float pct = 0.0;
vec2 brightness = vec2(0.0);
pct = step(distance(st,vec2(u_mouse/100.0)),0.5);
vec3 color = vec3(0.);
color = vec3(pct);
brightness = vec2(1.0);
gl_FragColor = vec4(color,brightness);
}
Here is an example using Shadertoy, that can be trivially adapted to your OpenGL/GLSL code.
The code comes from a basic 2D tutorial on Shadertoy on how to draw a circle around the centre of the screen, by coloring a pixel based on whether it lies within a given cartesian distance (ie. its radius) from its centre. Then it is modified to instead draw the circle around the mouse pointer:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 m = (iMouse.xy / iResolution.xy);
vec2 uv = (fragCoord.xy / iResolution.xy);
uv.x *= iResolution.x/iResolution.y;
m.x *= iResolution.x/iResolution.y;
float radius = 0.25;
vec3 pixel;
if( (uv.x-m.x)*(uv.x-m.x) + (uv.y-m.y)*(uv.y-m.y) < radius*radius ) {
pixel = vec3(0.3, 0.3, 1.0);
} else {
pixel = vec3(1.0, 0.3, 0.2);
}
fragColor = vec4(pixel, 1.0);
}
Demo:
Is the code duplicated by accident? I would check that you are passing in the values you expect for mouse and resolution, and take into account whether your window is fullscreen or not.
Related
Based on the accepted answer for the question Is there a way to draw a circle with the fragment shader at the position of a point from the vertex shader?, I am having the following results when I try to draw 3 circles based on the points (0.0, -0.75, 0.0), (0.0, 0.0, 0.0) and (0.0, 0.75, 0.0). Both window and viewport are 418x418.
The question is: Why only the center point is rendered properly, while the bottom circle is stretched and the top circle is shrinked, both on the Y-axis?
Vertex Shader
precision highp float;
attribute vec4 vPosition;
varying vec2 pointPos;
uniform vec2 windowSize; // = (window-width, window-height)
void main()
{
gl_Position = vPosition;
gl_PointSize = 900.0;
vec2 ndcPos = gl_Position.xy / gl_Position.w;
pointPos = windowSize * (ndcPos*0.5 + 0.5);
}
Fragment Shader
precision highp float;
varying vec2 pointPos;
uniform vec4 fColor;
const float threshold = 0.3;
const float aRadius = 10.0;
void main()
{
float dist = distance(pointPos, gl_FragCoord.xy);
if (dist > aRadius)
discard;
float d = dist / aRadius;
vec3 color = mix(fColor.rgb, vec3(0.0), step(1.0-threshold, d));
gl_FragColor = vec4(color, 1.0);
}
I am struggling to understand why the top and bottom circles are not being rendered properly, but I could not figure it out yet.
I want to draw a smooth circle in GLSL but with a border of variable width, in a separate colour. Potentially, the interior of the circle could be transparent.
My original non-smooth shader:
#version 330
layout(location=0) out vec4 frag_colour;
in vec4 color;
uniform float radius;
uniform vec2 position;
uniform vec4 borderColor;
uniform float borderThickness;
void main()
{
float distanceX = abs(gl_FragCoord.x - position.x);
float distanceY = abs(gl_FragCoord.y - position.y);
if(sqrt(distanceX * distanceX + distanceY * distanceY) > radius)
discard;
else if(sqrt(distanceX * distanceX + distanceY * distanceY) <= radius &&
sqrt(distanceX * distanceX + distanceY * distanceY) >= radius-borderThickness)
frag_colour = borderColor;
else
frag_colour = color;
}
This works, but is not smooth. I can draw smooth circles:
#version 330
layout(location=0) out vec4 frag_colour;
in vec4 color;
uniform float radius;
uniform vec2 position;
uniform vec4 borderColor;
uniform float borderThickness;
void main()
{
vec2 uv = gl_FragCoord.xy - position;
float d = sqrt(dot(uv,uv));
float t = 1.0 - smoothstep(radius-borderThickness,radius, d);
frag_colour = vec4(color.rgb,color.a*t);
}
But I can't work out how to add my border to the above.
You have to compute the absolut value of the difference between the radius and the distance and interpolate between 0.0 and borderThickness:
float t = 1.0 - smoothstep(0.0, borderThickness, abs(radius-d));
If you want to fill the circle, then you need 2 gradients. 1 for the transition between the inner circle and the border and a 2nd one for the alpha channel on the outline. mix the colors by the former and set the alpha channel by the later:
float t1 = 1.0 - smoothstep(radius-borderThickness, radius, d);
float t2 = 1.0 - smoothstep(radius, radius+borderThickness, d);
frag_colour = vec4(mix(color.rgb, baseColor.rgb, t1), t2);
I'd like my faded lighting (based on distance from a point) to be a perfect circle no matter the resolution. Currently, the light is only a circle if the height and width of the window are equal.
This is what it looks like right now:
My fragment shader looks like this:
precision mediump float;
#endif
#define MAX_LIGHTS 10
// varying input variables from our vertex shader
varying vec4 v_color;
varying vec2 v_texCoords;
// a special uniform for textures
uniform sampler2D u_texture;
uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 lightsPos[MAX_LIGHTS];
uniform vec3 lightsColor[MAX_LIGHTS];
uniform float lightsSize[MAX_LIGHTS];
uniform vec2 cam;
uniform vec2 randPos;
uniform bool dark;
void main()
{
vec4 lights = vec4(0.0,0.0,0.0,1.0);
float ratio = u_resolution.x/u_resolution.y;
vec2 st = gl_FragCoord.xy/u_resolution;
vec2 loc = vec2(.5 + randPos.x, 0.5 + randPos.y);
for(int i = 0; i < MAX_LIGHTS; i++)
{
if(lightsSize[i] != 0.0)
{
// trying to reshape the light
// vec2 st2 = st;
// st2.x *= ratio;
float size = 2.0/lightsSize[i];
float dist = max(0.0, distance(lightsPos[i], st)); // st here was replaced with st2 when experimenting
lights = lights + vec4(max(0.0, lightsColor[i].x - size * dist), max(0.0, lightsColor[i].y - size * dist), max(0.0, lightsColor[i].z - size * dist), 0.0);
}
}
if(dark)
{
lights.r = max(lights.r, 0.075);
lights.g = max(lights.g, 0.075);
lights.b = max(lights.b, 0.075);
}
else
{
lights.r += 1.0;
lights.g += 1.0;
lights.b += 1.0;
}
gl_FragColor = texture2D(u_texture, v_texCoords) * lights;
}
I tried reshaping the light by multiplying the x value of the pixel by the ratio of the screen width to the screen height but that caused the lights to be out of place. I couldn't figure out anything that would put them back in their correct place while maintaining their shape.
EDIT: the displacement is determined by my camera's position in my libgdx scene.
what you need is to rescale the difference between light position and fragment position
vec2 dr = st-lightsPos[i];
dr.x*=ratio;
float dist = length(dr);
Try normalizing st like that
vec2 st = (gl_FragCoord.xy - .5*u_resolution.xy) / min(u_resolution.x, u_resolution.y);
So that coordinates of your fragments are in range [-1; 1] for y and [-ratio/2; ratio/2] where ratio = u_resolution.x/u_resolution.y
You can also make it [0; 1] for y and [0; ratio] for x by doing
vec2 st = gl_FragCoord.xy / min(u_resolution.x, u_resolution.y);
But the former is more convenient in many cases
I have some code I wrote in the book of shaders editor:
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;
float remap(float a, float b, float c, float d, float t) {
return ((t - a) / (b - a)) * (d-c) + c;
}
float outline(vec2 st) {
return smoothstep(0.99, 1.0, st.y) + smoothstep(0.99, 1.0, st.x) + smoothstep(0.01, 0.0, st.y) + smoothstep(0.01, 0.0, st.x);
}
float mouseFoo(vec2 scaledSt, vec2 u_mouse, float scaleVal) {
vec2 scaledMouse = u_mouse * scaleVal;
if(scaledSt.x < ceil(scaledMouse.x) && scaledSt.x > floor(scaledMouse.x) && scaledSt.y < ceil(scaledMouse.y) && scaledSt.y > floor(scaledMouse.y)) {
// if(u_mouse.x < 100.0) {
return 1.0;
} else {
return 0.0;
}
}
void main(){
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(0.03,0.07,0.15);
vec3 redColor = vec3(1.0, 0.0, 0.0);
vec3 outlineColor = vec3(1.0);
float floorSt;
float scaleVal = 5.0;
vec2 scaledSt = st * scaleVal;
// tile
st *= scaleVal;
floorSt = floor(st.x);
st = fract(st);
// inner color
color = mix(color, redColor, mouseFoo(scaledSt, u_mouse/u_resolution.xy, scaleVal));
// outline
color = mix(color, outlineColor, outline(st));
gl_FragColor = vec4(color, 1.0 );
}
I'm wondering if it's possible to have the red color tween to the blue color when a box is hovered off? I think I might have an idea of how to do it if I were to write data to a texture and look that up, but even then I'm not entirely sure.
Use mix
Use mix to interpolate between red and blue. You need another variable that transitions from 0-1 to do the blend, which is mix's 3rd parameter.
ShaderToy example:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord/iResolution.xy;
vec3 red = vec3(1,0,0);
vec3 blue = vec3(0,0,1);
// Output to screen
fragColor = vec4(mix(red, blue, uv.x),1.0);
}
which produces:
In your case, you'll want the 3rd parameter (the alpha or lerp parameter) to be driven over some time (say, .2 seconds) after the mouse entered the hover area. You'll need to do one of the following:
Detect the hover entered at a higher level and then pass the mouse down time in as a uniform
Drive the 3rd parameter directly from a uniform
I'm trying to make an effect in fragment shader... This is what I get without effects:
This is what I get by multiplying the color by a 'gradient':
float fragPosition = gl_FragCoord.y / screenSize.y;
outgoingLight /= fragPosition;
So I tried to dividing but the color is kind of burned by light
float fragPosition = gl_FragCoord.y / screenSize.y;
outgoingLight /= fragPosition;
And here are the kind of colors/gradient I want (per face if available):
EDIT
Here is the vertex shader (I use three JS chunks)
precision highp float;
precision highp int;
#define PHONG
uniform float time;
attribute vec4 data;
varying vec3 vViewPosition;
#ifndef FLAT_SHADED
varying vec3 vNormal;
#endif
$common
$map_pars_vertex
$lightmap_pars_vertex
$envmap_pars_vertex
$lights_phong_pars_vertex
$color_pars_vertex
$morphtarget_pars_vertex
$skinning_pars_vertex
$shadowmap_pars_vertex
$logdepthbuf_pars_vertex
void main(){
float displacementAmount = data.x;
int x = int(data.y);
int y = int(data.z);
bool edge = bool(data.w);
$map_vertex
$lightmap_vertex
$color_vertex
$morphnormal_vertex
$skinbase_vertex
$skinnormal_vertex
$defaultnormal_vertex
#ifndef FLAT_SHADED
vNormal = normalize( transformedNormal );
#endif
$morphtarget_vertex
$skinning_verte
$default_vertex
if( edge == false ){
vec3 displacement = vec3(sin(time * 0.001 * displacementAmount) * 0.2);
mvPosition = mvPosition + vec4(displacement, 1.0);
gl_Position = projectionMatrix * mvPosition;
}
$logdepthbuf_vertex
vViewPosition = -mvPosition.xyz;
$worldpos_vertex
$envmap_vertex
$lights_phong_vertex
$shadowmap_vertex
vec3 newPosition = position + vec3(mvPosition.xyz);
gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
EDIT 2:
After #gamedevelopmentgerm suggestion to mix here is what I get:
It's much better what I get but is it possible to avoid black to white gradient in background. I only want blue to white.