13 Commits

52 changed files with 5962 additions and 30909 deletions

2
.gitignore vendored
View File

@@ -428,6 +428,4 @@ FodyWeavers.xsd
**/docs/*
**/doc/*
**/pose_iter_160000.caffemodel
# End of https://www.toptal.com/developers/gitignore/api/c++,visualstudio,visualstudiocode,opencv

4495
res/House.obj Normal file

File diff suppressed because it is too large Load Diff

BIN
res/Mayo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 323 KiB

BIN
res/Texture.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 970 B

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,59 +0,0 @@
#include "BackgroundRemover.h"
/*
Author: Pierfrancesco Soffritti https://github.com/PierfrancescoSoffritti
*/
namespace computervision
{
BackgroundRemover::BackgroundRemover(void) {
background;
calibrated = false;
}
void BackgroundRemover::calibrate(Mat input) {
cvtColor(input, background, CV_BGR2GRAY);
calibrated = true;
}
Mat BackgroundRemover::getForeground(Mat input) {
Mat foregroundMask = getForegroundMask(input);
//imshow("foregroundMask", foregroundMask);
Mat foreground;
input.copyTo(foreground, foregroundMask);
return foreground;
}
Mat BackgroundRemover::getForegroundMask(Mat input) {
Mat foregroundMask;
if (!calibrated) {
foregroundMask = Mat::zeros(input.size(), CV_8UC1);
return foregroundMask;
}
cvtColor(input, foregroundMask, CV_BGR2GRAY);
removeBackground(foregroundMask, background);
return foregroundMask;
}
void BackgroundRemover::removeBackground(Mat input, Mat background) {
int thresholdOffset = 25;
for (int i = 0; i < input.rows; i++) {
for (int j = 0; j < input.cols; j++) {
uchar framePixel = input.at<uchar>(i, j);
uchar bgPixel = background.at<uchar>(i, j);
if (framePixel >= bgPixel - thresholdOffset && framePixel <= bgPixel + thresholdOffset)
input.at<uchar>(i, j) = 0;
else
input.at<uchar>(i, j) = 255;
}
}
}
}

View File

@@ -1,58 +0,0 @@
#pragma once
#include"opencv2\opencv.hpp"
#include <opencv2/imgproc\types_c.h>
/*
Author: Pierfrancesco Soffritti https://github.com/PierfrancescoSoffritti
*/
namespace computervision
{
using namespace cv;
using namespace std;
class BackgroundRemover {
public:
/**
* @brief constructor,
* create background variable and set calibrated to faslse
*
*/
BackgroundRemover(void);
/**
* @brief sets the input image to a grayscale image
* sets calibrated to true
*
* @param input input the image that has to be calibrated
*/
void calibrate(Mat input);
/**
* @brief Gets the mask of the foregorund of the input image
* and copies it to another image
*
* @param input The image from which the forground needs to be picked
* @return The image on which te foregroundmask is copied
*/
Mat getForeground(Mat input);
private:
Mat background;
bool calibrated = false;
/**
* @brief Sets the image to grayscale and removes the background
*
* @param input The image from which the forground needs to be picked
* @return The mask of the foreground of the image
*/
Mat getForegroundMask(Mat input);
/**
* @brief makes everything on the background black
*
* @param input the image from which the background needs to be removed
* @param background the background of the image
*/
void removeBackground(Mat input, Mat background);
};
}

View File

@@ -1,53 +0,0 @@
#include "FaceDetector.h"
/*
Author: Pierfrancesco Soffritti https://github.com/PierfrancescoSoffritti
*/
namespace computervision
{
Rect getFaceRect(Mat input);
String faceClassifierFileName = "res/haarcascade_frontalface_alt.xml";
CascadeClassifier faceCascadeClassifier;
FaceDetector::FaceDetector(void) {
if (!faceCascadeClassifier.load(faceClassifierFileName))
throw runtime_error("can't load file " + faceClassifierFileName);
}
void FaceDetector::removeFaces(Mat input, Mat output) {
vector<Rect> faces;
Mat frameGray;
cvtColor(input, frameGray, CV_BGR2GRAY);
equalizeHist(frameGray, frameGray);
faceCascadeClassifier.detectMultiScale(frameGray, faces, 1.1, 2, 0 | 2, Size(120, 120)); // HAAR_SCALE_IMAGE is 2
for (size_t i = 0; i < faces.size(); i++) {
rectangle(
output,
Point(faces[i].x, faces[i].y),
Point(faces[i].x + faces[i].width, faces[i].y + faces[i].height),
Scalar(0, 0, 0),
-1
);
}
}
Rect getFaceRect(Mat input) {
vector<Rect> faceRectangles;
Mat inputGray;
cvtColor(input, inputGray, CV_BGR2GRAY);
equalizeHist(inputGray, inputGray);
faceCascadeClassifier.detectMultiScale(inputGray, faceRectangles, 1.1, 2, 0 | 2, Size(120, 120)); // HAAR_SCALE_IMAGE is 2
if (faceRectangles.size() > 0)
return faceRectangles[0];
else
return Rect(0, 0, 1, 1);
}
}

View File

@@ -1,31 +0,0 @@
#pragma once
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/types_c.h>
#include <opencv2/objdetect.hpp>
#include <opencv2/core.hpp>
#include <opencv2/objdetect/objdetect.hpp>
/*
Author: Pierfrancesco Soffritti https://github.com/PierfrancescoSoffritti
*/
using namespace cv;
using namespace std;
namespace computervision
{
class FaceDetector {
public:
/**
* @brief Constructor for the class FaceDetector, loads training data from a file
*
*/
FaceDetector(void);
/**
* @brief Detects faces on an image and blocks them with a black rectangle
*
* @param input Input image
* @param output Output image
*/
void removeFaces(Mat input, Mat output);
};
}

View File

