How to get the room (or screen) coordinates from inside a Gamemaker Studio 2 shader? - opengl

I'm mostly new to writing shaders, and this might not be a great place to start, but I'm trying to make a shader to make an object "sparkle." I won't get into the specifics on how it's supposed to look, but to make it I need a value that changes with the object's position in the room (or on the screen, as the camera is fixed). I've tried v_vTexcoord, in_Position, gl_Position, and others without the intended result. If I've used them wrong or missed something, I wouldn't be surprised, but any advice is helpful.
I don't think they'll be helpful but here's my vertex shader:
//it's mostly the same as the default
// Simple passthrough vertex shader
//
attribute vec3 in_Position; // (x,y,z)
//attribute vec3 in_Normal; // (x,y,z) unused in this shader.
attribute vec4 in_Colour; // (r,g,b,a)
attribute vec2 in_TextureCoord; // (u,v)
varying vec2 v_vTexcoord;
varying vec4 v_vColour;
varying vec3 v_inpos;
void main()
{
vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0);
gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos;
v_vColour = in_Colour;
v_vTexcoord = in_TextureCoord;
v_inpos = /*this is the variable that i'd like to set to the x,y*/;
}
and my fragment shader:
//
//
//
varying vec2 v_vTexcoord; //x is <1, >.5
varying vec4 v_vColour;
varying vec3 v_inpos;
uniform float pixelH; //unused, but left in for accuracy
uniform float pixelW; //see above
void main() //WHEN AN ERROR HAPPENS, THE SHADER JUST WON'T DO ANYTHING AT ALL.
{
vec2 offset = vec2 (pixelW, pixelH);
gl_FragColor = v_vColour * texture2D( gm_BaseTexture, v_vTexcoord );
/* i am planning on just testing different math until something works, but i can't
vec3 test = vec3 (v_inpos.x, v_inpos.x, v_inpos.x); //find the values i need to test it
test.x = mod(test.x,.08);
test.x = test.x - 4;
test.x = abs(test.x);
while (test.x > 1.0){
test.x = test.x/10;
}
test = vec3 (test.x, test.x, test.x);
gl_FragColor.a = test.x;
*/
//everything above doesn't cause an error when uncommented, i think
//if (v_inpos.x == 0.0){gl_FragColor.rgb = vec3 (1,0,0);}
//if (v_inpos.x > 1) {gl_FragColor.rgb = vec3 (0,1,0);}
//if (v_inpos.x < 1) {gl_FragColor.rgb = vec3 (0,0,1);}
}
if this question doesn't make sense, i'll try to clarify any other questions in the comments.

If you want to get a position in world space, then you have to transform the vertex coordinate from model space to world space.
This can be done by the model (world) matrix (gm_Matrices[MATRIX_WORLD]). See game-maker-studio-2 - Matrices.
e.g.:
vec4 object_space_pos = vec4(in_Position.xyz, 1.0);
vec4 world_space_pos = gm_Matrices[MATRIX_WORLD] * object_space_pos;
Not, the Cartesian world space position can be get by:
(See also Swizzling)
vec3 pos = world_space_pos.xyz;

Related

Incorrect tracing with SSLR (Screen Space Local Reflections)

