Shaders v_vPosition to position on screen.

A

AlekM

Guest
Hello!
I am making a water shader, and I would like my water to have a reflection of the environment. My game so far uses a surface to take an upside down picture from under the water and save it to a texture, which is then passed into the shader.

Now I would like to fragment shader to take the current pixel's position, and convert it to screen coordinates, so it can select the correct pixel from the samples texture.

How would I go about converting from world space to screen space in GLSL?

Thanks,
Alek
 

YellowAfterlife

ᴏɴʟɪɴᴇ ᴍᴜʟᴛɪᴘʟᴀʏᴇʀ
Forum Staff
Moderator
You need to add a "varying" parameter for position and have your vertex shader set it so that the fragment shader can use it.

Vertex shader:
Code:
attribute vec3 in_Position;
attribute vec4 in_Colour;
attribute vec2 in_TextureCoord;
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition; // <- added
//
void main() {
   v_vPosition = in_Position; // <- added
   gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION]
       * vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
   v_vColour = in_Colour;
   v_vTexcoord = in_TextureCoord;
}
Fragment shader:
Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition; // <- added
//
void main() {
   // (v_vPosition will contain XYZ of the current pixel)
   vec4 col = v_vColour * texture2D(gm_BaseTexture, v_vTexcoord);
   col.a *= float((v_vPosition.y % 10.0) < 5.0); // make every other stripe transparent, for example
   gl_FragColor = col;
}
 
A

AlekM

Guest
You need to add a "varying" parameter for position and have your vertex shader set it so that the fragment shader can use it.

Vertex shader:
Code:
attribute vec3 in_Position;
attribute vec4 in_Colour;
attribute vec2 in_TextureCoord;
//
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition; // <- added
//
void main() {
   v_vPosition = in_Position; // <- added
   gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION]
       * vec4(in_Position.x, in_Position.y, in_Position.z, 1.0);
   v_vColour = in_Colour;
   v_vTexcoord = in_TextureCoord;
}
Fragment shader:
Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition; // <- added
//
void main() {
   // (v_vPosition will contain XYZ of the current pixel)
   vec4 col = v_vColour * texture2D(gm_BaseTexture, v_vTexcoord);
   col.a *= float((v_vPosition.y % 10.0) < 5.0); // make every other stripe transparent, for example
   gl_FragColor = col;
}
This is my current code so far:

Code:
//Most of the code is currently commented out to test just the reflection bit, I removed it for easier reading
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vNormal;
varying vec3 v_vPosition;
varying vec2 fragCoord;  //This is actually in_Position.xy, because someone in the comments mentioned that is the same as gl_fragCoord

uniform vec3 skyColour;
uniform vec3 sunPos;
uniform vec3 cameraPos;
uniform sampler2D normalMap;
uniform sampler2D reflect_tex;

void main()
{
    vec2 fragCoordMini = vec2(fragCoord.x/1280.0, fragCoord.y/720.0);
    vec2 fragCoordFlipped = vec2(fragCoordMini.x, 0.5-(fragCoordMini.y-0.5));
    vec4 col = texture2D(reflect_tex, fragCoordFlipped);

    gl_FragColor = col;
}
I was hoping to do this:
(it is time stamped to his demonstration of how it works).

He does this long process of using all sorts of data he calculated in his engine, however someone in the comments mentioned:
"gl_FragCoord gives the position on the screen in terms of pixels, so the coordinate system for that goes from (0, 0) to (displayWidth, displayHeight). To use this we would still need to divide by the display width and height."

I could not find a gl_fragCoord function, but xor's tutorial said I could do it with:
"You will need to create a varying vec2 called "fragCoord". Then set it in the vertex shader to "in_Position.xy""

However I have tried this and I have an abomination of a reflection:
 

Attachments

D

David Allen

Guest
Code:
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_vPosition; // <- added
//
void main() {
   // (v_vPosition will contain XYZ of the current pixel)
   vec4 col = v_vColour * texture2D(gm_BaseTexture, v_vTexcoord);
   col.a *= float((v_vPosition.y % 10.0) < 5.0); // make every other stripe transparent, for example
   gl_FragColor = col;
}
Does anyone know why I get an error when I try to use a modulus in fragment shaders?
Even this fails: float aaa = 5.0 % 3.0;

This works fine: float(mod(v_vPosition.x, 10.0) < 5.0)

I thought modulus never worked in gamemaker shader code, but this makes me wonder if there's something on my end.
 

Yal

🐧 *penguin noises*
GMC Elder
How would I go about converting from world space to screen space in GLSL?
In GLSL, texture coordinates are always in the range 0.0 --> 1.0, so the easiest way would be to add a vec2 uniform which you set to the width and height of the region in GM's world space. Then you can sample at delta_pixels/size_uniform pixels to get the pixel-sized displacement you want in the texture (where size_uniform is the new uniform I'm proposing, and delta_pixels is the displacement in pixels). If you're sampling something that's on a separate texture page (surfaces should always be iirc) and have texture repeating turned on, it'll even wrap around automatically at the edges! (if you want that to happen in your effect, it's just a gpu_set_texture_repeat() call... and if not, you don't need to do anything)
 
Top