i am trying to get the mouse cursor in world space pos from window space(-1,1 window width and height) using the viewprojectionmatrix.
This is how i calculate my projection matrix:
static mat4 Perspective4x4(float FOV, float AspectRatio, float FarC, float NearC)
{
// Positive x is right
// Positive y is up
// Positive z is forward into the screen
float Cotangent = 1.0f / tanf((FOV)*0.5f);
float Depth = NearC - FarC;
float A = (-FarC - NearC) / Depth;
float B = 2.0f * FarC * NearC / Depth;
return
{
Cotangent/AspectRatio, 0.0f, 0.0f, 0.0f,
0.0f, Cotangent, 0.0f, 0.0f,
0.0f, 0.0f, -A, -B,
0.0f, 0.0f, 1.0f, 0.0f,
};
}
...
float WidthOverHeight = ...;
mat4 ProjectionMatrix = Perspective4x4(DegreesToRadians(90.0f), WidthOverHeight, 50.0f, 0.1f);
This is how i calculate my view matrix:
static mat4 Translate4x4(vec3 V)
{
return
{
1.0f, 0.0f, 0.0f, V.X,
0.0f, 1.0f, 0.0f, V.Y,
0.0f, 0.0f, 1.0f, V.Z,
0.0f, 0.0f, 0.0f, 1.0f
};
}
...
mat4 ViewMatrix = Translate4x4(-CameraPosition);
This is how i calculate the cursor position in worldspace:
mat4 ProjectionMatrix = ...;
mat4 ViewMatrix = ...;
vec2 CursorP = GetBilateralCursorPos(Input); // Values between -1 and 1
v4_f32 WorldSpacePNear = Inverse(ProjectionMatrix) * V4F32(CursorP, -1.0f, 1.0f);
WorldSpacePNear /= WorldSpacePNear.W;
WorldSpacePNear = Inverse(ViewMatrix) * WorldSpacePNear;
v4_f32 WorldSpacePFar = Inverse(ProjectionMatrix) * V4F32(CursorP, 1.0f, 1.0f);
WorldSpacePFar /= WorldSpacePFar.W;
WorldSpacePFar = Inverse(ViewMatrix) * WorldSpacePFar;
WorldSpacePFar.Z *= -1.0f;
WorldSpacePNear.Z *= -1.0f;
EDIT: I also tried dividing by W at the end but it doesnt work properly either.
This is how i send the matrices to OpenGL (legacy):
// I send them transposed because my matrices are row-major
mat4 ProjectionMatrix = Transpose(...);
mat4 ViewMatrix = Transpose(...);
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(ProjectionMatrix.E);
glMatrixMode(GL_MODELVIEW);
glLoadMatrixf(ViewMatrix.E);
The resulting positions do not seem to take in account the view projection because a change in the camera position will offset them making them not accurate.
NOTES:
vec4, vec2, mat4 are custom float-based math types. (they are what you would expect)
I know legacy OpenGL is deprecated, in fact im going to switch to modern opengl very soon, i just want to get this working.
i fixed the issue calculating the cursor pos like this:
mat4 ProjectionMatrix = ...;
mat4 ViewMatrix = ...;
// Z Distance from camera pos
float WorldDistanceFromCameraZ = 1.0f;
vec2 CursorP = GetBilateralCursorPos(Input); // Values between -1 and 1
vec4 ProbeZ = V4F32(World->Camera.P - WorldDistanceFromCameraZ*World->Camera.P.Z, 1.0f);
ProbeZ = (ProjectionMatrix*ViewMatrix) * ProbeZ;
vec4 ClipP = V4F32(CursorP.X*ProbeZ.W, CursorP.Y*ProbeZ.W, ProbeZ.Z, ProbeZ.W);
vec4 WorldP = Inverse(ProjectionMatrix*ViewMatrix) * ClipP;
There seems to be an odd problem with my Phong lighting shader in OpenGL. The specular highlight appears on the wrong side of the object.
The problem at hand:
As you can see, the specular highlight appears on the opposite side of the cube (and also appears in the corners of the perpendicular edges of the cube, from the light's perspective. It should only appear on the side closest to the light.
The cube's vertices:
float cubeVertices[] = {
// positions // normals // texture coords
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
1.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, -1.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
1.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-1.0f, -1.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, -1.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
The vertex shader:
#version 330 core
layout (location = 0) in vec3 vPos;
layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec2 vTexCoords;
out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
FragPos = vec3(model * vec4(vPos, 1.0));
Normal = mat3(transpose(inverse(model))) * vNormal;
TexCoords = vTexCoords;
gl_Position = projection * view * vec4(FragPos, 1.0);
}
The fragment shader:
#version 330 core
out vec4 FragColor;
in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;
uniform vec3 viewPos;
uniform sampler2D diffuseMap;
struct Light {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
uniform Light lights[8];
uniform int numLights;
vec3 calculateAmbient(vec3 fragPos, vec3 materialAmbient)
{
vec3 ambient = vec3(0.0);
for (int i = 0; i < numLights && i < 8; i++)
{
ambient += lights[i].ambient * materialAmbient;
}
return ambient * 0.5;
}
vec3 calculateDiffuse(vec3 fragPos, vec3 normal, vec3 materialDiffuse)
{
vec3 diffuse = vec3(0.0);
for (int i = 0; i < numLights && i < 8; i++)
{
vec3 lightDir = normalize(lights[i].position - fragPos);
float diff = max(dot(normal, lightDir), 0.0);
diffuse += lights[i].diffuse * (diff * materialDiffuse);
}
return diffuse;
}
vec3 calculateSpecular(vec3 fragPos, vec3 normal, vec3 viewDir, vec3 materialSpecular, float shininess)
{
vec3 specular = vec3(0.0);
for (int i = 0; i < numLights && i < 8; i++)
{
vec3 lightDir = normalize(lights[i].position - fragPos);
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0f * shininess);
specular += lights[i].specular * (spec * materialSpecular);
}
return specular;
}
void main()
{
vec4 tex = texture(diffuseMap, TexCoords);
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
vec3 ambient = calculateAmbient(FragPos, material.ambient);
vec3 diffuse = calculateDiffuse(FragPos, norm, material.diffuse);
vec3 specular = calculateSpecular(FragPos, norm, viewDir, material.specular, material.shininess);
vec3 result = (ambient + diffuse + specular) * tex.rgb;
FragColor = vec4(result, 1.0);
}
The specular highlight appears also on the faces which are back side facing to the light source, because relfect actually computes:
refelct(I, N) = I - 2.0 * dot(N, I) * N
On back faces the normal vector points away from the light source, but refelct(I, N) == refelct(I, -N), because:
I - 2.0 * dot(N, I) * N == I - 2.0 * dot(-N, I) * -N
In the Phong reflection model, the specular hightlight is only add, if the diffuse light is > 0. e.g:
for (int i = 0; i < numLights && i < 8; i++)
{
vec3 lightDir = normalize(lights[i].position - fragPos);
float NdotL = dot(normal, lightDir);
if (NdotL > 0.0)
{
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32.0f * shininess);
specular += lights[i].specular * (spec * materialSpecular);
}
}
I have a code (game) with a fixed camera in an ortho projection. It runs smoothly until I change the camera position from (0,0,1) to (0,0,-1).
In a nutshell, I have 2 textures:
{ //texture 1
960.0f, 0.0f, -5.0f, 0.0f, 0.0f,
960.0f, 1080.0f, -5.0f, 1.0f, 0.0f,
1920.0f, 0.0f, -5.0f, 0.0f, 1.0f,
1920.0f, 1080.0f, -5.0f, 1.0f, 1.0f
}
{ // texture 2
1290.0f, 390.0f, -7.0f, 0.0f, 0.0f,
1290.0f, 690.0f, -7.0f, 1.0f, 0.0f,
1590.0f, 390.0f, -7.0f, 0.0f, 1.0f,
1590.0f, 690.0f, -7.0f, 1.0f, 1.0f
}
the transformation matrices:
view = glm::lookAt
(
glm::vec3( 0.0f, 0.0f, 1.0f ),
glm::vec3( 0.0f, 0.0f, 0.0f ),
glm::vec3( 0.0f, 1.0f, 0.0f )
);
projection = glm::ortho
(
0.0f,
1920.0f,
0.0f,
1080.0f,
1.0f, // zNear
10.0f // zFar
);
the vertex shader:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4( aPos, 1.0 );
TexCoord = vec2( aTexCoord.x, aTexCoord.y );
}
If I run this code, it properly displays both textures, does depth testing,...
However, if I change the camera position to (0, 0, -1) and textures' Z-coordinate to their inverse +5 and +7, and keep the same direction (0, 0, 0), no texture is displayed (rendered). Shouldn't it display the same as before the changes ?
The issue is related to the orthographic projection matrix, because it is not centered. When the z axis of the view is inverted, then the x axis is inverted, too. Note the Right-hand rule has to be still fulfilled and the x.axis is the cross product of the y-axis and z-axis.
When the geometry is at z-5and the view and projection matrix is as follows
view = glm::lookAt(
glm::vec3(0.0f, 0.0f, 1.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f);
projection = glm::ortho(0.0f, 1920.0f, 0.0f, 1080.0f, 1.0f, 10.0f);
then the object is projected to the viewport:
But if you switch the z position of the geometry and the view, then you get the following situation:
view = glm::lookAt(
glm::vec3(0.0f, 0.0f, -1.0f),
glm::vec3(0.0f, 0.0f, 0.0f),
glm::vec3(0.0f, 1.0f, 0.0f);
then the object is beside the viewport:
Shift the the orthographic projection along the X-axis, to solve your issue:
projection = glm::ortho(-1920.0f, 0.0f, 0.0f, 1080.0f, 1.0f, 10.0f);
Opengl has right-hand coordinate system. It means z values increase towards me.
right-hand coordinate system
I draw two triangles:
float vertices[] =
{
//position //color
//triangle 1
0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//0
-1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//1
1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 0.0f,//2
//triangle 2
0.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,//3
1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,//4
-1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f//5
};
Why triangle 1 is in front? Triangle 2 should be in front, because of 0.0f > -1.0f.
I have only gl_Position = vec4(aPos, 1.0); in vertex shader.
After it, if I translate vertices by z=-3 in vertex shader, this translation behaves as it should be. Object becomes further.
Why triangle 1 is in front? Triangle 2 should be in front, because of 0.0f > -1.0f.
I have only gl_Position = vec4(aPos, 1.0); in vertex shader.
Of course the red triangle is in front of the blue one, because you don't use any projection matrix. You forgot to transform the input vertex by the projection matrix before you assign the vertex coordinate to gl_Position.
This causes that the vertices are equal to the normalized device space coordinates. In normalized device space the z-axis points into the viewport and the "projection" is orthographic and not perspective.
You have to do something like this:
in vec3 aPos;
mat4 modelProjectionMatrix;
void main()
{
gl_Position = modelProjectionMatrix * vec4(aPos, 1.0);
}
I need to move two objects in OpenGL independently.
This is vertex positions array:
const float vertexPositions[] = {
0.25f, 0.25f, 0.0f, 1.0f,
0.25f, -0.25f, 0.0f, 1.0f,
-0.25f, -0.25f, 0.0f, 1.0f,
0.75f, 0.45f, 0.0f, 1.0f,
0.45f, -0.45f, 0.0f, 1.0f,
-0.65f, -0.95f, 0.0f, 1.0f,
};
This go to a buffer and then there is the following command which draws these triangles:
glDrawArrays(GL_TRIANGLES, 0, 3*2);
Below is part responsible for rotating:
#version 330
layout(location = 0) in vec4 position;
uniform float loopDuration;
uniform float time;
void main()
{
float timeScale = 3.14159f * 2.0f / loopDuration;
float currTime = mod(time, loopDuration);
vec4 totalOffset = vec4(
cos(currTime * timeScale) * 0.5f,
sin(currTime * timeScale) * 0.5f,
0.0f,
0.0f);
gl_Position = position + totalOffset;
}
Unfortunately it does not work as I expected - instead of moving independently, these triangles seems to be joined together like there were on a plate of glass. What I can do in order to translate and rotate them independently? How can I do it using GPU, not CPU?
I think you'ra doing this tutorial. In that case I suggest you to remove the last 12 floats from the vertexPositions, so you get the following:
const float vertexPositions[] = {
0.25f, 0.25f, 0.0f, 1.0f,
0.25f, -0.25f, 0.0f, 1.0f,
-0.25f, -0.25f, 0.0f, 1.0f,
};
And change the glDrawArrays(GL_TRIANGLES, 0, 3*2); to glDrawArrays(GL_TRIANGLES, 0, 3);. In your display() function, paste after the first calling of glDrawArrays() the following:
glUniform1f(loopDurationUnf, 2.5f);
glDrawArrays(GL_TRIANGLES, 0, 3);
This should draw the same triangle with twice the speed.