I'm trying to implement bump mapping on a cube using OpenGL and GLSL. However, when I rotate my cube around, only the left-facing square and right-facing square appear (that is, in the negative x and positive x direction), the other four faces of the cube (top, bottom, front, back) are black. Here is an example:
My mesh class consists of an indexList and vertexList (the Vertex class contains x, y, z, etc). I'm using this simple cube.ply model, which contains s,t texture coordinates. Borrowing from this example, I calculate the tangent vectors as follows:
void Mesh::computeTangents() {
for (size_t i = 0; i < m_indexList.size(); i += 3) {
Vertex v1 = m_vertexList[m_indexList[i]];
Vertex v2 = m_vertexList[m_indexList[i+1]];
Vertex v3 = m_vertexList[m_indexList[i+2]];
glm::vec3 pos1 = glm::vec3(v1.getX(), v1.getY(), v1.getZ());
glm::vec3 pos2 = glm::vec3(v2.getX(), v2.getY(), v2.getZ());
glm::vec3 pos3 = glm::vec3(v3.getX(), v3.getY(), v3.getZ());
glm::vec2 tex1 = glm::vec2(v1.getS(), v1.getT());
glm::vec2 tex2 = glm::vec2(v2.getS(), v2.getT());
glm::vec2 tex3 = glm::vec2(v3.getS(), v3.getT());
glm::vec3 edge1 = glm::normalize(pos2 - pos1);
glm::vec3 edge2 = glm::normalize(pos3 - pos1);
glm::vec2 texEdge1 = glm::normalize(tex2 - tex1);
glm::vec2 texEdge2 = glm::normalize(tex3 - tex1);
float det = (texEdge1.x * texEdge2.y) - (texEdge1.y * texEdge2.x);
glm::vec3 tangent;
if(fabsf(det) < 1e-6f) {
tangent.x = 1.0;
tangent.y = 0.0;
tangent.z = 0.0;
}
else {
det = 1.0 / det;
tangent.x = (texEdge2.y * edge1.x - texEdge1.y * edge2.x) * det;
tangent.y = (texEdge2.y * edge1.y - texEdge1.y * edge2.y) * det;
tangent.z = (texEdge2.y * edge1.z - texEdge1.y * edge2.z) * det;
glm::normalize(tangent);
}
m_vertexList[m_indexList[i]].setTanX(tangent.x);
m_vertexList[m_indexList[i]].setTanY(tangent.y);
m_vertexList[m_indexList[i]].setTanZ(tangent.z);
m_vertexList[m_indexList[i+1]].setTanX(tangent.x);
m_vertexList[m_indexList[i+1]].setTanY(tangent.y);
m_vertexList[m_indexList[i+1]].setTanZ(tangent.z);
m_vertexList[m_indexList[i+2]].setTanX(tangent.x);
m_vertexList[m_indexList[i+2]].setTanY(tangent.y);
m_vertexList[m_indexList[i+2]].setTanZ(tangent.z);
}
}
If I output the values of the tangent vector for each triangle, I get these values:
1, 0, 0
1, 0, 0
0, 0, -1
0, 0, -1
0, 0, 1
0, 0, 1
-1, 0, 0
-1, 0, 0,
1, 0, 0
1, 0, 0
1, 0, 0
1, 0, 0
If these are correct, then the problem is likely in the shader. My shader is as follows (mostly taken from a book):
vert:
attribute vec4 vertexPosition;
attribute vec3 vertexNormal;
attribute vec2 vertexTexture;
attribute vec3 vertexTangent;
varying vec2 texCoord;
varying vec3 viewDirection;
varying vec3 lightDirection;
uniform vec3 diffuseColor;
uniform float shininess;
uniform vec4 lightPosition;
uniform mat4 modelViewMatrix;
uniform mat4 normalMatrix;
uniform mat4 MVP; // modelview projection
void main() {
vec4 eyePosition = modelViewMatrix * vertexPosition;
vec3 N = normalize(vec3(normalMatrix * vec4(vertexNormal, 1.0)));
vec3 T = normalize(vec3(normalMatrix * vec4(vertexTangent, 1.0)));
vec3 B = normalize(cross(N, T));
vec3 v;
v.x = dot(lightPosition.xyz, T);
v.y = dot(lightPosition.xyz, B);
v.z = dot(lightPosition.xyz, N);
lightDirection = normalize(v);
v.x = dot(eyePosition.xyz, T);
v.y = dot(eyePosition.xyz, B);
v.z = dot(eyePosition.xyz, N);
viewDirection = normalize(v);
texCoord = vertexTexture;
gl_Position = MVP * vertexPosition;
}
Frag:
varying vec2 texCoord;
varying vec3 viewDirection;
varying vec3 lightDirection;
uniform vec3 diffuseColor;
uniform float shininess;
void main() {
float bumpDensity = 16.0;
float bumpSize = 0.15;
vec2 c = bumpDensity * texCoord;
vec2 p = fract(c) - vec2(0.5);
float d, f;
d = dot(p, p);
f = 1.0 / sqrt(d + 1.0);
if (d >= bumpSize) {
p = vec2(0.0);
f = 1.0;
}
vec3 normalDelta = vec3(p.x, p.y, 1.0) * f;
vec3 litColor = diffuseColor * max(dot(normalDelta, lightDirection), 0.0);
vec3 reflectDir = reflect(lightDirection, normalDelta);
float spec = max(dot(viewDirection, reflectDir), 0.0);
spec *= shininess;
litColor = min(litColor + spec, vec3(1.0));
gl_FragColor = vec4(litColor, 1.0);
}
Edit: Changed background to more clearly see the black faces. Also, I incorrectly noted which faces were actually appearing before.
Edit 2: I'm finding that the value of max(dot(normalDelta, lightDirection), 0.0) in the fragment shader returns 0 for those faces. However, I still don't know why.
Edit 3: Well, the problem turned out to be that I was passing the wrong index of the tangent vectors in my Vertex class. That is, I had 10 in this line instead of 9:
glVertexAttribPointer(v3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)(sizeof( float ) * 9));
Okay, so the problem is that any face with a normal on the xz-plane isn't rendering properly, i.e. the ones that are rendering properly are the ones with normals along the y-axis (top and bottom faces).
And your list of tangents:
1, 0, 0
1, 0, 0
0, 0, -1
0, 0, -1
0, 0, 1
0, 0, 1
-1, 0, 0
-1, 0, 0
1, 0, 0
1, 0, 0
1, 0, 0
1, 0, 0
Are all either along the x or z axes. So what I'm guessing might be happening is that your normals and tangents are pointing in the same (or opposite) directions, in which case this line in your vertex shader:
vec3 B = normalize(cross(N, T));
is going to result in vec3(0.0, 0.0, 0.0), which can't be normalized.
My recommendation is to try manually giving the x and z faces tangents along the y-axis, see if that makes a difference. If it helps, then you know that the problem is with your computation of the tangents.
If it doesn't help, you can troubleshoot by outputting values from the fragment shader as on-screen colours. Try displaying the viewDirection, lightDirection, normalDelta, reflectDir, and anything else you can think of to see which variable is causing the blackness.
Bonus: Switch the glClear color to something other than black? So that it doesn't look like a face floating in space.
Related
I am looking to turn my current circular light into an ellipse by having a vec2 radius which can have different x and y values. Is there any way to do this based on my current code in the fragment shader?
uniform struct Light
{
vec4 colour;
vec3 position;
vec2 radius;
float intensity;
} allLights[MAX_LIGHTS];
vec4 calculateLight(Light light)
{
vec2 lightDir = fragmentPosition.xy - light.position.xy;
float lightDistance = length(lightDir);
if (lightDistance >= light.radius.x)
{
return vec4(0, 0, 0, 1); //outside of radius make it black
}
return light.intensity * (1 - lightDistance / light.radius.x) * light.colour;
}
Divide the vector to the light source with the semi-axis of the ellipse and check whether the length of the vector is greater than 1.0:
if (length(lightDir / light.radius) >= 1.0)
return vec4(0, 0, 0, 1); //outside of radius make it black
return light.intensity * (1 - length(lightDir / light.radius)) * light.colour;
I have a plain that is created using this method: Heres an image showing my way of thinking
I separate these stripes of triangles so that each one can have unique color and I still am able to use Vertex Indexing.
My problem is whit normals buffer. I create normals like this (this is in the algorithm that calculates vertices):
//Calculating Vertices
for (unsigned int z = 0; z < m_size; z++)
{
for (unsigned int x = 0; x <= m_size; x++)
{
Vertices.push_back(glm::vec3(m_startingPos.x + x * m_sqrWidth, m_startingPos.y, m_startingPos.z + z * m_sqrWidth));
Vertices.push_back(glm::vec3(m_startingPos.x + x * m_sqrWidth, m_startingPos.y, m_startingPos.z + (z + 1) * m_sqrWidth));
glm::vec3 TL = glm::vec3(m_startingPos.x + x * m_sqrWidth, m_startingPos.y, m_startingPos.z + z * m_sqrWidth);
glm::vec3 TR = glm::vec3(m_startingPos.x + (x + 1) * m_sqrWidth, m_startingPos.y, m_startingPos.z + z * m_sqrWidth);
glm::vec3 BL = glm::vec3(m_startingPos.x + x * m_sqrWidth, m_startingPos.y, m_startingPos.z + (z + 1) * m_sqrWidth);
glm::vec3 BR = glm::vec3(m_startingPos.x + (x + 1) * m_sqrWidth, m_startingPos.y, m_startingPos.z + (z + 1) * m_sqrWidth);
//Normals:
Normals.push_back(glm::normalize(glm::cross(TL - BR, BL - BR)));
Normals.push_back(glm::normalize(glm::cross(TR - BR, TL - BR)));
//Color:
colors.push_back(0.0f); colors.push_back(0.0f); colors.push_back(0.5f);
colors.push_back(0.0f); colors.push_back(0.5f); colors.push_back(0.0f);
}
}
So every normal is 0 1 0, I know this.
Here I create a buffer and attribPointer for normals (Its all in a class so unsigned int normalsBuffer is declared in .h file and initialised as NULL):
glGenBuffers(1, &normalsBuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalsBuffer);
glBufferData(GL_ARRAY_BUFFER, Normals.size() * sizeof(float) * 3, &Normals[0].x, GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
In glVertexAttribPointer inedex is set to 2 because vertices take 0 and colors take 1.
So now heres my shader:
#shader vertex
#version 330 core
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 color_in;
layout(location = 2) in vec3 normals_in;
uniform mat4 u_MVP;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
out vec3 FragPos;
out vec3 Normal;
out vec3 color_f;
void main()
{
color_f = color_in;
FragPos = vec3(model * vec4(position, 1.0));
Normal = normals_in;
Normal = mat3(transpose(inverse(model))) * normals_in;
gl_Position = projection * view * vec4(FragPos, 1.0);
};
#shader fragment
#version 330 core
out vec4 color;
in flat vec3 Normal;
in vec3 FragPos;
in flat vec3 color_f;
uniform vec4 u_Color;
uniform vec3 lightPos;
uniform vec3 viewPos;
uniform vec3 lightColor;
void main()
{
vec3 objectColor = color_f;
// ambient
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
// specular
float specularStrength = 0.5;
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);
vec3 specular = specularStrength * spec * lightColor;
vec3 result = (ambient + diffuse + specular) * objectColor;
color = vec4(result, 1.0);
}
Heres an example how object with same shader works and how my plain behaves, It totally lacks diffuse lighting
If I go to the fragment shader and set vec3 norm = vec3(0.0, 1.0, 0.0) it all works fine but thats not the way I want to do it.
So I send color data the same way and its fine but sending normals data doesnt seem to be working.
Heres how it looks like when I got to fragment shader and set norm to 0 1 0
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
so you enable the VertexAttribArray for the color ( 1 )
you should activate the VertexAttribArray for the normals ( 2 ) and also
make sure you got the (void*)0 correct if you are using a struct make sure to
use offsetof it is more reliable especially if you use compiler with optimizations
On my scene, I rendering landscape (approximately 522000 triangles, from a heights map, all points of the heights map are used to create a triangle mesh) and shadow mapping / blur is active. I noticed a strong fall in FPS. At the moment I have one light source - a kind of "sun". Therefore, light source far_plane is extremely high - 512 (the maximum point of the landscape is 128, the minimum point is 0). I need to somehow optimize it to get better performance.
An example of a generated landscape with heights map 512x512
My first idea is to reduce the number of triangles in the grid. I think for a heights map 512*512 522 thousand triangles is too much. Also, when scaling, the landscape is extremely smooth, even without averaging the normals. This is the reason to make the terrain lower polygonal.
If I reduce the height of the vertices (scale them) and, accordingly, reduce far_plane of light source, can this give an increase in performance?
My shaders:
Vertex shader:
#version 130
in vec4 a_Position; // Per-vertex position information we will pass in.
void main() {
gl_Position = a_Position;
}
Geometry shader:
#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices=3) out;
uniform mat4 u_Model, u_View, u_Projection;
uniform float greenValue = 64;
uniform float greyValue = 96;
out vec3 norm;
out vec4 v_Position;
out mat4 model, view, projection;
out vec4 ambientColor;
out vec4 diffuseColor;
out vec4 specularColor;
void main() {
vec4 v1Eye = u_View * u_Model * gl_in[0].gl_Position;
vec4 v2Eye = u_View * u_Model * gl_in[1].gl_Position;
vec4 v3Eye = u_View * u_Model * gl_in[2].gl_Position;
vec4 v1v2 = v1Eye - v2Eye;
vec4 v2v3 = v2Eye - v3Eye;
vec3 normal = cross(vec3(v1v2), vec3(v2v3));
normal = normalize(normal);
if (normal.z < 0) normal = -normal;
mat4 MVPMatrix = u_Projection * u_View * u_Model;
for (int i = 0; i < gl_in.length(); i++) {
v_Position = gl_in[i].gl_Position;
gl_Position = MVPMatrix * gl_in[i].gl_Position;
model = u_Model;
view = u_View;
projection = u_Projection;
norm = normal;
if (v_Position.y < greenValue) {
ambientColor = vec4(0, 1, 0, 1);
diffuseColor = ambientColor;
specularColor = vec4(0, 0, 0, 1);
} else if (v_Position.y < greyValue) {
ambientColor = vec4(0.4, 0.4, 0.4, 1);
diffuseColor = ambientColor;
specularColor = vec4(0, 0, 0, 1);
} else {
ambientColor = vec4(1, 1, 1, 1);
diffuseColor = ambientColor;
specularColor = ambientColor;
}
EmitVertex();
}
EndPrimitive();
}
Fragment shader:
#version 330 core
precision mediump float; // Set the default precision to medium. We don't need as high of a
// precision in the fragment shader.
#define MAX_LAMPS_COUNT 8 // Max lamps count.
uniform vec3 u_ViewPos; // Camera position
uniform int u_LampsCount; // Lamps count
uniform float brightnessThreshold = 0.3; // brightness threshold variable
uniform float far_plane; // shadow matrix far plane
in mat4 model, view, projection;
in vec4 v_Position; // Position for this fragment in world space
in vec4 ambientColor;
in vec4 diffuseColor;
in vec4 specularColor;
in vec3 norm;
struct Lamp {
float ambientStrength;
float diffuseStrength;
float specularStrength;
float kc; // constant term
float kl; // linear term
float kq; // quadratic term
int shininess;
vec3 lampPos; // in world space
vec3 lampColor;
};
uniform samplerCube shadowMaps[MAX_LAMPS_COUNT];
uniform Lamp u_Lamps[MAX_LAMPS_COUNT];
vec3 fragPos;
vec3 fragWorldPos;
vec3 lampEyePos; // Transformed lamp position into eye space
float shadow;
// for PCF
vec3 sampleOffsetDirections[20] = vec3[] (
vec3(1, 1, 1), vec3(1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1),
vec3(1, 1, -1), vec3(1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1),
vec3(1, 1, 0), vec3(1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0),
vec3(1, 0, 1), vec3(-1, 0, 1), vec3(1, 0, -1), vec3(-1, 0, -1),
vec3(0, 1, 1), vec3(0, -1, 1), vec3(0, -1, -1), vec3(0, 1, -1)
);
// output colors
layout(location = 0) out vec4 fragColor;
layout(location = 1) out vec4 fragBrightColor;
float calculateShadow(vec3 lightDir, int index) {
// get vector between fragment position and light position
vec3 fragToLight = fragWorldPos - u_Lamps[index].lampPos;
// now get current linear depth as the length between the fragment and light position
float currentDepth = length(fragToLight);
// now test for shadows
//float bias = max(0.5 * (1.0 - dot(norm, lightDir)), 0.005);
float bias = 1;
// PCF
float viewDistance = length(u_ViewPos - fragWorldPos);
float diskRadius = (1.0 + (viewDistance / far_plane)) / 25.0;
for (int i = 0; i < 20; ++i) {
float closestDepth = texture(shadowMaps[index], fragToLight + sampleOffsetDirections[i] * diskRadius).r;
closestDepth *= far_plane; // Undo mapping [0;1]
if(currentDepth - bias > closestDepth) shadow += 1.0;
}
shadow /= 20;
//fragColor = vec4(vec3(closestDepth / far_plane), 1.0); // visualizing
return shadow;
}
float calculateAttenuation(Lamp lamp) {
float distance = length(lampEyePos - fragPos);
return 1.0 / (
lamp.kc +
lamp.kl * distance +
lamp.kq * (distance * distance)
);
}
vec4 toVec4(vec3 v) {
return vec4(v, 1);
}
// The entry point for our fragment shader.
void main() {
fragWorldPos = vec3(model * v_Position);
// Transform the vertex into eye space
mat4 mvMatrix = view * model;
fragPos = vec3(mvMatrix * v_Position);
vec3 viewDir = normalize(u_ViewPos - fragPos);
vec3 ambientResult = vec3(0, 0, 0); // result of ambient lighting for all lamps
vec3 diffuseResult = vec3(0, 0, 0); // result of diffuse lighting for all lamps
vec3 specularResult = vec3(0, 0, 0); // result of specular lighting for all lamps
for (int i = 0; i<u_LampsCount; i++) {
lampEyePos = vec3(view * toVec4(u_Lamps[i].lampPos));
// attenuation
float attenuation = calculateAttenuation(u_Lamps[i]);
// ambient
vec3 ambient = u_Lamps[i].ambientStrength * u_Lamps[i].lampColor * attenuation;
// diffuse
vec3 lightDir = normalize(lampEyePos - fragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = u_Lamps[i].diffuseStrength * diff * u_Lamps[i].lampColor * attenuation;
// specular
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), u_Lamps[i].shininess);
vec3 specular = u_Lamps[i].specularStrength * spec * u_Lamps[i].lampColor * attenuation;
// calculate shadow
shadow = calculateShadow(lightDir, i);
// result for this(i) lamp
ambientResult += ambient;
diffuseResult += diffuse * (1-shadow);
specularResult += specular * (1-shadow);
}
fragColor =
toVec4(ambientResult) * ambientColor +
toVec4(diffuseResult) * diffuseColor +
toVec4(specularResult) * specularColor;
// brightness calculation
float brightness = dot(fragColor.rgb, vec3(0.2126, 0.7152, 0.0722));
if (brightness > brightnessThreshold) fragBrightColor = vec4(fragColor.rgb, 1.0);
}
And my shadow shaders:
Vertex shader:
#version 130
attribute vec3 a_Position;
uniform mat4 u_ModelMatrix;
void main() {
gl_Position = u_ModelMatrix * vec4(a_Position, 1.0);
}
Geometry shader:
#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices=18) out;
uniform mat4 shadowMatrices[6];
out vec4 fragPos; // FragPos from GS (output per emitvertex)
void main() {
for(int face = 0; face < 6; face++) {
gl_Layer = face; // built-in variable that specifies to which face we render.
// for each triangle's vertices
for(int i = 0; i < 3; i++) {
fragPos = gl_in[i].gl_Position;
gl_Position = shadowMatrices[face] * fragPos;
EmitVertex();
}
EndPrimitive();
}
}
Fragment shader:
#version 330 core
in vec4 fragPos; // world space
uniform vec3 lightPos; // world space
uniform float far_plane; // shadow matrix far plane
void main()
{
float lightDistance = length(fragPos.xyz - lightPos);
// map to [0;1] range by dividing by far_plane
lightDistance = lightDistance / far_plane;
// write this as modified depth
gl_FragDepth = lightDistance;
}
I hope for your help in optimizing this scene.
I'm trying to handle the transform of texture in fragment shader.
the resolution of window is (640,360), the rotation is 30 degree, and the scale is vec2(0.5,0.5).
this is what I want:
here is my fragment shader:
precision mediump float;
varying vec2 v_texCoord;
uniform sampler2D s_texture;
mat3 makeTranslation(vec2 t) {
mat3 m = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, t.x, t.y, 1.0);
return m;
}
mat3 makeRotation( float angleInRadians ){
float c = cos(angleInRadians);
float s = sin(angleInRadians);
mat3 m = mat3(c, -s, 0, s, c, 0, 0, 0, 1);
return m;
}
mat3 makeScale(vec2 s) {
mat3 m = mat3( s.x, 0, 0, 0, s.y, 0, 0, 0, 1);
return m;
}
void main(){
vec2 position = vec2(0.0,0.0);
vec2 scale = vec2(0.5,0.5);
float rotation = 30.0;
float r = rotation/180.0*3.14159;
vec2 size = vec2(640.0,480.0);
mat3 mt = makeTranslation( translation );
mat3 mr = makeRotation( r );
mat3 ms = makeScale( 1.0/scale );
//transform
vec3 newCoord = vec3(v_texCoord.xy,1.0);
newCoord = mt*newCoord;
newCoord = mr*ms*vec3(newCoord.x - 0.5, newCoord.y - 0.5,0.0) + vec3(0.5, 0.5, 0.0);
gl_FragColor = texture2D(s_texture, vec2(newCoord.x, newCoord.y) );
}
the result is:
As you can see, the result is incorrect.
so, I apply a ratio of rectangle size to the texcoord.y:
//transform
float fy = 0.5*(1.0 - size.y*1.0/size.x);
newCoord.y = (newCoord.y-0.5)*size.y/size.x+fy;
newCoord = mt*newCoord; \n"
newCoord = mr*ms*vec3(newCoord.x - 0.5, newCoord.y - 0.5,0.0) + vec3(0.5, 0.5, 0.0);
newCoord.y = (newCoord.y+0.5)*size.x/size.y-fy;
what I've got:
the rectangle is correct, but the position of center point is incorrect.
So, how to get the right result?
thanks.
here is the origin texture:
Getting the right order of operations is very important.
When you receive your texture coordinates, they are in the range [0, 1]. However, you need to translate them, so that they are in [-0.5, 0.5], before you rotate them, so that you are rotating around the center of the texture. Then apply your scale, and finally your translation.
you dont include screen and texture size proportions
Shadertoy code: (iChannel0 is texture, or BufA then uncomment line 26)
mat3 makeTranslation(vec2 t) {
mat3 m = mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, t.x, t.y, 1.0);
return m;
}
mat3 makeRotation( float angleInRadians ){
float c = cos(angleInRadians);
float s = sin(angleInRadians);
mat3 m = mat3(c, -s, 0, s, c, 0, 0, 0, 1);
return m;
}
mat3 makeScale(vec2 s) {
mat3 m = mat3( s.x, 0, 0, 0, s.y, 0, 0, 0, 1);
return m;
}
void mainImage( out vec4 fragColor, in vec2 fragCoord ){
vec2 screen_res = iResolution.xy/iResolution.y;
vec2 uv = fragCoord/iResolution.y-0.5*screen_res;
vec2 position = vec2(0.0,0.0);
vec2 scale = vec2(0.5,0.5);
float rotation = 180.*iMouse.x/iResolution.x;
float r = rotation/180.0*3.14159;
vec2 size = vec2(640.0,480.0);
//vec2 target_res = vec2(textureSize(iChannel0,0).xy)/float(textureSize(iChannel0,0).y);
vec2 target_res = vec2(1.,.5);
mat3 mt = makeTranslation( vec2(0.5*target_res) );
mat3 mr = makeRotation( r );
mat3 ms = makeScale( 1.0/scale );
//transform
vec3 newCoord = vec3(uv.xy,1.0);
newCoord = mt*newCoord;
newCoord = mr*ms*vec3(newCoord.x - 0.5*target_res.x, newCoord.y - 0.5*target_res.y,0.0) + vec3(0.5*target_res, 0.0);
newCoord.xy*= 1./target_res;
fragColor = texture(iChannel0, vec2(newCoord.x, newCoord.y) );
}
As a test, I created a simple quad. Here are its attributes:
Vertex vertices[] =
{
// Positions Normals
{vec3(-1,-1, 0), vec3(-1,-1, 1)}, // v0
{vec3( 1,-1, 0), vec3( 1,-1, 1)}, // v1
{vec3(-1, 1, 0), vec3(-1, 1, 1)}, // v2
{vec3( 1, 1, 0), vec3( 1, 1, 1)}, // v3
};
And I put it in my world space at (0.0, 0.0, -9.5). Then I put my point light position at (0.0, 0.0, -8.0). My camera is at the origin (0.0, 0.0, 0.0). When I run my program, this works as expected:
But then, when I replace this quad with 9 scaled down quads, put them all at -9.5 on Z (in other word, they are all parallel to each other on Z), my diffuse lighting gets a little weird
It looks like the corners are showing too much lighting, breaking the nice diffuse circle that we see on a regular quad.
Here is my shader program:
precision mediump int;
precision mediump float;
varying vec3 v_position;
varying vec3 v_normal;
#if defined(VERTEX)
uniform mat4 u_mvpMatrix;
uniform mat4 u_mvMatrix;
uniform mat3 u_normalMatrix;
attribute vec4 a_position;
attribute vec3 a_normal;
void main()
{
vec4 position = u_mvMatrix * a_position;
v_position = position.xyz / position.w;
v_normal = normalize(u_normalMatrix * a_normal);
gl_Position = u_mvpMatrix * a_position;
}
#endif // VERTEX
#if defined(FRAGMENT)
uniform vec3 u_pointLightPosition;
void main()"
{
vec3 viewDir = normalize(-v_position);
vec3 normal = normalize(v_normal);
vec3 lightPosition = u_pointLightPosition - v_position;
vec3 pointLightDir = normalize(lightPosition);
float distance = length(lightPosition);
float pointLightAttenuation = 1.0 / (1.0 + (0.25 * distance * distance));
float diffuseTerm = max(dot(pointLightDir, normal), 0.15);
gl_FragColor = vec4(diffuseTerm * pointLightAttenuation);
}
#endif // FRAGMENT
My uniforms are uploaded as followed (I'm using GLM):
const mat4 &view_matrix = getViewMatrix();
mat4 mv_matrix = view * getModelMatrix();
mat4 mvp_matrix = getProjectionMatrix() * mv_matrix;
mat3 normal_matrix = inverseTranspose(mat3(mv_matrix));
vec3 pointLightPos = vec3(view_matrix * vec4(getPointLightPos(), 1.0f));
glUniformMatrix4fv( mvpMatrixUniformID, 1, GL_FALSE, (GLfloat*)&mvp_matrix);
glUniformMatrix4fv( vpMatrixUniformID, 1, GL_FALSE, (GLfloat*)&mv_matrix);
glUniformMatrix3fv(normalMatrixUniformID, 1, GL_FALSE, (GLfloat*)&normal_matrix);
glUniform3f(pointLightPosUniformID, pointLightPos.x, pointLightPos.y, pointLightPos.z);
Am I doing anything wrong?
Thanks!
Without going too much into your code, I think everything is working just fine. I see a very similar result with a quick blender setup:
The issue is the interpolation of the normal doesn't produce a spherical bump.
It ends up being a patch like this (I simply subdivided a smooth shaded cube)...
If you want a more spherical bump, you could generate the normals implicitly in a fragment shader (for example as is done here (bottom image)), use a normal map, or use more tessellated geometry such as an actual sphere.