OpenGL: debugging "Single-pass Wireframe Rendering" - opengl

I'm trying to implement the paper "Single-Pass Wireframe Rendering", which seems pretty simple, but it's giving me what I'd expect as far as thick, dark values.
The paper didn't give the exact code to figure out the altitudes, so I did it as I thought fit. The code should project the three vertices into viewport space, get their "altitudes" and send them to the fragment shader.
The fragment shader determines the distance of the closest edge and generates an edgeIntensity. I'm not sure what I'm supposed to do with this value, but since it's supposed to scale between [0,1], I multiply the inverse against my outgoing color, but it's just very weak.
I had a few questions that I'm not sure are addressed in the papers. First, should the altitudes be calculated in 2D instead of 3D? Second, they site DirectX features, where DirectX has a different viewport-space z-range, correct? Does that matter? I'm premultiplying the outgoing altitude distances by the w-value of the viewport-space coordinates as they recommend to correct for perspective projection.
image trying to correct for perspective projection
no correction (not premultiplying by w-value)
The non-corrected image seems to have clear problems not correcting for the perspective on the more away-facing sides, but the perspective-corrected one has very weak values.
Can anyone see what's wrong with my code or how to go about debugging it from here?
my vertex code in GLSL...
float altitude(in vec3 a, in vec3 b, in vec3 c) { // for an ABC triangle
vec3 ba = a - b;
vec3 bc = c - b;
vec3 ba_onto_bc = dot(ba,bc) * bc;
return(length(ba - ba_onto_bc));
}
in vec3 vertex; // incoming vertex
in vec3 v2; // first neighbor (CCW)
in vec3 v3; // second neighbor (CCW)
in vec4 color;
in vec3 normal;
varying vec3 worldPos;
varying vec3 worldNormal;
varying vec3 altitudes;
uniform mat4 objToWorld;
uniform mat4 cameraPV;
uniform mat4 normalToWorld;
void main() {
worldPos = (objToWorld * vec4(vertex,1.0)).xyz;
worldNormal = (normalToWorld * vec4(normal,1.0)).xyz;
//worldNormal = normal;
gl_Position = cameraPV * objToWorld * vec4(vertex,1.0);
// also put the neighboring polygons in viewport space
vec4 vv1 = gl_Position;
vec4 vv2 = cameraPV * objToWorld * vec4(v2,1.0);
vec4 vv3 = cameraPV * objToWorld * vec4(v3,1.0);
altitudes = vec3(vv1.w * altitude(vv1.xyz,vv2.xyz,vv3.xyz),
vv2.w * altitude(vv2.xyz,vv3.xyz,vv1.xyz),
vv3.w * altitude(vv3.xyz,vv1.xyz,vv2.xyz));
gl_FrontColor = color;
}
and my fragment code...
varying vec3 worldPos;
varying vec3 worldNormal;
varying vec3 altitudes;
uniform vec3 cameraPos;
uniform vec3 lightDir;
uniform vec4 singleColor;
uniform float isSingleColor;
void main() {
// determine frag distance to closest edge
float d = min(min(altitudes.x, altitudes.y), altitudes.z);
float edgeIntensity = exp2(-2.0*d*d);
vec3 L = lightDir;
vec3 V = normalize(cameraPos - worldPos);
vec3 N = normalize(worldNormal);
vec3 H = normalize(L+V);
//vec4 color = singleColor;
vec4 color = isSingleColor*singleColor + (1.0-isSingleColor)*gl_Color;
//vec4 color = gl_Color;
float amb = 0.6;
vec4 ambient = color * amb;
vec4 diffuse = color * (1.0 - amb) * max(dot(L, N), 0.0);
vec4 specular = vec4(0.0);
gl_FragColor = (edgeIntensity * vec4(0.0)) + ((1.0-edgeIntensity) * vec4(ambient + diffuse + specular));
}