@@ -1,298 +0,0 @@
#include "FingerCount.h"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
/*
Author: Nicol<6F> Castellazzi https://github.com/nicast
*/
#define LIMIT_ANGLE_SUP 60
#define LIMIT_ANGLE_INF 5
#define BOUNDING_RECT_FINGER_SIZE_SCALING 0.3
#define BOUNDING_RECT_NEIGHBOR_DISTANCE_SCALING 0.05
namespace computervision
{
FingerCount::FingerCount(void) {
color_blue = Scalar(255, 0, 0);
color_green = Scalar(0, 255, 0);
color_red = Scalar(0, 0, 255);
color_black = Scalar(0, 0, 0);
color_white = Scalar(255, 255, 255);
color_yellow = Scalar(0, 255, 255);
color_purple = Scalar(255, 0, 255);
}
Mat FingerCount::findFingersCount(Mat input_image, Mat frame) {
Mat contours_image = Mat::zeros(input_image.size(), CV_8UC3);
// check if the source image is good
if (input_image.empty())
return contours_image;
// we work only on the 1 channel result, since this function is called inside a loop we are not sure that this is always the case
if (input_image.channels() != 1)
return contours_image;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(input_image, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
// we need at least one contour to work
if (contours.size() <= 0)
return contours_image;
// find the biggest contour (let's suppose it's our hand)
int biggest_contour_index = -1;
double biggest_area = 0.0;
for (int i = 0; i < contours.size(); i++) {
double area = contourArea(contours[i], false);
if (area > biggest_area) {
biggest_area = area;
biggest_contour_index = i;
}
}
if (biggest_contour_index < 0)
return contours_image;
// find the convex hull object for each contour and the defects, two different data structure are needed by the OpenCV api
vector<Point> hull_points;
vector<int> hull_ints;
// for drawing the convex hull and for finding the bounding rectangle
convexHull(Mat(contours[biggest_contour_index]), hull_points, true);
// for finding the defects
convexHull(Mat(contours[biggest_contour_index]), hull_ints, false);
// we need at least 3 points to find the defects
vector<Vec4i> defects;
if (hull_ints.size() > 3)
convexityDefects(Mat(contours[biggest_contour_index]), hull_ints, defects);
else
return contours_image;
// we bound the convex hull
Rect bounding_rectangle = boundingRect(Mat(hull_points));
// we find the center of the bounding rectangle, this should approximately also be the center of the hand
Point center_bounding_rect(
(bounding_rectangle.tl().x + bounding_rectangle.br().x) / 2,
(bounding_rectangle.tl().y + bounding_rectangle.br().y) / 2
);
// we separate the defects keeping only the ones of intrest
vector<Point> start_points;
vector<Point> far_points;
for (int i = 0; i < defects.size(); i++) {
start_points.push_back(contours[biggest_contour_index][defects[i].val[0]]);
// filtering the far point based on the distance from the center of the bounding rectangle
if (findPointsDistance(contours[biggest_contour_index][defects[i].val[2]], center_bounding_rect) < bounding_rectangle.height * BOUNDING_RECT_FINGER_SIZE_SCALING)
far_points.push_back(contours[biggest_contour_index][defects[i].val[2]]);
}
// we compact them on their medians
vector<Point> filtered_start_points = compactOnNeighborhoodMedian(start_points, bounding_rectangle.height * BOUNDING_RECT_NEIGHBOR_DISTANCE_SCALING);
vector<Point> filtered_far_points = compactOnNeighborhoodMedian(far_points, bounding_rectangle.height * BOUNDING_RECT_NEIGHBOR_DISTANCE_SCALING);
// now we try to find the fingers
vector<Point> filtered_finger_points;
if (filtered_far_points.size() > 1) {
vector<Point> finger_points;
for (int i = 0; i < filtered_start_points.size(); i++) {
vector<Point> closest_points = findClosestOnX(filtered_far_points, filtered_start_points[i]);
if (isFinger(closest_points[0], filtered_start_points[i], closest_points[1], LIMIT_ANGLE_INF, LIMIT_ANGLE_SUP, center_bounding_rect, bounding_rectangle.height * BOUNDING_RECT_FINGER_SIZE_SCALING))
finger_points.push_back(filtered_start_points[i]);
}
if (finger_points.size() > 0) {
// we have at most five fingers usually :)
while (finger_points.size() > 5)
finger_points.pop_back();
// filter out the points too close to each other
for (int i = 0; i < finger_points.size() - 1; i++) {
if (findPointsDistanceOnX(finger_points[i], finger_points[i + 1]) > bounding_rectangle.height * BOUNDING_RECT_NEIGHBOR_DISTANCE_SCALING * 1.5)
filtered_finger_points.push_back(finger_points[i]);
}
if (finger_points.size() > 2) {
if (findPointsDistanceOnX(finger_points[0], finger_points[finger_points.size() - 1]) > bounding_rectangle.height * BOUNDING_RECT_NEIGHBOR_DISTANCE_SCALING * 1.5)
filtered_finger_points.push_back(finger_points[finger_points.size() - 1]);
}
else
filtered_finger_points.push_back(finger_points[finger_points.size() - 1]);
}
}
// we draw what found on the returned image
drawContours(contours_image, contours, biggest_contour_index, color_green, 2, 8, hierarchy);
polylines(contours_image, hull_points, true, color_blue);
rectangle(contours_image, bounding_rectangle.tl(), bounding_rectangle.br(), color_red, 2, 8, 0);
circle(contours_image, center_bounding_rect, 5, color_purple, 2, 8);
drawVectorPoints(contours_image, filtered_start_points, color_blue, true);
drawVectorPoints(contours_image, filtered_far_points, color_red, true);
drawVectorPoints(contours_image, filtered_finger_points, color_yellow, false);
putText(contours_image, to_string(filtered_finger_points.size()), center_bounding_rect, FONT_HERSHEY_PLAIN, 3, color_purple);
// and on the starting frame
drawContours(frame, contours, biggest_contour_index, color_green, 2, 8, hierarchy);
circle(frame, center_bounding_rect, 5, color_purple, 2, 8);
drawVectorPoints(frame, filtered_finger_points, color_yellow, false);
putText(frame, to_string(filtered_finger_points.size()), center_bounding_rect, FONT_HERSHEY_PLAIN, 3, color_purple);
amount_of_fingers = filtered_finger_points.size();
return contours_image;
}
int FingerCount::getAmountOfFingers()
{
return amount_of_fingers;
}
double FingerCount::findPointsDistance(Point a, Point b) {
Point difference = a - b;
return sqrt(difference.ddot(difference));
}
vector<Point> FingerCount::compactOnNeighborhoodMedian(vector<Point> points, double max_neighbor_distance) {
vector<Point> median_points;
if (points.size() == 0)
return median_points;
if (max_neighbor_distance <= 0)
return median_points;
// we start with the first point
Point reference = points[0];
Point median = points[0];
for (int i = 1; i < points.size(); i++) {
if (findPointsDistance(reference, points[i]) > max_neighbor_distance) {
// the point is not in range, we save the median
median_points.push_back(median);
// we swap the reference
reference = points[i];
median = points[i];
}
else
median = (points[i] + median) / 2;
}
// last median
median_points.push_back(median);
return median_points;
}
double FingerCount::findAngle(Point a, Point b, Point c) {
double ab = findPointsDistance(a, b);
double bc = findPointsDistance(b, c);
double ac = findPointsDistance(a, c);
return acos((ab * ab + bc * bc - ac * ac) / (2 * ab * bc)) * 180 / CV_PI;
}
bool FingerCount::isFinger(Point a, Point b, Point c, double limit_angle_inf, double limit_angle_sup, Point palm_center, double min_distance_from_palm) {
double angle = findAngle(a, b, c);
if (angle > limit_angle_sup || angle < limit_angle_inf)
return false;
// the finger point sohould not be under the two far points
int delta_y_1 = b.y - a.y;
int delta_y_2 = b.y - c.y;
if (delta_y_1 > 0 && delta_y_2 > 0)
return false;
// the two far points should not be both under the center of the hand
int delta_y_3 = palm_center.y - a.y;
int delta_y_4 = palm_center.y - c.y;
if (delta_y_3 < 0 && delta_y_4 < 0)
return false;
double distance_from_palm = findPointsDistance(b, palm_center);
if (distance_from_palm < min_distance_from_palm)
return false;
// this should be the case when no fingers are up
double distance_from_palm_far_1 = findPointsDistance(a, palm_center);
double distance_from_palm_far_2 = findPointsDistance(c, palm_center);
if (distance_from_palm_far_1 < min_distance_from_palm / 4 || distance_from_palm_far_2 < min_distance_from_palm / 4)
return false;
return true;
}
vector<Point> FingerCount::findClosestOnX(vector<Point> points, Point pivot) {
vector<Point> to_return(2);
if (points.size() == 0)
return to_return;
double distance_x_1 = DBL_MAX;
double distance_1 = DBL_MAX;
double distance_x_2 = DBL_MAX;
double distance_2 = DBL_MAX;
int index_found = 0;
for (int i = 0; i < points.size(); i++) {
double distance_x = findPointsDistanceOnX(pivot, points[i]);
double distance = findPointsDistance(pivot, points[i]);
if (distance_x < distance_x_1 && distance_x != 0 && distance <= distance_1) {
distance_x_1 = distance_x;
distance_1 = distance;
index_found = i;
}
}
to_return[0] = points[index_found];
for (int i = 0; i < points.size(); i++) {
double distance_x = findPointsDistanceOnX(pivot, points[i]);
double distance = findPointsDistance(pivot, points[i]);
if (distance_x < distance_x_2 && distance_x != 0 && distance <= distance_2 && distance_x != distance_x_1) {
distance_x_2 = distance_x;
distance_2 = distance;
index_found = i;
}
}
to_return[1] = points[index_found];
return to_return;
}
double FingerCount::findPointsDistanceOnX(Point a, Point b) {
double to_return = 0.0;
if (a.x > b.x)
to_return = a.x - b.x;
else
to_return = b.x - a.x;
return to_return;
}
void FingerCount::drawVectorPoints(Mat image, vector<Point> points, Scalar color, bool with_numbers) {
for (int i = 0; i < points.size(); i++) {
circle(image, points[i], 5, color, 2, 8);
if (with_numbers)
putText(image, to_string(i), points[i], FONT_HERSHEY_PLAIN, 3, color);
}
}
}

View File

@@ -1,119 +0,0 @@
#pragma once
#include "opencv2/core.hpp"
#include <opencv2/imgproc/types_c.h>
/*
Author: Nicol<6F> Castellazzi https://github.com/nicast
*/
namespace computervision
{
using namespace cv;
using namespace std;
class FingerCount {
public:
FingerCount(void);
/**
* @brief gets the amount of fingers that are held up.
*
* @param input_image the source image to find the fingers on. It should be a mask of a hand
* @param frame the frame to draw the resulting values on (how many fingers are held up etc)
* @return a new image with all the data drawn on it.
*/
Mat findFingersCount(Mat input_image, Mat frame);
/**
* @brief gets the currently held-up finger count.
*
* @return the currently held-up finger count
*/
int getAmountOfFingers();
private:
// colors to use
Scalar color_blue;
Scalar color_green;
Scalar color_red;
Scalar color_black;
Scalar color_white;
Scalar color_yellow;
Scalar color_purple;
int amount_of_fingers;
/**
* @brief finds the distance between 2 points.
*
* @param a the first point
* @param b the second point
* @return a double representing the distance
*/
double findPointsDistance(Point a, Point b);
/**
* @brief compacts the given points on their medians.
* what it does is for each point, it checks if the distance to it's neighbour is greater than the
* max distance. If so, it just adds it to the list that is returned. If not, it calculates the
* median and adds it to the returned list
*
* @param points the points to compact
* @param max_neighbor_distance the maximum distance between points
* @return a vector with the points now compacted.
*/
vector<Point> compactOnNeighborhoodMedian(vector<Point> points, double max_neighbor_distance);
/**
* @brief finds the angle between 3 different points.
*
* @param a the first point
* @param b the second point
* @param c the third point
* @return the angle between the 3 points
*/
double findAngle(Point a, Point b, Point c);
/**
* @brief checks if the given points make up a finger.
*
* @param a the first point to check for
* @param b the second point to check for
* @param c the third point to check for
* @param limit_angle_inf the limit of the angle between 2 fingers
* @param limit_angle_sup the limit of the angle between a finger and a convex point
* @param palm_center the center of the palm
* @param distance_from_palm_tollerance the distance from the palm tolerance
* @return true if the points are a finger, false if not.
*/
bool isFinger(Point a, Point b, Point c, double limit_angle_inf, double limit_angle_sup, cv::Point palm_center, double distance_from_palm_tollerance);
/**
* @brief finds the closest point to the given point that is in the given list.
*
* @param points the points to check for
* @param pivot the pivot to check against
* @return a vector containing the point that is closest
*/
vector<Point> findClosestOnX(vector<Point> points, Point pivot);
/**
* @brief finds the distance between the x coords of the points.
*
* @param a the first point
* @param b the second point
* @return the distance between the x values
*/
double findPointsDistanceOnX(Point a, Point b);
/**
* @brief draws the points on the image.
*
* @param image the image to draw on
* @param points the points to draw
* @param color the color to draw them with
* @param with_numbers if the numbers should be drawn with the points
*/
void drawVectorPoints(Mat image, vector<Point> points, Scalar color, bool with_numbers);
};
}

View File

@@ -1,125 +0,0 @@
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/video.hpp>
#include "ObjectDetection.h"
#include "BackgroundRemover.h"
#include "SkinDetector.h"
#include "FaceDetector.h"
#include "FingerCount.h"
namespace computervision
{
cv::VideoCapture cap(1);
cv::Mat img, imgGray, img2, img2Gray, img3, img4;
int handMaskStartXPos, handMaskStartYPos, handMaskWidth, handMaskHeight;
bool handMaskGenerated = false;
Mat frame, frameOut, handMask, foreground, fingerCountDebug;
BackgroundRemover backgroundRemover;
SkinDetector skinDetector;
FaceDetector faceDetector;
FingerCount fingerCount;
ObjectDetection::ObjectDetection()
{
}
cv::Mat ObjectDetection::readCamera() {
cap.read(img);
return img;
}
bool ObjectDetection::detectHand(Mat cameraFrame)
{
Mat inputFrame = generateHandMaskSquare(cameraFrame);
frameOut = inputFrame.clone();
// detect skin color
skinDetector.drawSkinColorSampler(frameOut);
// remove background from image
foreground = backgroundRemover.getForeground(inputFrame);
// detect the hand contours
handMask = skinDetector.getSkinMask(foreground);
// count the amount of fingers and put the info on the matrix
fingerCountDebug = fingerCount.findFingersCount(handMask, frameOut);
// get the amount of fingers
int fingers_amount = fingerCount.getAmountOfFingers();
// draw the hand rectangle on the camera input, and draw text showing if the hand is open or closed.
drawHandMaskRect(&cameraFrame);
string hand_text = fingers_amount > 0 ? "open" : "closed";
putText(cameraFrame,hand_text, Point(10, 75), FONT_HERSHEY_PLAIN, 2.0, Scalar(255, 0, 255),3);
imshow("camera", cameraFrame);
imshow("output", frameOut);
imshow("foreground", foreground);
imshow("handMask", handMask);
imshow("handDetection", fingerCountDebug);
int key = waitKey(1);
if (key == 98) // b, calibrate the background
backgroundRemover.calibrate(inputFrame);
else if (key == 115) // s, calibrate the skin color
skinDetector.calibrate(inputFrame);
return fingers_amount > 0;
}
void ObjectDetection::calculateDifference()
{
cap.read(img);
cap.read(img2);
cv::cvtColor(img, imgGray, cv::COLOR_RGBA2GRAY);
cv::cvtColor(img2, img2Gray, cv::COLOR_RGBA2GRAY);
cv::absdiff(imgGray, img2Gray, img3);
cv::threshold(img3, img4, 50, 170, cv::THRESH_BINARY);
imshow("threshold", img4);
}
cv::Mat ObjectDetection::generateHandMaskSquare(cv::Mat img)
{
handMaskStartXPos = 20;
handMaskStartYPos = img.rows / 5;
handMaskWidth = img.cols / 3;
handMaskHeight = img.cols / 3;
cv::Mat mask = cv::Mat::zeros(img.size(), img.type());
cv::Mat dstImg = cv::Mat::zeros(img.size(), img.type());
cv::rectangle(mask, Rect(handMaskStartXPos, handMaskStartYPos, handMaskWidth, handMaskHeight), Scalar(255, 255, 255), -1);
img.copyTo(dstImg, mask);
handMaskGenerated = true;
return dstImg;
}
bool ObjectDetection::drawHandMaskRect(cv::Mat* input)
{
if (!handMaskGenerated) return false;
rectangle(*input, Rect(handMaskStartXPos, handMaskStartYPos, handMaskWidth, handMaskHeight), Scalar(255, 255, 255));
return true;
}
void ObjectDetection::showWebcam()
{
imshow("Webcam image", img);
}
}

View File

@@ -1,72 +0,0 @@
#pragma once
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/objdetect.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
namespace computervision
{
class ObjectDetection
{
private:
public:
/**
* @brief default constructor of ObjectDetection
*
*/
ObjectDetection();
/**
* @brief Displays an image of the current webcam-footage
*
*/
void showWebcam();
/**
* @brief Calculates the difference between two images
* and outputs an image that only shows the difference
*
*/
void calculateDifference();
/**
* @brief generates the square that will hold the mask in which the hand will be detected.
*
* @param img the current camear frame
* @return a matrix containing the mask
*/
cv::Mat generateHandMaskSquare(cv::Mat img);
/**
* @brief reads the camera and returns it in a matrix.
*
* @return the camera frame in a matrix
*/
cv::Mat readCamera();
/**
* @brief detects a hand based on the given hand mask input frame.
*
* @param inputFrame the input frame from the camera
* @return true if hand is open, false if hand is closed
*/
bool detectHand(cv::Mat cameraFrame);
/**
* @brief draws the hand mask rectangle on the given input matrix.
*
* @param input the input matrix to draw the rectangle on
*/
bool drawHandMaskRect(cv::Mat *input);
};
}

View File

@@ -1,95 +0,0 @@
#include "OpenPoseVideo.h"
using namespace std;
using namespace cv;
using namespace cv::dnn;
namespace computervision
{
#define MPI
#ifdef MPI
const int POSE_PAIRS[7][2] =
{
{0,1}, {1,2}, {2,3},
{3,4}, {1,5}, {5,6},
{6,7}
};
string protoFile = "res/pose/mpi/pose_deploy_linevec_faster_4_stages.prototxt";
string weightsFile = "res/pose/mpi/pose_iter_160000.caffemodel";
int nPoints = 8;
#endif
#ifdef COCO
const int POSE_PAIRS[17][2] =
{
{1,2}, {1,5}, {2,3},
{3,4}, {5,6}, {6,7},
{1,8}, {8,9}, {9,10},
{1,11}, {11,12}, {12,13},
{1,0}, {0,14},
{14,16}, {0,15}, {15,17}
};
string protoFile = "pose/coco/pose_deploy_linevec.prototxt";
string weightsFile = "pose/coco/pose_iter_440000.caffemodel";
int nPoints = 18;
#endif
Net net;
void OpenPoseVideo::setup() {
net = readNetFromCaffe(protoFile, weightsFile);
}
void OpenPoseVideo::movementSkeleton(Mat inputImage) {
int inWidth = 368;
int inHeight = 368;
float thresh = 0.01;
Mat frame;
int frameWidth = inputImage.size().width;
int frameHeight = inputImage.size().height;
double t = (double)cv::getTickCount();
frame = inputImage;
Mat inpBlob = blobFromImage(frame, 1.0 / 255, Size(inWidth, inHeight), Scalar(0, 0, 0), false, false);
net.setInput(inpBlob);
Mat output = net.forward();
int H = output.size[2];
int W = output.size[3];
// find the position of the body parts
vector<Point> points(nPoints);
for (int n = 0; n < nPoints; n++)
{
// Probability map of corresponding body's part.
Mat probMap(H, W, CV_32F, output.ptr(0, n));
Point2f p(-1, -1);
Point maxLoc;
double prob;
minMaxLoc(probMap, 0, &prob, 0, &maxLoc);
if (prob > thresh)
{
p = maxLoc;
p.x *= (float)frameWidth / W;
p.y *= (float)frameHeight / H;
circle(frame, cv::Point((int)p.x, (int)p.y), 8, Scalar(0, 255, 255), -1);
cv::putText(frame, cv::format("%d", n), cv::Point((int)p.x, (int)p.y), cv::FONT_HERSHEY_COMPLEX, 1.1, cv::Scalar(0, 0, 255), 2);
}
points[n] = p;
}
imshow("Output-Keypoints", frame);
}
}

View File

@@ -1,19 +0,0 @@
#pragma once
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
using namespace cv;
namespace computervision
{
class OpenPoseVideo{
private:
public:
void movementSkeleton(Mat inputImage);
void setup();
};
}

View File

@@ -1,105 +0,0 @@
#include "SkinDetector.h"
/*
Author: Pierfrancesco Soffritti https://github.com/PierfrancescoSoffritti
*/
namespace computervision
{
SkinDetector::SkinDetector(void) {
hLowThreshold = 0;
hHighThreshold = 0;
sLowThreshold = 0;
sHighThreshold = 0;
vLowThreshold = 0;
vHighThreshold = 0;
calibrated = false;
skinColorSamplerRectangle1, skinColorSamplerRectangle2;
}
void SkinDetector::drawSkinColorSampler(Mat input) {
int frameWidth = input.size().width, frameHeight = input.size().height;
int rectangleSize = 25;
Scalar rectangleColor = Scalar(255, 0, 255);
skinColorSamplerRectangle1 = Rect(frameWidth / 5, frameHeight / 2, rectangleSize, rectangleSize);
skinColorSamplerRectangle2 = Rect(frameWidth / 5, frameHeight / 3, rectangleSize, rectangleSize);
rectangle(
input,
skinColorSamplerRectangle1,
rectangleColor
);
rectangle(
input,
skinColorSamplerRectangle2,
rectangleColor
);
}
void SkinDetector::calibrate(Mat input) {
Mat hsvInput;
cvtColor(input, hsvInput, CV_BGR2HSV);
Mat sample1 = Mat(hsvInput, skinColorSamplerRectangle1);
Mat sample2 = Mat(hsvInput, skinColorSamplerRectangle2);
calculateThresholds(sample1, sample2);
calibrated = true;
}
void SkinDetector::calculateThresholds(Mat sample1, Mat sample2) {
int offsetLowThreshold = 80;
int offsetHighThreshold = 30;
Scalar hsvMeansSample1 = mean(sample1);
Scalar hsvMeansSample2 = mean(sample2);
hLowThreshold = min(hsvMeansSample1[0], hsvMeansSample2[0]) - offsetLowThreshold;
hHighThreshold = max(hsvMeansSample1[0], hsvMeansSample2[0]) + offsetHighThreshold;
sLowThreshold = min(hsvMeansSample1[1], hsvMeansSample2[1]) - offsetLowThreshold;
sHighThreshold = max(hsvMeansSample1[1], hsvMeansSample2[1]) + offsetHighThreshold;
// the V channel shouldn't be used. By ignorint it, shadows on the hand wouldn't interfire with segmentation.
// Unfortunately there's a bug somewhere and not using the V channel causes some problem. This shouldn't be too hard to fix.
vLowThreshold = min(hsvMeansSample1[2], hsvMeansSample2[2]) - offsetLowThreshold;
vHighThreshold = max(hsvMeansSample1[2], hsvMeansSample2[2]) + offsetHighThreshold;
//vLowThreshold = 0;
//vHighThreshold = 255;
}
Mat SkinDetector::getSkinMask(Mat input) {
Mat skinMask;
if (!calibrated) {
skinMask = Mat::zeros(input.size(), CV_8UC1);
return skinMask;
}
Mat hsvInput;
cvtColor(input, hsvInput, CV_BGR2HSV);
inRange(
hsvInput,
Scalar(hLowThreshold, sLowThreshold, vLowThreshold),
Scalar(hHighThreshold, sHighThreshold, vHighThreshold),
skinMask);
performOpening(skinMask, MORPH_ELLIPSE, { 3, 3 });
dilate(skinMask, skinMask, Mat(), Point(-1, -1), 3);
return skinMask;
}
void SkinDetector::performOpening(Mat binaryImage, int kernelShape, Point kernelSize) {
Mat structuringElement = getStructuringElement(kernelShape, kernelSize);
morphologyEx(binaryImage, binaryImage, MORPH_OPEN, structuringElement);
}
}

View File

@@ -1,76 +0,0 @@
#pragma once
#include <opencv2\core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgproc/types_c.h>
/*
Author: Pierfrancesco Soffritti https://github.com/PierfrancescoSoffritti
*/
namespace computervision
{
using namespace cv;
using namespace std;
class SkinDetector {
public:
SkinDetector(void);
/*
* @brief draws the positions in where the skin color will be sampled.
*
* @param input the input matrix to sample the skin color from
*/
void drawSkinColorSampler(Mat input);
/*
* @brief calibrates the skin color detector with the given input frame
*
* @param input the input frame to calibrate from
*/
void calibrate(Mat input);
/*
* @brief gets the mask for the hand
*
* @param input the input matrix to get the skin mask from
* @returns the skin mask in a new matrix
*/
Mat getSkinMask(Mat input);
private:
// thresholds for hsv calculation
int hLowThreshold = 0;
int hHighThreshold = 0;
int sLowThreshold = 0;
int sHighThreshold = 0;
int vLowThreshold = 0;
int vHighThreshold = 0;
// wether or not the skindetector has calibrated yet.
bool calibrated = false;
// rectangles that get drawn to show where the skin color will be sampled
Rect skinColorSamplerRectangle1, skinColorSamplerRectangle2;
/*
* @brief calculates the skin tresholds for the given samples
*
* @param sample1 the first sample
* @param sample2 the second sample
*/
void calculateThresholds(Mat sample1, Mat sample2);
/**
* @brief the opening. it generates the structuring element and performs the morphological transformations required to detect the hand.
* This needs to be done to get the skin mask.
*
* @param binaryImage the matrix to perform the opening on. This needs to be a binary image, so consisting of only 1's and 0's.
* @param structuralElementShape the shape to use for the kernel that is used with generating the structuring element
* @param structuralElementSize the size of the kernel that will be used with generating the structuring element.
*/
void performOpening(Mat binaryImage, int structuralElementShape, Point structuralElementSize);
};
}

View File

@@ -9,24 +9,42 @@ namespace entities
void Camera::Move(GLFWwindow* window)
{
float movement_speed = 0;
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
{
position.z -= SPEED;
movement_speed -= SPEED;
}
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
{
position.z += SPEED;
movement_speed += SPEED;
}
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
{
position.x += SPEED;
rotation.y += ROT_SPEED;
}
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
{
position.x -= SPEED;
}
rotation.y -= ROT_SPEED;
}
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
{
rotation.x -= ROT_SPEED;
}
if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS)
{
rotation.x += ROT_SPEED;
}
float dx = glm::cos(glm::radians(rotation.y + 90)) * movement_speed;
float dz = glm::sin(glm::radians(rotation.y + 90)) * movement_speed;
position.x += dx;
position.z += dz;
}
}

