PDA

View Full Version : Specular problem



Scaribo
10-19-2017, 06:20 PM
Greetings, fellow humans.

I'm having a problem getting proper specular shading in my openGL 3.3 core application (using glfw, and GLAD, on win7 64, AMD Radeon HD 6570, v. 15.200.1062.1004). As you can see here (https://imgur.com/4QNuiiZ), no matter the viewing angle, the entire cube is uniformly covered in specular highlights. I've combed through the code over and over, and I simply cannot find where I'm going wrong. This is all from a tutorial found at https://learnopengl.com/#!Lighting/Lighting-maps.

Here is the main class:




int main()
{

glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Yabba-dabba-doooooo!", NULL, NULL);
if(window == NULL)
{
std::cout << "Failed to create window. Stopping program.";

glfwTerminate();
return -1;
}

glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
glfwSetCursorPosCallback(window, mouse_callback);
glfwSetScrollCallback(window, scroll_callback);
//mine
glfwSetMouseButtonCallback(window, mouse_button_callback);

// tell GLFW to capture our mouse
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);//GLFW_CURSOR_DISABLED

if(!gladLoadGLLoader((GLADloadproc)glfwGetProcAddr ess))
{
std::cout << "Failed to initialize GLAD";
}

glEnable(GL_DEPTH_TEST);

Shader lightingShader(vertDmapDirectory, fragDmapDirectory);
Shader lampShader(vertLightDirectory, fragLightDirectory);


float vertices[] = {
// positions // normals // texture coords
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f,

-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,

-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
-0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f,

0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f,

-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,
0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f,

-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f,
0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f
};

// first, configure the cube's VAO (and VBO)
unsigned int VBO, cubeVAO;
glGenVertexArrays(1, &cubeVAO);
glGenBuffers(1, &VBO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

glBindVertexArray(cubeVAO);


// position attribute
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
// normal attribute
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
//texture attribute
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);



// second, configure the light's VAO (VBO stays the same; the vertices are the same for the light object which is also a 3D cube)
unsigned int lightVAO;
glGenVertexArrays(1, &lightVAO);
glBindVertexArray(lightVAO);

glBindBuffer(GL_ARRAY_BUFFER, VBO);
// note that we update the lamp's position attribute's stride to reflect the updated buffer data
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);


//load texture
unsigned int diffuseMap = loadTexture(containerImagePath);

// shader configuration
// --------------------
lightingShader.use();
lightingShader.setInt("material.diffuse", 0);



while(!glfwWindowShouldClose(window)) //this is the render loop, which also handles user input
{

float currentFrame = glfwGetTime();
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;

// input
// -----
processInput(window);

// render
// ------
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // also clear the depth buffer now!


// be sure to activate shader when setting uniforms/drawing objects
lightingShader.use();
lightingShader.setVec3("light.position", lightPos);
lightingShader.setVec3("viewPos", camera.Position);


// light properties
lightingShader.setVec3("light.ambient", glm::vec3(0.2f, 0.2f, 0.2f));
lightingShader.setVec3("light.diffuse", glm::vec3(0.5f, 0.5f, 0.5f));
lightingShader.setVec3("light.specular", glm::vec3( 1.0f, 1.0f, 1.0f));

// material properties
lightingShader.setVec3("material.specular", glm::vec3(0.5f, 0.5f, 0.5f));
lightingShader.setFloat("material.shininess", 32.0f);

//attempts to fix the whiteness
lightingShader.setVec3("material.objectColor", glm::vec3(1.0f, 1.0f, 1.0f));
//failure, but interesting in that it allows for further color customization

// view/projection transformations
glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f);
glm::mat4 view = camera.GetViewMatrix();
lightingShader.setMat4("projection", projection);
lightingShader.setMat4("view", view);

// world transformation
glm::mat4 model;
lightingShader.setMat4("model", model);

// bind diffuse map
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, diffuseMap);

// render the cube
glBindVertexArray(cubeVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);

// also draw the lamp object
lampShader.use();
lampShader.setMat4("projection", projection);
lampShader.setMat4("view", view);

