This commit is contained in:
Peder Bergebakken Sundt 2019-02-19 16:16:13 +01:00
parent 4645e40b62
commit 4247ae3659
7 changed files with 200 additions and 87 deletions

2
.gitignore vendored
View File

@ -30,3 +30,5 @@
*.exe *.exe
*.out *.out
*.app *.app
build/

View File

@ -1,12 +1,67 @@
#version 430 core #version 430 core
in layout(location = 0) vec3 normal; in layout(location = 0) vec3 normal;
in layout(location = 1) vec3 vertex;
// point lights
struct Light {
vec3 position;
mat4 MV;
bool is_spot;
vec3 spot_target; // MV space coordinates
};
#define N_LIGHTS 3
uniform Light light[N_LIGHTS];
out vec4 color; out vec4 color;
// constants
float shininess = 15;
vec3 c_diffuse = vec3(0.75390625, 0.4296875, 0.4375);
vec3 c_emissive = vec3(0.01171875, 0.0, 0.15234375);
vec3 c_specular = vec3(0.9453125, 0.94921875, 0.84765625);
float spot_cuttof_angle = cos(4 / 180.0 * 3.1415926535);
void main() void main()
{ {
float intensity = dot(normalize(normal), vec3(0, 0, 1)); vec3 nnormal = normalize(normal);
color = vec4(0.5 * normal + 0.5, 1.0);
//color = vec4(intensity, intensity, intensity, 1.0f); float diffuse_intensity = 0.0;
float specular_intensity = 0.0;
for (int i = 0; i<3; i++) {
vec3 L = vec3(light[i].MV * vec4(light[i].position, 1.0f)) - vertex;
float attenuation = clamp(1000/(1 + 40*length(L) + 0.1*length(L)*length(L)), 0.0, 1.25);
L = normalize(L);
if (light[i].is_spot) {
vec3 L2 = normalize(vec3(light[i].MV * vec4(light[i].position, 1.0f)) - light[i].spot_target);
if (dot(L2, L) < spot_cuttof_angle) {
continue;
}
attenuation *= 70;
}
float diffuse_i = dot(nnormal, L);
float specular_i = pow(dot(reflect(-L, nnormal), normalize(vec3(0,0,0) - vertex)), shininess);
if (diffuse_i > 0) diffuse_intensity += attenuation*diffuse_i;
if (specular_i > 0) specular_intensity += attenuation*specular_i;
}
//diffuse_intensity *= 1.0 / N_LIGHTS;
//specular_intensity *= 1.0 / N_LIGHTS;
//float intensity = dot(normalize(normal), normalize(light_pos_2));
//color = vec4(0.5 * normal + 0.5, 1.0);
color = vec4(c_emissive
+ c_diffuse*diffuse_intensity
+ c_specular*specular_intensity, 1.0f);
} }

View File

@ -4,11 +4,16 @@ in layout(location = 0) vec3 position;
in layout(location = 1) vec3 normal_in; in layout(location = 1) vec3 normal_in;
uniform layout(location = 3) mat4 MVP; uniform layout(location = 3) mat4 MVP;
uniform layout(location = 4) mat4 MV;
uniform layout(location = 5) mat4 MVnormal;
out layout(location = 0) vec3 normal_out; out layout(location = 0) vec3 normal_out;
out layout(location = 1) vec3 vertex_out;
void main() void main()
{ {
normal_out = normal_in; normal_out = normalize(vec3(MVnormal * vec4(normal_in, 1.0f)));
gl_Position = MVP * vec4(position, 1.0f); vertex_out = vec3(MV*vec4(position, 1.0f));
gl_Position = MVP * vec4(position, 1.0f);
} }

View File