View File

@@ -1,14 +1,20 @@
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/gtc/matrix_transform.hpp>
namespace entities
{
/*
* This class represents the viewport of the game. The whole game is seen through this class
*/
class Camera
{
private:
const float SPEED = 0.02f;
// The movement speed of the camera
const float SPEED = 0.52f;
const float ROT_SPEED = 1.0f;
glm::vec3 position;
glm::vec3 rotation;
@@ -16,6 +22,11 @@ namespace entities
public:
Camera(const ::glm::vec3& position, const ::glm::vec3& rotation);
/*
* @brief: This funtion moves the camera's position from the inputs of the keyboard
*
* @param window: The OpenGL window
*/
void Move(GLFWwindow* window);
inline glm::vec3 GetPosition() const{ return position; }

View File

@@ -5,6 +5,10 @@
namespace entities
{
/*
* This class represents a movable model in the game
*/
class Entity
{
private:
@@ -16,7 +20,18 @@ namespace entities
public:
Entity(const models::TexturedModel& model, const glm::vec3& position, const glm::vec3& rotation, float scale);
/*
* @brief: This function increases the position of the entity
*
* @param distance: The amount of distance in each axis the entity needs to move
*/
void IncreasePosition(const glm::vec3& distance);
/*
* @brief: This function increases the rotation of the entity
*
* @param rotation: The angle of each axis the entity needs to rotate
*/
void IncreaseRotation(const glm::vec3& rotation);
inline models::TexturedModel GetModel() const{return model;}

30
src/entities/light.h Normal file
View File

@@ -0,0 +1,30 @@
#pragma once
#include <glm/vec3.hpp>
namespace entities
{
/*
* This class represents a light in the game
*/
class Light
{
private:
glm::vec3 position;
glm::vec3 color;
glm::vec3 attenuation = { 1, 0, 0 };
public:
Light(const glm::vec3& position, const glm::vec3& color) : position(position), color(color) { }
Light(const glm::vec3& position, const glm::vec3& color, const glm::vec3& attenuation)
: position(position), color(color), attenuation(attenuation) { }
glm::vec3 GetPosition() const { return position; }
void setPosition(const glm::vec3& position) { this->position = position; }
glm::vec3 GetColor() const { return color; }
void setColor(const glm::vec3& color) { this->color = color; }
glm::vec3 GetAttenuation() const { return attenuation; }
void SetAttenuation(const glm::vec3& attenuation) { this->attenuation = attenuation; }
};
}

26
src/gui/gui_element.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#include <glm/gtc/matrix_transform.hpp>
#include "../toolbox/toolbox.h"
namespace gui
{
/*
* Structure for representing a gui item to display on the screen
*
* texture = The texture for the gui
* position = The center position of the gui
* scale = The size (scale) of the gui
*/
struct GuiTexture
{
int texture;
glm::vec2 position;
glm::vec2 scale;
GuiTexture(int texture, glm::vec2 position, glm::vec2 scale): texture(texture), position(position), scale(scale)
{
scale.x /= (WINDOW_WIDTH / WINDOW_HEIGT);
}
};
}

View File

@@ -0,0 +1,83 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "gui_interactable.h"
namespace gui
{
InteractableGui::InteractableGui(int default_texture, glm::vec2 position, glm::vec2 scale)
: GuiTexture(default_texture, position, scale)
{
this->default_texture = default_texture;
minXY = glm::vec2(position.x - scale.x, position.y - scale.y);
maxXY = glm::vec2(position.x + scale.x, position.y + scale.y);
}
void InteractableGui::Update(GLFWwindow* window)
{
if (IsHoveringAbove(window) && glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
{
if (clicked_texture != 0)
{
texture = clicked_texture;
}
else
{
texture = default_texture;
}
if (!is_clicking)
{
OnClick();
is_clicking = true;
}
}
else
{
if (is_clicking)
{
is_clicking = false;
}
}
}
bool InteractableGui::IsHoveringAbove(GLFWwindow* window)
{
double x_pos, y_pos;
glfwGetCursorPos(window, &x_pos, &y_pos);
const float x_rel = (x_pos / SCALED_WIDTH / DEFAULT_WIDTH) * 2.0f - 1.0f;
const float y_rel = -((y_pos / SCALED_HEIGHT / DEFAULT_HEIGHT) * 2.0f - 1.0f);
if (x_rel >= minXY.x && x_rel <= maxXY.x &&
y_rel >= minXY.y && y_rel <= maxXY.y)
{
if (hover_texture != 0)
{
texture = hover_texture;
}
else
{
texture = default_texture;
}
if (!is_hovering)
{
OnEnter();
is_hovering = true;
}
return true;
}
texture = default_texture;
if (is_hovering)
{
OnExit();
is_hovering = false;
}
return false;
}
}

112
src/gui/gui_interactable.h Normal file
View File

@@ -0,0 +1,112 @@
#pragma once
#include <glm/gtc/matrix_transform.hpp>
#include "../toolbox/toolbox.h"
#include "gui_element.h"
namespace gui
{
/*
* This class represents a gui item which can be interacted with
*/
class InteractableGui : public GuiTexture
{
private:
int default_texture;
int clicked_texture = 0;
int hover_texture = 0;
bool is_hovering = false;
bool is_clicking = false;
glm::vec2 minXY;
glm::vec2 maxXY;
public:
InteractableGui(int default_texture, glm::vec2 position, glm::vec2 scale);
/*
* @brief: Call this function every frame
*
* @param window: An openGL window
*/
void Update(GLFWwindow* window);
/*
* @brief: This function gets called when the InteractabeGui is clicked
*/
virtual void OnClick() = 0;
/*
* @brief: This function gets called when the mouse starts hovering above the InteractableGUI
*/
virtual void OnEnter() = 0;
/*
* @brief: This function gets called when the mouse stops hovering above the InteractableGUI
*/
virtual void OnExit() = 0;
/*
* @brief: This function sets the texture of the InteractableGUI for when the InteractableGUI is clicked
*/
void SetClickedTexture(int texture) { clicked_texture = texture; }
/*
* @brief: This function sets the texture of the InteractableGUI for when the mouse is hovering above the InteractableGUI
*/
void SetHoverTexture(int texture) { hover_texture = texture; }
private:
/*
* @brief: This function checks if the mouse is hovering above the InteractableGUI
*
* @param window: An openGL window
*
* @return: True or false
*/
bool IsHoveringAbove(GLFWwindow* window);
};
/*
* This class represents a button
*/
class Button : public InteractableGui
{
private:
void (*on_click_action)();
void (*on_enter_action)();
void (*on_exit_action)();
public:
Button(int default_texture, glm::vec2 position, glm::vec2 scale) : InteractableGui(default_texture, position, scale) {}
/*
* @brief: This function sets an action (function pointer) to the OnClick function
*
* @param fun: A function pointer to a function (or lambda)
*/
void SetOnClickAction(void (*fun)()) { on_click_action = fun; }
/*
* @brief: This function sets an action (function pointer) to the OnEnter function
*
* @param fun: A function pointer to a function (or lambda)
*/
void SetOnEnterAction(void (*fun)()) { on_enter_action = fun; }
/*
* @brief: This function sets an action (function pointer) to the OnExit function
*
* @param fun: A function pointer to a function (or lambda)
*/
void SetOnExitAction(void (*fun)()) { on_exit_action = fun; }
protected:
void OnClick() override { if (on_click_action != nullptr) on_click_action(); }
void OnEnter() override { if (on_enter_action != nullptr) on_enter_action(); }
void OnExit() override { if (on_exit_action != nullptr) on_exit_action(); }
};
}

View File

@@ -2,24 +2,24 @@
#include <GLFW/glfw3.h>
#include <glm/gtc/matrix_transform.hpp>
#define STB_IMAGE_IMPLEMENTATION
#include <iostream>
#include <map>
#include "stb_image.h"
#include <ostream>
#include <stdlib.h>
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/video.hpp>
#include "gui/gui_interactable.h"
#include "models/model.h"
#include "renderEngine/loader.h"
#include "renderEngine/obj_loader.h"
#include "renderEngine/renderer.h"
#include "shaders/static_shader.h"
#include "shaders/entity_shader.h"
#include "toolbox/toolbox.h"
#include "computervision/ObjectDetection.h"
//#include "computervision/OpenPoseImage.h"
#include "computervision/OpenPoseVideo.h"
#include "scenes/scene.h"
#include "scenes/in_Game_Scene.h"
#include "scenes/startup_Scene.h"
#pragma comment(lib, "glfw3.lib")
#pragma comment(lib, "glew32s.lib")
@@ -28,7 +28,7 @@
static double UpdateDelta();
static GLFWwindow* window;
scene::Scene* current_scene;
int main(void)
{
@@ -46,66 +46,51 @@ int main(void)
glGetError();
#pragma endregion
current_scene = new scene::Startup_Scene();
glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int scancode, int action, int mods)
{
current_scene->onKey(window, key, scancode, action, mods);
if (key == GLFW_KEY_ESCAPE)
glfwSetWindowShouldClose(window, true);
});
models::RawModel raw_model = LoadObjModel("res/Tree.obj");
models::ModelTexture texture = { render_engine::loader::LoadTexture("res/TreeTexture.png") };
models::TexturedModel model = { raw_model, texture };
entities::Entity entity(model, glm::vec3(0, -5, -20), glm::vec3(0, 0, 0), 1);
shaders::StaticShader shader;
shader.Init();
render_engine::renderer::Init(shader);
entities::Camera camera(glm::vec3(0, 0, 0), glm::vec3(0, 0, 0));
// create object detection object instance
computervision::ObjectDetection objDetect;
//computervision::OpenPoseImage openPoseImage;
computervision::OpenPoseVideo openPoseVideo;
// set up object detection
//objDetect.setup();
cv::Mat cameraFrame;
openPoseVideo.setup();
bool window_open = true;
// Main game loop
while (!glfwWindowShouldClose(window))
while (!glfwWindowShouldClose(window) && window_open)
{
//Update
const double delta = UpdateDelta();
entity.IncreaseRotation(glm::vec3(0, 1, 0));
camera.Move(window);
// Render
render_engine::renderer::Prepare();
shader.Start();
shader.LoadViewMatrix(camera);
scene::Scenes return_value = current_scene->start(window);
delete current_scene;
switch (return_value) {
case scene::Scenes::STOP:
window_open = false;
break;
render_engine::renderer::Render(entity, shader);
case scene::Scenes::STARTUP:
current_scene = new scene::Startup_Scene();
break;
cameraFrame = objDetect.readCamera();
//objDetect.detectHand(cameraFrame);
openPoseVideo.movementSkeleton(cameraFrame);
case scene::Scenes::INGAME:
current_scene = new scene::In_Game_Scene();
break;
// Finish up
shader.Stop();
glfwSwapBuffers(window);
glfwPollEvents();
default:
std::cout << "Wrong return value!!! ->" << std::endl;
break;
}
}
// Clean up
shader.CleanUp();
render_engine::loader::CleanUp();
// Clean up -> preventing memory leaks!!!
std::cout << "ending..." << std::endl;
delete current_scene;
glfwTerminate();
return 0;
}

View File

@@ -5,24 +5,31 @@
namespace models
{
/*
Structure for storing a vboID and vertex_count.
Structure for storing a vboID and vertex_count (this representa a mesh without a model).
This structure represents a Bare bones Model (A mesh without a texture).
The vao_id, points to an ID stored by openGL and the
vertex_count is how many triangles in the mesh there are.
vao_id = The openGL id of the model
vertex_count = The amount of vertices in the model
model_size = The size on each axis of the model
*/
struct RawModel
{
GLuint vao_id;
int vertex_count;
glm::vec3 model_size = { -1, -1, -1 };
};
/*
Structure for storing a texture (texture_id) to apply to a RawModel.
texture_id = The openGL id of the textures
shine_damper = A damper for the angle the model needs to be look at to see reflections
reflectivity = The amount of light the model reflects
*/
struct ModelTexture
{
GLuint texture_id;
float shine_damper = 1;
float reflectivity = 0;
};
/*

View File

@@ -1,7 +1,10 @@
#include <GL/glew.h>
#include <glm/vec3.hpp>
#include "../stb_image.h"
#include "loader.h"
#include <iostream>
namespace render_engine
{
namespace loader
@@ -9,22 +12,38 @@ namespace render_engine
static GLuint CreateVao();
static void StoreDataInAttributeList(int attribute_number, int coordinate_size, std::vector<float>& data);
static void BindIndicesBuffer(std::vector<unsigned int>& indices);
static glm::vec3 GetSizeModel(std::vector<float>& positions);
static std::vector<GLuint> vaos;
static std::vector<GLuint> vbos;
static std::vector<GLuint> textures;
/*
This function will generate a Model from vertex positions, textureCoordinates and indices.
This function will generate a Model from vertex positions, textureCoordinates normals and indices.
*/
struct models::RawModel LoadToVAO(std::vector<float>& positions, std::vector<float>& texture_coords, std::vector<unsigned int>& indices)
models::RawModel LoadToVAO(std::vector<float>& positions, std::vector<float>& texture_coords, std::vector<float>& normals, std::vector<unsigned int>& indices)
{
GLuint vao_id = CreateVao();
const GLuint vao_id = CreateVao();
BindIndicesBuffer(indices);
StoreDataInAttributeList(0, 3, positions);
StoreDataInAttributeList(1, 2, texture_coords);
StoreDataInAttributeList(2, 3, normals);
glBindVertexArray(0);
return { vao_id, static_cast<int>(indices.size()) };
const glm::vec3 model_size = GetSizeModel(positions);
return { vao_id, static_cast<int>(indices.size()), model_size };
}
/*
This function will generate a Model from vertex positions.
*/
models::RawModel LoadToVAO(std::vector<float>& positions)
{
const GLuint vao_id = CreateVao();
StoreDataInAttributeList(0, 2, positions);
glBindVertexArray(0);
return { vao_id, static_cast<int>(positions.size()) / 2 };
}
/*
@@ -40,6 +59,12 @@ namespace render_engine
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture_id);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imgData);
// Set mipmapping with a constant LOD
glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.4f);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -113,5 +138,72 @@ namespace render_engine
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_id);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * indices.size(), &indices[0], GL_STATIC_DRAW);
}
/**
* @brief gets the width, height and depth of a model
* @param positions all the points of a model
* @returns vec3<float> the size values of a model (width, height and depth)
**/
static glm::vec3 GetSizeModel(std::vector<float>& positions)
{
float minX = 100;
float maxX = -100;
float minY = 100;
float maxY = -100;
float minZ = 100;
float maxZ = -100;
for (int i = 0; i < positions.size(); ++i)
{
const int index = i % 3;
const float value = positions[i];
switch (index)
{
case 0: // x
{
if (value < minX)
{
minX = value;
} else if (value > maxX)
{
maxX = value;
}
break;
}
case 1: // y
{
if (value < minY)
{
minY = value;
}
else if (value > maxY)
{
maxY = value;
}
break;
}
case 2: // z
{
if (value < minZ)
{
minZ = value;
}
else if (value > maxZ)
{
maxZ = value;
}
break;
}
}
}
const float sizeX = maxX - minX;
const float sizeY = maxY - minY;
const float sizeZ = maxZ - minZ;
return { sizeX, sizeY, sizeZ };
}
}
}

View File

@@ -9,17 +9,36 @@ namespace render_engine
namespace loader
{
/*
This function generates a model from model data.
* @brief: This function generates a model from model data.
*
* @param position: The positions of each vertex (in order: x, y, z) in the model
* @param texture_coords: The texture coordinates of the model
* @param normals: The normals of each face of the model
* @param indices: A list with a sort of lookup table to the positions parameter
*
* @return: A new rawmodel which represents al the parameters in one struct
*/
struct models::RawModel LoadToVAO(std::vector<float>& positions, std::vector<float>& texture_coords, std::vector<unsigned int>& indices);
models::RawModel LoadToVAO(std::vector<float>& positions, std::vector<float>& texture_coords, std::vector<float>& normals, std::vector<unsigned int>& indices);
/*
Loads a texture from a file into openGL using stb_image.h
* @brief: Overloaded function of the function above, but does not need normals and indices.
* Use this function to for example load GUI items to OpenGL.
*
* @param position: The positions of each vertex (in order: x, y, z) in the model
*
* @return: A new rawmodel which represents al the parameters in one struct
*/
models::RawModel LoadToVAO(std::vector<float>& positions);
/*
* @brief: Loads a texture from a file into openGL using stb_image.h
*
* @param file_name: The filepath to the texture
*/
GLuint LoadTexture(std::string file_name);
/*
Call this function when cleaning up all the meshes (when exiting the program).
* @brief: Call this function when cleaning up all the meshes (when exiting the program).
*/
void CleanUp();
}

View File

@@ -1,8 +1,11 @@
#include <GL/glew.h>
#include <glm/gtc/matrix_transform.hpp>
#include "../models/model.h"
#include "renderer.h"
#include "loader.h"
#include "../toolbox/toolbox.h"
#include "renderer.h"
#include <iostream>
namespace render_engine
{
@@ -12,17 +15,27 @@ namespace render_engine
static const float NEAR_PLANE = 0.01f;
static const float FAR_PLANE = 1000.0f;
/*
This function will load the projectionMatrix into the shader
*/
void Init(shaders::StaticShader& shader)
{
const glm::mat4 projectionMatrix =
glm::perspective(glm::radians(FOV), (float)(WINDOW_WIDTH / WINDOW_HEIGT), NEAR_PLANE, FAR_PLANE);
// GUI variables
static models::RawModel quad;
void Init(shaders::EntityShader& shader)
{
// Faces which are not facing the camera are not rendered
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
const glm::mat4 projectionMatrix =
glm::perspective(glm::radians(FOV), (WINDOW_WIDTH / WINDOW_HEIGT), NEAR_PLANE, FAR_PLANE);
// Load the projectionmatrix into the shader
shader.Start();
shader.LoadProjectionMatrix(projectionMatrix);
shader.Stop();
// Initialize the quad for the GUI
std::vector<float> quad_positions = { -1, 1, -1, -1, 1, 1, 1, -1 };
quad = loader::LoadToVAO(quad_positions);
}
/*
@@ -32,36 +45,82 @@ namespace render_engine
{
glEnable(GL_DEPTH_TEST);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.3f, 0.4f, 0.6f, 1.0f);
glClearColor(SKY_COLOR.r, SKY_COLOR.g, SKY_COLOR.b, 1.0f);
}
/*
This function will Render a Model on the screen.
*/
void Render(entities::Entity& entity, shaders::StaticShader& shader)
void Render(entities::Entity& entity, shaders::EntityShader& shader)
{
const models::TexturedModel model = entity.GetModel();
const models::RawModel rawModel = model.raw_model;
const models::RawModel raw_model = model.raw_model;
const models::ModelTexture texture = model.texture;
// Enable the model
glBindVertexArray(rawModel.vao_id);
// Enable the model (VAO)
glBindVertexArray(raw_model.vao_id);
// Enable the inputs for the vertexShader
// Enable the VBO's from the model (VAO)
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
// Load the transformation of the model into the shader
const glm::mat4 modelMatrix = toolbox::CreateModelMatrix(entity.GetPosition(), entity.GetRotation(), entity.GetScale());
shader.LoadModelMatrix(modelMatrix);
shader.LoadShineVariables(texture.shine_damper, texture.reflectivity);
// Draw the model
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, model.texture.texture_id);
glDrawElements(GL_TRIANGLES, rawModel.vertex_count, GL_UNSIGNED_INT, 0);
glDrawElements(GL_TRIANGLES, raw_model.vertex_count, GL_UNSIGNED_INT, 0);
// Disable the VBO's and model (VAO)
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glDisableVertexAttribArray(2);
glBindVertexArray(0);
}
void Render(std::vector<gui::GuiTexture*>& guis, shaders::GuiShader& shader)
{
shader.Start();
// Enable the VAO and the positions VBO
glBindVertexArray(quad.vao_id);
glEnableVertexAttribArray(0);
// Enable alpha blending (for transparency in the texture)
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// Disable depth testing to textures with transparency can overlap
glDisable(GL_DEPTH_TEST);
// Render each gui to the screen
for (gui::GuiTexture* gui : guis)
{
// Bind the texture of the gui to the shader
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gui->texture);
glm::mat4 matrix = toolbox::CreateModelMatrix(gui->position, gui->scale);
shader.LoadModelMatrix(matrix);
glDrawArrays(GL_TRIANGLE_STRIP, 0, quad.vertex_count);
}
// Enable depth test again
glEnable(GL_DEPTH_TEST);
// Disable alpha blending
glDisable(GL_BLEND);
// Disable the VBO and VAO
glDisableVertexAttribArray(0);
glBindVertexArray(0);
shader.Stop();
}
}
}