model = glm::mat4();
model = glm::translate(model, lightPos);
model = glm::scale(model, glm::vec3(0.2f)); // a smaller cube
lampShader.setMat4("model", model);

glBindVertexArray(lightVAO);
glDrawArrays(GL_TRIANGLES, 0, 36);


// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}

glDeleteVertexArrays(1, &cubeVAO);
glDeleteVertexArrays(1, &lightVAO);
glDeleteBuffers(1, &VBO);

// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}


void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{

if(firstMouse)
{
lastX = xpos;
lastY = ypos;
firstMouse = false;
}

if(leftClick != true)
{
lastX = xpos;
lastY = ypos;
//return;

}

float xoffset = xpos - lastX;
float yoffset = lastY - ypos;
lastX = xpos;
lastY = ypos;

camera.ProcessMouseMovement(xoffset, yoffset);
}
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
{
//GLFW_RELEASE.
if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS)
{
leftClick = true;
camera.leftClick = true;
// std::cout << "left clicked." << std::endl;
}
else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE)
{
leftClick = false;
camera.leftClick = false;
}
// popup_menu();
}



Here is the vertex shader code in glsl:



#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;

out vec3 FragPos;
out vec3 Normal;
out vec2 TexCoords;

uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
FragPos = vec3(model * vec4(aPos, 1.0));
Normal = mat3(transpose(inverse(model))) * aNormal;
TexCoords = aTexCoords;

gl_Position = projection * view * vec4(FragPos, 1.0);
}


And here is the fragment shader:



#version 330 core
out vec4 FragColor;

struct Material {
sampler2D diffuse;
vec3 specular;
float shininess;
vec3 objectColor;//experimental
};

struct Light {
vec3 position;

vec3 ambient;
vec3 diffuse;
vec3 specular;
};

in vec3 FragPos;
in vec3 Normal;
in vec2 TexCoords;

uniform vec3 viewPos;
uniform Material material;
uniform Light light;

void main()
{
// ambient
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;

// diffuse
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;

// specular
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * (spec * material.specular); //light.specular * (spec * material.specular);

vec3 result = (ambient + diffuse + specular) * material.objectColor; //vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}


This compromises the bulk of the code I'm using, although as you can see, there is a camera and shader header as well. Thanks in advance for those willing to wade through.

Silence
10-20-2017, 03:37 AM
lightingShader.setVec3("viewPos", camera.Position);


Is camera.Position in the same space than the calculations done in your fragment shader ?

Scaribo
10-20-2017, 01:09 PM
lightingShader.setVec3("viewPos", camera.Position);


Is camera.Position in the same space than the calculations done in your fragment shader ?



Yes, it is. In the fragment shader....



...
uniform vec3 viewPos;
...
vec3 viewDir = normalize(viewPos - FragPos);
...


...is used to derive a bunch of other values.


There's two functions that set the viewing angle and position of the camera.



void processInput(GLFWwindow *window)
{
if(glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}

if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
camera.ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
camera.ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
camera.ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
camera.ProcessKeyboard(RIGHT, deltaTime);
}
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
if(leftClick != true)
{
lastX = xpos;
lastY = ypos;
}

float xoffset = xpos - lastX;
float yoffset = lastY - ypos;
lastX = xpos;
lastY = ypos;

camera.ProcessMouseMovement(xoffset, yoffset);
}


Then, in the camera header...



void ProcessKeyboard(Camera_Movement direction, float deltaTime)
{
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
}

// Processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true)
{
if(leftClick == true)
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;

Yaw += xoffset;
Pitch += yoffset;
}

// Make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}

// Update Front, Right and Up Vectors using the updated Eular angles
updateCameraVectors();
}





In the main loop, we tell the camera to set it's view matrix.



...
glm::mat4 view = camera.GetViewMatrix();
...



Then, the camera returns the view matrix.



// Returns the view matrix calculated using Eular Angles and the LookAt Matrix
glm::mat4 GetViewMatrix()
{
return glm::lookAt(Position, Position + Front, Up);
}

Scaribo
10-20-2017, 08:47 PM
Alright, I got it working. What was the problem? I never actually found it. Instead, I simply created a new project and followed the tutorial to a 't.' My guess is that it had to do with the camera, but the world will never know.