I'm writing a simple 3D world in OpenGL, that can render various stuff. I'm relatively new to OpenGL, and might not notice something, but there's a really big problem with (I guess) fragment shader.
What it does is it ignores z-value and draws faces in order that they were given by index buffer. What I mean by that, is if there is, for example, conditional index buffer, and it contains triangle 1, triangle 2, and triangle 3, and they stand in a row in front of the camera, then triangle 3, regardless of it's z-value, will be drawn on top of other two, 'cause it's last.
This image shows exactly what I mean. The front side behaves like it's transparent, relatively to the neighbor side, but in terms of transparency, it ignores the parallel side, 'cause they are drawn in such an order.
My code for camera:
PCamera::PCamera(GLFWwindow* projectWindow, float windowWidth, float windowHeight)
{
window = projectWindow;
wWidth = windowWidth;
wHeight = windowHeight;
Position = glm::vec3(0.f, 0.f, -10.f);
Rotation = glm::vec3(0.f, glm::pi<float>(), 0.f);
if (glfwRawMouseMotionSupported())
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
glfwGetCursorPos(window, &xposnormal, &yposnormal);
}
PCamera::~PCamera()
{
}
glm::mat4 PCamera::NavigateCamera()
{
double xpos, ypos;
int state;
glfwGetCursorPos(window, &xpos, &ypos);
state = glfwGetKey(window, GLFW_KEY_ESCAPE);
if (state == GLFW_PRESS)
{
bMouseControl = false;
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
state = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT);
if ((state == GLFW_PRESS) && (bMouseControl == false))
{
bMouseControl = true;
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_HIDDEN);
glfwGetCursorPos(window, &xposnormal, &yposnormal);
}
if (bMouseControl)
{
glfwGetCursorPos(window, &xpos, &ypos);
Rotation.x += (float)(yposnormal - ypos) / -300.f;
Rotation.y += (float)(xposnormal - xpos) / -300.f;
glfwSetCursorPos(window, xposnormal, yposnormal);
}
glm::mat4 RTSMatrix = glm::rotate(UnitMatrix, Rotation.x, glm::vec3(1.f, 0.f, 0.f)) * glm::rotate(UnitMatrix, Rotation.y, glm::vec3(0.f, 1.f, 0.f));
glm::vec3 DeltaPosition(0.f, 0.f, 0.f);
state = glfwGetKey(window, GLFW_KEY_W);
if (state == GLFW_PRESS) DeltaPosition.z += 0.01f;
state = glfwGetKey(window, GLFW_KEY_S);
if (state == GLFW_PRESS) DeltaPosition.z -= 0.01f;
state = glfwGetKey(window, GLFW_KEY_A);
if (state == GLFW_PRESS) DeltaPosition.x += 0.01f;
state = glfwGetKey(window, GLFW_KEY_D);
if (state == GLFW_PRESS) DeltaPosition.x -= 0.01f;
state = glfwGetKey(window, GLFW_KEY_LEFT_SHIFT);
if (state == GLFW_PRESS) DeltaPosition.y -= 0.01f;
state = glfwGetKey(window, GLFW_KEY_SPACE);
if (state == GLFW_PRESS) DeltaPosition.y += 0.01f;
glm::vec4 D4Position(Position, 0.f);
glm::mat4 InverseRTSMatrix = glm::rotate(UnitMatrix, -Rotation.y, glm::vec3(0.f, 1.f, 0.f)) * glm::rotate(UnitMatrix, -Rotation.x, glm::vec3(1.f, 0.f, 0.f));
D4Position -= InverseRTSMatrix*glm::vec4(DeltaPosition, 0.0);
Position.x = D4Position.x;
Position.y = D4Position.y;
Position.z = D4Position.z;
RTSMatrix = RTSMatrix * glm::translate(UnitMatrix, -Position);
return RTSMatrix;
}
void PCamera::UpdateProjectionMatrix(float Angle, float windowWidth, float windowHeight)
{
ProjectionMatrix = glm::perspective(Angle, (GLfloat)windowWidth / (GLfloat)windowHeight, -1.0f, 1.0f);
}
Code for my renderer:
void PRenderer::Draw(PObject * Object)
{
Object->Bind();
glDrawElements(GL_TRIANGLES, Object->IBCount, GL_UNSIGNED_INT, nullptr);
}
Code of my main execution file:
PProject::PProject(PRenderer * Renderer)
{
ProjectRenderer = Renderer;
}
PProject::~PProject()
{
}
int PProject::Launch()
{
GLFWwindow* window;
if (!glfwInit()) return -1;
window = glfwCreateWindow(640, 480, "PhysMaker", NULL, NULL);
if (!window) { glfwTerminate(); return -1; }
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) return -1;
float pos[] =
{
-0.5, -0.5, -0.5, 1.0, 0.0, 0.0,
-0.5, -0.5, 0.5, 0.0, 1.0, 0.0,
-0.5, 0.5, 0.5, 0.0, 0.0, 1.0,
-0.5, 0.5, -0.5, 1.0, 0.0, 1.0,
0.5, 0.5, 0.5, 1.0, 0.0, 1.0,
0.5, -0.5, 0.5, 1.0, 1.0, 0.0,
0.5, -0.5, -0.5, 1.0, 0.0, 0.0,
0.5, 0.5, -0.5, 0.0, 1.0, 1.0,
0.5, -0.5, 0.5, 1.0, 0.0, 0.0,
-0.5, -0.5, 0.5, 0.0, 1.0, 0.0,
0.5, 0.5, 0.5, 0.0, 0.0, 1.0,
-0.5, 0.5, 0.5, 1.0, 0.0, 0.0
};
unsigned int ind[]
{
0, 1, 2,
2, 3, 0,
6, 5, 4,
4, 7, 6,
8, 9, 10,
9, 11, 10
};
PShader NewShader("Source/Shaders/Vertex.shader","Source/Shaders/Fragment.shader");
NewShader.Bind();
glfwGetWindowSize(window, &windowWidth, &windowHeight);
PCamera MainCamera(window, windowWidth, windowHeight);
PObject NewObject(pos, 24, ind, 18, 0);
ProjectRenderer->SceneObjects.insert(ProjectRenderer->SceneObjects.end(), &NewObject);
while (!glfwWindowShouldClose(window))
{
glfwGetWindowSize(window, &windowWidth, &windowHeight);
glViewport(0, 0, windowWidth, windowHeight);
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
MainCamera.UpdateProjectionMatrix(45.f, windowWidth, windowHeight);
glm::mat4 translation = MainCamera.ProjectionMatrix * MainCamera.NavigateCamera();
glUniformMatrix4fv(glGetUniformLocation(NewShader.Shader_ID, "u_MVP"), 1, GL_FALSE, &translation[0][0]);
ProjectRenderer->Draw(&NewObject);
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
return 0;
}
Fragment and Vertex shaders:
#FRAGMENT
#version 330 core
out vec4 color;
in vec3 vertexColor;
void main()
{
color = vec4(vertexColor, 1.0);;
}
#VERTEX
#version 330 core
in layout(location = 0) vec3 position;
in layout(location = 1) vec3 Color;
out vec3 vertexColor;
uniform mat4 u_MVP;
void main()
{
gl_Position = (u_MVP * vec4(position, 1.f));
vertexColor = Color;
}
Maybe it's something wrong with perspective? Should I use depth, and how? I used it before, but it didn't help. It seems like it's something with the projection matrix. So, what's wrong?
You have to enable the Depth test. If the depth test is enabled, then the depth of of a fragment is tested against the depth of the sample being written to. If it fails, the fragment is discarded.
Depth test is a global state. It is sufficient to enable it once, before the application loop;
glEnable(GL_DEPTH_TEST);
Once the depth test is enabled, you have to clear the depth buffer, too:
(See glClear
)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);