How to draw a Point Primitive with a world space width? - opengl

I want to draw a point, to simulate the position of which the light originates, however the issue I am facing now is that it is always the same size, regardless of the distance:
I push literally one vertex to the GPU, my code:
point.vs.glsl
#version 440 core
layout(location = 0) in vec4 position;
layout(location = 0) uniform mat4 model_matrix;
layout(location = 1) uniform mat4 view_matrix;
layout(location = 2) uniform mat4 proj_matrix;
void main(void) {
gl_PointSize = 100.0;
gl_Position = proj_matrix * view_matrix * model_matrix * position;
}
point.fs.glsl
#version 440 core
out vec4 color;
void main(void) {
//create round point
vec2 p = gl_PointCoord * 2.0 - vec2(1.0);
if (dot(p, p) > 1.0) {
discard;
}
color = vec4(0.5, 0.0, 0.0, 1.0);
}
Also does the code for creating a round point actually work in 3D? I believe it came from a 2D tutorial if I'm not mistaken.
About the point size again, I know what I am doing wrong, however how would I correctly calcualte the size? I have the information available I think, with view_matrix and somehow I need to get the distance to the point, and scale depending on that.

Related

Normal mapping working incorrectly, weird half-light effect

We are trying to implement normal mapping in our 2D Game Engine and get weird effect.
If normal is set manually like that
vec3 Normal = vec3(0.0, 0.0, 1.0) light works correctly, but we dont get "deep" effect that we want to achieve by normal mapping:
But if we get normal using normal map texture: vec3 Normal = texture(NormalMap, TexCoord).rgb it doesn't work at all. What should not be illuminated is illuminated and vice versa (such as the gaps between the bricks). And besides this, a dark area is on the bottom (or top, depending on the position of the light) side of the texture.
Although the texture of the normal map itself looks fine:
This is our fragment shader:
#version 330 core
layout (location = 0) out vec4 FragColor;
in vec2 TexCoord;
in vec2 FragPos;
uniform sampler2D OurTexture;
uniform sampler2D NormalMap;
struct point_light
{
vec3 Position;
vec3 Color;
};
uniform point_light Light;
void main()
{
vec4 Color = texture(OurTexture, TexCoord);
vec3 Normal = texture(NormalMap, TexCoord).rgb;
if (Color.a < 0.1)
discard;
vec3 LightDir = vec3(Light.Position.xy - FragPos, Light.Position.z);
float D = length(LightDir);
vec3 L = normalize(LightDir);
Normal = normalize(Normal * 2.0 - 1.0);
vec3 Diffuse = Light.Color * max(dot(Normal, L), 0);
vec3 Ambient = vec3(0.3, 0.3, 0.3);
vec3 Falloff = vec3(1, 0, 0);
float Attenuation = 1.0 /(Falloff.x + Falloff.y*D + Falloff.z*D*D);
vec3 Intensity = (Ambient + Diffuse) * Attenuation;
FragColor = Color * vec4(Intensity, 1);
}
And vertex as well:
#version 330 core
layout (location = 0) in vec2 aPosition;
layout (location = 1) in vec2 aTexCoord;
uniform mat4 Transform;
uniform mat4 ViewProjection;
out vec2 FragPos;
out vec2 TexCoord;
void main()
{
gl_Position = ViewProjection * Transform * vec4(aPosition, 0.0, 1.0);
TexCoord = aTexCoord;
FragPos = vec2(Transform * vec4(aPosition, 0.0, 1.0));
}
I google about that and found some people that get the same result, but their questions remained unanswered.
Any idea of what is the cause?
What texture format are you using for the normal map? SRGB, SNORM, etc? That might be the issue. Try UNORM.
Additionally, since you are not using a tangent space, make sure the plane's Z axis aligns with the Z axis of the normals. Also OGL reads Y in the reversed direction, so you need to flip the Y coordinates of the normals that you read from the normal map. Alternatively, you can use a reversed Y normal map (green pointing down).

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 :)

uniform sampler2D in Vertex Shader

