From 62779b6f78b91834603220b8e861b02dfc58ab55 Mon Sep 17 00:00:00 2001 From: Epicalert Date: Fri, 1 Jan 2021 16:23:44 +0800 Subject: [PATCH] separate face and head - Head position is now calculated from the midpoint of points 2 and 14 (sides of head) - Face position is calculated from point 30 (nose tip) --- src/graphics.cpp | 157 +++++++++++++++++++++++++++-------------------- src/graphics.hpp | 6 +- src/main.cpp | 22 +++++-- 3 files changed, 114 insertions(+), 71 deletions(-) diff --git a/src/graphics.cpp b/src/graphics.cpp index 0feea10..473459d 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -11,24 +11,37 @@ #include -GLuint vbo; //vertex buffer -GLuint ebo; //element buffer -GLuint vao; //vertex array (holds shader relations etc to vertex buffer) +//VAOs for different parts +//TODO: make this more modular +GLuint head; //head object +GLuint face; //face object GLuint shader; //standard shader program used for all elements GLuint transUniform; //location of the "transMatrix" transformation matrix uniform in the shader +GLuint texHead; //head texture +GLuint texFace; //face texture + +glm::mat4 matHead(1.0f); //transformation matrix for head object +glm::mat4 matFace(1.0f); //transformation matrix for face object + void display () { glClear(GL_COLOR_BUFFER_BIT); + glBindVertexArray(head); + glBindTexture(GL_TEXTURE_2D, texHead); + glUniformMatrix4fv(transUniform, 1, GL_FALSE, glm::value_ptr(matHead)); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + + glBindVertexArray(face); + glBindTexture(GL_TEXTURE_2D, texFace); + glUniformMatrix4fv(transUniform, 1, GL_FALSE, glm::value_ptr(matFace)); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); glutSwapBuffers(); } -void initBuffers () { - glewInit(); - +void initBuffers (GLuint* vaoNum) { //TODO: put quad stuff in header file or something GLfloat quad[] = { //vertex UV/texcoord @@ -43,6 +56,73 @@ void initBuffers () { 2, 3, 0 }; + glGenVertexArrays(1, vaoNum); + glBindVertexArray(*vaoNum); + + GLuint vbo; //vertex buffer + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + //change to GL_DYNAMIC_DRAW when using deformable meshes + glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW); + + GLuint ebo; //element buffer + glGenBuffers(1, &ebo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadElements), quadElements, GL_STATIC_DRAW); + + //tell OpenGL what to put in the input vars + GLuint posAttr = glGetAttribLocation(shader, "position"); + glVertexAttribPointer(posAttr, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), 0); + glEnableVertexAttribArray(posAttr); + GLuint uvAttr = glGetAttribLocation(shader, "texcoord"); + glVertexAttribPointer(uvAttr, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)(2*sizeof(GLfloat))); + glEnableVertexAttribArray(uvAttr); + + +} + +void initGraphics () { + int argc = 1; + char *argv[1] = {(char*)"fc2d"}; + + glutInit(&argc, argv); + glutCreateWindow("FaceCam2D"); + glutInitWindowSize(512, 512); + glutDisplayFunc(display); + + glewInit(); + + initShader(); + + initBuffers(&head); + initBuffers(&face); + + initTexture(&texHead, "head-base.png"); + initTexture(&texFace, "head-face.png"); + + //enable blending for alpha textures + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + //set background color + glClearColor(0.5f, 0.5f, 0.5f, 1.0f); +} + +void initTexture (GLuint* texNum, const char* path) { + glGenTextures(1, texNum); + glBindTexture(GL_TEXTURE_2D, *texNum); + + int x, y, channels; + GLubyte* pixels = stbi_load(path, &x, &y, &channels, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +} + +void initShader() { const char* vsSrc = "#version 150\n" "in vec2 position;" @@ -63,18 +143,6 @@ void initBuffers () { "color = texture(tex, uv);" "}"; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - //change to GL_DYNAMIC_DRAW when using deformable meshes - glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW); - - glGenBuffers(1, &ebo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quadElements), quadElements, GL_STATIC_DRAW); - //compile vert shader GLuint vs = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs, 1, &vsSrc, NULL); @@ -91,7 +159,6 @@ void initBuffers () { glGetShaderiv(fs, GL_COMPILE_STATUS, &status); if (status != GL_TRUE) { std::cout << "fragment shader borked" << std::endl; printShaderCompileLog(vs); } - //link shaders into a shader program shader = glCreateProgram(); @@ -101,48 +168,9 @@ void initBuffers () { glLinkProgram(shader); glUseProgram(shader); - - //tell OpenGL what to put in the input vars - GLuint posAttr = glGetAttribLocation(shader, "position"); - glVertexAttribPointer(posAttr, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), 0); - glEnableVertexAttribArray(posAttr); - GLuint uvAttr = glGetAttribLocation(shader, "texcoord"); - glVertexAttribPointer(uvAttr, 2, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (void*)(2*sizeof(GLfloat))); - glEnableVertexAttribArray(uvAttr); - + //set an identity ("do nothing") transformation matrix as default transUniform = glGetUniformLocation(shader, "transMatrix"); glUniformMatrix4fv(transUniform, 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f))); - - GLuint tex; - glGenTextures(1, &tex); - glBindTexture(GL_TEXTURE_2D, tex); - - int x, y, channels; - GLubyte* pixels = stbi_load("face.png", &x, &y, &channels, 4); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - //enable blending for alpha textures - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); -} - -void initGraphics () { - int argc = 1; - char *argv[1] = {(char*)"fc2d"}; - - glutInit(&argc, argv); - glutCreateWindow("FaceCam2D"); - glutInitWindowSize(512, 512); - glutDisplayFunc(display); - - initBuffers(); - - glClearColor(0.5f, 0.5f, 0.5f, 1.0f); } void graphicsFrame () { @@ -160,12 +188,11 @@ void initModel () { } -void updateModel(glm::vec2 headPos) { - //calculate transform - glm::mat4 transMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(headPos.x, headPos.y, 0.0f)); - - //upload to GPU and put in transMatrix uniform var in shader program - glUniformMatrix4fv(transUniform, 1, GL_FALSE, glm::value_ptr(transMatrix)); +void updateModel(glm::vec2 headPos, glm::vec2 facePos) { + //calculate transforms + matHead = glm::translate(glm::mat4(1.0f), glm::vec3(headPos.x, -headPos.y, 0.0f)); + matFace = glm::translate(glm::mat4(1.0f), glm::vec3(facePos.x, -facePos.y, 0.0f)); + //tell FreeGLUT to schedule a screen update glutPostRedisplay(); } diff --git a/src/graphics.hpp b/src/graphics.hpp index c6fbd0f..5df815b 100644 --- a/src/graphics.hpp +++ b/src/graphics.hpp @@ -8,8 +8,12 @@ void initGraphics (); void graphicsFrame (); +void initTexture (GLuint* texNum, const char* path); + +void initShader(); + void printShaderCompileLog(GLuint shader); -void updateModel(glm::vec2 headPos); +void updateModel(glm::vec2 headPos, glm::vec2 facePos); #endif diff --git a/src/main.cpp b/src/main.cpp index b5b500f..f032a22 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,13 +43,25 @@ int main () { std::vector> landmarks; if (facemark->fit (frame, faces, landmarks)) { - for (int i = 0; i < landmarks[biggestFace].size(); i++) { - cv::circle (frame, landmarks[biggestFace][i], 2, cv::Scalar (255, 255, 255)); - } + //for (int i = 0; i < landmarks[biggestFace].size(); i++) { + // cv::circle (frame, landmarks[biggestFace][i], 2, cv::Scalar (255, 255, 255)); + //} + cv::circle(frame, cv::Point2f( + (landmarks[biggestFace][2].x + landmarks[biggestFace][14].x) / 2, + (landmarks[biggestFace][2].y + landmarks[biggestFace][14].y) / 2 + ), 6, cv::Scalar(0, 0, 255)); + cv::circle (frame, landmarks[biggestFace][30], 6, cv::Scalar (0, 255, 255)); + //send control information to graphics updateModel(glm::vec2( - ((faces[biggestFace].x + (faces[biggestFace].width / 2)) * 2) / (float)frame.cols - 1, - ((faces[biggestFace].y + (faces[biggestFace].height / 2)) * 2) / -(float)frame.rows + 1 + (landmarks[biggestFace][2].x + landmarks[biggestFace][14].x) / 2 + * 2 / (float)frame.cols - 1, + (landmarks[biggestFace][2].y + landmarks[biggestFace][14].y) / 2 + * 2 / (float)frame.rows - 1 + ), + glm::vec2( + landmarks[biggestFace][30].x * 2 / (float)frame.cols - 1, + landmarks[biggestFace][30].y * 2 / (float)frame.rows - 1 )); }