View File

@@ -1,25 +1,43 @@
#pragma once
#include "../gui/gui_element.h"
#include "../entities/entity.h"
#include "../shaders/static_shader.h"
#include "../shaders/entity_shader.h"
#include "../shaders/gui_shader.h"
namespace render_engine
{
namespace renderer
{
/*
Call this function when starting the program
*/
void Init(shaders::StaticShader& shader);
const glm::vec3 SKY_COLOR = { 0.3f, 0.4f, 0.6f };
/*
Call this function before rendering.
@brief: Call this function when starting the program
@param shader: The shader to render the entities with
*/
void Init(shaders::EntityShader& shader);
/*
@brief: Call this function before rendering.
This function will enable culling and load the projectionMatrix into the shader.
*/
void Prepare();
/*
Call this function when wanting to Render a mesh to the screen.
@brief: Call this function when wanting to Render a mesh to the screen.
@param entity: The entity which needs to be rendered
@param shader: The shader the entity needs to be rendered with
*/
void Render(entities::Entity& entity, shaders::StaticShader& shader);
void Render(entities::Entity& entity, shaders::EntityShader& shader);
/*
@brief: Call this function to render gui_textures on the screen
@param guis: A list with all the GUI textures you want to render
@param shade: The shader the GUI textures need to be rendered with
*/
void Render(std::vector<gui::GuiTexture*>& guis, shaders::GuiShader& shader);
}
}

