Move circle with Projection matrix - c++

I need some help trying to move my circle with view matrix. I can position the circle but cant move it. How can i make this happen?
Right now the the bounding rectangle moves but not the circle.
I've tried to center the circle in the rectangle and but this doesnt work.
Any help is appreciated!
#include <glew.h>
#include "circle.h"
Circle::Circle()
{
const std::string vertexShaderSource = R"END(
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>
uniform mat4 model;
uniform mat4 projection;
uniform mat4 view;
void main()
{
gl_Position = projection * view * model * vec4(vertex.xy, 0.0, 1.0);
}
)END";
const std::string fragmentShaderSource = R"END(
#version 330 core
out vec4 color;
uniform vec2 dim;
uniform vec2 pos;
/**
* Convert r, g, b to normalized vec3
*/
vec3 rgb(float r, float g, float b) {
return vec3(r / 255.0, g / 255.0, b / 255.0);
}
/**
* Draw a circle at vec2 `pos` with radius `rad` and
* color `color`.
*/
vec4 circle(vec2 uv, vec2 pos, float rad, vec3 color) {
float d = length(pos - uv) - rad;
float t = clamp(d, 0.0, 1.0);
return vec4(color, 1.0 - t);
}
void main() {
vec2 uv = gl_FragCoord.xy;
float radius = 60;
vec2 center = pos;
// Background layer
vec4 layer1 = vec4(rgb(210.0, 222.0, 228.0), 0.3);
// Circle
vec3 red = rgb(225.0, 95.0, 60.0);
vec4 layer2 = circle(uv, center, radius, red);
// Blend the two
color = mix(layer1, layer2, layer2.a);
}
)END";
shader.Compile(vertexShaderSource.c_str(), fragmentShaderSource.c_str());
// Configure VAO etc..
}
void Circle::Update(float deltaTime, int width, int height)
{
// Activate shader
shader.Activate();
auto camera = Services::Get<RenderService>()->camera;
glm::mat4 model = glm::mat4(1.0f);
glm::mat4 view;
if (skipPan == false)
{
view = camera.GetViewMatrix();
}
else
{
view = glm::mat4{1.0f};
}
projection = glm::ortho(0.0f, static_cast<float>(width),
static_cast<float>(height), 0.0f, -1.0f, 1.0f);
model = glm::translate(model, glm::vec3(transform.position.x, transform.position.y, 0.0f));
model = glm::scale(model, glm::vec3(transform.dimension.width, transform.dimension.height, 1.0f));
shader.setMat4("projection", projection);
shader.setMat4("model", model);
shader.setMat4("view", view);
shader.setVec2("dim", glm::vec2{transform.dimension.width, transform.dimension.height});
shader.setVec2("pos", glm::vec2{transform.position.x, transform.position.y});
shader.setVec4("spriteColor", glm::vec4{style.Background.r, style.Background.g, style.Background.b, style.Background.a});
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
This is an issue i've been struggeling with for some time now. This applies to other shapes aswell that renders with SDF and such.
// configure VAO/VBO
const float vertices[] = {
0.0f, 1.0f, 0.0f,
1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f};
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void *)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);

You say that you're trying to move the circle with the view matrix. You indeed pass that matrix to your vertex shader and use it in the computation of gl_Position. However, your fragment shader calculation is based on gl_FragCoord and doesn't incorporate the view matrix in any way. Remember that gl_FragCoord is the fragment coordinates relative to the framebuffer bottom-left corner (usually), and is therefore not affected by the model/view/projection transformations.
To solve this, you can do any of the following:
Calculate the fragment coordinates of the center of your circle in Circle::Update and pass that to the pos uniform:
glm::vec4 pos = view*glm::vec4{transform.position.x, transform.position.y, 0.0f, 1.0f};
shader.setVec2("pos", pos.xy);
Apply the viewport transformation in the fragment shader -- same as above but done in the shader. This is kinda ugly as you would be applying view but not model because the later is already accounted for in the value of pos. Also it involves more calculations in the fragment shader.
Change your fragment shader to work off texture coordinates instead of gl_FragCoord. If you set fixed texture coordinates at the vertices of the quad, then the interpolated coordinates within the quad will transform correctly with regards to any of the view/model/projection, thus handling scaling or even perspective projections out-of-the-box. This would probably be the neatest solution in your case. (That being said, rasterization based on gl_FragCoord is sometimes necessary to avoid artifacts on the seam between the two triangles of the quad.)

