The problem is specifically when i look at the corners of the room. When i do that the specular lightning gets brighter:
...and when i look at a flat wall doesn't:
Here i post the entire code:
#include <windows.h>
#include <iostream>
#include <fstream>
#include <cstring>
#include <vector>
#include <cmath>
#include <algorithm>
#define GLEW_STATIC
#include <glew.h>
#include <GL/glfw.h>
template <typename T>
T clamp(T value, T min, T max) {
if (value < min) return min;
if (value > max) return max;
return value;
}
// CAMERA PROPERTIES
float posX = 0.0f, posY = 0.0f, posZ = 5.0f; // position
float rotX = 0.0f, rotY = 3.0f; // rotation
// movement speed and mouse sensitivity
float speed = 0.05f;
const float mouseSensitivity = 0.005f;
// MOUSE INPUT TRACKING
double lastMouseX, lastMouseY;
// ROOM BOUNDARIES
float x_min = -5.0f, x_max = 5.0f;
float z_min = -5.0f, z_max = 5.0f;
float collision = 0.2f;
void checkCollision(float &posX, float &posZ) {
if (posX < x_min + collision) posX = x_min + collision; // left
if (posX > x_max - collision) posX = x_max - collision; // right
if (posZ < z_min + collision) posZ = z_min + collision; // back
if (posZ > z_max - collision) posZ = z_max - collision; // front
}
void drawLightMarker() {
glDisable(GL_LIGHTING);
glColor3f(1.0f, 1.0f, 0.0f);
glPushMatrix();
glTranslatef(0.0f, 0.5f, 0.0f);
glBegin(GL_QUADS);
// FRONT FACE
glVertex3f(-0.1f, -0.1f, 0.1f);
glVertex3f(0.1f, -0.1f, 0.1f);
glVertex3f(0.1f, 0.1f, 0.1f);
glVertex3f(-0.1f, 0.1f, 0.1f);
// BACK FACE
glVertex3f(-0.1f, -0.1f, -0.1f);
glVertex3f(0.1f, -0.1f, -0.1f);
glVertex3f(0.1f, 0.1f, -0.1f);
glVertex3f(-0.1f, 0.1f, -0.1f);
// LEFT FACE
glVertex3f(-0.1f, -0.1f, -0.1f);
glVertex3f(-0.1f, -0.1f, 0.1f);
glVertex3f(-0.1f, 0.1f, 0.1f);
glVertex3f(-0.1f, 0.1f, -0.1f);
// RIGHT FACE
glVertex3f(0.1f, -0.1f, -0.1f);
glVertex3f(0.1f, -0.1f, 0.1f);
glVertex3f(0.1f, 0.1f, 0.1f);
glVertex3f(0.1f, 0.1f, -0.1f);
// TOP FACE
glVertex3f(-0.1f, 0.1f, 0.1f);
glVertex3f(0.1f, 0.1f, 0.1f);
glVertex3f(0.1f, 0.1f, 0.1f);
glVertex3f(-0.1f, 0.1f, 0.1f);
// BOTTOM FACE
glVertex3f(-0.1f, -0.1f, -0.1f);
glVertex3f(0.1f, -0.1f, -0.1f);
glVertex3f(0.1f, -0.1f, 0.1f);
glVertex3f(-0.1f, -0.1f, 0.1f);
glEnd();
glPopMatrix();
glEnable(GL_LIGHTING);
}
// ********TO FIX********
void setupLightning() {
// PROPERTIES
GLfloat ambient[] = {0.0f, 0.0f, 0.0f, 1.0f};
GLfloat diffuse[] = {2.0f, 2.0f, 2.0f, 1.0f};
GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat mat_specular[] = {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat shininess[] = {20.0f};
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient);
glMaterialfv(GL_FRONT, GL_DIFFUSE, diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, specular);
glMaterialfv(GL_FRONT, GL_SHININESS, shininess);
// ATTENUATION
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.5f);
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.1f);
glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.01f);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
glShadeModel(GL_SMOOTH);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_NORMALIZE);
}
void processInput(GLFWwindow *window) {
// FORWARD/BACKWARD MOVEMENT
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) {
posX += speed * sin(rotY);
posZ += speed * cos(rotY);
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) {
posX -= speed * sin(rotY);
posZ -= speed * cos(rotY);
}
// LEFT/RIGHT STRAFING
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) {
posX += speed * cos(rotY);
posZ -= speed * sin(rotY);
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) {
posX -= speed * cos(rotY);
posZ += speed * sin(rotY);
}
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwDestroyWindow(window);
glfwTerminate();
}
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) speed = 0.5f;
if (glfwGetKey(window, GLFW_KEY_BACKSPACE) == GLFW_PRESS) speed = 0.05f;
//checkCollision(posX, posZ);
}
void mouseCallback(GLFWwindow* window, double xpos, double ypos) {
// calculate mouse delta
double deltaX = xpos - lastMouseX;
double deltaY = ypos - lastMouseY;
lastMouseX = xpos;
lastMouseY = ypos;
// UPDATE ROTATION
rotY -= deltaX * mouseSensitivity; // Horizontal rotation
rotX -= deltaY * mouseSensitivity; // Vertical rotation
rotX = clamp(rotX, -1.5f, 1.5f);
}
void renderRoom() {
glBegin(GL_QUADS);
// FLOOR
glColor3f(0.5f, 0.5f, 0.5f);
glNormal3f(0.0f, 1.0f, 0.0f);
glVertex3f(-5.0f, -1.0f, -5.0f);
glVertex3f(5.0f, -1.0f, -5.0f);
glVertex3f(5.0f, -1.0f, 5.0f);
glVertex3f(-5.0f, -1.0f, 5.0f);
// CEILING
glColor3f(0.3f, 0.3f, 0.3f);
glNormal3f(0.0f, -1.0f, 0.0f);
glVertex3f(-5.0f, 1.0f, -5.0f);
glVertex3f(5.0f, 1.0f, -5.0f);
glVertex3f(5.0f, 1.0f, 5.0f);
glVertex3f(-5.0f, 1.0f, 5.0f);
// WALLS
// back wall
glColor3f(0.8f, 0.2f, 0.2f);
glNormal3f(0.0f, 0.0f, 1.0f);
glVertex3f(-5.0f, -1.0f, -5.0f);
glVertex3f(5.0f, -1.0f, -5.0f);
glVertex3f(5.0f, 1.0f, -5.0f);
glVertex3f(-5.0f, 1.0f, -5.0f);
// front wall
glNormal3f(0.0f, 0.0f, -1.0f);
glVertex3f(-5.0f, -1.0f, 5.0f);
glVertex3f(5.0f, -1.0f, 5.0f);
glVertex3f(5.0f, 1.0f, 5.0f);
glVertex3f(-5.0f, 1.0f, 5.0f);
// left wall
glNormal3f(1.0f, 0.0f, 0.0f);
glVertex3f(-5.0f, -1.0f, -5.0f);
glVertex3f(-5.0f, -1.0f, 5.0f);
glVertex3f(-5.0f, 1.0f, 5.0f);
glVertex3f(-5.0f, 1.0f, -5.0f);
// right wall
glNormal3f(-1.0f, 0.0f, 0.0f);
glVertex3f(5.0f, -1.0f, -5.0f);
glVertex3f(5.0f, -1.0f, 5.0f);
glVertex3f(5.0f, 1.0f, 5.0f);
glVertex3f(5.0f, 1.0f, -5.0f);
glEnd();
}
GLFWwindow* initWindowFullScreen() {
// INITIALIZE GLFW
if (!glfwInit()) std::cerr << "Failed to initialize GLFW" << std::endl;
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
if (!monitor) {
glfwTerminate();
std::cerr << "Failed to get primary monitor" << std::endl;
}
const GLFWvidmode* mode = glfwGetVideoMode(monitor);
GLFWwindow* window = glfwCreateWindow(mode->width, mode->height, "3D Room full-screen", monitor, NULL);
if (!window) {
std::cerr << "Failed to create GLFW window" << std::endl;
glfwTerminate();
exit(EXIT_FAILURE);
}
glfwMakeContextCurrent(window);
return window;
}
int main() {
GLFWwindow* window = initWindowFullScreen();
// MOUSE CALLBACK
glfwSetCursorPosCallback(window, mouseCallback);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
glfwGetCursorPos(window, &lastMouseX, &lastMouseY);
setupLightning();
// MAIN LOOP
while (!glfwWindowShouldClose(window)) {
processInput(window);
// RENDERING
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(70.0, 800.0 / 600.0, 0.1, 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// APPLY CAMERA TRANSFORMATIONS
float lookX = posX + sin(rotY) * cos(rotX);
float lookY = posY + sin(rotX);
float lookZ = posZ + cos(rotY) * cos(rotX);
gluLookAt(posX, posY, posZ, lookX, lookY, lookZ, 0.0f, 1.0f, 0.0f);
GLfloat lightPos[] = {0.0f, 0.5f, 0.0f, 1.0f};
glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
renderRoom();
drawLightMarker();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
I tried to modify the specular, the ambient, diffuse lightning but nothing.
In the smooth shading mode which you use, fragments of triangle are interpolated based on properties of vertices.
So, suppose you have a triangle:
v0 --- v1
| /
v2
now specular contribution of lighting effect is computed per v0
, v1
, v2
. When triangle is being rendered, all area which fills the triangle is interpolated. To see specular contribution, light ray needs to hit some vertices v0, v1, v2. In your scene it is hard to be satisfied because position of light is (0,0,0) and each face of box has 4 vertices where length of side is 10.
--------------- seen from top along Y axis towards negative values
|
|
| (L) -> L is position of light
|
|
(Y)------------
Y is position of camera. Specular effect is based on angle between view direction and reflection vector when light ray hits box's face. Taking left face of box as seen above, you need some more vertices along the distance between L and Y.
The view above was created when floor is rendered as 100 quads in range [-5,5] in both X and Z axis. So dx and dy offsets are 1. And left face is rendered with dz = 1 and dy = 0.2 offsets (it is also 100 quads).
So as conclusion, you need to make geometry denser, to see lighting effects. On the floor specular effect is visible. On left face we see diffuse effect.
The code for generating the floor:
// FLOOR
glColor3f(0.5f, 0.5f, 0.5f);
glNormal3f(0.0f, 1.0f, 0.0f);
for (float z = -5; z < 5; z += 1)
for (float x = -5; x < 5; x += 1)
{
glVertex3f(x, -1.0f, z);
glVertex3f(x+1, -1.0f, z);
glVertex3f(x+1, -1.0f, z+1);
glVertex3f(x, -1.0f, z+1);
}