View File

@@ -6,6 +6,8 @@
#include "loader.h"
#include "obj_loader.h"
namespace render_engine
{
static void Split(const std::string& s, char delim, std::vector<std::string>& elems)
{
std::stringstream ss;
@@ -109,7 +111,8 @@ models::RawModel LoadObjModel(std::string file_name)
break;
}
}
} catch (const std::exception& e)
}
catch (const std::exception& e)
{
// Always go in here
}
@@ -125,5 +128,6 @@ models::RawModel LoadObjModel(std::string file_name)
vertex_array[p++] = vertex.z;
}
return render_engine::loader::LoadToVAO( vertex_array, texture_array, indices);
return render_engine::loader::LoadToVAO(vertex_array, texture_array, normal_array, indices);
}
}

View File

@@ -3,4 +3,12 @@
#include <string>
#include "../models/model.h"
namespace render_engine
{
/*
* @brief: This function retrieves an .obj file, loads it into the VBO and returns a RawModel
*
* @param file_name: The path to the .obj file
*/
models::RawModel LoadObjModel(std::string file_name);
}

View File

@@ -0,0 +1,118 @@
#include <iostream>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "in_Game_Scene.h"
#include "startup_Scene.h"
#include "../gui/gui_interactable.h"
#include "../models/model.h"
#include "../renderEngine/loader.h"
#include "../renderEngine/obj_loader.h"
#include "../renderEngine/renderer.h"
#include "../shaders/entity_shader.h"
#include "../toolbox/toolbox.h"
namespace scene
{
std::vector<entities::Entity> entities;
std::vector<entities::Light> lights;
models::RawModel raw_model;
models::ModelTexture texture;
shaders::EntityShader *shader;
shaders::GuiShader *gui_shader;
entities::Camera camera(glm::vec3(0, 0, 0), glm::vec3(0, 0, 0));
std::vector<gui::GuiTexture*> guis;
In_Game_Scene::In_Game_Scene()
{
shader = new shaders::EntityShader;
shader->Init();
render_engine::renderer::Init(*shader);
gui_shader = new shaders::GuiShader();
gui_shader->Init();
}
scene::Scenes scene::In_Game_Scene::start(GLFWwindow* window)
{
raw_model = render_engine::LoadObjModel("res/House.obj");
texture = { render_engine::loader::LoadTexture("res/Texture.png") };
texture.shine_damper = 10;
texture.reflectivity = 0;
models::TexturedModel model = { raw_model, texture };
int z = 0;
for (int i = 0; i < 5; ++i)
{
entities.push_back(entities::Entity(model, glm::vec3(0, -50, -50 - z), glm::vec3(0, 90, 0), 20));
z += (raw_model.model_size.x * 20);
}
lights.push_back(entities::Light(glm::vec3(0, 1000, -7000), glm::vec3(5, 5, 5)));
lights.push_back(entities::Light(glm::vec3(0, 0, -30), glm::vec3(2, 0, 2), glm::vec3(0.0001f, 0.0001f, 0.0001f)));
lights.push_back(entities::Light(glm::vec3(0, 0, -200), glm::vec3(0, 2, 0), glm::vec3(0.0001f, 0.0001f, 0.0001f)));
// GUI stuff
gui::Button button(render_engine::loader::LoadTexture("res/Mayo.png"), glm::vec2(0.5f, 0.0f), glm::vec2(0.25f, 0.25f));
button.SetHoverTexture(render_engine::loader::LoadTexture("res/Texture.png"));
button.SetClickedTexture(render_engine::loader::LoadTexture("res/Mayo.png"));
button.SetOnClickAction([]()
{
std::cout << "I got clicked on!" << std::endl;
});
guis.push_back(&button);
while (return_value == scene::Scenes::INGAME)
{
update(window);
button.Update(window);
render();
glfwSwapBuffers(window);
glfwPollEvents();
}
shader->CleanUp();
gui_shader->CleanUp();
render_engine::loader::CleanUp();
return return_value;
}
void scene::In_Game_Scene::render()
{
// Render
render_engine::renderer::Prepare();
shader->Start();
shader->LoadSkyColor(render_engine::renderer::SKY_COLOR);
shader->LoadLights(lights);
shader->LoadViewMatrix(camera);
// Renders each entity in the entities list
for (entities::Entity& entity : entities)
{
render_engine::renderer::Render(entity, *shader);
}
// Render GUI items
render_engine::renderer::Render(guis, *gui_shader);
// Stop rendering the entities
shader->Stop();
}
void scene::In_Game_Scene::update(GLFWwindow* window)
{
camera.Move(window);
}
void scene::In_Game_Scene::onKey(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
{
return_value = scene::Scenes::STOP;
}
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "scene.h"
namespace scene
{
class In_Game_Scene : public scene::Scene
{
private:
scene::Scenes return_value = scene::Scenes::INGAME;
public:
In_Game_Scene();
Scenes start(GLFWwindow* window) override;
void render() override;
void update(GLFWwindow* window) override;
void onKey(GLFWwindow* window, int key, int scancode, int action, int mods) override;
};
}

7
src/scenes/scene.cpp Normal file
View File

@@ -0,0 +1,7 @@
#include "scene.h"
namespace scene
{
}

31
src/scenes/scene.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <map>
namespace scene {
enum class Scenes
{
STARTUP,
INGAME,
GAMEOVER,
CALIBRATION,
STOP
};
class Scene
{
public:
virtual Scenes start(GLFWwindow* window) = 0;
virtual void render() = 0;
virtual void update(GLFWwindow* window) = 0;
virtual void onKey(GLFWwindow* window, int key, int scancode, int action, int mods) {};
};
}

View File

@@ -0,0 +1,40 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <map>
#include "startup_Scene.h"
namespace scene
{
scene::Scenes scene::Startup_Scene::start(GLFWwindow *window)
{
while (return_value == scene::Scenes::STARTUP)
{
render();
update(window);
glfwSwapBuffers(window);
glfwPollEvents();
}
return return_value;
}
void scene::Startup_Scene::render()
{
}
void scene::Startup_Scene::update(GLFWwindow* window)
{
}
void scene::Startup_Scene::onKey(GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS)
{
return_value = scene::Scenes::INGAME;
}
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include "scene.h"
#include <map>
namespace scene
{
extern GLFWwindow* window;
class Startup_Scene : public scene::Scene
{
private:
scene::Scenes return_value = scene::Scenes::STARTUP;
public:
Scenes start(GLFWwindow* window) override;
void render() override;
void update(GLFWwindow* window) override;
void onKey(GLFWwindow* window, int key, int scancode, int action, int mods) override;
};
}

View File

@@ -0,0 +1,204 @@
#include "entity_shader.h"
#include "../toolbox/toolbox.h"
namespace shaders
{
static std::string vertex_shader = R"(
#version 400 core
// The VertexShader is run for each vertex on the screen.
// Position of the vertex
in vec3 position;
// Coordinates of the texture
in vec2 texture_coords;
// The normal of the vertex
in vec3 normal;
// Equal to the texture_coords
out vec2 pass_texture_coords;
out vec3 surface_normal;
out vec3 to_light_vector[4];
out vec3 to_camera_vector;
out float visibility;
uniform mat4 model_matrix;
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
uniform vec3 light_position[4];
const float density = 0.0017;
const float gradient = 4;
void main(void)
{
// Calculate the real position of the vertex (after rotation and scaling)
vec4 world_position = model_matrix * vec4(position, 1.0);
vec4 position_rel_to_cam = view_matrix * world_position;
// Tell OpenGL where to render the vertex
gl_Position = projection_matrix * position_rel_to_cam;
// Pass the textureCoords directly to the fragment shader
pass_texture_coords = texture_coords;
surface_normal = (model_matrix * vec4(normal, 0.0)).xyz;
for (int i = 0; i < 4; i++)
{
to_light_vector[i] = light_position[i] - world_position.xyz;
}
to_camera_vector = (inverse(view_matrix) * vec4(0.0, 0.0, 0.0, 1.0)).xyz - world_position.xyz;
// Calculate the density/visibility of the vertex with the fog
float distance = length(position_rel_to_cam.xyz);
visibility = exp(-pow((distance * density), gradient));
visibility = clamp(visibility, 0.0, 1.0);
}
)";
static std::string fragment_shader = R"(
#version 400 core
// The FragmentShader is run for each pixel in a face on the screen.
// Interpolated textureCoordinates of the vertex (relative to the distance to each vertex)
in vec2 pass_texture_coords;
in vec3 surface_normal;
in vec3 to_light_vector[4];
in vec3 to_camera_vector;
in float visibility;
// Final color of the pixel
out vec4 out_color;
// The texture of the model
uniform sampler2D model_texture;
uniform vec3 light_color[4];
uniform vec3 attenuation[4];
uniform float shine_damper;
uniform float reflectivity;
uniform vec3 sky_color;
const float min_diffuse_lighting = 0.1;
void main(void)
{
vec3 unit_normal = normalize(surface_normal);
vec3 unit_camera_vector = normalize(to_camera_vector);
vec3 total_diffuse = vec3(0.0);
vec3 total_specular = vec3(0.0);
for (int i = 0; i < 4; i++)
{
float distance = length(to_light_vector[i]);
float att_factor = attenuation[i].x + (attenuation[i].y * distance) + (attenuation[i].z * distance * distance);
vec3 unit_light_vector = normalize(to_light_vector[i]);
// Calculate the diffuse lighting
float dot_diffuse = dot(unit_normal, unit_light_vector);
float brightness = max(dot_diffuse, 0.0);
// Calculate the specular lighting
vec3 light_direction = -unit_light_vector;
vec3 reflected_light_direction = reflect(light_direction, unit_normal);
float dot_specular = dot(reflected_light_direction, unit_camera_vector);
dot_specular = max(dot_specular, 0.0);
float damped_specular = pow(dot_specular, shine_damper);
total_diffuse = total_diffuse + (brightness * light_color[i]) / att_factor;
total_specular = total_specular + (damped_specular * reflectivity * light_color[i]) / att_factor;
}
total_diffuse = max(total_diffuse, min_diffuse_lighting);
out_color = vec4(total_diffuse, 1.0) * texture(model_texture, pass_texture_coords) + vec4(total_specular, 1.0);
out_color = mix(vec4(sky_color, 1.0), out_color, visibility);
}
)";
EntityShader::EntityShader(): ShaderProgram(vertex_shader, fragment_shader)
{ }
void EntityShader::LoadModelMatrix(const glm::mat4& matrix) const
{
LoadMatrix(location_model_matrix, matrix);
}
void EntityShader::LoadProjectionMatrix(const glm::mat4& projection) const
{
LoadMatrix(location_projection_matrix, projection);
}
void EntityShader::LoadViewMatrix(entities::Camera& camera) const
{
const glm::mat4 view_matrix = toolbox::CreateViewMatrix(camera);
LoadMatrix(location_view_matrix, view_matrix);
}
void EntityShader::LoadLights(std::vector<entities::Light>& lights) const
{
for (int i = 0; i < MAX_LIGHTS; ++i)
{
if (i < lights.size())
{
LoadVector(location_light_position[i], lights[i].GetPosition());
LoadVector(location_light_color[i], lights[i].GetColor());
LoadVector(location_light_attenuation[i], lights[i].GetAttenuation());
} else
{
LoadVector(location_light_position[i], glm::vec3(0, 0, 0));
LoadVector(location_light_color[i], glm::vec3(0, 0, 0));
LoadVector(location_light_attenuation[i], glm::vec3(1, 0, 0));
}
}
}
void EntityShader::LoadShineVariables(float shine_damper, float reflectivity) const
{
LoadFloat(location_shine_damper, shine_damper);
LoadFloat(location_reflectivity, reflectivity);
}
void EntityShader::LoadSkyColor(glm::vec3 sky_color) const
{
LoadVector(location_sky_color, sky_color);
}
void EntityShader::SetAttributes() const
{
// Load the position VBO and textureCoords VBO from the VAO into the shader "in" variables
SetAttribute(0, "position");
SetAttribute(1, "texture_coords");
SetAttribute(2, "normal");
}
void EntityShader::GetAllUniformLocations()
{
// Get the locations from the uniform variables from the shaders
location_model_matrix = GetUniformLocation("model_matrix");
location_projection_matrix = GetUniformLocation("projection_matrix");
location_view_matrix = GetUniformLocation("view_matrix");
location_shine_damper = GetUniformLocation("shine_damper");
location_reflectivity = GetUniformLocation("reflectivity");
location_sky_color = GetUniformLocation("sky_color");
for (int i = 0; i < MAX_LIGHTS; ++i)
{
std::string light_pos = std::string("light_position[") + std::to_string(i) + "]";
location_light_position[i] = GetUniformLocation(light_pos.c_str());
std::string light_color = std::string("light_color[") + std::to_string(i) + "]";
location_light_color[i] = GetUniformLocation(light_color.c_str());
std::string light_attenuation = std::string("attenuation[") + std::to_string(i) + "]";
location_light_attenuation[i] = GetUniformLocation(light_attenuation.c_str());
}
}
}

View File

@@ -0,0 +1,80 @@
#pragma once
#include <glm/gtc/matrix_transform.hpp>
#include <vector>
#include "shader_program.h"
#include "../entities/camera.h"
#include "../entities/light.h"
/*
This class handles the shaders for the entities.
*/
namespace shaders
{
class EntityShader : public ShaderProgram
{
private:
const static int MAX_LIGHTS = 4;
GLuint location_model_matrix;
GLuint location_projection_matrix;
GLuint location_view_matrix;
GLuint location_light_position[MAX_LIGHTS];
GLuint location_light_color[MAX_LIGHTS];
GLuint location_light_attenuation[MAX_LIGHTS];
GLuint location_shine_damper;
GLuint location_reflectivity;
GLuint location_sky_color;
public:
EntityShader();
/*
* @brief: A method to load the model matrix into the shader
*
* @param matrix: The model matrix
*/
void LoadModelMatrix(const glm::mat4& matrix) const;
/*
* @brief: A method to load the projection matrix into the shader
*
* @param projection: The projection matrix
*/
void LoadProjectionMatrix(const glm::mat4& projection) const;
/*
* @brief: A method to load the view matrix (camera) into the shader
*
* @param camera: The camera which the scene needs to be rendered from
*/
void LoadViewMatrix(entities::Camera& camera) const;
/*
* @brief: A method to load some lights into the shader
*
* @param lights: The lights
*/
void LoadLights(std::vector<entities::Light>& lights) const;
/*
* @brief: A method to load the the shine variables from a model into the shader
*
* @param shine_damper: The dampening of the angle from when to render reflectivity on the vertex
* @param reflectivity: The amount the model reflects
*/
void LoadShineVariables(float shine_damper, float reflectivity) const;
/*
* @brief: A method to load the sky color into the shader. This color will be used for the fog
*
* @param sky_color: The color of the sky
*/
void LoadSkyColor(glm::vec3 sky_color) const;
protected:
void SetAttributes() const override;
void GetAllUniformLocations() override;
};
}

View File

@@ -0,0 +1,57 @@
#include "gui_shader.h"
namespace shaders
{
static std::string vertex_shader = R"(
#version 140
in vec2 position;
out vec2 texture_coords;
uniform mat4 model_matrix;
void main(void)
{
gl_Position = model_matrix * vec4(position, 0.0, 1.0);
// This makes top left corner coordinate (0, 0) and bottom right (1, 1)
texture_coords = vec2((position.x + 1.0) / 2.0, 1 - (position.y + 1.0) / 2.0);
}
)";
static std::string fragment_shader = R"(
#version 140
in vec2 texture_coords;
out vec4 out_color;
uniform sampler2D gui_texture;
void main(void)
{
out_color = texture(gui_texture, texture_coords);
}
)";
GuiShader::GuiShader() : ShaderProgram(vertex_shader, fragment_shader)
{ }
void GuiShader::LoadModelMatrix(const glm::mat4& matrix) const
{
LoadMatrix(location_model_matrix, matrix);
}
void GuiShader::SetAttributes() const
{
SetAttribute(0, "position");
}
void GuiShader::GetAllUniformLocations()
{
location_model_matrix = GetUniformLocation("model_matrix");
}
}