I have implemented swine's idea, and the result is perfect, here is my screenshot:
struct MYBUFFEREDVERTEX {
float x, y, z;
float nx, ny, nz;
float u, v;
float bx, by, bz;
};
const MYBUFFEREDVERTEX g_vertex_buffer_data[] = {
-1.0f, -1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 1.0f,
0.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f,
1.0f, 1.0f,
1.0f, 0.0f, 0.0f,
};
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
vertex shader:
#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif
uniform mat4 u_mvp_matrix;
uniform vec3 u_light_direction;
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texcoord;
attribute vec3 a_barycentric;
varying vec2 v_texcoord;
varying float v_light_intensity;
varying vec3 v_barycentric;
void main()
{
// Calculate vertex position in screen space
gl_Position = u_mvp_matrix * vec4(a_position, 1.0);
// calculate light intensity, range of 0.3 ~ 1.0
v_light_intensity = max(dot(u_light_direction, a_normal), 0.3);
// Pass texture coordinate to fragment shader
v_texcoord = a_texcoord;
// Pass bary centric to fragment shader
v_barycentric = a_barycentric;
}
fragment shader:
#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif
uniform sampler2D u_texture;
varying vec2 v_texcoord;
varying float v_light_intensity;
varying vec3 v_barycentric;
void main()
{
float min_dist = min(min(v_barycentric.x, v_barycentric.y), v_barycentric.z);
float edgeIntensity = 1.0 - step(0.005, min_dist);
// Set diffuse color from texture
vec4 diffuse = texture2D(u_texture, v_texcoord) * vec4(vec3(v_light_intensity), 1.0);
gl_FragColor = edgeIntensity * vec4(0.0, 1.0, 1.0, 1.0) + (1.0 - edgeIntensity) * diffuse;
}

first, your function altitude() is flawed, ba_onto_bc is calculated wrong because bc is not unit length (either normalize bc, or divide ba_onto_bc by dot(bc, bc) which is length squared - you save calculating the square root).
The altitudes should be calculated in 2D if you want constant-thickness edges, or in 3D if you want perspective-correct edges.
It would be much easier just to use barycentric coordinates as a separate vertex attribute (ie. vertex 0 of the triangle would get (1 0 0), the second vertex (0 1 0) and the last vertex (0 0 1)). In fragment shader you would calculate minimum and use step() or smoothstep() to calculate edge-ness.
That would only require 1 attribute instead of current two, and it would also eliminate the need for calculating height in vertex shader (although it may be useful if you would like to prescale the barycentric coordinates so you have uniformly thick lines - but calculate it offline). It should also be working pretty much instantly so it would be a good starting point to get to the desired behavior.

Related

Billboard-like Representation For Spheres OpenGL

The world is made of spheres. Since drawing a sphere in OpenGL takes a lot of triangles, I thought it would be faster to use a point and radius to represent a sphere, then use Billboarding in OpenGL to draw it. The current approach I took causes adjacent spheres to not touch when rotating the view.
Here's an example:
There are two spheres:
Sphere 1 Position (0, 0, -3) Radius (0.5)
Sphere 2 Position (-1, 0, -3) Radius (0.5)
The projection matrix is defined using:
glm::perspective(glm::radians(120.0f), 1.0f, 1.0f, 100.0f);
Image 1: When there is no rotation, it looks as expected.
Image 2: When there is rotation, billboarding responds to the camera as expected, but the spheres' do not touch anymore. And if they were actually spheres that were next to each other, you would expect them to touch.
What I have tried:
I tried GL_POINTS, they didn't work as good because it didn't seem to
handle the depth test correctly for me.
I tried a geometry shader that creates a square before and after
the projection matrix was applied.
Here's the code I have now that created the images:
Vertex Shader
#version 460
layout(location = 0) in vec3 position;
layout(location = 1) in float radius;
out float radius_vs;
void main()
{
gl_Position = vec4(position, 1.0);
radius_vs = radius;
}
Geometry Shader
#version 460
layout(points) in;
layout(triangle_strip, max_vertices = 4) out;
layout(location = 2) uniform mat4 view_mat;
layout(location = 3) uniform mat4 projection_mat;
in float radius_vs[];
out vec2 bounds;
void main()
{
vec3 x_dir = vec3(view_mat[0][0], view_mat[1][0], view_mat[2][0]) * radius_vs[0];
vec3 y_dir = vec3(view_mat[0][1], view_mat[1][1], view_mat[2][1]) * radius_vs[0];
mat4 fmat = projection_mat * view_mat;
gl_Position = fmat * vec4(gl_in[0].gl_Position.xyz - x_dir - y_dir, 1.0f);
bounds = vec2(-1.0f, -1.0f);
EmitVertex();
gl_Position = fmat * vec4(gl_in[0].gl_Position.xyz - x_dir + y_dir, 1.0f);
bounds = vec2(-1.0f, 1.0f);
EmitVertex();
gl_Position = fmat * vec4(gl_in[0].gl_Position.xyz + x_dir - y_dir, 1.0f);
bounds = vec2(1.0f, -1.0f);
EmitVertex();
gl_Position = fmat * vec4(gl_in[0].gl_Position.xyz + x_dir + y_dir, 1.0f);
bounds = vec2(1.0f, 1.0f);
EmitVertex();
EndPrimitive();
}
Fragment Shader
#version 460
out vec4 colorOut;
in vec2 bounds;
void main()
{
vec2 circCoord = bounds;
if (dot(circCoord, circCoord) > 1.0)
{
discard;
}
colorOut = vec4(1.0f, 1.0f, 0.0f, 1.0);
}

