ex1 done
This commit is contained in:
parent
4645e40b62
commit
4247ae3659
|
@ -30,3 +30,5 @@
|
|||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
build/
|
||||
|
|
|
@ -1,12 +1,67 @@
|
|||
#version 430 core
|
||||
|
||||
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;
|
||||
|
||||
// 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()
|
||||
{
|
||||
float intensity = dot(normalize(normal), vec3(0, 0, 1));
|
||||
color = vec4(0.5 * normal + 0.5, 1.0);
|
||||
//color = vec4(intensity, intensity, intensity, 1.0f);
|
||||
vec3 nnormal = normalize(normal);
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -4,11 +4,16 @@ in layout(location = 0) vec3 position;
|
|||
in layout(location = 1) vec3 normal_in;
|
||||
|
||||
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 = 1) vec3 vertex_out;
|
||||
|
||||
void main()
|
||||
{
|
||||
normal_out = normal_in;
|
||||
gl_Position = MVP * vec4(position, 1.0f);
|
||||
normal_out = normalize(vec3(MVnormal * vec4(normal_in, 1.0f)));
|
||||
vertex_out = vec3(MV*vec4(position, 1.0f));
|
||||
gl_Position = MVP * vec4(position, 1.0f);
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <SFML/Audio/Sound.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <string>
|
||||
#include "gamelogic.h"
|
||||
#include "sceneGraph.hpp"
|
||||
|
||||
|
@ -33,6 +34,8 @@ SceneNode* boxNode;
|
|||
SceneNode* ballNode;
|
||||
SceneNode* padNode;
|
||||
|
||||
SceneNode* lightNode[3];
|
||||
|
||||
double ballRadius = 3.0f;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
|
||||
|
@ -108,7 +111,7 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) {
|
|||
unsigned int padVAO = generateBuffer(pad);
|
||||
|
||||
rootNode = createSceneNode();
|
||||
boxNode = createSceneNode();
|
||||
boxNode = createSceneNode() ;
|
||||
padNode = createSceneNode();
|
||||
ballNode = createSceneNode();
|
||||
|
||||
|
@ -125,12 +128,28 @@ void initGame(GLFWwindow* window, CommandLineOptions gameOptions) {
|
|||
ballNode->vertexArrayObjectID = ballVAO;
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
|
@ -146,17 +165,30 @@ void updateNodeTransformations(SceneNode* node, glm::mat4 transformationThusFar)
|
|||
* glm::scale(glm::mat4(1.0), node->scale);
|
||||
break;
|
||||
case POINT_LIGHT:
|
||||
|
||||
break;
|
||||
case SPOT_LIGHT:
|
||||
|
||||
transformationMatrix =
|
||||
glm::translate(glm::mat4(1.0), node->position);
|
||||
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) {
|
||||
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), float(M_PI), glm::vec3(0, 1, 0));
|
||||
|
||||
glm::mat4 VP = projection * cameraTransform;
|
||||
|
||||
updateNodeTransformations(rootNode, VP);
|
||||
updateNodeTransformations(rootNode, glm::mat4(1.0), cameraTransform, projection);
|
||||
|
||||
boxNode->position = {-boxDimensions.x / 2, -boxDimensions.y / 2 - 15, boxDimensions.z - 10};
|
||||
padNode->position = {-boxDimensions.x / 2 + (1 - padPositionX) * (boxDimensions.x - padDimensions.x),
|
||||
|
@ -313,6 +343,8 @@ void updateFrame(GLFWwindow* window) {
|
|||
|
||||
void renderNode(SceneNode* node) {
|
||||
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) {
|
||||
case GEOMETRY:
|
||||
|
@ -320,13 +352,19 @@ void renderNode(SceneNode* node) {
|
|||
glBindVertexArray(node->vertexArrayObjectID);
|
||||
glDrawElements(GL_TRIANGLES, node->VAOIndexCount, GL_UNSIGNED_INT, nullptr);
|
||||
}
|
||||
break;
|
||||
case POINT_LIGHT:
|
||||
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
for(SceneNode* child : node->children) {
|
||||
|
|
|
@ -57,7 +57,8 @@ void runProgram(GLFWwindow* window, CommandLineOptions options)
|
|||
void handleKeyboardInput(GLFWwindow* 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);
|
||||
}
|
||||
|
|
|
@ -1,67 +1,74 @@
|
|||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <stdbool.h>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
enum SceneNodeType {
|
||||
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.
|
||||
// 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.
|
||||
// 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 {
|
||||
SceneNode() {
|
||||
position = glm::vec3(0, 0, 0);
|
||||
rotation = glm::vec3(0, 0, 0);
|
||||
scale = glm::vec3(1, 1, 1);
|
||||
|
||||
referencePoint = glm::vec3(0, 0, 0);
|
||||
vertexArrayObjectID = -1;
|
||||
VAOIndexCount = 0;
|
||||
|
||||
nodeType = GEOMETRY;
|
||||
}
|
||||
|
||||
// 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.
|
||||
std::vector<SceneNode*> children;
|
||||
|
||||
// The node's position and rotation relative to its parent
|
||||
glm::vec3 position;
|
||||
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;
|
||||
|
||||
// The location of the node's reference point
|
||||
glm::vec3 referencePoint;
|
||||
|
||||
// The ID of the VAO containing the "appearance" of this SceneNode.
|
||||
int vertexArrayObjectID;
|
||||
unsigned int VAOIndexCount;
|
||||
|
||||
// Node type is used to determine how to handle the contents of a node
|
||||
SceneNodeType nodeType;
|
||||
};
|
||||
|
||||
// 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.
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/mat4x4.hpp>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <stack>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <stdbool.h>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
enum SceneNodeType {
|
||||
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.
|
||||
// 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.
|
||||
// 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 {
|
||||
SceneNode() {
|
||||
position = glm::vec3(0, 0, 0);
|
||||
rotation = glm::vec3(0, 0, 0);
|
||||
scale = glm::vec3(1, 1, 1);
|
||||
|
||||
referencePoint = glm::vec3(0, 0, 0);
|
||||
vertexArrayObjectID = -1;
|
||||
VAOIndexCount = 0;
|
||||
|
||||
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.
|
||||
std::vector<SceneNode*> children;
|
||||
|
||||
// The node's position and rotation relative to its parent
|
||||
glm::vec3 position;
|
||||
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; // MVP
|
||||
glm::mat4 currentTransformationMatrixMV; // MV
|
||||
glm::mat4 currentTransformationMatrixMVnormal; // transpose(inverse(MV))
|
||||
|
||||
// The location of the node's reference point
|
||||
glm::vec3 referencePoint;
|
||||
|
||||
// The ID of the VAO containing the "appearance" of this SceneNode.
|
||||
int vertexArrayObjectID;
|
||||
unsigned int VAOIndexCount;
|
||||
|
||||
// Node type is used to determine how to handle the contents of a node
|
||||
SceneNodeType nodeType;
|
||||
|
||||
// for lights:
|
||||
unsigned int lightID;
|
||||
SceneNode* targeted_by; // spot
|
||||
};
|
||||
|
||||
// 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.
|
||||
|
|
|
@ -19,6 +19,11 @@ namespace Gloom
|
|||
public:
|
||||
Shader() { mProgram = glCreateProgram(); }
|
||||
|
||||
// hack?:
|
||||
GLint location(std::string const& name) {
|
||||
return glGetUniformLocation(mProgram, name.c_str());
|
||||
}
|
||||
|
||||
// Public member functions
|
||||
void activate() { glUseProgram(mProgram); }
|
||||
void deactivate() { glUseProgram(0); }
|
||||
|
|
Loading…
Reference in New Issue