31
src/shaders/gui_shader.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
#include <glm/gtc/matrix_transform.hpp>
#include "shader_program.h"
namespace shaders
{
/*
* This class handles the shaders for all the GUI items
*/
class GuiShader : public ShaderProgram
{
private:
GLuint location_model_matrix;
public:
GuiShader();
/*
* @brief: A method to load the model matrix into the shader
*
* @param matrix: The model matrix
*/
void LoadModelMatrix(const glm::mat4& matrix) const;
protected:
void SetAttributes() const override;
void GetAllUniformLocations() override;
};
}

View File

@@ -1,4 +1,5 @@
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <iostream>
#include <fstream>
#include <vector>

View File

@@ -21,29 +21,87 @@ namespace shaders
ShaderProgram(std::string& vertex_shader, std::string& fragment_shader);
virtual ~ShaderProgram() = default;
// Call this function after making the shaderprogram (sets all the attributes of the shader)
/*
* @brief: Call this function after making the shaderprogram (sets all the attributes of the shader)
*/
void Init();
// Call this function before rendering
/*
* @brief: Call this function before rendering
*/
void Start() const;
// Call this function after rendering
/*
* @brief: Call this function after rendering
*/
void Stop() const;
// Call this function when closing the application
/*
* @brief: Call this function when closing the application
*/
void CleanUp() const;
protected:
// Set the inputs of the vertex shader
/*
* @brief: Set the inputs of the vertex shader
*/
virtual void SetAttributes() const = 0;
/*
* @brief: Sets/binds a input variable (in) to a VBO from the model
*
* @param attribute: The id of the VBO
* @param variable_name: The name of the "in" variable in the shader
*/
void SetAttribute(const GLuint attribute, const char* variable_name) const;
// Loads value's (uniform variables) into the shader
/*
* @brief: This function loads a float value into a uniform variable into the shader
*
* @param location: The location of the variable in openGL
* @param value: The value which will be loaded into the variable
*/
void LoadFloat(GLuint location, GLfloat value) const;
/*
* @brief: This function loads a vector value into a uniform variable into the shader
*
* @param location: The location of the variable in openGL
* @param vector: The value which will be loaded into the variable
*/
void LoadVector(GLuint location, glm::vec3 vector) const;
/*
* @brief: This function loads a 4x4 matrix value into a uniform variable into the shader
*
* @param location: The location of the variable in openGL
* @param matrix: The value which will be loaded into the variable
*/
void LoadMatrix(GLuint location, glm::mat4 matrix) const;
/*
* @brief: This function will get all the locations of each uniform variable
*/
virtual void GetAllUniformLocations() = 0;
/*
* @brief: This function will retrieve the location of a uniform variable
*
* @param uniform_name: The name of the uniform variable
*
* @return: The location of the uniform variable
*/
GLuint GetUniformLocation(const GLchar* uniform_name) const;
private:
/*
* @brief: This function will load a shader into openGL
*
* @param shader_string: The shader as a string (the whole code)
* @param type: The type of the shader (Vertex/Fragment)
*
* @return: The id of the shader given by openGL
*/
GLuint LoadShader(const std::string& shader_string, GLuint type) const;
};
}