SSAO & Shadow mapping | Shadows do not work with the SSAO

The SSAO in our engine seems to be working, however I cannot get the SSAO to work with shadow mapping. Here is a screenshot of the bug I am currently having when shadows are applied....
With shadows applied
But also, depending on the camera view and camera position, random shadows sometimes appear...
Random Shadows depending on camera view and position
Here is the gbuffer vertex shader..
#version 330 core
layout (location = 0) in vec3 positions;
layout (location = 1) in vec2 texCoords;
layout (location = 2) in vec3 normals;
out vec3 FragPos;
out vec3 ShadowFragPos;
out vec2 TexCoords;
out vec3 Normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 proj;
void main()
{
vec4 viewPos = view * model * vec4(positions, 1.0);
FragPos = viewPos.xyz;
TexCoords = texCoords;
mat3 normalMatrix = transpose(inverse(mat3(view * model)));
Normal = normalMatrix * normals;
gl_Position = proj * viewPos;
}
Here is the lighting shader..
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gAlbedoSpec;
uniform sampler2D gShadowmap;
uniform sampler2D gSsao;
uniform vec3 cameraPos;
uniform mat4 lightSpaceMatrix;
vec3 Normal;
vec3 FragPos;
uniform vec3 lightPos;
float calculate_shadows(vec4 light_space_pos)
{
// perform perspective divide
vec3 projCoords = light_space_pos.xyz / light_space_pos.w;
// transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
float closestDepth = texture(gShadowmap, projCoords.xy).r;
// get depth of current fragment from light's perspective
float currentDepth = projCoords.z;
// check whether current frag pos is in shadow
vec3 lightDir = normalize(vec3(2.0f, 4.0f, 1.0f) - FragPos);
float bias = max(0.05 * (1.0 - dot(Normal, lightDir)), 0.005);
float shadow = 0.0;
vec2 texelSize = 1.0 / textureSize(gShadowmap, 0);
// 8x8 kernel PCF
float x;
float y;
for (y = -3.5; y <= 3.5 ; y += 1.0)
{
for (x = -3.5; x <= 3.5 ; x += 1.0)
{
float pcfDepth = texture(gShadowmap, projCoords.xy + vec2(x, y) * texelSize).r;
shadow += currentDepth - bias > pcfDepth ? 1.0 : 0.0;
}
}
shadow /= 64.0;
return shadow;
}
void main(void)
{
FragPos = texture(gPosition, TexCoords).rgb;
Normal = texture(gNormal, TexCoords).rgb;
vec3 Diffuse = texture(gAlbedoSpec, TexCoords).rgb;
float Specular = texture(gAlbedoSpec, TexCoords).a;
float AmbientOcclusion = texture(gSsao, TexCoords).r;
vec3 lighting = vec3(0.3 * Diffuse * AmbientOcclusion);
vec3 viewDir = normalize(-FragPos);
vec3 lightDir = normalize(lightPos - FragPos);
vec3 diffuse = max(dot(Normal, lightDir), 0.0) * Diffuse * vec3(1.0f, 0.5f, 0.3f);
vec3 halfwayDir = normalize(lightDir + viewDir);
float spec = pow(max(dot(Normal, halfwayDir), 0.0), 8.0);
vec3 specular = vec3(1.0f, 0.5f, 0.3f) * spec * Specular;
float shadow = calculate_shadows(lightSpaceMatrix * vec4(FragPos, 1.0));
lighting += ((1.0 - shadow) * (diffuse + specular));
FragColor = vec4(lighting, 1.0f);
}
The textures are binded in the light pass as follows..
// bind the positions texture and store in the first texture slot/unit
glActiveTexture(GL_TEXTURE0); // texture unit 0
glBindTexture(GL_TEXTURE_2D, gbuffer.gPositions); // geometry positions
// bind the normals texture and store in the second texture slot/unit
glActiveTexture(GL_TEXTURE1); // texture unit 1
glBindTexture(GL_TEXTURE_2D, gbuffer.gNormals); // geometry normals
// bind the albedo & specular texture and store in the third texture slot/unit
glActiveTexture(GL_TEXTURE2); // texture unit 2
glBindTexture(GL_TEXTURE_2D, gbuffer.gAlbedoSpec); // geometry albedospec
// bind the albedo & specular texture and store in the third texture slot/unit
glActiveTexture(GL_TEXTURE3); // texture unit 3
glBindTexture(GL_TEXTURE_2D, gbuffer.gShadowmap); // geometry albedospec
glActiveTexture(GL_TEXTURE4); // texture unit 2
glBindTexture(GL_TEXTURE_2D, gbuffer.ssaoColorBuffer); // geometry albedospec
Finally, here is the calculation of the lightSpaceMatrix..
light_projection = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, 1.0f, 7.5f);
light_view = glm::lookAt(glm::vec3(0.0f, 4.0f, 5.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
light_space_matrix = light_projection * light_view;
Any ideas why this could be happening? how do I get shadows to work with SSAO?
any help is much appreciated.
FragPos is a camera view space position.
light_space_pos, the input parameter to calculate_shadows has to be a clip space coordinate, as seen from the light source.
This mean that when you do
float shadow = calculate_shadows(lightSpaceMatrix * vec4(FragPos, 1.0));
lightSpaceMatrix has to be the transformation from the camera view space to the clip space of the light source.
To do so, you have to do 3 transformations:
camera view space to world space. This can bed done by the inverse view matrix.
world space to light space, which is the transformation by light_view.
light view space to light clip space, is the transformation by light_projection.
So the setting of light_space_matrix = light_projection * light_view; is not sufficient, it has to be
light_space_matrix = light_projection * light_view * glm::inverse(view);

Stuck on rendering lights after binding FBO using deffered rendering using OpenGL

First of all I am sorry for this long post after trying to make this work the whole day.
I have many questions about this especially because I use inheritance in C++ to build lights.
I use directional light as my core model for light since i can give the light direction and it will calculate the light, then on top of it I build point light where i just calculate the vector from light to fragment position, and finally for spot light I use point light with the addition of cut off angle to create spot lights (just ignore whatever is outside the cone). I have tested lights and they work fine with forward rendering but now I would like to change my light model to PBR (basically just change how I calculate light in directional light) and move to differed rendering.
Today i started working on deferred rendering and I can get the position, texture, normal and depth buffers, however i have a problem when trying to render lights.
That was the first problem, the second, since each type of light has it own shader and i build them using polymorphism. My second question is I can loop through each light in C++ and call each light to be renderer or there is another way that i can solve this in shaders.
Prototypes of lights are
EDIT: I fixed a small issue where iw as transforming the render quat with VP projection but still i can not draw anything and i have no idea if FB are working correctlly now. Nvidia opengl debugger is just crashing.
Light(glm::vec3& color, float intensity, float ambient, ShaderProgram& lightShader);
DirectionalLight(glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3& position = glm::vec3(0.0f, 0.0f, 0.0f), float intensity = 1.0f, float ambient = 0.0f, ShaderProgram& lightShader = ShaderProgram("Directional Light"));
PointLight(glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3& position = glm::vec3(0.0f, 0.0f, 0.0f), float intensity = 1.0f, float ambient = 0.0f, LightAttenuation& lightAttenuation = LightAttenuation(), ShaderProgram& lightShader = ShaderProgram("Point Light"));
SpotLight(glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f), glm::vec3& position = glm::vec3(0.0f, 0.0f, 0.0f),
My render path looks like this.
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
defferedShader_.startProgram();
defferedShader_.setUniformMat4("VP", camera.getVP());
glBindFramebuffer(GL_FRAMEBUFFER, deferredFbo);
//the scene is small and does not need culling.
for (auto* mesh : world.getMeshes()) {
//mesh->draw(light->getLightShader());
//mesh->draw(activeLight_->getLightShader());
mesh->draw(defferedShader_);
drawCallCounter += mesh->getMeshObjectSize();
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
defferedShader_.stopProgram();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, positionFbo);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, normalFbo);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, albedoFbo);
//This is where i got stuck, I would like to make directional light work then test other lights then test the whole program with more than one light
//for (auto* light : world.getLights()) {
// //glEnable(GL_CULL_FACE);
// //glCullFace(GL_FRONT);
glDisable(GL_DEPTH_TEST);
activeLight_->getLightShader().startProgram();
activeLight_->getLightShader().setUniformMat4("VP", camera.getVP());
activeLight_->getLightShader().setUniformVec3("eyePosition", camera.getCameraPosition());
//activeLight_->getLightShader();
RenderQuad();
activeLight_->getLightShader().stopProgram();
//}
The shader code that i started building is (PS i removed the shadows for now)
Vertex Shader
#version 410 core
#include "../Global/GlobalShader.inc"
#include "../Global/GlobalMesh.inc"
out vec3 Position;
out vec2 TexCoord;
//out vec4 ShadowCoord;
//uniform mat4 ShadowMatrix;
void main() {
Position = position;
TexCoord = texCoord;
//ShadowCoord = ShadowMatrix * vec4(position, 1.0);
gl_Position = VP * vec4(position, 1.0);
}
Fragment shader
One thing that is bothering me is i can not set the uniform values for gPosition, gPosition and gAlbedoSpec even if I use them, and no matter what i change in the shader the output will be the same.
#version 410 core
#include "../Global/GlobalShader.inc"
#include "../Global/GlobalMesh.inc"
#include "../Global/GlobalLight.inc"
//#include "../Global/ShadowSampling.inc"
in vec3 Position;
in vec2 TexCoord;
//in vec4 ShadowCoord;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D gAlbedoSpec;
float specularStrength = 32.0f; // to be impelemented
out vec4 gl_FragColor;
void main() {
//vec4 lightning = vec4(0.0f);
////vec4 shadowMapping = vec4(0.0f);
//
vec3 FragPos = texture(gPosition, TexCoord).rgb;
vec3 Normal = texture(gNormal, TexCoord).rgb;
vec3 Diffuse = texture(gAlbedoSpec, TexCoord).rgb;
float Specular = texture(gAlbedoSpec, TexCoord).a;
//vec3 Diffuse = texture(gAlbedoSpec, TexCoord).rgb;
//lightning = calculateDirectionalLight(directionalLight.light, directionalLight.position, Normal, Position, specularStrength, eyePosition, material, TexCoord);
//gl_fragColor = vec3(Position, 1.0);
//shadowMapping = calculateShadow(shadowMap, ShadowCoord, directionalLight.light.ambient);
//gl_FragColor = vec4(Diffuse, 1.0);
gl_FragColor = vec4(1.0); //vec4(Diffuse, 1.0);// lightning;//g * shadowMapping;
//gl_FragColor = lightning;// * shadowMapping;
}
in case you want to see global light
struct Light
{
vec3 color;
float intensity;
float ambient;
};
struct DirectionalLight
{
Light light;
vec3 position;
};
struct Attenuation
{
float constant;
float linear;
float quadratic;
};
struct PointLight
{
Light light;
Attenuation atten;
vec3 position;
float range;
};
struct SpotLight
{
PointLight pointLight;
//vec3 lookAt;
vec3 direction;
float cutOff;
};
vec3 GAMMA = vec3(1.0/2.2);
vec4 calculateDirectionalLight(Light light, vec3 direction, vec3 normal, vec3 worldPosition, float specularIntensity, vec3 eyePosition, Material material, vec2 texCoord)
{
vec3 diffuseFactor = ( light.color * material.diffuse * vec3(texture(material.texture.diffuse, texCoord.st)) )
* (light.intensity * clamp(dot(normal, direction), 0.0, 1.0) ) ;
vec3 viewDir = normalize(eyePosition - worldPosition);
vec3 reflectDir = normalize(reflect(-direction, normal));
float specularFactor = pow(clamp(dot(viewDir, reflectDir), 0.0, 1.0), specularIntensity);
vec3 specularColor = ( light.color * material.specular * vec3(texture(material.texture.specular, texCoord.st)) ) * (specularFactor * material.shininess);
return vec4(pow((diffuseFactor + specularColor + light.ambient + material.ambient), GAMMA), 1.0);
}
vec4 calculatePointLight(PointLight pointLight, vec3 normal, vec3 worldPosition, float specularIntensity, vec3 eyePosition, Material material, vec2 texCoord)
{
// DO NOT NORMALIZE lightDirection, WE NEED IT TO CALCULATE THE DISTANCE TO COMPARE RANGE OF LIGHT
vec3 lightDirection = pointLight.position - worldPosition;
float distanceToPoint = length(lightDirection);
// I dont like conditionals in shader, but since this is fragment based lighting i believe
// this will speed-up things insetead of calculating the light
if(distanceToPoint > pointLight.range)
return vec4(0.0,0.0,0.0,0.0);
vec4 light = calculateDirectionalLight(pointLight.light, lightDirection, normal, worldPosition, specularIntensity, eyePosition, material, texCoord);
// light attenuateion explained https://developer.valvesoftware.com/wiki/Constant-Linear-Quadratic_Falloff
// http://www.ogre3d.org/tikiwiki/tiki-index.php?page=Light+Attenuation+Shortcut
float attenuation = max(pointLight.atten.constant
+ pointLight.atten.linear * distanceToPoint
+ pointLight.atten.quadratic * distanceToPoint * distanceToPoint,
1.0);
return light / attenuation;
}
vec4 calculateSpotLight(SpotLight spotLight, vec3 normal, vec3 worldPosition, float specularIntensity, vec3 eyePosition, Material material, vec2 texCoord)
{
vec3 lightDirection = normalize(spotLight.pointLight.position - worldPosition);
float spotFactor = dot(lightDirection, spotLight.direction);
vec4 light = vec4(0.0f);
if(spotFactor > spotLight.cutOff)
{
light = calculatePointLight(spotLight.pointLight, normal, worldPosition, specularIntensity, eyePosition, material, texCoord) * (1.0 - (1.0 - spotFactor)/(1.0 - spotLight.cutOff));
}
return light;
}
Global mesh
struct Texture {
sampler2D diffuse;
sampler2D specular;
sampler2D normal;
sampler2D ambient;
sampler2D height;
//vec2 texCoord;
};
struct Material {
vec3 ambient; // Ka
vec3 diffuse; // Kd
vec3 specular; // Ks
vec3 transmittance; // Tr
vec3 emission; // Ke
float shininess; // Ns
float ior; // Ni
float dissolve; // Dissolve
int illum; // Illum
Texture texture;
};
uniform Material material;
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoord;
layout (location = 2) in vec3 normal;
Global Shader
uniform mat4 VP;
uniform mat4 P;
What i am getting now after binding the buffers and running the directional shader is
and just as example to see the scene this is the position buffer
Fixed it. I had the clean buffer and color in the wrong place. It should be after I bind the buffer not at the beginning of each frame.
glEnable(GL_DEPTH_TEST);
glBindFramebuffer(GL_FRAMEBUFFER, deferredFbo);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
defferedShader_.startProgram();
defferedShader_.setUniformMat4("VP", camera.getVP());
.
.
. rest of the code