Related

Draw a 2D Quad in OpenGL

Whenever I think I understand something about openGL I find I don't understand anything.
I don't understand what I'm doing wrong.
The quad is not rendered.
Here is how I init the data
std::vector<glm::vec3> vertices;
vertices.resize(6);
// first triangle
vertices[0] = glm::vec3(x+w, y, 0.0f); // top right
vertices[1] = glm::vec3(x+w, y+h, 0.0f); // bottom right
vertices[2] = glm::vec3(x, y, 0.0f); // top left
// second triangle
vertices[3] = glm::vec3(x+w, y+h, 0.0f); // bottom right
vertices[4] = glm::vec3(x, y+h, 0.0f); // bottom left
vertices[5] = glm::vec3(x, y, 0.0f); // top left
Where (x, y) is coord of the top left corner in pixel screen position and (w, h) is the length of the sides of the quad
This is how I set in the GPU the data
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
This is how I render it
glBindVertexArray(vao);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
And these are my vertex and fragment shader
#version 330 core
layout (location = 0) in vec3 position;
void main() {
gl_Position = vec4(position, 1.0);
}
#version 330 core
out vec4 outColor;
void main() {
outColor = vec4(1.0);
}
UPDATE
How Rabbit76 point out: I do not see the rectangle, because it is outside the view. If you don't use a projection matrix, the vertex coordinates must be in range [-1.0, 1.0]. If you want to use "window" coordinates you must use an orthographic projection"
So I changed the vertex shader in the following way and everything works!
#version 330 core
layout (location = 0) in vec3 position;
uniform vec2 viewport; //Width and Height of the viewport
void main() {
// From pixels to 0-1
vec2 coord = position.xy / viewport;
// Flip Y so that 0 is top
coord.y = (1.0-coord.y);
// Map to NDC -1,+1
coord.xy = coord.xy * 2.0 - 1.0;
gl_Position = vec4(coord.xy, 0.0, 1.0);
}
You don't see the rectangle because it's out of view. If you are not using a projection matrix, the vertex coordinates must be in the range [-1.0, 1.0]. If you want to use "window" coordinates you must use an Orthographic projection.
You need to transform the vertex coordinates through the projection matrix. This is usually done in the vertex shader. However, it is also possible to transform the vertex coordinates on the CPU. Use glm::ortho to define the orthographic projection matrix and transform the vertices:
glm::mat4 projection = glm::ortho(0.0f, window_width, window_height, 0.0f, -1.0f, 1.0f);
for (auto &vertex : vertices)
vertex = glm::vec3(projection * glm::vec4(vertex, 1.0f));

Additional sprite UVs when rendering sprites in OpenGL