View File

@@ -1,87 +0,0 @@
#include "static_shader.h"
#include "../toolbox/toolbox.h"
namespace shaders
{
static std::string vertex_shader = R"(
#version 400 core
// The VertexShader is run for each vertex on the screen.
// Position of the vertex
in vec3 position;
// Coordinates of the texture
in vec2 texture_coords;
// Equal to the texture_coords
out vec2 pass_texture_coords;
uniform mat4 model_matrix;
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
void main(void)
{
// Tell OpenGL where to render the vertex
gl_Position = projection_matrix * view_matrix * model_matrix * vec4(position, 1.0);
// Pass the texture_coords directly to the fragment shader
pass_texture_coords = texture_coords;
}
)";
static std::string fragment_shader = R"(
#version 400 core
// The FragmentShader is run for each pixel in a face on the screen.
// Interpolated textureCoordinates of the vertex (relative to the distance to each vertex)
in vec2 pass_texture_coords;
// Final color of the pixel
out vec4 out_color;
// The texture of the model
uniform sampler2D texture_sampler;
void main(void)
{
out_color = texture(texture_sampler, pass_texture_coords);
}
)";
StaticShader::StaticShader(): ShaderProgram(vertex_shader, fragment_shader)
{
}
void StaticShader::LoadModelMatrix(const glm::mat4& matrix) const
{
LoadMatrix(location_model_matrix, matrix);
}
void StaticShader::LoadProjectionMatrix(const glm::mat4& projection) const
{
LoadMatrix(location_projection_matrix, projection);
}
void StaticShader::LoadViewMatrix(entities::Camera& camera) const
{
const glm::mat4 view_matrix = toolbox::CreateViewMatrix(camera);
LoadMatrix(location_view_matrix, view_matrix);
}
void StaticShader::SetAttributes() const
{
SetAttribute(0, "position");
SetAttribute(1, "texture_coords");
}
void StaticShader::GetAllUniformLocations()
{
location_model_matrix = GetUniformLocation("model_matrix");
location_projection_matrix = GetUniformLocation("projection_matrix");
location_view_matrix = GetUniformLocation("view_matrix");
}
}