SpotLight is not seen - OpenGL

I am doing a project on spotlight in OpenGL. I guess I wrote the code correctly but I couldn't able to see a round spot in my output. Your help would be much appreciated. Here I am writing my fragment shader file and light definition.
fragmentShader.fs
#version 330
in vec3 N; // interpolated normal for the pixel
in vec3 v; // interpolated position for the pixel
// Uniform block for the light source properties
layout (std140) uniform LightSourceProp {
// Light source position in eye space (i.e. eye is at (0, 0, 0))
uniform vec4 lightSourcePosition;
uniform vec4 diffuseLightIntensity;
uniform vec4 specularLightIntensity;
uniform vec4 ambientLightIntensity;
// for calculating the light attenuation
uniform float constantAttenuation;
uniform float linearAttenuation;
uniform float quadraticAttenuation;
// Spotlight direction
uniform vec3 spotDirection;
uniform float cutOffExponent;
// Spotlight cutoff angle
uniform float spotCutoff;
};
// Uniform block for surface material properties
layout (std140) uniform materialProp {
uniform vec4 Kambient;
uniform vec4 Kdiffuse;
uniform vec4 Kspecular;
uniform float shininess;
};
out vec4 color;
// This fragment shader is an example of per-pixel lighting.
void main() {
// Now calculate the parameters for the lighting equation:
// color = Ka * Lag + (Ka * La) + attenuation * ((Kd * (N dot L) * Ld) + (Ks * ((N dot HV) ^ shininess) * Ls))
// Ka, Kd, Ks: surface material properties
// Lag: global ambient light (not used in this example)
// La, Ld, Ls: ambient, diffuse, and specular components of the light source
// N: normal
// L: light vector
// HV: half vector
// shininess
// attenuation: light intensity attenuation over distance and spotlight angle
vec3 lightVector;
float attenuation = 1.0;
float se;
// point light source
lightVector = normalize(lightSourcePosition.xyz - v);
//Calculate Spoteffect
// calculate attenuation
float angle = dot( normalize(spotDirection),
normalize(lightVector));
angle = max(angle,0);
// Test whether vertex is located in the cone
if(acos (angle) > radians(5))
{
float distance = length(lightSourcePosition.xyz - v);
angle = pow(angle,2.0);
attenuation = angle / (constantAttenuation + (linearAttenuation * distance)
+(quadraticAttenuation * distance * distance));
//calculate Diffuse Color
float NdotL = max(dot(N,lightVector), 0.0);
vec4 diffuseColor = Kdiffuse * diffuseLightIntensity * NdotL;
// calculate Specular color. Here we use the original Phong illumination model.
vec3 E = normalize(-v); // Eye vector. We are in Eye Coordinates, so EyePos is (0,0,0)
vec3 R = normalize(-reflect(lightVector,N)); // light reflection vector
float RdotE = max(dot(R,E),0.0);
vec4 specularColor = Kspecular * specularLightIntensity * pow(RdotE,shininess);
// ambient color
vec4 ambientColor = Kambient * ambientLightIntensity;
color = ambientColor + attenuation * (diffuseColor + specularColor);
}
else
color = vec4(1,1,0,1); // lit (yellow)
}
The light definition in main.cpp
struct SurfaceMaterialProp {
float Kambient[4]; //ambient component
float Kdiffuse[4]; //diffuse component
float Kspecular[4]; // Surface material property: specular component
float shininess;
};
SurfaceMaterialProp surfaceMaterial1 = {
{1.0f, 1.0f, 1.0f, 1.0f}, // Kambient: ambient coefficient
{1.0f, 0.8f, 0.72f, 1.0f}, // Kdiffuse: diffuse coefficient
{1.0f, 1.0f, 1.0f, 1.0f}, // Kspecular: specular coefficient
5.0f // Shininess
};
struct LightSourceProp {
float lightSourcePosition[4];
float diffuseLightIntensity[4];
float specularLightIntensity[4];
float ambientLightIntensity[4];
float constantAttenuation;
float linearAttenuation;
float quadraticAttenuation;
float spotlightDirection[4];
float spotlightCutoffAngle;
float cutOffExponent;
};
LightSourceProp lightSource1 = {
{ 0.0,400.0,0.0, 1.0 }, // light source position
{1.0f, 0.0f, 0.0f, 1.0f}, // diffuse light intensity
{1.0f, 0.0f, 0.0f, 1.0f}, // specular light intensity
{1.0f, 0.2f, 0.0f, 1.0f}, // ambient light intensity
1.0f, 0.5, 0.1f, // constant, linear, and quadratic attenuation factors
{0.0,50.0,0.0}, // spotlight direction
{5.0f}, // spotlight cutoff angle (in radian)
{2.0f} // spotexponent
};
The order of a couple of members of the LightSourceProp struct in the C++ code is different from the one in the uniform block.
Last two members of the uniform block:
uniform float cutOffExponent;
uniform float spotCutoff;
};
Last two members of C++ struct:
float spotlightCutoffAngle;
float cutOffExponent;
};
These two values are swapped.
Also, the cutoff angle looks suspiciously large:
{5.0f}, // spotlight cutoff angle (in radian)
That's an angle of 286 degrees, which isn't much of a spotlight. For an actual spotlight, you'll probably want something much smaller, like 0.1f or 0.2f.
Another aspect that might be giving you unexpected results is that you have a lot of ambient intensity:
{1.0f, 1.0f, 1.0f, 1.0f}, // Kambient: ambient coefficient
...
{1.0f, 0.2f, 0.0f, 1.0f}, // ambient light intensity
Depending on how you use these values in the shader code, it's likely that your colors will be saturated from the ambient intensity alone, and you won't get any visible contribution from the other terms of the light source and material. Since the ambient intensity is constant, this would result in a completely flat color for the entire geometry.