@ -12,6 +12,7 @@
#include <SFML/Audio/Sound.hpp> #include <SFML/Audio/Sound.hpp>
#include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <string>
#include "gamelogic.h" #include "gamelogic.h"
#include "sceneGraph.hpp" #include "sceneGraph.hpp"
@ -33,6 +34,8 @@ SceneNode* boxNode;
SceneNode* ballNode; SceneNode* ballNode;
SceneNode* padNode; SceneNode* padNode;
SceneNode* lightNode[3];
double ballRadius = 3.0f; double ballRadius = 3.0f;
// These are heap allocated, because they should not be initialised at the start of the program // These are heap allocated, because they should not be initialised at the start of the program
@ -55,7 +58,7 @@ bool hasLost = false;
bool jumpedToNextFrame = false; bool jumpedToNextFrame = false;
// Modify if you want the music to start further on in the track. Measured in seconds. // Modify if you want the music to start further on in the track. Measured in seconds.
const float debug_startTime = 0; const float debug_startTime = 45;
double totalElapsedTime = debug_startTime; double totalElapsedTime = debug_startTime;
@ -108,7 +111,7 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) {
unsigned int padVAO = generateBuffer(pad); unsigned int padVAO = generateBuffer(pad);
rootNode = createSceneNode(); rootNode = createSceneNode();
boxNode = createSceneNode(); boxNode = createSceneNode() ;
padNode = createSceneNode(); padNode = createSceneNode();
ballNode = createSceneNode(); ballNode = createSceneNode();
@ -125,12 +128,28 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) {
ballNode->vertexArrayObjectID = ballVAO; ballNode->vertexArrayObjectID = ballVAO;
ballNode->VAOIndexCount = sphere.indices.size(); ballNode->VAOIndexCount = sphere.indices.size();
// task 1a, add point lights
for (int i = 0; i<3; i++) {
lightNode[i] = createSceneNode();
lightNode[i]->nodeType = SceneNodeType::POINT_LIGHT;
lightNode[i]->lightID = i;
}
rootNode->children.push_back(lightNode[0]);
rootNode->children.push_back(lightNode[1]);
ballNode->children.push_back(lightNode[2]);
lightNode[0]->position = {boxDimensions.x/2 - 10, boxDimensions.y/2 - 10, boxDimensions.z/2 - 10};
lightNode[1]->position = {300,300,400};
lightNode[2]->position = {0, 0, 0};
lightNode[1]->nodeType = SPOT_LIGHT;
padNode->targeted_by = lightNode[1];
getTimeDeltaSeconds(); getTimeDeltaSeconds();
std::cout << "Ready. Click to start!" << std::endl; std::cout << "Ready. Click to start!" << std::endl;
} }
void updateNodeTransformations(SceneNode* node, glm::mat4 transformationThusFar) { void updateNodeTransformations(SceneNode* node, glm::mat4 transformationThusFar, glm::mat4 V, glm::mat4 P) {
glm::mat4 transformationMatrix(1.0); glm::mat4 transformationMatrix(1.0);
@ -146,17 +165,30 @@ void updateNodeTransformations(SceneNode* node, glm::mat4 transformationThusFar)
* glm::scale(glm::mat4(1.0), node->scale); * glm::scale(glm::mat4(1.0), node->scale);
break; break;
case POINT_LIGHT: case POINT_LIGHT:
break;
case SPOT_LIGHT: case SPOT_LIGHT:
transformationMatrix =
glm::translate(glm::mat4(1.0), node->position);
break; break;
} }
glm::mat4 M = transformationThusFar * transformationMatrix;
glm::mat4 MV = V*M;
node->currentTransformationMatrix = transformationThusFar * transformationMatrix; node->currentTransformationMatrixMV = MV;
node->currentTransformationMatrix = P*MV;
node->currentTransformationMatrixMVnormal = glm::inverse(glm::transpose(MV));
for(SceneNode* child : node->children) { for(SceneNode* child : node->children) {
updateNodeTransformations(child, node->currentTransformationMatrix); updateNodeTransformations(child, M, V, P);
}
if (node->targeted_by != nullptr) {
assert(node->targeted_by->nodeType == SPOT_LIGHT);
node->targeted_by->rotation = glm::vec3(MV*glm::vec4(node->position, 1.0));
//std::cout << node->targeted_by->rotation[0]
// << " " << node->targeted_by->rotation[1]
// << " " << node->targeted_by->rotation[2]
// << std::endl;
} }
} }
@ -295,9 +327,7 @@ void updateFrame(GLFWwindow* window) {
* glm::rotate(glm::mat4(1.0), 0.2f, glm::vec3(1, 0, 0)) * glm::rotate(glm::mat4(1.0), 0.2f, glm::vec3(1, 0, 0))
* glm::rotate(glm::mat4(1.0), float(M_PI), glm::vec3(0, 1, 0)); * glm::rotate(glm::mat4(1.0), float(M_PI), glm::vec3(0, 1, 0));
glm::mat4 VP = projection * cameraTransform; updateNodeTransformations(rootNode, glm::mat4(1.0), cameraTransform, projection);
updateNodeTransformations(rootNode, VP);
boxNode->position = {-boxDimensions.x / 2, -boxDimensions.y / 2 - 15, boxDimensions.z - 10}; boxNode->position = {-boxDimensions.x / 2, -boxDimensions.y / 2 - 15, boxDimensions.z - 10};
padNode->position = {-boxDimensions.x / 2 + (1 - padPositionX) * (boxDimensions.x - padDimensions.x), padNode->position = {-boxDimensions.x / 2 + (1 - padPositionX) * (boxDimensions.x - padDimensions.x),
@ -313,6 +343,8 @@ void updateFrame(GLFWwindow* window) {
void renderNode(SceneNode* node) { void renderNode(SceneNode* node) {
glUniformMatrix4fv(3, 1, GL_FALSE, glm::value_ptr(node->currentTransformationMatrix)); glUniformMatrix4fv(3, 1, GL_FALSE, glm::value_ptr(node->currentTransformationMatrix));
glUniformMatrix4fv(4, 1, GL_FALSE, glm::value_ptr(node->currentTransformationMatrixMV));
glUniformMatrix4fv(5, 1, GL_FALSE, glm::value_ptr(node->currentTransformationMatrixMVnormal));
switch(node->nodeType) { switch(node->nodeType) {
case GEOMETRY: case GEOMETRY:
@ -320,13 +352,19 @@ void renderNode(SceneNode* node) {
glBindVertexArray(node->vertexArrayObjectID); glBindVertexArray(node->vertexArrayObjectID);
glDrawElements(GL_TRIANGLES, node->VAOIndexCount, GL_UNSIGNED_INT, nullptr); glDrawElements(GL_TRIANGLES, node->VAOIndexCount, GL_UNSIGNED_INT, nullptr);
} }
break;
case POINT_LIGHT:
break; break;
case SPOT_LIGHT: case SPOT_LIGHT:
case POINT_LIGHT: {
std::string pre = "light[" + std::to_string(node->lightID) + "]";
glUniform3fv(shader->location(pre+".position"), 1, glm::value_ptr(node->position));
glUniformMatrix4fv(shader->location(pre+".MV"), 1, GL_FALSE, glm::value_ptr(node->currentTransformationMatrixMV));
glUniform1i(shader->location(pre+".is_spot"), node->nodeType == SPOT_LIGHT);
glUniform3fv(shader->location(pre+".spot_target"), 1, glm::value_ptr(node->rotation));
break; break;
}
} }
for(SceneNode* child : node->children) { for(SceneNode* child : node->children) {

View File

@ -57,7 +57,8 @@ void runProgram(GLFWwindow* window, CommandLineOptions options)
void handleKeyboardInput(GLFWwindow* window) void handleKeyboardInput(GLFWwindow* window)
{ {
// Use escape key for terminating the GLFW window // Use escape key for terminating the GLFW window
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS
|| glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
{ {
glfwSetWindowShouldClose(window, GL_TRUE); glfwSetWindowShouldClose(window, GL_TRUE);
} }

View File

@ -1,67 +1,74 @@
#pragma once #pragma once
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/mat4x4.hpp> #include <glm/mat4x4.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <stack> #include <stack>
#include <vector> #include <vector>
#include <cstdio> #include <cstdio>
#include <stdbool.h> #include <stdbool.h>
#include <cstdlib> #include <cstdlib>
#include <ctime> #include <ctime>
#include <chrono> #include <chrono>
#include <fstream> #include <fstream>
enum SceneNodeType { enum SceneNodeType {
GEOMETRY, POINT_LIGHT, SPOT_LIGHT GEOMETRY, POINT_LIGHT, SPOT_LIGHT
}; };
// In case you haven't got much experience with C or C++, let me explain this "typedef" you see below. // In case you haven't got much experience with C or C++, let me explain this "typedef" you see below.
// The point of a typedef is that you it, as its name implies, allows you to define arbitrary data types based upon existing ones. For instance, "typedef float typeWhichMightBeAFloat;" allows you to define a variable such as this one: "typeWhichMightBeAFloat variableName = 5.0;". The C/C++ compiler translates this type into a float. // The point of a typedef is that you it, as its name implies, allows you to define arbitrary data types based upon existing ones. For instance, "typedef float typeWhichMightBeAFloat;" allows you to define a variable such as this one: "typeWhichMightBeAFloat variableName = 5.0;". The C/C++ compiler translates this type into a float.
// What is the point of using it here? A smrt person, while designing the C language, thought it would be a good idea for various reasons to force you to explicitly state that you are using a data structure datatype (struct). So, when defining a variable, you'd have to type "struct SceneNode node = ..." in the case of a SceneNode. Which can get in the way of readability. // What is the point of using it here? A smrt person, while designing the C language, thought it would be a good idea for various reasons to force you to explicitly state that you are using a data structure datatype (struct). So, when defining a variable, you'd have to type "struct SceneNode node = ..." in the case of a SceneNode. Which can get in the way of readability.
// If we just use typedef to define a new type called "SceneNode", which really is the type "struct SceneNode", we can omit the "struct" part when creating an instance of SceneNode. // If we just use typedef to define a new type called "SceneNode", which really is the type "struct SceneNode", we can omit the "struct" part when creating an instance of SceneNode.
struct SceneNode { struct SceneNode {
SceneNode() { SceneNode() {
position = glm::vec3(0, 0, 0); position = glm::vec3(0, 0, 0);
rotation = glm::vec3(0, 0, 0); rotation = glm::vec3(0, 0, 0);
scale = glm::vec3(1, 1, 1); scale = glm::vec3(1, 1, 1);
referencePoint = glm::vec3(0, 0, 0); referencePoint = glm::vec3(0, 0, 0);
vertexArrayObjectID = -1; vertexArrayObjectID = -1;
VAOIndexCount = 0; VAOIndexCount = 0;
nodeType = GEOMETRY; nodeType = GEOMETRY;
} targeted_by = nullptr;
}
// A list of all children that belong to this node.
// For instance, in case of the scene graph of a human body shown in the assignment text, the "Upper Torso" node would contain the "Left Arm", "Right Arm", "Head" and "Lower Torso" nodes in its list of children. // A list of all children that belong to this node.
std::vector<SceneNode*> children; // For instance, in case of the scene graph of a human body shown in the assignment text, the "Upper Torso" node would contain the "Left Arm", "Right Arm", "Head" and "Lower Torso" nodes in its list of children.
std::vector<SceneNode*> children;
// The node's position and rotation relative to its parent
glm::vec3 position; // The node's position and rotation relative to its parent
glm::vec3 rotation; glm::vec3 position;
glm::vec3 scale; glm::vec3 rotation;
glm::vec3 scale;
// A transformation matrix representing the transformation of the node's location relative to its parent. This matrix is updated every frame.
glm::mat4 currentTransformationMatrix; // A transformation matrix representing the transformation of the node's location relative to its parent. This matrix is updated every frame.
glm::mat4 currentTransformationMatrix; // MVP
// The location of the node's reference point glm::mat4 currentTransformationMatrixMV; // MV
glm::vec3 referencePoint; glm::mat4 currentTransformationMatrixMVnormal; // transpose(inverse(MV))
// The ID of the VAO containing the "appearance" of this SceneNode. // The location of the node's reference point
int vertexArrayObjectID; glm::vec3 referencePoint;
unsigned int VAOIndexCount;
// The ID of the VAO containing the "appearance" of this SceneNode.
// Node type is used to determine how to handle the contents of a node int vertexArrayObjectID;
SceneNodeType nodeType; unsigned int VAOIndexCount;
};
// Node type is used to determine how to handle the contents of a node
// Struct for keeping track of 2D coordinates SceneNodeType nodeType;
SceneNode* createSceneNode(); // for lights:
void addChild(SceneNode* parent, SceneNode* child); unsigned int lightID;
void printNode(SceneNode* node); SceneNode* targeted_by; // spot
};
// For more details, see SceneGraph.cpp. // Struct for keeping track of 2D coordinates
SceneNode* createSceneNode();
void addChild(SceneNode* parent, SceneNode* child);
void printNode(SceneNode* node);
// For more details, see SceneGraph.cpp.

View File

@ -19,6 +19,11 @@ namespace Gloom
public: public:
Shader() { mProgram = glCreateProgram(); } Shader() { mProgram = glCreateProgram(); }
// hack?:
GLint location(std::string const& name) {
return glGetUniformLocation(mProgram, name.c_str());
}
// Public member functions // Public member functions
void activate() { glUseProgram(mProgram); } void activate() { glUseProgram(mProgram); }
void deactivate() { glUseProgram(0); } void deactivate() { glUseProgram(0); }