While implementing SSLR, I ran into the problem of incorrectly displaying objects: they are infinitely projected "down" and displayed in no way at all in the mirror. I give the code and screenshot below.
Fragment SSLR shader:
#version 330 core
uniform sampler2D normalMap; // in view space
uniform sampler2D depthMap; // in view space
uniform sampler2D colorMap;
uniform sampler2D reflectionStrengthMap;
uniform mat4 projection;
uniform mat4 inv_projection;
in vec2 texCoord;
layout (location = 0) out vec4 fragColor;
vec3 calcViewPosition(in vec2 texCoord) {
// Combine UV & depth into XY & Z (NDC)
vec3 rawPosition = vec3(texCoord, texture(depthMap, texCoord).r);
// Convert from (0, 1) range to (-1, 1)
vec4 ScreenSpacePosition = vec4(rawPosition * 2 - 1, 1);
// Undo Perspective transformation to bring into view space
vec4 ViewPosition = inv_projection * ScreenSpacePosition;
// Perform perspective divide and return
return ViewPosition.xyz / ViewPosition.w;
}
vec2 rayCast(vec3 dir, inout vec3 hitCoord, out float dDepth) {
dir *= 0.25f;
for (int i = 0; i < 20; i++) {
hitCoord += dir;
vec4 projectedCoord = projection * vec4(hitCoord, 1.0);
projectedCoord.xy /= projectedCoord.w;
projectedCoord.xy = projectedCoord.xy * 0.5 + 0.5;
float depth = calcViewPosition(projectedCoord.xy).z;
dDepth = hitCoord.z - depth;
if(dDepth < 0.0) return projectedCoord.xy;
}
return vec2(-1.0);
}
void main() {
vec3 normal = texture(normalMap, texCoord).xyz * 2.0 - 1.0;
vec3 viewPos = calcViewPosition(texCoord);
// Reflection vector
vec3 reflected = normalize(reflect(normalize(viewPos), normalize(normal)));
// Ray cast
vec3 hitPos = viewPos;
float dDepth;
float minRayStep = 0.1f;
vec2 coords = rayCast(reflected * max(minRayStep, -viewPos.z), hitPos, dDepth);
if (coords != vec2(-1.0)) fragColor = mix(texture(colorMap, texCoord), texture(colorMap, coords), texture(reflectionStrengthMap, texCoord).r);
else fragColor = texture(colorMap, texCoord);
}
Screenshot:
Also, the lamp is not reflected at all
I will grateful for help
UPDATE:
colorMap:
normalMap:
depthMap:
UPDATE: I solved the problem with the wrong reflection, but there are still problems.
I solved it as follows: ViewPosition.y *= -1
Now, as you can see in the screenshot, the lower parts of the objects are not reflected for some reason.
The question still remains open.
I m struggling to get a fine ssr too. I found two things that could help.
To get the view space normals you have to keep only the rotation of the camera and remove the translation, because if you dont, you will get the normals stretched to the opposite direction of the camera movement and will no longer have the right direction even if you normalize them again, for column major mat4 you can do it like:
mat4 viewNoTranslation = view;
viewNoTranslation[3] = vec4(0.0, 0.0, 0.0, 1.0);
The depth sampling from the depth image is logarithmic and if you linearize it you will get indeed the values from 0 to 1 but they will be inaccurate as to the needed precision. I tried to get the depth value straight from the vertex shader:
gl_Position = ubo.projection * ubo.view * ubo.model * inPos;
depth = gl_Position.z;
I dont know if it is right but the depth now is more accurate.
If you make proggress, please update :)

OpenGL Simple Shading, Artifacts

