I got an orthographic camera working however I wanted to try and implement a perspective camera so I can do some parallax effects later down the line. I am having some issues when trying to implement it. It seems like the depth is not working correctly. I am rotating a 2d image along the x-axis to simulate it laying somewhat down so I get see the projection matrix working. It is still showing as an orthographic perspective though.
Here is some of my code:
CameraPersp::CameraPersp() :
_camPos(0.0f,0.0f,0.0f), _modelMatrix(1.0f), _viewMatrix(1.0f), _projectionMatrix(1.0f)
Function called init to setup the matrix variables:
void CameraPersp::init(int screenWidth, int screenHeight)
{
_screenHeight = screenHeight;
_screenWidth = screenWidth;
_modelMatrix = glm::translate(_modelMatrix, glm::vec3(0.0f, 0.0f, 0.0f));
_modelMatrix = glm::rotate(_modelMatrix, glm::radians(-55.0f), glm::vec3(1.0f, 0.0f, 0.0f));
_viewMatrix = glm::translate(_viewMatrix, glm::vec3(0.0f, 0.0f, -3.0f));
_projectionMatrix = glm::perspective(glm::radians(45.0f), static_cast<float>(_screenWidth) / _screenHeight, 0.1f, 100.0f);
}
Initializing a texture to be loaded in with x,y,z,width,height,src
_sprites.back()->init(-0.5f, -0.5f, 0.0f, 1.0f, 1.0f, "src/content/sprites/DungeonCrawlStoneSoupFull/monster/deep_elf_death_mage.png");
Sending in the matrices to the vertexShader:
GLint mLocation = _colorProgram.getUniformLocation("M");
glm::mat4 mMatrix = _camera.getMMatrix();
//glUniformMatrix4fv(mLocation, 1, GL_FALSE, &(mMatrix[0][0]));
glUniformMatrix4fv(mLocation, 1, GL_FALSE, glm::value_ptr(mMatrix));
GLint vLocation = _colorProgram.getUniformLocation("V");
glm::mat4 vMatrix = _camera.getVMatrix();
//glUniformMatrix4fv(vLocation, 1, GL_FALSE, &(vMatrix[0][0]));
glUniformMatrix4fv(vLocation, 1, GL_FALSE, glm::value_ptr(vMatrix));
GLint pLocation = _colorProgram.getUniformLocation("P");
glm::mat4 pMatrix = _camera.getPMatrix();
//glUniformMatrix4fv(pLocation, 1, GL_FALSE, &(pMatrix[0][0]));
glUniformMatrix4fv(pLocation, 1, GL_FALSE, glm::value_ptr(pMatrix));
Here is my vertex shader:
#version 460
//The vertex shader operates on each vertex
//input data from VBO. Each vertex is 2 floats
in vec3 vertexPosition;
in vec4 vertexColor;
in vec2 vertexUV;
out vec3 fragPosition;
out vec4 fragColor;
out vec2 fragUV;
//uniform mat4 MVP;
uniform mat4 M;
uniform mat4 V;
uniform mat4 P;
void main() {
//Set the x,y position on the screen
//gl_Position.xy = vertexPosition;
gl_Position = M * V * P * vec4(vertexPosition, 1.0);
//the z position is zero since we are 2d
//gl_Position.z = 0.0;
//indicate that the coordinates are nomalized
gl_Position.w = 1.0;
fragPosition = vertexPosition;
fragColor = vertexColor;
// opengl needs to flip the coordinates
fragUV = vec2(vertexUV.x, 1.0 - vertexUV.y);
}
I can see the image "squish" a little because it is still rendering the perspective as orthographic. If I remove the rotation on the x-axis, it is not longer squished because it isn't laying down at all. Any thoughts on what I am doing wrong? I can supply more info upon request but I think I put in most of the meat of things.
Picture:
You shouldn't modify gl_Position.w
gl_Position = M * V * P * vec4(vertexPosition, 1.0); // gl_Position is good
//indicate that the coordinates are nomalized < not true
gl_Position.w = 1.0; // Now perspective divisor is lost, projection isn't correct
Related
My scene: (the video is blurry because I had to convert this to a GIF)
There are two other objects that should be rendered here!
I am writing a program with GLFW/OpenGL. Essentially what I am trying to do is to be able to render a bunch of independent objects, who all can move freely around. To do this, I create a shader, a VAO, a VBO, and a EBO for each model that I want to render. static_models is a vector of class Model, and class Model is just a way to organize my vertices, indices, colors, and normals.
First is creating the vector of Models: (I know this class works as it should, because I use the exact same class for different shaders and buffer objects and things render well)
std::vector<Model> static_models; // scale // color
Model plane("models/plane.ply", { 1.0f, 1.0f, 1.0f }, { 1.0f, 1.0f, 1.0f });
Model tetrahedron("models/tetrahedron.ply", { 1.0f, 1.0f, 1.0f }, { 0.2f, 1.0f, 1.0f });
static_models.emplace_back(plane);
static_models.emplace_back(tetrahedron);
The code for generating the shader objects, VAOS, VBOS, and EBOS:
for (int i = 0; i < static_models.size(); i++)
{
Shader tempShader("plane.vert", "plane.frag");
// create a shader program for each model (in case we need to rotate them or transform them in some way they will be independent)
static_model_shaders.emplace_back(tempShader);
VAOS_static.emplace_back();
VAOS_static.back().Bind();
VBO tempVBO(&static_models.at(i).vertices.front(), static_models.at(i).vertices.size() * sizeof(GLfloat));
EBO tempEBO(&static_models.at(i).indices.front(), static_models.at(i).indices.size() * sizeof(GLuint));
VAOS_static.back().LinkAttrib(tempVBO, 0, 3, GL_FLOAT, 11 * sizeof(float), (void*)0);
VAOS_static.back().LinkAttrib(tempVBO, 1, 3, GL_FLOAT, 11 * sizeof(float), (void*)(3 * sizeof(float)));
VAOS_static.back().LinkAttrib(tempVBO, 2, 2, GL_FLOAT, 11 * sizeof(float), (void*)(6 * sizeof(float)));
VAOS_static.back().LinkAttrib(tempVBO, 3, 3, GL_FLOAT, 11 * sizeof(float), (void*)(8 * sizeof(float)));
VAOS_static.back().Unbind();
tempVBO.Unbind();
tempEBO.Unbind();
}
Then the code to create the positions and mat4 matrixes for each model:
// static model vectors for position and matrix
std::vector<glm::vec3> staticModelPositions;
std::vector<glm::mat4> staticModels;
// initialize all static_model object positions
for (int i = 0; i < static_models.size(); i++)
{
staticModelPositions.emplace_back();
staticModelPositions.back() = glm::vec3(0.0f, 1.0f, 0.0f);
staticModels.emplace_back();
staticModels.back() = glm::translate(staticModels.back(), staticModelPositions.back());
}
Then I set some initial values for the uniforms:
std::vector<Texture> textures;
//static objects
for (int i = 0; i < static_models.size(); i++)
{
//activate first before setting uniforms
static_model_shaders.at(i).Activate();
// static model load model, then load lightColor, then load lightPos for each static_model
glUniformMatrix4fv(glGetUniformLocation(static_model_shaders.at(i).ID, "model"), 1, GL_FALSE, glm::value_ptr(staticModels.at(i)));
glUniform4f(glGetUniformLocation(static_model_shaders.at(i).ID, "lightColor"), lightColor.x, lightColor.y, lightColor.z, 1.0f);
glUniform3f(glGetUniformLocation(static_model_shaders.at(i).ID, "lightPos"), lightPos.x, lightPos.y, lightPos.z);
//create texture objects
textures.emplace_back(Texture("brick.png", GL_TEXTURE_2D, GL_TEXTURE0, GL_RGBA, GL_UNSIGNED_BYTE));
textures.back().texUnit(static_model_shaders.at(i), "tex0", 0);
}
Then drawing the models in the game loop: (game loop not shown this is a big program)
//draw all static models (each with a different shader and matrix)
for (int i = 0; i < static_model_shaders.size(); i++)
{
//activate shader for current model
// Tells OpenGL which Shader Program we want to use
static_model_shaders.at(i).Activate();
// Exports the camera Position to the Fragment Shader for specular lighting
glUniform3f(glGetUniformLocation(static_model_shaders.at(i).ID, "camPos"), camera.Position.x, camera.Position.y, camera.Position.z);
glUniformMatrix4fv(glGetUniformLocation(static_model_shaders.at(i).ID, "model"), 1, GL_FALSE, glm::value_ptr(staticModels.at(i)));
glUniform4f(glGetUniformLocation(static_model_shaders.at(i).ID, "lightColor"), lightColor.x, lightColor.y, lightColor.z, 1.0f);
// Export the camMatrix to the Vertex Shader of the pyramid
camera.Matrix(static_model_shaders.at(i), "camMatrix");
// Binds texture so that is appears in rendering
textures.at(i).Bind();
VAOS_static.at(i).Bind();
glDrawElements(GL_TRIANGLES, static_models.at(i).indices.size(), GL_UNSIGNED_INT, 0);
VAOS_static.at(i).Unbind();
}
My vertex shader:
#version 330 core
// Positions/Coordinates
layout (location = 0) in vec3 aPos;
// Colors
layout (location = 1) in vec3 aColor;
// Texture Coordinates
layout (location = 2) in vec2 aTex;
// Normals (not necessarily normalized)
layout (location = 3) in vec3 aNormal;
// Outputs the color for the Fragment Shader
out vec3 color;
// Outputs the texture coordinates to the Fragment Shader
out vec2 texCoord;
// Outputs the normal for the Fragment Shader
out vec3 Normal;
// Outputs the current position for the Fragment Shader
out vec3 crntPos;
// Imports the camera matrix from the main function
uniform mat4 camMatrix;
// Imports the model matrix from the main function
uniform mat4 model;
void main()
{
// calculates current position
crntPos = vec3(model * vec4(aPos, 1.0f));
// Outputs the positions/coordinates of all vertices
gl_Position = camMatrix * vec4(crntPos, 1.0);
// Assigns the colors from the Vertex Data to "color"
color = aColor;
// Assigns the texture coordinates from the Vertex Data to "texCoord"
texCoord = aTex;
// Assigns the normal from the Vertex Data to "Normal"
Normal = aNormal;
}
And fragment shader:
#version 330 core
// Outputs colors in RGBA
out vec4 FragColor;
// Imports the color from the Vertex Shader
in vec3 color;
// Imports the texture coordinates from the Vertex Shader
in vec2 texCoord;
// Imports the normal from the Vertex Shader
in vec3 Normal;
// Imports the current position from the Vertex Shader
in vec3 crntPos;
// Gets the Texture Unit from the main function
uniform sampler2D tex0;
// Gets the color of the light from the main function
uniform vec4 lightColor;
// Gets the position of the light from the main function
uniform vec3 lightPos;
// Gets the position of the camera from the main function
uniform vec3 camPos;
void main()
{
// ambient lighting
float ambient = 0.40f;
// diffuse lighting
vec3 normal = normalize(Normal);
vec3 lightDirection = normalize(lightPos - crntPos);
float diffuse = max(dot(normal, lightDirection), 0.0f);
// specular lighting
float specularLight = 0.50f;
vec3 viewDirection = normalize(camPos - crntPos);
vec3 reflectionDirection = reflect(-lightDirection, normal);
float specAmount = pow(max(dot(viewDirection, reflectionDirection), 0.0f), 8);
float specular = specAmount * specularLight;
// outputs final color
FragColor = texture(tex0, texCoord) * lightColor * (diffuse + ambient + specular);
}
I have other objects in the scene, and they render and update well. There are no errors in the code and everything runs fine, the objects in static_models are just not being rendered. Anyone have any ideas as to why it wouldn't be showing anything?
I fixed this after a very long time spent. The issue was this block of code:
// static model vectors for position and matrix
std::vector<glm::vec3> staticModelPositions;
std::vector<glm::mat4> staticModels;
// initialize all static_model object positions
for (int i = 0; i < static_models.size(); i++)
{
staticModelPositions.emplace_back();
staticModelPositions.back() = glm::vec3(0.0f, 1.0f, 0.0f);
staticModels.emplace_back();
staticModels.back() = glm::translate(staticModels.back(), staticModelPositions.back());
}
There is a line missing here. After doing staticModels.emplace_back(); we must create the identity matrix for the model. This code allows the program to function as intended:
// static model vectors for position and matrix
std::vector<glm::vec3> staticModelPositions;
std::vector<glm::mat4> staticModels;
// initialize all static_model object positions
for (int i = 0; i < static_models.size(); i++)
{
staticModelPositions.emplace_back();
staticModelPositions.back() = glm::vec3(0.0f, 1.0f, 0.0f);
staticModels.emplace_back();
staticModels.at(i) = glm::mat4(1.0f);
staticModels.back() = glm::translate(staticModels.back(), staticModelPositions.back());
}
I'm trying to make a quad rotate around its center. I am using glm::rotate() and setting the quad to rotate on the z axis. However when I do this it gives this weird effect. The quad stretches and warps. It almost looks 3d but since I am rotating it around the z axis that shouldn't happen right?
Here's relevant code for context:
float rotation = 0.0f;
double prevTime = glfwGetTime();
while (!glfwWindowShouldClose(window))
{
GLCall(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
GLCall(glClear(GL_COLOR_BUFFER_BIT));
updateInput(window);
shader.Use();
glUniform1f(xMov, x);
glUniform1f(yMov, y);
test.Bind();
double crntTime = glfwGetTime();
if (crntTime - prevTime >= 1 / 60)
{
rotation += 0.5f;
prevTime = crntTime;
}
glm::mat4 model = glm::mat4(1.0f);
model = glm::rotate(model, glm::radians(rotation), glm::vec3(0.0f, 0.0f, 1.0f));
int modelLoc = glGetUniformLocation(shader.id, "model");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
vao.Bind();
vBuffer1.Bind();
iBuffer1.Bind();
GLCall(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
glfwSwapBuffers(window);
glfwPollEvents();
}
Shader:
#version 440 core
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
layout(location = 2) in vec2 aTex;
out vec3 color;
out vec2 texCoord;
uniform float xMove;
uniform float yMove;
uniform mat4 model;
void main()
{
gl_Position = model * vec4(aPos.x + xMove, aPos.y + yMove, aPos.z, 1.0);
color = aColor;
texCoord = aTex;
}
Without you showing the graphical output it is hard to say.
Your first issue is, you are not rotating around the center, to rotate by the center you must, offset the quad so that its center is at 0,0. then rotate, then offset back to the original position, but you have this line:
gl_Position = model * vec4(aPos.x + xMove, aPos.y + yMove, aPos.z, 1.0);
Under the assumption that the quad as at the origin to begin with you are rotating it around the point (-xMove, -yMove).
I have been playing around with OpenGL and shaders and got myself into shadow mapping.
Trying to follow tutorials on the Internet (ogldev and learnopengl), got some unexpected results.
The issue is best described with few screenshots (I have added a static quad with depth framebuffer for debugging):
Somehow I managed to get shadows to be rendered on a ground quad once, with a static light (this commit). But the shadow pattern is, again, incorrect. I strongly suspect model transformation matrix calculaitons on this:
The way I render the scene is quite straightforward:
create the pipelines:
for mapping the shadows (filling the depth frame buffer)
for rendering the scene using the depth frame buffer
(extra) debugging one, rendering depth frame buffer to a static quad on a screen
fill the depth frame buffer: using the shadow mapping pipeline, render the scene from the light point, using orthographic projection
render the shaded scene: using the rendering pipeline and depth frame buffer bind as the first texture, render the scene from a camera point, using perspective projection
Seems like the algorithm in all those tutorials on shadow mapping out there. Yet, instead of a mouray effect (like in all of the tutorials), I get no shadow on the bottom plane whatsoever and weird artifacts (incorrect shadow mapping) on the 3D (chicken) model.
Interestingly enough, if I do not render (for both the shadow mapping and final rendering pass) the chicken model, the plane is lit with the same weird pattern:
I also had to remove any normal transformations from the fragment shader and disable face culling to make the ground plane lit. With front-face culling the plane does not appear in the shadow map (depth buffer).
I assume the following might be causing this issue:
wrong depth frame buffer setup (data format or texture parameters)
flipped depth frame buffer texture
wrong shadow calculations in rendering shaders
wrong light matrices (view & projection) setup
wrong matrix calculations in the rendering shaders (given the model transformation matrices for both chicken model and the quad contain both rotation and scaling)
Unfortunately, I ran out of ideas even on how to assess the above assumptions.
Looking for any help on the matter (also feel free to criticize any of my approaches, including C++, CMake, OpenGL and computer graphics).
The full solution source code is available on GitHub, but for convenience I have placed the heavily cut source code below.
shadow-mapping.vert:
#version 410
layout (location = 0) in vec3 vertexPosition;
out gl_PerVertex
{
vec4 gl_Position;
};
uniform mat4 lightSpaceMatrix;
uniform mat4 modelTransformation;
void main()
{
gl_Position = lightSpaceMatrix * modelTransformation * vec4(vertexPosition, 1.0);
}
shadow-mapping.frag:
#version 410
layout (location = 0) out float fragmentDepth;
void main()
{
fragmentDepth = gl_FragCoord.z;
}
shadow-rendering.vert:
#version 410
layout (location = 0) in vec3 vertexPosition;
layout (location = 1) in vec3 vertexNormal;
layout (location = 2) in vec2 vertexTextureCoord;
out VS_OUT
{
vec3 fragmentPosition;
vec3 normal;
vec2 textureCoord;
vec4 fragmentPositionInLightSpace;
} vsOut;
out gl_PerVertex {
vec4 gl_Position;
};
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
uniform mat4 lightSpaceMatrix;
void main()
{
vsOut.fragmentPosition = vec3(model * vec4(vertexPosition, 1.0));
vsOut.normal = transpose(inverse(mat3(model))) * vertexNormal;
vsOut.textureCoord = vertexTextureCoord;
vsOut.fragmentPositionInLightSpace = lightSpaceMatrix * model * vec4(vertexPosition, 1.0);
gl_Position = projection * view * model * vec4(vertexPosition, 1.0);
}
shadow-rendering.frag:
#version 410
layout (location = 0) out vec4 fragmentColor;
in VS_OUT {
vec3 fragmentPosition;
vec3 normal;
vec2 textureCoord;
vec4 fragmentPositionInLightSpace;
} fsIn;
uniform sampler2D shadowMap;
uniform sampler2D diffuseTexture;
uniform vec3 lightPosition;
uniform vec3 lightColor;
uniform vec3 cameraPosition;
float shadowCalculation()
{
vec2 shadowMapCoord = fsIn.fragmentPositionInLightSpace.xy * 0.5 + 0.5;
float occluderDepth = texture(shadowMap, shadowMapCoord).r;
float thisDepth = fsIn.fragmentPositionInLightSpace.z * 0.5 + 0.5;
return occluderDepth < thisDepth ? 1.0 : 0.0;
}
void main()
{
vec3 color = texture(diffuseTexture, fsIn.textureCoord).rgb;
vec3 normal = normalize(fsIn.normal);
// ambient
vec3 ambient = 0.3 * color;
// diffuse
vec3 lightDirection = normalize(lightPosition - fsIn.fragmentPosition);
float diff = max(dot(lightDirection, normal), 0.0);
vec3 diffuse = diff * lightColor;
// specular
vec3 viewDirection = normalize(cameraPosition - fsIn.fragmentPosition);
vec3 halfwayDirection = normalize(lightDirection + viewDirection);
float spec = pow(max(dot(normal, halfwayDirection), 0.0), 64.0);
vec3 specular = spec * lightColor;
// calculate shadow
float shadow = shadowCalculation();
vec3 lighting = ((shadow * (diffuse + specular)) + ambient) * color;
fragmentColor = vec4(lighting, 1.0);
}
main.cpp, setting up shaders and frame buffer:
// loading the shadow mapping shaders
auto shadowMappingVertexProgram = ...;
auto shadowMappingFragmentProgram = ...;
auto shadowMappingLightSpaceUniform = shadowMappingVertexProgram->getUniform<glm::mat4>("lightSpaceMatrix");
auto shadowMappingModelTransformationUniform = shadowMappingVertexProgram->getUniform<glm::mat4>("modelTransformation");
auto shadowMappingPipeline = std::make_unique<globjects::ProgramPipeline>();
shadowMappingPipeline->useStages(shadowMappingVertexProgram.get(), gl::GL_VERTEX_SHADER_BIT);
shadowMappingPipeline->useStages(shadowMappingFragmentProgram.get(), gl::GL_FRAGMENT_SHADER_BIT);
// (omitted) loading the depth frame buffer debugging shaders and creating a pipeline here
// loading the rendering shaders
auto shadowRenderingVertexProgram = ...;
auto shadowRenderingFragmentProgram = ...;
auto shadowRenderingModelTransformationUniform = shadowRenderingVertexProgram->getUniform<glm::mat4>("model");
auto shadowRenderingViewTransformationUniform = shadowRenderingVertexProgram->getUniform<glm::mat4>("view");
auto shadowRenderingProjectionTransformationUniform = shadowRenderingVertexProgram->getUniform<glm::mat4>("projection");
auto shadowRenderingLightSpaceMatrixUniform = shadowRenderingVertexProgram->getUniform<glm::mat4>("lightSpaceMatrix");
auto shadowRenderingLightPositionUniform = shadowRenderingFragmentProgram->getUniform<glm::vec3>("lightPosition");
auto shadowRenderingLightColorUniform = shadowRenderingFragmentProgram->getUniform<glm::vec3>("lightColor");
auto shadowRenderingCameraPositionUniform = shadowRenderingFragmentProgram->getUniform<glm::vec3>("cameraPosition");
auto shadowRenderingPipeline = std::make_unique<globjects::ProgramPipeline>();
shadowRenderingPipeline->useStages(shadowRenderingVertexProgram.get(), gl::GL_VERTEX_SHADER_BIT);
shadowRenderingPipeline->useStages(shadowRenderingFragmentProgram.get(), gl::GL_FRAGMENT_SHADER_BIT);
// loading the chicken model
auto chickenModel = Model::fromAiNode(chickenScene, chickenScene->mRootNode, { "media" });
// INFO: this transformation is hard-coded specifically for Chicken.3ds model
chickenModel->setTransformation(glm::rotate(glm::scale(glm::mat4(1.0f), glm::vec3(0.01f)), glm::radians(-90.0f), glm::vec3(1.0f, 0, 0)));
// loading the quad model
auto quadModel = Model::fromAiNode(quadScene, quadScene->mRootNode);
// INFO: this transformation is hard-coded specifically for quad.obj model
quadModel->setTransformation(glm::rotate(glm::scale(glm::translate(glm::mat4(1.0f), glm::vec3(-5, 0, 5)), glm::vec3(10.0f, 0, 10.0f)), glm::radians(-90.0f), glm::vec3(1.0f, 0, 0)));
// loading the floor texture
sf::Image textureImage = ...;
auto defaultTexture = std::make_unique<globjects::Texture>(static_cast<gl::GLenum>(GL_TEXTURE_2D));
defaultTexture->setParameter(static_cast<gl::GLenum>(GL_TEXTURE_MIN_FILTER), static_cast<GLint>(GL_LINEAR));
defaultTexture->setParameter(static_cast<gl::GLenum>(GL_TEXTURE_MAG_FILTER), static_cast<GLint>(GL_LINEAR));
defaultTexture->image2D(0, static_cast<gl::GLenum>(GL_RGBA8), glm::vec2(textureImage.getSize().x, textureImage.getSize().y), 0, static_cast<gl::GLenum>(GL_RGBA), static_cast<gl::GLenum>(GL_UNSIGNED_BYTE), reinterpret_cast<const gl::GLvoid*>(textureImage.getPixelsPtr()));
// initializing the depth frame buffer
auto shadowMapTexture = std::make_unique<globjects::Texture>(static_cast<gl::GLenum>(GL_TEXTURE_2D));
shadowMapTexture->setParameter(static_cast<gl::GLenum>(GL_TEXTURE_MIN_FILTER), static_cast<gl::GLenum>(GL_LINEAR));
shadowMapTexture->setParameter(static_cast<gl::GLenum>(GL_TEXTURE_MAG_FILTER), static_cast<gl::GLenum>(GL_LINEAR));
shadowMapTexture->setParameter(static_cast<gl::GLenum>(GL_TEXTURE_WRAP_S), static_cast<gl::GLenum>(GL_CLAMP_TO_BORDER));
shadowMapTexture->setParameter(static_cast<gl::GLenum>(GL_TEXTURE_WRAP_T), static_cast<gl::GLenum>(GL_CLAMP_TO_BORDER));
shadowMapTexture->setParameter(static_cast<gl::GLenum>(GL_TEXTURE_BORDER_COLOR), glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
shadowMapTexture->image2D(0, static_cast<gl::GLenum>(GL_DEPTH_COMPONENT), glm::vec2(window.getSize().x, window.getSize().y), 0, static_cast<gl::GLenum>(GL_DEPTH_COMPONENT), static_cast<gl::GLenum>(GL_FLOAT), nullptr);
auto framebuffer = std::make_unique<globjects::Framebuffer>();
framebuffer->attachTexture(static_cast<gl::GLenum>(GL_DEPTH_ATTACHMENT), shadowMapTexture.get());
main.cpp, rendering (main loop):
// (omitted) event handling, camera updates go here
glm::mat4 cameraProjection = glm::perspective(glm::radians(fov), (float) window.getSize().x / (float) window.getSize().y, 0.1f, 100.0f);
glm::mat4 cameraView = glm::lookAt(cameraPos, cameraPos + cameraForward, cameraUp);
// moving light together with the camera, for debugging purposes
glm::vec3 lightPosition = cameraPos;
// light settings
const float nearPlane = 1.0f;
const float farPlane = 10.0f;
glm::mat4 lightProjection = glm::ortho(-5.0f, 5.0f, -5.0f, 5.0f, nearPlane, farPlane);
glm::mat4 lightView = glm::lookAt(lightPosition, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 lightSpaceMatrix = lightProjection * lightView;
::glViewport(0, 0, static_cast<GLsizei>(window.getSize().x), static_cast<GLsizei>(window.getSize().y));
// first render pass - shadow mapping
framebuffer->bind();
::glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
::glClear(GL_DEPTH_BUFFER_BIT);
framebuffer->clearBuffer(static_cast<gl::GLenum>(GL_DEPTH), 0, glm::vec4(1.0f));
glEnable(GL_DEPTH_TEST);
// cull front faces to prevent peter panning the generated shadow map
glCullFace(GL_FRONT);
shadowMappingPipeline->use();
shadowMappingLightSpaceUniform->set(lightSpaceMatrix);
shadowMappingModelTransformationUniform->set(chickenModel->getTransformation());
chickenModel->draw();
shadowMappingModelTransformationUniform->set(quadModel->getTransformation());
quadModel->draw();
framebuffer->unbind();
shadowMappingPipeline->release();
glCullFace(GL_BACK);
// second pass - switch to normal shader and render picture with depth information to the viewport
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
shadowRenderingPipeline->use();
shadowRenderingLightPositionUniform->set(lightPosition);
shadowRenderingLightColorUniform->set(glm::vec3(1.0, 1.0, 1.0));
shadowRenderingCameraPositionUniform->set(cameraPos);
shadowRenderingProjectionTransformationUniform->set(cameraProjection);
shadowRenderingViewTransformationUniform->set(cameraView);
shadowRenderingLightSpaceMatrixUniform->set(lightSpaceMatrix);
// draw chicken
shadowMapTexture->bind();
shadowRenderingModelTransformationUniform->set(chickenModel->getTransformation());
chickenModel->draw();
shadowRenderingModelTransformationUniform->set(quadModel->getTransformation());
defaultTexture->bind();
quadModel->draw();
defaultTexture->unbind();
shadowMapTexture->unbind();
shadowRenderingPipeline->release();
// (omitted) render the debugging quad with depth (shadow) map
window.display();
As shameful as it might be, the issue was with the wrong texture being bound.
The globjects library that I use to have few nice(-r) abstractions over OpenGL actually does not provide a smart logic around texture binding (as I blindly assumed). So using just Texture::bind() and Texture::unbind() won't automagically keep track of how many textures have been bound and increment an index.
E.g. it does not behave (roughly) like this:
static int boundTextureIndex = -1;
void Texture::bind() {
glBindTexture(this->textureType, this->textureId);
glActivateTexture(GL_TEXTURE0 + (++boundTextureIndex));
}
void Texture::unbind() {
--boundTextureIndex;
}
So after changing the texture->bind() to texture->bindActive(0) followed by shaderProgram->setUniform("texture", 0), I finally got to the mouray effect and correct shadow mapping:
Full change is in this commit.
I need to use perspective transformation but I can't understand how to define model coordinates of sprite. If I use orthogonal projection I can define coordinate of each vertex as number pixels on screen. But with perspective projection I can't.
Orthogonal projection:
glm::ortho<GLfloat>(0.0f, screen_width, screen_height, 0.0f, 1.0f, -1.0f));
Perspective:
glm::perspective(glm::radians(45.f), (float)screen_width / (float)screen_height, 0.1f, 100.f);
Vertex shader:
#version 330 core
layout (std140) uniform Matrices
{
mat4 ProjectionMatrix;
mat4 ViewMatrix;
mat4 ModelMatrix;
};
layout (location = 0) in vec2 position;
layout (location = 1) in vec2 inTexCoords;
out vec2 TextureCoords;
void main()
{
TextureCoords = inTexCoords;
gl_Position = ProjectionMatrix * ViewMatrix * ModelMatrix * vec4(position, 1.f, 1.0);
}
For example
vertices[1] = 0.f;
vertices[8] = 0.f;
vertices[12] = 0.f;
vertices[13] = 0.f;
for (GLuint i = 0; i < m_totSprites; ++i) {
// Vertex pos
vertices[0] = m_clips[i].w;
vertices[4] = vertices[0];
vertices[5] = m_clips[i].h;
vertices[9] = vertices[5];
// Texture pos
vertices[2] = (m_clips[i].x + m_clips[i].w) / tw;
vertices[3] = (m_clips[i].y + m_clips[i].h) / th;
vertices[6] = (m_clips[i].x + m_clips[i].w) / tw;
vertices[7] = m_clips[i].y / th;
vertices[10] = m_clips[i].x / tw;
vertices[11] = m_clips[i].y / th;
vertices[14] = m_clips[i].x / tw;
vertices[15] = (m_clips[i].y + m_clips[i].h) / th;
It works well with orthogonal projection. How can I define vertex coordinates for perspective?
What the different with model coordinates in orthogonal projection and perspective? Why in first case it's easy to set coords of vertices as pixel sizes, but in all examples with perspective they normalized between -0.5 to 0.5? It's necessary?
Initially I was misunderstood difference between orthogonal and perspective projections. As I understood now all vertices mapped initially in NDC for perspective projection. Then they moved, scaled, etc with model matrix. Pixel perfect rendering can be realized only with some constant depth or with orthogonal. I't unuseful for 3D with perspective projection.
if you have projection matrix you need a view matrix too.
there's glm::lookAt() for ex
i use this combo usually
glm::lookAt(glm::vec3(-1.2484,0.483,1.84384), glm::vec3(-0.3801, -0.4183,-3.15),glm::vec3( 0., 0.2,-00.))
glm::perspective(45., 1., 1.2, 300.)
glm::mat4(1.)
I've been following a tutorial on modern OpenGL with the GLM library
I'm on a segment where we introduce matrices for transforming models, positioning the camera, and adding perspective.
I've got a triangle:
const GLfloat vertexBufferData[] = {
-1.0f, -1.0f, 0.0f,
1.0f, -1.0f, 0.0f,
0.0f, 1.0f, 0.0f,
};
I've got my shaders:
GLuint programID = loadShaders("testVertexShader.glsl",
"testFragmentShader.glsl");
I've got a model matrix that does no transformations:
glm::mat4 modelMatrix = glm::mat4(1.0f); /* Identity matrix */
I've got a camera matrix:
glm::mat4 cameraMatrix = glm::lookAt(
glm::vec3(4.0f, 4.0f, 3.0f), /*Camera position*/
glm::vec3(0.0f, 0.0f, 0.0f), /*Camera target*/
glm::vec3(0.0f, 1.0f, 0.0f) /*Up vector*/
);
And I've got a projection matrix:
glm::mat4 projectionMatrix = glm::perspective(
90.0f, /*FOV in degrees*/
4.0f / 3.0f, /*Aspect ratio*/
0.1f, /*Near clipping distance*/
100.0f /*Far clipping distance*/
);
Then I multiply all the matrices together to get the final matrix for the triangle I want to draw:
glm::mat4 finalMatrix = projectionMatrix
* cameraMatrix
* modelMatrix;
Then I send the matrix to GLSL (I think?):
GLuint matrixID = glGetUniformLocation(programID, "MVP");
glUniformMatrix4fv(matrixID, 1, GL_FALSE, &finalMatrix[0][0]);
Then I do shader stuff I don't understand very well:
/*vertex shader*/
#version 330 core
in vec3 vertexPosition_modelspace;
uniform mat4 MVP;
void main(){
vec4 v = vec4(vertexPosition_modelspace, 1);
gl_Position = MVP * v;
}
/*fragment shader*/
#version 330 core
out vec3 color;
void main(){
color = vec3(1, 1, 0);
}
Everything compiles and runs, but I see no triangle. I've moved the triangle and camera around, thinking maybe the camera was pointed the wrong way, but with no success. I was able to successfully get a triangle on the screen before we introduced matrices, but now, no triangle. The triangle should be at origin, and the camera is a few units away from origin, looking at origin.
Turns out, you need to send the matrix to the shader after you've bound the shader.
In other words, you call glUniformMatrix4fv() after glUseProgram()
Lots of things could be your problem - try outputting a vec4 color instead, with alpha explicitly set to 1. One thing I often do as a sanity check is to have the vertex shader ignore all inputs, and to just output vertices directly, e.g. something like:
void main(){
if (gl_VertexID == 0) {
gl_Position = vec4(-1, -1, 0, 1);
} else if (gl_VertexID == 1) {
gl_Position = vec4(1, -1, 0, 1);
} else if (gl_VertexID == 2) {
gl_Position = vec4(0, 1, 0, 1);
}
}
If that works, then you can try adding your vertex position input back in. If that works, you can add your camera or projection matrices back in, etc.
More generally, remove things until something works, and you understand why it works, and then add parts back in until you stop understanding why things don't work. Quite often I've been off by a sign, or in the order of multiplication.