I tried to realize height map with GLSL.
For it, i need to sent my picture to VertexShader and get grey component.
glActiveTexture(GL_TEXTURE0);
Texture.bind();
glUniform1i(mShader.getUniformLocation("heightmap"), 0);
mShader.getUniformLocation uses glGetUniformLocation and work good for other uniforms values, that used in Fragment, Vertex Shaders. But for heightmap return -1...
VertexShader code:
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 color;
layout (location = 2) in vec2 texCoords;
layout (location = 3) in vec3 normal;
out vec3 Normal;
out vec3 FragPos;
out vec2 TexCoords;
out vec4 ourColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform sampler2D heightmap;
void main()
{
float bias = 0.25;
float h = 0.0;
float scale = 5.0;
h = scale * ((texture2D(heightmap, texCoords).r) - bias);
vec3 hnormal = vec3(normal.x*h, normal.y*h, normal.z*h);
vec3 position1 = position * hnormal;
gl_Position = projection * view * model * vec4(position1, 1.0f);
FragPos = vec3(model * vec4(position, 1.0f));
Normal = mat3(transpose(inverse(model))) * normal;
ourColor = color;
TexCoords = texCoords;
}
may be algorithm of getting height is bad, but error with getting uniformlocation stops my work..
What is wrong? Any ideas?
UPD: texCoords (not TexCoords) of course is using in
h = scale * ((texture2D(heightmap, texCoords).r) - bias);
my mistake, but it doesn't solve the problem. Having same error..
My bet is your variable has been optimized out by driver or the shader did not compile/link properly. After trying to compile your shader (on my nVidia) I got this in the logs:
0(9) : warning C7050: "TexCoords" might be used before being initialized
You should always check the GLSL compile/link logs ? see
How to debug GLSL Fragment shader
especially how the glGetShaderInfoLog is used.
In line
h = scale * ((texture2D(heightmap, TexCoords).r) - bias);
You are using TexCoords which is output variable and not yet set so the behavior is undefined and most likely your gfx driver throw that line away (and may be others) removing the TexCoords from shader completely but that is just my assumption.
What driver and gfx card you got?
What returns the logs on your setup?

GLSL When using an in variable the fragment shader causes an unexpected output

I am busy implementing a deferred lighting system and have gotten all the way to having the bound position, diffuse and normal textures in my fragment shader in which I am to calculate the lighting specifications for each fragment.
#version 400 core
in vec3 fs_position;
in vec3 fs_color;
in vec4 fs_attenuation;
layout (location = 0) out vec4 outColor;
uniform sampler2D diffuseSampler;
uniform sampler2D positionSampler;
uniform sampler2D normalSampler;
const float cutOffFactor = 200;
const float reflectivity = 0.15;
const float shineDamper = 1;
void main(void){
vec2 frag = gl_PointCoord.xy;
frag.x = (frag.x+1)/2f;
frag.y = ((frag.y+1)/2f);
vec4 texDiffuse = texture(diffuseSampler,frag);
vec4 texPosition = texture(positionSampler,frag);
vec4 texNormal = texture(normalSampler,frag);
vec3 p = vec3(fs_position.xyz);
vec3 ePosition = texPosition.xyz;
ePosition = ePosition*200;
vec3 eNormal = texNormal.xyz;
vec3 unitNormal = normalize(eNormal);
outColor = vec4(texNormal.xyz,1.0);
}
That is literally all that my Fragment Shader contains.
The probem lies at "vec3 p = vec3(fs_position.xyz);".
When I remove it the program renders a perfect normal map, but when I add it a blank screen in which I can rotate and eventually a certain color flickers.
fs_position has nothing to do with color and was inputted from the geometry shader (all references are correct) yet it somehow causes a massive malfunction.
Same thing happens as well with all in variables (fs_color and fs_attenuation).
Whats being rendered is a non-blended quad of equal per-vertex properties that covers the viewport that renders to a color_attachment that exists(as said without that line everything works).
(blending does nothing, and I will put additive blending on when I get a result worthy of allowing me to continue)
Any help will be appreciated, the engine and shaders have never acted this way for me before and no errors are popping up.
Extra code:
Vertex shader
#version 400 core
in vec3 position;
in vec3 color;
in vec4 attenuation;
out vec3 gs_position;
out vec3 gs_color;
out vec4 gs_attenuation;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
void main(void){
vec4 worldPosition = vec4(position,1.0);
vec4 viewPosition = viewMatrix * worldPosition;
gl_Position = projectionMatrix * viewPosition;
gs_position = viewPosition.xyz;
gs_color = color;
gs_attenuation = attenuation;
}
GeometryShader
#version 150
layout (points) in;
layout (triangle_strip,max_vertices = 4) out;
in vec3 gs_position[];
in vec3 gs_color[];
in vec4 gs_attenuation[];
out vec3 fs_position;
out vec3 fs_color;
out vec4 fs_attenuation;
void main(void){
gl_Position = vec4(-1,1,0,1);
fs_position = gs_position[0];
fs_color = gs_color[0];
fs_attenuation = gs_attenuation[0];
EmitVertex();
gl_Position = vec4(-1,-1,0,1);
fs_position = gs_position[0];
fs_color = gs_color[0];
fs_attenuation = gs_attenuation[0];
EmitVertex();
gl_Position = vec4(1,1,0,1);
fs_position = gs_position[0];
fs_color = gs_color[0];
fs_attenuation = gs_attenuation[0];
EmitVertex();
gl_Position = vec4(1,-1,0,1);
fs_position = gs_position[0];
fs_color = gs_color[0];
fs_attenuation = gs_attenuation[0];
EmitVertex();
EndPrimitive();
}
Example of light values:
Position: -1, 0.5, -1
Color: 0, 0.5 ,0
Attenuation: 1, 0.1, 0.2, 0
As for the requested screenshots, basically without referencing an in variable I get something like this:
And with it I get a black screen, which is pretty easy to visualise.
(Although when rotating the view matrix (y-axis) there is a certain point at which the quad gets colored green, although I cant get values for it)