I've been trying to implement a simple light / shading system, a simple Phong lighting system without specular lights to be precise. It basically works, except it has some (in my opinion) nasty artifacts.
My first thought was that maybe this is a problem of the texture mipmaps, but disabling them didn't work. My next best guess would be a shader issue, but I can't seem to find the error.
Has anybody ever experienced a similiar issue or an idea on how to solve this?
Image of the artifacts
Vertex shader:
#version 330 core
// Vertex shader
layout(location = 0) in vec3 vpos;
layout(location = 1) in vec2 vuv;
layout(location = 2) in vec3 vnormal;
out vec2 uv; // UV coordinates
out vec3 normal; // Normal in camera space
out vec3 pos; // Position in camera space
out vec3 light[3]; // Vertex -> light vector in camera space
uniform mat4 mv; // View * model matrix
uniform mat4 mvp; // Proj * View * Model matrix
uniform mat3 nm; // Normal matrix for transforming normals into c-space
void main() {
// Pass uv coordinates
uv = vuv;
// Adjust normals
normal = nm * vnormal;
// Calculation of vertex in camera space
pos = (mv * vec4(vpos, 1.0)).xyz;
// Vector vertex -> light in camera space
light[0] = (mv * vec4(0.0,0.3,0.0,1.0)).xyz - pos;
light[1] = (mv * vec4(-6.0,0.3,0.0,1.0)).xyz - pos;
light[2] = (mv * vec4(0.0,0.3,4.8,1.0)).xyz - pos;
// Pass position after projection transformation
gl_Position = mvp * vec4(vpos, 1.0);
}
Fragment shader:
#version 330 core
// Fragment shader
layout(location = 0) out vec3 color;
in vec2 uv; // UV coordinates
in vec3 normal; // Normal in camera space
in vec3 pos; // Position in camera space
in vec3 light[3]; // Vertex -> light vector in camera space
uniform sampler2D tex;
uniform float flicker;
void main() {
vec3 n = normalize(normal);
// Ambient
color = 0.05 * texture(tex, uv).rgb;
// Diffuse lights
for (int i = 0; i < 3; i++) {
l = normalize(light[i]);
cos = clamp(dot(n,l), 0.0, 1.0);
length = length(light[i]);
color += 0.6 * texture(tex, uv).rgb * cos / pow(length, 2);
}
}
As the first comment says, it looks like your color computation is using insufficient precision. Try using mediump or highp floats.
Additionally, the length = length(light[i]); pow(length,2) expression is quite inefficient, and could also be a source of the observed banding; you should use dot(light[i],light[i]) instead.
So i found information about my problem described as "gradient banding", also discussed here. The problem appears to be in the nature of my textures, since both, only the "white" texture and the real texture are mostly grey/white and there are effectively 256 levels of grey when using 8 bit per color channel.
The solution would be to implement post-processing dithering or to use better textures.

How to use a directional light in a blinn shader instead of point light?

So I am using a blinn shader program on some of my models, that uses a DIRECTIONAL light as opposed to a point light. I started out this original code that uses a point light:
VERTEX:
varying vec3 Half;
varying vec3 Light;
varying vec3 Normal;
varying vec4 Ambient;
void main()
{
// Vertex location in modelview coordinates
vec3 P = vec3(gl_ModelViewMatrix * gl_Vertex);
Light = vec3(gl_LightSource[0].position) - P;
Normal = gl_NormalMatrix * gl_Normal;
Half = gl_LightSource[0].halfVector.xyz;
Ambient = gl_FrontMaterial.emission + gl_FrontLightProduct[0].ambient + gl_LightModel.ambient*gl_FrontMaterial.ambient;
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}
FRAGMENT:
varying vec3 Half;
varying vec3 Light;
varying vec3 Normal;
varying vec4 Ambient;
uniform sampler2D tex;
vec4 blinn()
{
vec3 N = normalize(Normal);
vec3 L = normalize(Light);
vec4 color = Ambient;
float Id = dot(L,N);
if (Id>0.0)
{
color += Id*gl_FrontLightProduct[0].diffuse;
vec3 H = normalize(Half);
float Is = dot(H,L); // Specular is cosine of reflected and view vectors
if (Is>0.0) color += pow(Is,gl_FrontMaterial.shininess)*gl_FrontLightProduct[0].specular;
}
return color;
}
void main()
{
gl_FragColor = blinn() * texture2D(tex,gl_TexCoord[0].xy);
}
However, as stated above, instead of a point light I want I want a directional light, such that no matter where in the scene the model is the direction of the light is the same. So I make the following changes:
Instead of:
varying vec3 Light;
and
vec3 P = vec3(gl_ModelViewMatrix * gl_Vertex);
Light = vec3(gl_LightSource[0].position) - P;
I get rid of the above lines of code and instead in my fragment shader have:
uniform vec4 lightDir;
and
vec3 L = normalize(lightDir.xyz);
I pass the direction of the light as a uniform outside of a my shader program, and this works good: the model is lighted from a single direction no matter its location in the world! HOWEVER, now the lighting changes dramatically and unrealistically depending on the user's view, which makes sense since I got rid of ("-P ") in the light calculation in the original code. I've already tried adding that to the code (by moving lightDir back to vertex shader and passing it along again in a varying) to what I have and it just doesn't fix the problem. I'm afraid I just don't understand what is going well enough to figure this out, I understand that the " - P" for the Light vec3 is necessary: to make specular/reflection work, but I don't know how to make it work for a directional light. How do I make take the original above code, and make it so the light is treated as a directional light as opposed to a point light?