View File

@@ -1,31 +0,0 @@
#pragma once
#include <glm/gtc/matrix_transform.hpp>
#include "shader_program.h"
#include "../entities/camera.h"
/*
This class does represents the shaders for the models.
*/
namespace shaders
{
class StaticShader : public ShaderProgram
{
private:
GLuint location_model_matrix;
GLuint location_projection_matrix;
GLuint location_view_matrix;
public:
StaticShader();
void LoadModelMatrix(const glm::mat4& matrix) const;
void LoadProjectionMatrix(const glm::mat4& projection) const;
void LoadViewMatrix(entities::Camera& camera) const;
protected:
void SetAttributes() const override;
void GetAllUniformLocations() override;
};
}

View File

@@ -2,6 +2,14 @@
namespace toolbox
{
glm::mat4 CreateModelMatrix(glm::vec2 translation, glm::vec2 scale)
{
glm::mat4 matrix(1.0f);
matrix = glm::translate(matrix, glm::vec3(translation.x, translation.y, 0));
matrix = glm::scale(matrix, glm::vec3(scale.x, scale.y, 0));
return matrix;
}
glm::mat4 CreateModelMatrix(glm::vec3 translation, glm::vec3 rotation, float scale)
{
glm::mat4 matrix(1.0f);

View File

@@ -5,10 +5,45 @@
namespace toolbox
{
#define WINDOW_WIDTH 1400
#define WINDOW_HEIGT 800
// Window macro's
#define DEFAULT_WIDTH 1920
#define DEFAULT_HEIGHT 1080
// Change these macros to change the window size
#define WINDOW_WIDTH 1400.0f
#define WINDOW_HEIGT 800.0f
#define SCALED_WIDTH (WINDOW_WIDTH/DEFAULT_WIDTH)
#define SCALED_HEIGHT (WINDOW_HEIGT/DEFAULT_HEIGHT)
//
/*
* @brief: This function will create a model matrix
*
* @param translation: The position of the model
* @param scale: The scale of the model
*
* @return: The model matrix of the model
*/
glm::mat4 CreateModelMatrix(glm::vec2 translation, glm::vec2 scale);
/*
* @brief: This function will create a model matrix
*
* @param translation: The position of the model
* @param rotation: The rotation of the model
* @param scale: The scale of the model
*
* @return: The model matrix of the model
*/
glm::mat4 CreateModelMatrix(glm::vec3 translation, glm::vec3 rotation, float scale);
/*
* @brief: This function will create a view matrix from the camera's position
*
* @param camera: The camera the view matrix needs to be made from
*
* @return: The view matrix
*/
glm::mat4 CreateViewMatrix(entities::Camera& camera);
}

View File

@@ -19,42 +19,39 @@
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\computervision\FaceDetector.cpp" />
<ClCompile Include="src\computervision\ObjectDetection.cpp" />
<ClCompile Include="src\computervision\OpenPoseVideo.cpp" />
<ClCompile Include="src\computervision\SkinDetector.cpp" />
<ClCompile Include="src\computervision\FingerCount.cpp" />
<ClCompile Include="src\computervision\BackgroundRemover.cpp" />
<ClCompile Include="src\scenes\in_Game_Scene.cpp" />
<ClCompile Include="src\scenes\scene.cpp" />
<ClCompile Include="src\entities\camera.cpp" />
<ClCompile Include="src\entities\entity.cpp" />
<ClCompile Include="src\gui\gui_interactable.cpp" />
<ClCompile Include="src\main.cpp" />
<ClCompile Include="src\renderEngine\loader.cpp" />
<ClCompile Include="src\renderEngine\obj_loader.cpp" />
<ClCompile Include="src\renderEngine\renderer.cpp" />
<ClCompile Include="src\shaders\gui_shader.cpp" />
<ClCompile Include="src\shaders\shader_program.cpp" />
<ClCompile Include="src\shaders\static_shader.cpp" />
<ClCompile Include="src\shaders\entity_shader.cpp" />
<ClCompile Include="src\toolbox\toolbox.cpp" />
<ClCompile Include="src\scenes\startup_Scene.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\computervision\FaceDetector.h" />
<ClInclude Include="src\computervision\FingerCount.h" />
<ClInclude Include="src\computervision\BackgroundRemover.h" />
<ClInclude Include="src\computervision\OpenPoseVideo.h" />
<ClInclude Include="src\computervision\SkinDetector.h" />
<ClInclude Include="src\computervision\ObjectDetection.h" />
<ClInclude Include="src\scenes\in_Game_Scene.h" />
<ClInclude Include="src\scenes\scene.h" />
<ClInclude Include="src\entities\camera.h" />
<ClInclude Include="src\entities\entity.h" />
<ClInclude Include="src\entities\light.h" />
<ClInclude Include="src\gui\gui_element.h" />
<ClInclude Include="src\gui\gui_interactable.h" />
<ClInclude Include="src\models\model.h" />
<ClInclude Include="src\renderEngine\loader.h" />
<ClInclude Include="src\renderEngine\obj_loader.h" />
<ClInclude Include="src\renderEngine\renderer.h" />
<ClInclude Include="src\shaders\gui_shader.h" />
<ClInclude Include="src\shaders\shader_program.h" />
<ClInclude Include="src\shaders\static_shader.h" />
<ClInclude Include="src\shaders\entity_shader.h" />
<ClInclude Include="src\stb_image.h" />
<ClInclude Include="src\toolbox\toolbox.h" />
</ItemGroup>
<ItemGroup>
<Xml Include="res\haarcascade_frontalface_alt.xml" />
<ClInclude Include="src\scenes\startup_Scene.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>

View File

@@ -33,31 +33,28 @@
<ClCompile Include="src\shaders\shader_program.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\shaders\static_shader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\renderEngine\obj_loader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\toolbox\toolbox.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\computervision\ObjectDetection.cpp">
<ClCompile Include="src\shaders\entity_shader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\computervision\SkinDetector.cpp">
<ClCompile Include="src\shaders\gui_shader.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\computervision\FingerCount.cpp">
<ClCompile Include="src\gui\gui_interactable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\computervision\FaceDetector.cpp">
<ClCompile Include="src\scenes\scene.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\computervision\BackgroundRemover.cpp">
<ClCompile Include="src\scenes\in_Game_Scene.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="src\computervision\OpenPoseVideo.cpp">
<ClCompile Include="src\scenes\startup_Scene.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
@@ -83,35 +80,35 @@
<ClInclude Include="src\shaders\shader_program.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\shaders\static_shader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\renderEngine\obj_loader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\toolbox\toolbox.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\computervision\ObjectDetection.h">
<ClInclude Include="src\entities\light.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\computervision\SkinDetector.h">
<ClInclude Include="src\shaders\entity_shader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\computervision\FingerCount.h">
<ClInclude Include="src\shaders\gui_shader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\computervision\FaceDetector.h">
<ClInclude Include="src\gui\gui_element.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\computervision\BackgroundRemover.h">
<ClInclude Include="src\gui\gui_interactable.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\computervision\OpenPoseVideo.h">
<ClInclude Include="src\scenes\scene.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\scenes\in_Game_Scene.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="src\scenes\startup_Scene.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Xml Include="res\haarcascade_frontalface_alt.xml" />
</ItemGroup>
</Project>