Shadow mapping shader

I've got a shader that implements shadow mapping like this:
#version 430 core
out vec4 color;
in VS_OUT {
vec3 N;
vec3 L;
vec3 V;
vec4 shadow_coord;
} fs_in;
layout(binding = 0) uniform sampler2DShadow shadow_tex;
uniform vec3 light_ambient_albedo = vec3(1.0);
uniform vec3 light_diffuse_albedo = vec3(1.0);
uniform vec3 light_specular_albedo = vec3(1.0);
uniform vec3 ambient_albedo = vec3(0.1, 0.1, 0.2);
uniform vec3 diffuse_albedo = vec3(0.4, 0.4, 0.8);
uniform vec3 specular_albedo = vec3(0.0, 0.0, 0.0);
uniform float specular_power = 128.0;
void main(void) {
//color = vec4(0.4, 0.4, 0.8, 1.0);
//normalize
vec3 N = normalize(fs_in.N);
vec3 L = normalize(fs_in.L);
vec3 V = normalize(fs_in.V);
//calculate R
vec3 R = reflect(-L, N);
//calcualte ambient
vec3 ambient = ambient_albedo * light_ambient_albedo;
//calculate diffuse
vec3 diffuse = max(dot(N, L), 0.0) * diffuse_albedo * light_diffuse_albedo;
//calcualte spcular
vec3 specular = pow(max(dot(R, V), 0.0), specular_power) * specular_albedo * light_specular_albedo;
//write color
color = textureProj(shadow_tex, fs_in.shadow_coord) * vec4(ambient + diffuse + specular, 0.5);
//if in shadow, then multiply color by 0.5 ^^, except alpha
}
What I want to do is to check first if the fragment is indeed in the shadow, and only then change the color (halve it, such that it becomes halfway between fully black and original color).
However how to check if the textureProj(...) result is indeed in shadow, as far as I know it returns a normalized float value.
Would something like textureProj(...) > 0.9999 suffice already? I know that it can returns values other than zero or one if you are using multisampling and I'd like behaviour that will not just break at one point.
The outputting vertex shader:
#version 430 core
layout(location = 0) in vec4 position;
layout(location = 0) uniform mat4 model_matrix;
layout(location = 1) uniform mat4 view_matrix;
layout(location = 2) uniform mat4 proj_matrix;
layout(location = 3) uniform mat4 shadow_matrix;
out VS_OUT {
vec3 N;
vec3 L;
vec3 V;
vec4 shadow_coord;
} vs_out;
uniform vec4 light_pos = vec4(-20.0, 7.5, -20.0, 1.0);
void main(void) {
vec4 local_light_pos = view_matrix * light_pos;
vec4 p = view_matrix * model_matrix * position;
//normal
vs_out.N = vec3(0.0, 1.0, 0.0);
//light vector
vs_out.L = local_light_pos.xyz - p.xyz;
//view vector
vs_out.V = -p.xyz;
//light space coordinates
vs_out.shadow_coord = shadow_matrix * position;
gl_Position = proj_matrix * p;
}
Note that the fragment shader is for terrain, and the vertex shader is for the floor, so there might be minor inconsistencies between the two, but they should be non relevant.
shadow_matrix is an uniform passed in as bias_matrix * light_projection_matrix * light_view_matrix * light_model_matrix.
textureProj (...) does not return a normalized floating-point value. It does return a single float if you use it on a sampler<1D|2D|2DRect>Shadow, but this value represents the result of a depth test. 1.0 = pass, 0.0 = fail.
Now, the interesting thing to note here, and the reason returning a float for a shadow sampler is meaningful at all has to do with filtering the shadow map. If you use a GL_LINEAR filter mode on the shadow map together with a shadow sampler, GL will actually pick the 4 closest texels in the shadow map and perform 4 independent depth tests.
Each depth test still has a binary result, but GL will return a weighted average of the result of all 4 tests (based on distance from the ideal sample location). So if you use GL_LINEAR in conjunction with a shadow sampler, you will have a value that lies somewhere in-between 0.0 and 1.0 representing the average occlusion for the 4 nearest depth samples.
I should point out that your use of textureProj (...) looks potentially wrong to me. The coordinate it uses is a 4D vector consisting of (s,t,r) [projected coordinates] and (q) [depth value to test]. I do not see anywhere in your code where you are assigning q a depth value. If you could edit your question to include the vertex/geometry shader that is outputting shadow_coord, that would help.
Try the following:
Get the distance from each vertex of your model to the light.
Send this distance to your fragment shader.
Compare the distance to the value stored in your shadow map sampler (I assume this texture stores the depth values of your scene from the camera's point of view?)
If the distance is greater than the sampler, the point is in shadow. Else, it is not.
If this is confusing, here's a pair of tutorials that should help:
http://ogldev.atspace.co.uk/www/tutorial23/tutorial23.html
http://ogldev.atspace.co.uk/www/tutorial24/tutorial24.html