fragment shader performs differently on different computers

When I run the program on my computer, it works exactly how I expected it to be working. However, when I try to run it on my campus lab computers, the fragment shader is all kinds of strange.
Right now it's just a simple Phong lighting calculation with a point source light at the origin. However, on the lab computers, it looks more like some strange cross between cel shading and a flashlight. I run an ATI graphics card, while the lab computers run NVIDIA. The shading works as expected on Macs as well (no idea about the graphics card).
The NVIDIA cards support up to OpenGL 3.1, though I run it on this Linux distribution at 2.1. I've tried clamping the shader version to 1.2 (GLSL), among a slew of other things, but they achieve the same results. The strangest thing is that when I do vertex shading rather than pixel shading, the result is the same on both computers...I've exhausted my ideas about how to fix this.
Here's the vertex shader:
#version 120
attribute vec2 aTexCoord;
attribute vec3 aPosition;
attribute vec3 aNormal;
attribute vec3 camLoc;
attribute float mat;
varying vec3 vColor;
varying vec2 vTexCoord;
varying vec3 normals;
varying vec3 lightPos;
varying vec3 camPos;
varying float material;
uniform mat4 uProjMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uModelMatrix;
uniform mat4 uNormMatrix;
uniform vec3 uLight;
uniform vec3 uColor;
void main()
{
//set up object position in world space
vec4 vPosition = uModelMatrix * vec4(aPosition, 1.0);
vPosition = uViewMatrix * vPosition;
vPosition = uProjMatrix * vPosition;
gl_Position = vPosition;
//set up light vector in world space
vec4 vLight = vec4(uLight, 1.0) * uViewMatrix;
lightPos = vLight.xyz - vPosition.xyz;
//set up normal vector in world space
normals = (vec4(aNormal,1.0) * uNormMatrix).xyz;
//set up view vector in world space
camPos = camLoc.xyz - vPosition.xyz;
//set up material shininess
material = mat;
//pass color and vertex
vColor = uColor;
vTexCoord = aTexCoord;
}
And the fragment shader:
#version 120
varying vec3 lightPos;
varying vec3 normals;
varying vec3 camPos;
varying vec2 vTexCoord;
varying vec3 vColor;
varying float material;
uniform sampler2D uTexUnit;
uniform mat4 uProjMatrix;
uniform mat4 uViewMatrix;
uniform mat4 uModelMatrix;
void main(void)
{
float diffuse;
float diffuseRed, diffuseBlue, diffuseGreen;
float specular;
float specRed, specBlue, specGreen;
vec3 lightColor = vec3(0.996, 0.412, 0.706); //color of light (HOT PINK) **UPDATE WHEN CHANGED**
vec4 L; //light vector
vec4 N; //normal vector
vec4 V; //view vector
vec4 R; //reflection vector
vec4 H; //halfway vector
float red;
float green;
float blue;
vec4 texColor1 = texture2D(uTexUnit, vTexCoord);
//diffuse calculations
L = vec4(normalize(lightPos),0.0);
N = vec4(normalize(normals),0.0);
N = uModelMatrix * N;
//calculate RGB of diffuse light
diffuse = max(dot(N,L),0.0);
diffuseRed = diffuse*lightColor[0];
diffuseBlue = diffuse*lightColor[1];
diffuseGreen = diffuse*lightColor[2];
//specular calculations
V = vec4(normalize(camPos),0.0);
V = uModelMatrix * V;
R = vec4(-1.0 * L.x, -1.0 * L.y, -1.0 * L.z, 0.0);
float temp = 2.0*dot(L,N);
vec3 tempR = vec3(temp * N.x, temp * N.y, temp * N.z);
R = vec4(R.x + tempR.x, R.y + tempR.y, R.z + tempR.z, 0.0);
R = normalize(R);
H = normalize(L + V);
specular = dot(H,R);
specular = pow(specular,material);
specRed = specular*lightColor[0];
specBlue = specular*lightColor[1];
specGreen = specular*lightColor[2];
//set new colors
//textures
red = texColor1[0]*diffuseRed + texColor1[0]*specRed*0.7 + texColor1[0]*.05;
green = texColor1[1]*diffuseBlue + texColor1[1]*specBlue*0.7 + texColor1[1]*.05;
blue = texColor1[2]*diffuseGreen + texColor1[2]*specGreen*0.7 + texColor1[2]*.05;
//colors
red = vColor[0]*diffuseRed + vColor[0]*specRed*0.7 + vColor[0]*.05;
green = vColor[1]*diffuseBlue + vColor[1]*specBlue*0.7 + vColor[1]*.05;
blue = vColor[2]*diffuseGreen + vColor[2]*specGreen*0.7 + vColor[2]*.05;
gl_FragColor = vec4(red, green, blue, 1.0);
}
Your code looks wrong in many, many ways.
The following code is wrong. The comment is misleading (it’s in clip space, not world space). But the major problem is that you overwrite vPosition with the clip space coordinates while using it as if it was in view space several lines after this part.
//set up object position in world space
vec4 vPosition = uModelMatrix * vec4(aPosition, 1.0);
vPosition = uViewMatrix * vPosition;
vPosition = uProjMatrix * vPosition;
gl_Position = vPosition;
The following code is wrong, too. First you need matrix * vector, not vector * matrix. But also, the comment says world space, yet you compute vLight in view space and add vPosition which is in clip space!
//set up light vector in world space
vec4 vLight = vec4(uLight, 1.0) * uViewMatrix;
lightPos = vLight.xyz - vPosition.xyz;
Again here, matrix * vector:
//set up normal vector in world space
normals = (vec4(aNormal,1.0) * uNormMatrix).xyz;
Now what is this? camPos is computed in world coordinates, yet you apply the model matrix which converts model space to world space.
//specular calculations
V = vec4(normalize(camPos),0.0);
V = uModelMatrix * V;
I have no idea why your shader performs differently on different computers, but I am pretty sure none of these computers shows anything remotely close to the expected result.
You really need to read your shaders again, and each time you see a vector, ask yourself “in what coordinate space is this vector meaningful?” and each time you see a matrix, ask yourself “what coordinate spaces does this matrix convert from and to?”

