Handmade Hero»Forums»Code
107 posts
Get fragment color on click

Hi!

Im trying to send a color from the shader to a variable in my gamecode on click, is this possible?

Right now im trying to assign the fragment to a uniform vec4 but get the error:

0(56) : error C7563: assignment to uniform v4Picked_col

This is my shader:

#version 330 core

in vec4 VS_out_col;
in vec2 VS_out_tCoord;

uniform ivec2 v2iResolution;
uniform vec4 v4Circle_pos;
uniform vec4 v4Picked_col;

out vec4 textured_surface;

uniform sampler2D in_texture;

void main()
{
	vec4 col = VS_out_col;
	vec2 uv = gl_FragCoord.xy / v2iResolution * 2.0;

	vec2 Cpos = v4Circle_pos.xy;
	vec2 Csz = v4Circle_pos.zw;

	vec2 origo = vec2(Cpos.x + (Csz.x / 2.0), Cpos.y + (Csz.y / 2.0));

	float distance = length(origo - uv);
	float radius = Csz.x / 2.0;
	float border = length(origo - Cpos);

	if(distance < (radius) && Cpos != 0.0) 
	{
		float sub_vector = length(uv - origo);
		float left_vector = length(uv - Cpos);
		float top_vector = length(uv - vec2(origo.x, Cpos.y + Csz.y));
		float right_vector = length(uv - vec2(Cpos.x + Csz.x, Cpos.y));

		if(sub_vector < 0.025)
			col.rgb = vec3(1.0, 0.0, 0.0);
		else if(sub_vector < 0.05)
			col.rgb = vec3(1.0, 0.0, 2.0);
		else if(sub_vector < 0.075)
			col.rgb = vec3(1.0, 0.5, 0.2);
		else if(sub_vector < 0.1)
			col.rgb = vec3(1.0, 1.0, 0.0);
		else if(sub_vector < 0.125)
			col.rgb = vec3(0.0, 1.0, 0.0);
		else if(sub_vector < 0.15)
			col.rgb = vec3(0.5, 1.0, 0.0);
		else if(sub_vector < 0.175)
			col.rgb = vec3(0.0, 0.0, 1.0);
		else if(sub_vector < 0.2)
			col.rgb = vec3(0.0, 1.0, 1.0);
		else if(sub_vector < 0.225)
			col.rgb = vec3(0.2, 0.2, 0.2);
		else if(sub_vector < 0.25)
			col.rgb = vec3(1.0, 1.0, 1.0);
                

                // THIS DOESN'T WORK
		v4Picked_col = col;

	}
	else if(distance > (radius) && distance < (border))
	{
		col.rgb = vec3(0.0f);
	}
	else
		col = VS_out_col;


	textured_surface = texture(in_texture, VS_out_tCoord) * col;
}

in vec4 VS_out_col; in vec2 VS_out_tCoord;

uniform ivec2 v2iResolution; uniform vec4 v4Circle_pos; uniform vec4 v4Picked_col;

out vec4 textured_surface;

uniform sampler2D in_texture;

void main() { vec4 col = VS_out_col; vec2 uv = gl_FragCoord.xy / v2iResolution * 2.0;

vec2 Cpos = v4Circle_pos.xy;
vec2 Csz = v4Circle_pos.zw;

vec2 origo = vec2(Cpos.x + (Csz.x / 2.0), Cpos.y + (Csz.y / 2.0));

float distance = length(origo - uv);
float radius = Csz.x / 2.0;
float border = length(origo - Cpos);

if(distance < (radius) && Cpos != 0.0) 
{
	float sub_vector = length(uv - origo);
	float left_vector = length(uv - Cpos);
	float top_vector = length(uv - vec2(origo.x, Cpos.y + Csz.y));
	float right_vector = length(uv - vec2(Cpos.x + Csz.x, Cpos.y));

	if(sub_vector < 0.025)
        col.rgb = vec3(1.0, 0.0, 0.0);
	else if(sub_vector < 0.05)
        col.rgb = vec3(1.0, 0.0, 2.0);
	else if(sub_vector < 0.075)
        col.rgb = vec3(1.0, 0.5, 0.2);
	else if(sub_vector < 0.1)
        col.rgb = vec3(1.0, 1.0, 0.0);
	else if(sub_vector < 0.125)
        col.rgb = vec3(0.0, 1.0, 0.0);
	else if(sub_vector < 0.15)
        col.rgb = vec3(0.5, 1.0, 0.0);
	else if(sub_vector < 0.175)
        col.rgb = vec3(0.0, 0.0, 1.0);
	else if(sub_vector < 0.2)
        col.rgb = vec3(0.0, 1.0, 1.0);
	else if(sub_vector < 0.225)
        col.rgb = vec3(0.2, 0.2, 0.2);
	else if(sub_vector < 0.25)
        col.rgb = vec3(1.0, 1.0, 1.0);
            

            // THIS DOESN'T WORK
	v4Picked_col = col;

}
else if(distance > (radius) && distance < (border))
{
	col.rgb = vec3(0.0f);
}
else
	col = VS_out_col;


textured_surface = texture(in_texture, VS_out_tCoord) * col;

}

[/code]

Mārtiņš Možeiko
2561 posts / 2 projects
Get fragment color on click
Edited by Mārtiņš Možeiko on

Uniforms are only for providing input to shader. It cannot be retrieved as output.

There are different ways to do this:

  1. add extra render target texture, and for every pixel write whatever you want to write there. Then on CPU after draw call read the texture back to cpu - not necessarily whole texture, can read just one pixel if you need it. Very simple way, but limits how much information and formats you can write to texture. This works since GL 3.0 version (or realistically 2.0 with FBO extension).

  2. use SSBO (Shader Storage Buffer Object) - these buffers allow writes or atomic appends from shader. You can append whatever data you want. It can be just for one pixel, or can be for many pixels. Afterwards read buffer on CPU and use the data. SSBO works since GL 4.3 version.

107 posts
Get fragment color on click
Replying to mmozeiko (#27137)

Ah okay, using either of these two?

  • glReadPixels ()
  • glGetTexImage()
Mārtiņš Možeiko
2561 posts / 2 projects
Get fragment color on click
Replying to C_Worm (#27138)

Yes, or glGetTextureSubImage.