Trouble with Specular Lighting in OpenGL

I'm having some issues with my specular lighting, I have ambient and diffuse but I am now looking at specular to try make a nice looking model.
I have the following in my vertexShader:
#version 330
layout (location = 0) in vec3 Position;
layout (location = 1) in vec3 Normal;
out vec4 Colour0;
// Transforms
uniform mat4 gModelToWorldTransform;
uniform mat4 gWorldToViewToProjectionTransform;
// Ambient light parameters
uniform vec3 gAmbientLightIntensity;
// Directional light parameters
uniform vec3 gDirectionalLightIntensity;
uniform vec3 gDirectionalLightDirection;
// Material constants
uniform float gKa;
uniform float gKd;
uniform float gKs;
uniform float gKsStrength;
void main()
{
// Transform the vertex from local space to homogeneous clip space
vec4 vertexPositionInModelSpace = vec4(Position, 1);
vec4 vertexInWorldSpace = gModelToWorldTransform * vertexPositionInModelSpace;
vec4 vertexInHomogeneousClipSpace = gWorldToViewToProjectionTransform * vertexInWorldSpace;
gl_Position = vertexInHomogeneousClipSpace;
// Calculate the directional light intensity at the vertex
// Find the normal in world space and normalise it
vec3 normalInWorldSpace = (gModelToWorldTransform * vec4(Normal, 0.0)).xyz;
normalInWorldSpace = normalize(normalInWorldSpace);
// Calculate the ambient light intensity at the vertex
// Ia = Ka * ambientLightIntensity
vec4 ambientLightIntensity = gKa * vec4(gAmbientLightIntensity, 1.0);
// Setup the light direction and normalise it
vec3 lightDirection = normalize(-gDirectionalLightDirection);
//lightDirection = normalize(gDirectionalLightDirection);
// Id = kd * lightItensity * N.L
// Calculate N.L
float diffuseFactor = dot(normalInWorldSpace, lightDirection);
diffuseFactor = clamp(diffuseFactor, 0.0, 1.0);
// N.L * light source colour * intensity
vec4 diffuseLightIntensity = gKd * vec4(gDirectionalLightIntensity, 1.0f) * diffuseFactor;
vec3 lightReflect = normalize(reflect(gDirectionalLightDirection, Normal));
//Calculate the specular light intensity at the vertex
float specularFactor = dot(normalInWorldSpace, lightReflect);
specularFactor = pow(specularFactor, gKsStrength);
vec4 specularLightIntensity = gKs * vec4(gDirectionalLightIntensity, 1.0f) * specularFactor;
// Final vertex colour is the product of the vertex colour
// and the total light intensity at the vertex
vec4 colour = vec4(0.0, 1.0, 0.0, 1.0);
Colour0 = colour * (ambientLightIntensity + diffuseLightIntensity + specularLightIntensity);
}
Then in my main.cpp I have the some code to try and get this working together, the specular light is definitely doing something, only, rather than making the model look shiny, it seems to intensify the light to the point where I can't see any details.
I create the following variables:
// Lighting uniforms location
GLuint gAmbientLightIntensityLoc;
GLuint gDirectionalLightIntensityLoc;
GLuint gDirectionalLightDirectionLoc;
GLuint gSpecularLightIntensityLoc;
// Materials uniform location
GLuint gKaLoc;
GLuint gKdLoc;
GLuint gKsLoc;
GLuint gKsStrengthLoc;
I then set my variables like so in the renderSceneCallBack() function which is called in the main:
// Set the material properties
glUniform1f(gKaLoc, 0.2f);
glUniform1f(gKdLoc, 0.9f);
glUniform1f(gKsLoc, 0.5f);
glUniform1f(gKsStrengthLoc, 0.5f);
I then create a initLights() function which I would like to handle all lighting, this is also called in the main:
static void initLights()
{
// Setup the ambient light
vec3 ambientLightIntensity = vec3(0.2f, 0.2f, 0.2f);
glUniform3fv(gAmbientLightIntensityLoc, 1, &ambientLightIntensity[0]);
// Setup the direactional light
vec3 directionalLightDirection = vec3(0.0f, 0.0f, -1.0f);
normalize(directionalLightDirection);
glUniform3fv(gDirectionalLightDirectionLoc, 1, &directionalLightDirection[0]);
vec3 directionalLightIntensity = vec3(0.8f, 0.8f, 0.8f);
glUniform3fv(gDirectionalLightIntensityLoc, 1, &directionalLightIntensity[0]);
//Setup the specular Light
vec3 specularLightIntensity = vec3(0.5f, 0.5f, 0.5f);
glUniform3fv(gSpecularLightIntensityLoc, 1, &specularLightIntensity[0]);
}
Can anyone see what I might be doing wrong, I could have some of the calculatiuons wrong and I just don't see it. Both the ambient/diffuse lighting are working correctly. This photo illustrates whats currently happening, ambient on the left, diffuse in the middle and specular with strength set to 30 on the right.
Answer
I forgot to pass this value into the main:
gKsStrengthLoc = glGetUniformLocation(shaderProgram, "gKsStrength");
//assert(gDirectionalLightDirectionLoc != 0xFFFFFFFF);
Everything works now using the answer selected
Your value for gKsStrength looks way too small:
glUniform1f(gKsStrengthLoc, 0.5f);
This value controls how shiny the object is, with higher values making it more shiny. This makes sense if you look at the calculation in the shader:
specularFactor = pow(specularFactor, gKsStrength);
The larger the exponent, the faster the value drops off, which means that the specular highlight becomes more narrow.
Typical values might be something like 10.0f for moderately shiny, 30.0f for quite shiny, and even higher for very shiny materials.
With your value of 0.5f, you get a very wide specular "highlight". Your value for the specular intensity is also fairly high (0.5), so the highlight is going to cover most of the object, and saturate the colors for large parts.