Tangent Space Normal Mapping - shader sanity check

I'm getting some pretty freaky results from my tangent space normal mapping shader :). In the scene I show here, the teapot and checkered walls are being shaded with my ordinary Phong-Blinn shader (obviously teapot backface cull gives it a lightly ephemeral look and feel :-) ). I've tried to add in normal mapping to the sphere, with psychedelic results:
The light is coming from the right (just about visible as a black blob). The normal map I'm using on the sphere looks like this:
I'm using AssImp to process input models, so it's calculating tangent and bi-normals for each vertex automatically for me.
The pixel and vertex shaders are below. I'm not too sure what's going wrong, but it wouldn't surprise me if the tangent basis matrix is somehow wrong. I assume I have to compute things into eye space and then transform the eye and light vectors into tangent space and that this is the correct way to go about it. Note that the light position comes into the shader already in view space.
// Vertex Shader
#version 420
// Uniform Buffer Structures
// Camera.
layout (std140) uniform Camera
{
mat4 Camera_Projection;
mat4 Camera_View;
};
// Matrices per model.
layout (std140) uniform Model
{
mat4 Model_ViewModelSpace;
mat4 Model_ViewModelSpaceInverseTranspose;
};
// Spotlight.
layout (std140) uniform OmniLight
{
float Light_Intensity;
vec3 Light_Position; // Already in view space.
vec4 Light_Ambient_Colour;
vec4 Light_Diffuse_Colour;
vec4 Light_Specular_Colour;
};
// Streams (per vertex)
layout(location = 0) in vec3 attrib_Position;
layout(location = 1) in vec3 attrib_Normal;
layout(location = 2) in vec3 attrib_Tangent;
layout(location = 3) in vec3 attrib_BiNormal;
layout(location = 4) in vec2 attrib_Texture;
// Output streams (per vertex)
out vec3 attrib_Fragment_Normal;
out vec4 attrib_Fragment_Position;
out vec3 attrib_Fragment_Light;
out vec3 attrib_Fragment_Eye;
// Shared.
out vec2 varying_TextureCoord;
// Main
void main()
{
// Compute normal.
attrib_Fragment_Normal = (Model_ViewModelSpaceInverseTranspose * vec4(attrib_Normal, 0.0)).xyz;
// Compute position.
vec4 position = Model_ViewModelSpace * vec4(attrib_Position, 1.0);
// Generate matrix for tangent basis.
mat3 tangentBasis = mat3( attrib_Tangent,
attrib_BiNormal,
attrib_Normal);
// Light vector.
attrib_Fragment_Light = tangentBasis * normalize(Light_Position - position.xyz);
// Eye vector.
attrib_Fragment_Eye = tangentBasis * normalize(-position.xyz);
// Return position.
gl_Position = Camera_Projection * position;
}
... and the pixel shader looks like this:
// Pixel Shader
#version 420
// Samplers
uniform sampler2D Map_Normal;
// Global Uniforms
// Material.
layout (std140) uniform Material
{
vec4 Material_Ambient_Colour;
vec4 Material_Diffuse_Colour;
vec4 Material_Specular_Colour;
vec4 Material_Emissive_Colour;
float Material_Shininess;
float Material_Strength;
};
// Spotlight.
layout (std140) uniform OmniLight
{
float Light_Intensity;
vec3 Light_Position;
vec4 Light_Ambient_Colour;
vec4 Light_Diffuse_Colour;
vec4 Light_Specular_Colour;
};
// Input streams (per vertex)
in vec3 attrib_Fragment_Normal;
in vec3 attrib_Fragment_Position;
in vec3 attrib_Fragment_Light;
in vec3 attrib_Fragment_Eye;
// Shared.
in vec2 varying_TextureCoord;
// Result
out vec4 Out_Colour;
// Main
void main(void)
{
// Compute normals.
vec3 N = normalize(texture(Map_Normal, varying_TextureCoord).xyz * 2.0 - 1.0);
vec3 L = normalize(attrib_Fragment_Light);
vec3 V = normalize(attrib_Fragment_Eye);
vec3 R = normalize(-reflect(L, N));
// Compute products.
float NdotL = max(0.0, dot(N, L));
float RdotV = max(0.0, dot(R, V));
// Compute final colours.
vec4 ambient = Light_Ambient_Colour * Material_Ambient_Colour;
vec4 diffuse = Light_Diffuse_Colour * Material_Diffuse_Colour * NdotL;
vec4 specular = Light_Specular_Colour * Material_Specular_Colour * (pow(RdotV, Material_Shininess) * Material_Strength);
// Final colour.
Out_Colour = ambient + diffuse + specular;
}
Edit: 3D Studio Render of the scene (to show the UV's are OK on the sphere):
I think your shaders are okay, but your texture coordinates on the sphere are totally off. It's as if they got distorted towards the poles along the longitude.