I have sprites in an atlas rendering in OpenGL properly with the code below. My problem comes from trying to add a secondary "texture" to sample so I can do some multitexturing magic. The problem I think it's that the second sprite is also in an atlas and it's being affected by the VAO offsets so I can't really pick the right UVs to get the exact point I need. I've tried adding some calculations to reverse engineer the correct UVs for this sprite inside the other texture (you can see my attempt at the bottom) but this doesn't seem to work. What would be the best approach to do this?
Preparation:
glm::vec4 fRect;
fRect.x = static_cast<float>(iRect.x) / textureWidth;
fRect.y = static_cast<float>(iRect.y) / textureHeight;
fRect.z = (static_cast<float>(iRect.z) / textureWidth) + fRect.x;
fRect.w = (static_cast<float>(iRect.w) / textureHeight) + fRect.y;
// Configure VAO/VBO
GLuint VBO;
GLfloat vertices[] = {
// Pos // Tex
0.0f, 1.0f, fRect.x, fRect.w,
1.0f, 0.0f, fRect.z, fRect.y,
0.0f, 0.0f, fRect.x, fRect.y,
0.0f, 1.0f, fRect.x, fRect.w,
1.0f, 1.0f, fRect.z, fRect.w,
1.0f, 0.0f, fRect.z, fRect.y
};
GLuint VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(VAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
Rendering:
// Prepare transformations
glm::mat4 modelMatrix;
modelMatrix = glm::translate(modelMatrix, position);
// modelMatrix = glm::translate(modelMatrix, -glm::vec3(spriteOffset.x, spriteOffset.y, 0.0f));
modelMatrix = glm::rotate(modelMatrix, rotate.x, glm::vec3(1.0f, 0.0f, 0.0f));
// modelMatrix = glm::rotate(modelMatrix, rotate.y, glm::vec3(0.0f, 1.0f, 0.0f));
modelMatrix = glm::rotate(modelMatrix, rotate.z, glm::vec3(0.0f, 0.0f, 1.0f));
modelMatrix = glm::translate(modelMatrix, glm::vec3(-spriteOffset.x, -spriteOffset.y, 0.0f));
modelMatrix = glm::scale(modelMatrix, glm::vec3(size, 1.0f));
//(...)
glUniformMatrix4fv(modelMatrixLocation, 1, false, glm::value_ptr( modelMatrix ) );
glUniformMatrix4fv(viewMatrixLocation, 1, false, glm::value_ptr(viewMatrix));
glUniformMatrix4fv(projectionMatrixLocation, 1, false, glm::value_ptr(projectionMatrix));
ASSERT( !HasOpenGLErrors(), "OpenGL error!" );
glUniform3f(multColorLocation, multColour.x, multColour.y, multColour.z );
glUniform3f(addColorLocation, addColour.x, addColour.y, addColour.z );
ASSERT( !HasOpenGLErrors(), "OpenGL error!" );
// Bind Texture, etc
glDrawArrays(GL_TRIANGLES, 0, 6);
Vertex shader:
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>
out vec2 TexCoords;
uniform mat4 model_matrix, view_matrix, projection_matrix;
void main()
{
TexCoords = vec2(vertex.z, 1.0 - vertex.w);
gl_Position = projection_matrix*view_matrix*model_matrix*vec4(vertex.xyz,1);
}
Fragment shader:
#version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D texture;
uniform vec3 multColour;
uniform vec3 addColour;
void main()
{
vec4 minColour = vec4(0.0, 0.0, 0.0, 0.0);
vec4 maxColour = vec4(1.0, 1.0, 1.0, 1.0);
vec4 texColour = texture(texture, TexCoords);
if(texColour.a < 0.01)
discard;
color = clamp(vec4(multColour, 1.0) * texColour + vec4(addColour,0.0), minColour, maxColour);
}
Failed attempt at reading the right UVs in fragment shader:
float normU = (TexCoords.x - currUVs.x) / (currUVs.z - currUVs.x);
float icU = mix(icUVs.x, icUVs.z, normU);
float normV = (TexCoords.y - currUVs.y) / (currUVs.w - currUVs.y);
float icV = mix(icUVs.y, icUVs.w, normV);
vec2 UV = vec2(icU, icV );
vec4 initial = texture(initialColor, UV);
Where currUVs are the values of fRect passed in the VAO above and the icUVs are the UV bounds (min and max values) for the second sprite within the atlas texture.
So far it seems like all sprites that have no offset applied will render properly but if I passed in any kind of spriteOffset into the rendering, then it will render wrong.
How can I solve this? Is there a way of applying the VAO rects in the shaders and then be able to get the second sprite correctly?

OPENGL How do I correctly render these 2 objects with different textures/mapping?

I am trying to incorporate both normal mapping & cube mapping into a single program, but I am having trouble getting them to render correctly. I am working on a simple exercise to help me with that before going onto something more complexed. I am trying to render both these objects into a single program. They both have different textures and the torus uses cube mapping while the wall uses normal mapping.
These are what they are supposed to look like individually:
Currently, this is what I've got. The torus renders correctly but the wall's textures don't appear.
I am using 2 separate shader programs for this, and it is my first time using more than 1 shader program, for a program. I suspect my issue could be with the initialising of shader variables, or something really obvious that I'm just not getting. I am using two different Vertex structs for the objects.
struct Vertex2
{
GLfloat position[3];
GLfloat normal[3];
GLfloat tangent[3];
GLfloat texCoord[2];
};
Vertex2 g_vertices[] = {
// Front: triangle 1
// vertex 1
-1.0f, 1.0f, 0.0f, // position
0.0f, 0.0f, 1.0f, // normal
1.0f, 0.0f, 0.0f, // tangent
0.0f, 1.0f, // texture coordinate
// vertex 2
-1.0f, -1.0f, 0.0f, // position
0.0f, 0.0f, 1.0f, // normal
1.0f, 0.0f, 0.0f, // tangent
0.0f, 0.0f, // texture coordinate
// vertex 3
1.0f, 1.0f, 0.0f, // position
0.0f, 0.0f, 1.0f, // normal
1.0f, 0.0f, 0.0f, // tangent
1.0f, 1.0f, // texture coordinate
// triangle 2
// vertex 1
1.0f, 1.0f, 0.0f, // position
0.0f, 0.0f, 1.0f, // normal
1.0f, 0.0f, 0.0f, // tangent
1.0f, 1.0f, // texture coordinate
// vertex 2
-1.0f, -1.0f, 0.0f, // position
0.0f, 0.0f, 1.0f, // normal
1.0f, 0.0f, 0.0f, // tangent
0.0f, 0.0f, // texture coordinate
// vertex 3
1.0f, -1.0f, 0.0f, // position
0.0f, 0.0f, 1.0f, // normal
1.0f, 0.0f, 0.0f, // tangent
1.0f, 0.0f, // texture coordinate
};
Main.cpp init function:
static void init(GLFWwindow* window)
{
glEnable(GL_DEPTH_TEST); // enable depth buffer test
glEnable(GL_TEXTURE_2D);
// read the image data
GLint imageWidth[5]; //image width info
GLint imageHeight[5]; //image height info
g_texImage[FRONT] = readBitmapRGBImage("images/cm_front.bmp", &imageWidth[0], &imageHeight[0]);
g_texImage[BACK] = readBitmapRGBImage("images/cm_back.bmp", &imageWidth[0], &imageHeight[0]);
g_texImage[LEFT] = readBitmapRGBImage("images/cm_left.bmp", &imageWidth[0], &imageHeight[0]);
g_texImage[RIGHT] = readBitmapRGBImage("images/cm_right.bmp", &imageWidth[0], &imageHeight[0]);
g_texImage[TOP] = readBitmapRGBImage("images/cm_top.bmp", &imageWidth[0], &imageHeight[0]);
g_texImage[BOTTOM] = readBitmapRGBImage("images/cm_bottom.bmp", &imageWidth[0], &imageHeight[0]);
g_texImage[6] = readBitmapRGBImage("images/Fieldstone.bmp", &imageWidth[1], &imageHeight[1]);
g_texImage[7] = readBitmapRGBImage("images/FieldstoneBumpDOT3.bmp", &imageWidth[2], &imageHeight[2]);
glGenTextures(10, g_textureID);
// ...
// create and compile our GLSL program from the shader files
g_shaderProgramID[0] = loadShaders("CubeEnvMapVS.vert", "CubeEnvMapFS.frag");
g_shaderProgramID[1] = loadShaders("NormalMappingVS.vert", "NormalMappingFS.frag");
// find the location of shader variables
for (int i = 0; i < 2; i++)
{
positionIndex[i] = glGetAttribLocation(g_shaderProgramID[i], "aPosition");
normalIndex[i] = glGetAttribLocation(g_shaderProgramID[i], "aNormal");
texCoordIndex[i] = glGetAttribLocation(g_shaderProgramID[i], "aTexCoord");
g_MVP_Index[i] = glGetUniformLocation(g_shaderProgramID[i], "uModelViewProjectionMatrix");
g_M_Index[i] = glGetUniformLocation(g_shaderProgramID[i], "uModelMatrix");
g_viewPointIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uViewPoint");
g_lightPositionIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.position");
g_lightAmbientIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.ambient");
g_lightDiffuseIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.diffuse");
g_lightSpecularIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.specular");
g_lightShininessIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uLightingProperties.shininess");
g_materialAmbientIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uMaterialProperties.ambient");
g_materialDiffuseIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uMaterialProperties.diffuse");
g_materialSpecularIndex[i] = glGetUniformLocation(g_shaderProgramID[i], "uMaterialProperties.specular");
}
g_envMapSamplerIndex = glGetUniformLocation(g_shaderProgramID[0], "uEnvironmentMap");
tangentIndex = glGetAttribLocation(g_shaderProgramID[1], "aTangent");
g_texSamplerIndex = glGetUniformLocation(g_shaderProgramID[1], "uTextureSampler");
g_normalSamplerIndex = glGetUniformLocation(g_shaderProgramID[1], "uNormalSampler");
// initialise model matrix to the identity matrix
g_mm_torus = glm::mat4(1.0f);
g_mm_wall = mat4(1.0f);
// ...
// load mesh
// load_mesh("models/sphere.obj");
load_mesh("models/torus.obj");
// ...
// generate identifier for VBOs and copy data to GPU
glGenBuffers(5, g_VBO);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*g_numberOfVertices, g_pMeshVertices, GL_STATIC_DRAW);
// generate identifier for IBO and copy data to GPU
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_VBO[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLint) * 3 * g_numberOfFaces, g_pMeshIndices, GL_STATIC_DRAW);
// generate identifiers for VAO
glGenVertexArrays(5, g_VAO);
// create VAO and specify VBO data
glBindVertexArray(g_VAO[0]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_VBO[1]);
glVertexAttribPointer(positionIndex[0], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, position)));
glVertexAttribPointer(normalIndex[0], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void*>(offsetof(Vertex, normal)));
glEnableVertexAttribArray(positionIndex[0]); // enable vertex attributes
glEnableVertexAttribArray(normalIndex[0]);
// generate identifier for VBOs and copy data to GPU
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertices), g_vertices, GL_STATIC_DRAW);
// create VAO and specify VBO data
glBindVertexArray(g_VAO[1]);
glBindBuffer(GL_ARRAY_BUFFER, g_VBO[2]);
glVertexAttribPointer(positionIndex[1], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, position)));
glVertexAttribPointer(normalIndex[1], 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, normal)));
glVertexAttribPointer(tangentIndex, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, tangent)));
glVertexAttribPointer(texCoordIndex[0], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, texCoord)));
// enable vertex attributes
glEnableVertexAttribArray(positionIndex[1]);
glEnableVertexAttribArray(normalIndex[1]);
glEnableVertexAttribArray(tangentIndex);
glEnableVertexAttribArray(texCoordIndex[0]);
}
Render scene function:
static void render_scene()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // clear colour buffer and depth buffer
glUseProgram(g_shaderProgramID[0]); // use the shaders associated with the shader program
glBindVertexArray(g_VAO[0]); // make VAO active
// set uniform shader variables
glm::mat4 MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_mm_torus;
glUniformMatrix4fv(g_MVP_Index[0], 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(g_M_Index[0], 1, GL_FALSE, &g_mm_torus[0][0]);
glUniform3fv(g_viewPointIndex[0], 1, &g_camera.getPosition()[0]);
glUniform4fv(g_lightPositionIndex[0], 1, &g_lightProperties.position[0]);
glUniform4fv(g_lightAmbientIndex[0], 1, &g_lightProperties.ambient[0]);
glUniform4fv(g_lightDiffuseIndex[0], 1, &g_lightProperties.diffuse[0]);
glUniform4fv(g_lightSpecularIndex[0], 1, &g_lightProperties.specular[0]);
glUniform1fv(g_lightShininessIndex[0], 1, &g_lightProperties.shininess);
glUniform4fv(g_materialAmbientIndex[0], 1, &g_materialProperties.ambient[0]);
glUniform4fv(g_materialDiffuseIndex[0], 1, &g_materialProperties.diffuse[0]);
glUniform4fv(g_materialSpecularIndex[0], 1, &g_materialProperties.specular[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, g_textureID[0]);
glUniform1i(g_envMapSamplerIndex, 0);
glDrawElements(GL_TRIANGLES, g_numberOfFaces * 3, GL_UNSIGNED_INT, 0); // display the vertices based on their indices and primitive type
glUseProgram(g_shaderProgramID[1]); // use the shaders associated with the shader program
glBindVertexArray(g_VAO[1]); // make VAO active
// set uniform shader variables
glClear(GL_DEPTH_BUFFER_BIT);
MVP = g_camera.getProjectionMatrix() * g_camera.getViewMatrix() * g_mm_wall;
glUniformMatrix4fv(g_MVP_Index[1], 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(g_M_Index[1], 1, GL_FALSE, &g_mm_wall[0][0]);
glUniform3fv(g_viewPointIndex[1], 1, &g_camera.getPosition()[0]);
glUniform4fv(g_lightPositionIndex[1], 1, &g_lightProperties.position[0]);
glUniform4fv(g_lightAmbientIndex[1], 1, &g_lightProperties.ambient[0]);
glUniform4fv(g_lightDiffuseIndex[1], 1, &g_lightProperties.diffuse[0]);
glUniform4fv(g_lightSpecularIndex[1], 1, &g_lightProperties.specular[0]);
glUniform1fv(g_lightShininessIndex[1], 1, &g_lightProperties.shininess);
glUniform4fv(g_materialAmbientIndex[1], 1, &g_materialProperties.ambient[0]);
glUniform4fv(g_materialDiffuseIndex[1], 1, &g_materialProperties.diffuse[0]);
glUniform4fv(g_materialSpecularIndex[1], 1, &g_materialProperties.specular[0]);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, g_textureID[6]);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, g_textureID[7]);
glUniform1i(g_texSamplerIndex, 1);
glUniform1i(g_normalSamplerIndex, 2);
glDrawArrays(GL_TRIANGLES, 0, 36);
glFlush(); // flush the pipeline
}
Vertex shader for torus:
#version 330 core
// input data (different for all executions of this shader)
in vec3 aPosition;
in vec3 aNormal;
// uniform input data
uniform mat4 uModelViewProjectionMatrix;
uniform mat4 uModelMatrix;
// output data (will be interpolated for each fragment)
out vec3 vNormal;
out vec3 vPosition;
void main()
{
// set vertex position
gl_Position = uModelViewProjectionMatrix * vec4(aPosition, 1.0);
// world space
vPosition = (uModelMatrix * vec4(aPosition, 1.0)).xyz;
vNormal = (uModelMatrix * vec4(aNormal, 0.0)).xyz;
}
Fragment shader for torus:
#version 330 core
// interpolated values from the vertex shaders
in vec3 vNormal;
in vec3 vPosition;
// uniform input data
struct LightProperties
{
vec4 position;
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
struct MaterialProperties
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
uniform LightProperties uLightingProperties;
uniform MaterialProperties uMaterialProperties;
uniform vec3 uViewPoint;
uniform samplerCube uEnvironmentMap;
// output data
out vec3 fColor;
void main()
{
vec3 N = normalize(vNormal);
vec3 L;
// determine whether the light is a point light source or directional light
if(uLightingProperties.position.w == 0.0f)
L = normalize((uLightingProperties.position).xyz);
else
L = normalize((uLightingProperties.position).xyz - vPosition);
vec3 V = normalize(uViewPoint - vPosition);
vec3 R = reflect(-L, N);
// calculate the ambient, diffuse and specular components
vec4 ambient = uLightingProperties.ambient * uMaterialProperties.ambient;
vec4 diffuse = uLightingProperties.diffuse * uMaterialProperties.diffuse * max(dot(L, N), 0.0);
vec4 specular = vec4(0.0f, 0.0f, 0.0f, 1.0f);
if(dot(L, N) > 0.0f)
{
specular = uLightingProperties.specular * uMaterialProperties.specular
* pow(max(dot(V, R), 0.0), uLightingProperties.shininess);
}
vec3 reflectEnvMap = reflect(-V, N);
// set output color
fColor = texture(uEnvironmentMap, reflectEnvMap).rgb;
fColor *= (diffuse + specular + ambient).rgb;
}
Vertex shader for wall:
#version 330 core
// input data (different for all executions of this shader)
in vec3 aPosition;
in vec3 aNormal;
in vec3 aTangent;
in vec2 aTexCoord;
// uniform input data
uniform mat4 uModelViewProjectionMatrix;
uniform mat4 uModelMatrix;
// output data (will be interpolated for each fragment)
out vec3 vPosition;
out vec3 vNormal;
out vec3 vTangent;
out vec2 vTexCoord;
void main()
{
// set vertex position
gl_Position = uModelViewProjectionMatrix * vec4(aPosition, 1.0);
// world space
vPosition = (uModelMatrix * vec4(aPosition, 1.0)).xyz;
vNormal = (uModelMatrix * vec4(aNormal, 0.0)).xyz;
vTangent = (uModelMatrix * vec4(aTangent, 0.0)).xyz;
vTexCoord = aTexCoord;
}
Fragment shader for wall:
#version 330 core
// interpolated values from the vertex shaders
in vec3 vPosition;
in vec3 vNormal;
in vec3 vTangent;
in vec2 vTexCoord;
// uniform input data
struct LightProperties
{
vec4 position;
vec4 ambient;
vec4 diffuse;
vec4 specular;
float shininess;
};
struct MaterialProperties
{
vec4 ambient;
vec4 diffuse;
vec4 specular;
};
uniform LightProperties uLightingProperties;
uniform MaterialProperties uMaterialProperties;
uniform vec3 uViewPoint;
uniform sampler2D uTextureSampler;
uniform sampler2D uNormalSampler;
// output data
out vec3 fColor;
void main()
{
// calculate normal map vectors
vec3 normal = normalize(vNormal);
vec3 tangent = normalize(vTangent);
vec3 biTangent = normalize(cross(tangent, normal));
vec3 normalMap = 2.0f * texture(uNormalSampler, vTexCoord).xyz - 1.0f;
// calculate vectors for lighting
vec3 N = normalize(mat3(tangent, biTangent, normal) * normalMap);
vec3 L;
// determine whether the light is a point light source or directional light
if(uLightingProperties.position.w == 0.0f)
L = normalize((uLightingProperties.position).xyz);
else
L = normalize((uLightingProperties.position).xyz - vPosition);
vec3 V = normalize(uViewPoint - vPosition);
vec3 R = reflect(-L, N);
// calculate Phong lighting
vec4 ambient = uLightingProperties.ambient * uMaterialProperties.ambient;
vec4 diffuse = uLightingProperties.diffuse * uMaterialProperties.diffuse * max(dot(L, N), 0.0);
vec4 specular = vec4(0.0f, 0.0f, 0.0f, 1.0f);
if(dot(L, N) > 0.0f)
{
specular = uLightingProperties.specular * uMaterialProperties.specular
* pow(max(dot(V, R), 0.0), uLightingProperties.shininess);
}
// set output color
fColor = (diffuse + specular + ambient).rgb;
fColor *= texture(uTextureSampler, vTexCoord).rgb;
}
PS: Sorry if I was a bit too irresponsible with my questions yesterday. Some of the advice I just didn't understand and thus didn't reply.
When you are drawing the 2nd part (wall), then you are binding the textures to the texture units GL_TEXTURE1 and GL_TEXTURE2:
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, g_textureID[6]);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, g_textureID[7]);
But you are setting the texture unit indices 0 and 1 to the texture sampler uniforms uTextureSampler and uNormalSampler:
glUniform1i(g_texSamplerIndex, 0);
glUniform1i(g_normalSamplerIndex, 1);`
Adapt your code like this:
glUniform1i(g_texSamplerIndex, 1); // GL_TEXTURE1
glUniform1i(g_normalSamplerIndex, 2); // GL_TEXTURE2
Further the attribute index of "aTexCoord" is stored to texCoordIndex[i] for g_shaderProgramID[i]:
for (int i = 0; i < 2; i++)
{
....
texCoordIndex[i] = glGetAttribLocation(g_shaderProgramID[i], "aTexCoord");
.....
}
You have to be aware of this when set up the vertex attribute pointer and enable the vertex attribute
Change this:
glVertexAttribPointer(texCoordIndex[0], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, texCoord)));
.....
glEnableVertexAttribArray(texCoordIndex[0]);
To this:
glVertexAttribPointer(texCoordIndex[1], 2, GL_FLOAT, GL_FALSE, sizeof(Vertex2), reinterpret_cast<void*>(offsetof(Vertex2, texCoord)));
.....
glEnableVertexAttribArray(texCoordIndex[1]);

OpenGL spritesheet shader

I'm staring to understand that a vertex Shader handles transformations of my texture. While the fragment Shader handles individual pixels. But this vector math is confusing.
What I'm trying to do is render a sprite from a sprite sheet. I can render a whole image just fine, but now i'm actually trying to write my own shader.
I think its more efficient to have the graphics card do the heavy lifting, that being said;
Currently I draw whole images like so:
In my init step,
void TextureRenderer::initRenderData()
{
// Configure VAO/VBO
game_uint VBO;
game_float vertices[] = {
// Pos // Tex
0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 0.0f, 1.0f, 0.0f
};
glGenVertexArrays(1, &this->quadVAO);
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glBindVertexArray(this->quadVAO);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(game_float), (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
Then when its time to draw any texture:
void TextureRenderer::DrawTexture(Texture2D &texture, vec2 position, vec2 size, game_float rotate, vec3 color)
{
// Prepare transformations
this->shader->Use();
glm::mat4 model;
model = glm::translate(model, vec3(position, 0.0f)); // First translate (transformations are: scale happens first, then rotation and then finall translation happens; reversed order)
model = glm::translate(model, vec3(0.5f * size.x, 0.5f * size.y, 0.0f)); // Move origin of rotation to center of quad
model = glm::rotate(model, rotate, vec3(0.0f, 0.0f, 1.0f)); // Then rotate
model = glm::translate(model, vec3(-0.5f * size.x, -0.5f * size.y, 0.0f)); // Move origin back
model = glm::scale(model, vec3(size, 1.0f)); // Last scale
this->shader->SetMatrix4("model", model);
// Render textured quad
this->shader->SetVector3f("spriteColor", color);
glActiveTexture(GL_TEXTURE0);
texture.Bind();
glBindVertexArray(this->quadVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);
}
TextureShader.vs:
#version 330 core
layout (location = 0) in vec4 vertex; // <vec2 position, vec2 texCoords>
out vec2 TexCoords;
uniform mat4 model;
uniform mat4 projection;
void main()
{
TexCoords = vertex.zw;
gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
}
Fragment Shader:
#version 330 core
in vec2 TexCoords; //Position
out vec4 color;
uniform sampler2D image;
uniform vec3 spriteColor;
void main()
{
color = vec4(spriteColor, 1.0) * texture(image, TexCoords);
}
Now that work all fine and dandy (assuming proper opengl setup ext.)
But id like to apply this to a Sprite sheet shader, and have the GPU handle the math to draw it.
void SpriteRenderer::drawSprite(Texture2D &texture, vec2 position,game_float spriteHeight,game_float spriteWidth,int frameIndex)
{
shader->Use();//Load a diffrent Shader here.
shader->SetInteger("frameindex", frameIndex);
shader->SetVector2f("position", position);
shader->SetFloat("spriteHeight", spriteHeight);
shader->SetFloat("spriteWidth", spriteWidth);
shader->SetMatrix4("model", model);
shader->SetVector3f("spriteColor", color);
glActiveTexture(GL_TEXTURE0); //Set texture to nothin
texture.Bind(); //Bind my texture.
glBindVertexArray(this->quadVAO); //Bind the fullscreen quad
glDrawArrays(GL_TRIANGLES, 0, 6); //Draw
glBindVertexArray(0); //Unbind the quad.
}
I assume:
Inside the vertex Shader, I manipulate the VAO quad to the position it is on the canvas then set the color of the pixles in the fragment shader to that spesific region.
How would that be done?
Or would it be better off for me to pre-calculate a VAO Array for each Sprite in a sprite class? Then each draw call would be:
void SpriteRenderer::drawSprite(Texture2D &texture, vec2 position,Sprite s)
Where the sprite has these vertices stored.
Iv seen:
Techniques for drawing spritesheets in OpenGL with shaders
Somewhat similar, but id like to have the GPU handle the math all together.

Changing the angle in glm::perspective reflects the object

I was drawing 2 cubes on the screen and I realized that my object behaves really weird when I changed the angle in the perspective matrix, here is my code
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(programID);
GLuint mvp = glGetUniformLocation(programID, "MVP");
glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 10.0f);
glm::mat4 translate = glm::translate(glm::mat4(1.0f), vec3(-2.0f, 0.0f, -5.0f));
glm::mat4 rotate = glm::rotate(glm::mat4(1.0f), 54.0f, vec3(-1.0f, 0.0f, 0.0f));
glm::mat4 MVP = Projection * translate * rotate;
glUniformMatrix4fv(mvp, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, numOfIndices, GL_UNSIGNED_SHORT, nullptr);
translate = glm::translate(glm::mat4(1.0f), vec3(3.0f, 0.0f, -6.0f));
rotate = glm::rotate(glm::mat4(1.0f), 54.0f, vec3(0.0f, 1.0f, 0.0f));
MVP = Projection * translate * rotate;
glUniformMatrix4fv(mvp, 1, GL_FALSE, &MVP[0][0]);
glDrawElements(GL_TRIANGLES, numOfIndices, GL_UNSIGNED_SHORT, nullptr);
The 2 cubes share the same projection matrix but different translate and rotation matrix. Here is my shader
#version 430
in layout(location=0) vec3 position;
in layout(location=1) vec3 color;
uniform mat4 MVP;
out vec3 theColor;
void main(){
gl_Position = MVP * vec4(position,1.0f);
theColor = color;
}
the shader just times the MVP matrix by the position vertex. When I ran the code with 45.0f for degree in perspective matrix I got this:
and then when I ran it with 55.0f I got this:
it seems like I got behind the object and looks at them from there, and when I did 50.0f it closed up and I can only see the corner of one of the cube.
Okay I figured it out, glm::perspective takes radian as it's first argument so I should've wrote (3.14f/180.0f) * 45.0f rather than just 45.0f