CP24: GeometryShader
一开始首先要认识到什么是最基础的图元:点,线,三角面
教程中的一开始初始化的点是在NDC设备,我的同样一样,在shader中,教程中vert 不包含projection * view *model,我的依然存在。
如果在Geometry绘制的线段依然要满足透视关系,所以也得把projection * view * model带入
在这里修改了LoaderShader.h
#ifndef LOADSHADER_H #define LOADSHADER_H #include <GL/glew.h> #include <iostream> #include <fstream> #include <string> #include <sstream> #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <vector> #include "ALG_TextureDelegate.h" namespace AlgebraMaster { using namespace std; // Shaders const char* vertexShaderSource = "#version 450 core " "layout (location = 0) in vec4 v_position; " "layout ( location = 1 ) in vec3 v_normal; " "layout ( location = 2 ) in vec2 v_texCoord; " "out vec2 myTexCoord; " "uniform mat4 model; " "uniform mat4 view; " "uniform mat4 projection; " "void main() " "{ " "gl_Position = projection * view * model * v_position; " "myTexCoord = v_texCoord; " "} "; const char* fragmentShaderSource = "#version 450 core " "out vec4 fColor; " "void main() " "{ " "fColor = vec4(1.0f, 1.0f, 1.0f , 1.0f); " "} "; // this have texture const char* fragmentShaderSource2 = "#version 450 core " "out vec4 fColor; " "in vec2 myTexCoord; " "struct Material " "{ " "float Kd; // diffuse mult " "float kS; // specular mult " "float shininess; // phong pow(,shine) " "sampler2D diffuse_map; " "sampler2D specular_map; " "sampler2D emission_map; " "}; " "uniform Material material; " "void main() " "{ " "vec4 df_tex=texture(material.diffuse_map, myTexCoord); ;" "fColor = vec4(df_tex.r,df_tex.g,df_tex.b,1.0f) ; " "} "; struct LoadShader { enum ShaderIOType{FILE,INLINE_DEFAULT_PROJECTION,INLINE_TEXTURE_PROJECTION}; void compileShaderProgram(bool needGeometryShader = false){ // create shader program and check it GLint success; GLchar infoLog[512]; shaderProgram = glCreateProgram(); glAttachShader(shaderProgram,vertexShader); glAttachShader(shaderProgram,fragmentShader); // if we need attach geometry shader if (needGeometryShader){ glAttachShader(shaderProgram,geometryShader); } glLinkProgram(shaderProgram ); glGetProgramiv( shaderProgram, GL_LINK_STATUS, &success ); // Get Link Status if (!success) { glGetProgramInfoLog( shaderProgram, 512, NULL, infoLog ); std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED " << infoLog << std::endl; } // Delete the allShaders as they're linked into our program now and no longer necessery glDeleteShader( vertexShader ); glDeleteShader( fragmentShader ); } void compileVertexShader(const string& code){ vertexShader = glCreateShader( GL_VERTEX_SHADER ); const char * src = code.c_str(); glShaderSource( vertexShader, 1, &(src), NULL ); glCompileShader( vertexShader ); GLint success; GLchar infoLog[512]; glGetShaderiv( vertexShader, GL_COMPILE_STATUS, &success ); if ( !success ) { glGetShaderInfoLog( vertexShader, 512, NULL, infoLog ); std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED " << infoLog << std::endl; } } void compileGeometryShader(const string& code){ const char *src = code.c_str(); GLint success; GLchar infoLog[512]; geometryShader = glCreateShader( GL_GEOMETRY_SHADER ); glShaderSource( geometryShader, 1, &src, NULL ); glCompileShader( geometryShader ); glGetShaderiv( geometryShader, GL_COMPILE_STATUS, &success ); // Get Compile status if ( !success ) { glGetShaderInfoLog( geometryShader, 512, NULL, infoLog ); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED " << infoLog << std::endl; } } void compileFragmentShader(const string& code){ const char * src = code.c_str(); GLint success; GLchar infoLog[512]; fragmentShader = glCreateShader( GL_FRAGMENT_SHADER ); glShaderSource( fragmentShader, 1, &src, NULL ); glCompileShader( fragmentShader ); glGetShaderiv( fragmentShader, GL_COMPILE_STATUS, &success ); // Get Compile status if ( !success ) { glGetShaderInfoLog( fragmentShader, 512, NULL, infoLog ); std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED " << infoLog << std::endl; } } void fromSrc(const string &vertCode, const string &fragCode){ compileVertexShader(vertCode); compileFragmentShader(fragCode); compileShaderProgram(); } void fromSrc(const string &vertCode, const string &fragCode, const string&geometryCode){ compileVertexShader(vertCode); compileFragmentShader(fragCode); compileGeometryShader(geometryCode); compileShaderProgram(true); } LoadShader(){ } ~LoadShader(){ } // ------------ this method do not compile the geometry shader ----------------------- void asSimpleTextureShader(){ shaderName = "simpleTex"; shaderIOType = INLINE_TEXTURE_PROJECTION; compileVertexShader(vertexShaderSource); compileFragmentShader(fragmentShaderSource2); compileShaderProgram(); } void asSimpleShader() { shaderName = "simpleCol"; shaderIOType = INLINE_DEFAULT_PROJECTION; compileVertexShader(vertexShaderSource); compileFragmentShader(fragmentShaderSource); compileShaderProgram(); } // ------------ this method do not compile the geometry shader ----------------------- void setShaderName(const string &name){ shaderName = name; } // ------------ read text file ----------------------- string _readFile(const char *path){ ifstream stream; stringstream ss; stream.exceptions(ifstream::badbit); try { stream.open(path); // open file ss << stream.rdbuf(); // get strings from file } catch (ifstream::failure e) { cout << "ERROR::OPEN FILE:" << path << endl; } // close file handle stream.close(); // get str() from stringstream string shaderCode = ss.str(); return shaderCode; } // ------------ load a vertex shader from a path ---------------------------------- void _loadVertexShader(const char *path){ // read shader code auto handle = _readFile(path); compileVertexShader(handle); } // ------------ load a fragment shader from a path ---------------------------------- void _loadFragmentShader(const char *path){ // read shader code auto handle = _readFile(path); compileFragmentShader(handle); } // ------------ load a geometry shader from a path ---------------------------------- void _loadGeometryShader(const char *path){ auto handle = _readFile(path); compileGeometryShader(handle); } // ------------ only load two shader : vert & frag ---------------------------------- void load(const char* vertShaderPath, const char* fragShaderPath){ shaderIOType = FILE; _loadVertexShader(vertShaderPath); _loadFragmentShader(fragShaderPath); // create shader program and check it compileShaderProgram(); } // ------------ shader program have 3 shader: vert&frag&geometry ---------------------------------- void load(const char* vertShaderPath, const char* fragShaderPath, const char* geometryShaderPath){ shaderIOType = FILE; _loadVertexShader(vertShaderPath); _loadFragmentShader(fragShaderPath); _loadGeometryShader(geometryShaderPath); // create shader program and check it compileShaderProgram(true); } // ------------ active current shader program ---------------------------------- void use(){ glUseProgram(shaderProgram); } // ------------ set shader method ---------------------------------- void setBool(const char *name, bool value) const { glUniform1i(glGetUniformLocation(shaderProgram, name), (int)value); } void setInt(const char *name, int value) const { glUniform1i(glGetUniformLocation(shaderProgram,name), value); } // ------------------------------------------------------------------------ void setFloat(const char *name, float value) const { glUniform1f(glGetUniformLocation(shaderProgram, name), value); } // ------------------------------------------------------------------------ void setVec2(const char *name, const glm::vec2 &value) const { glUniform2fv(glGetUniformLocation(shaderProgram,name), 1, &value[0]); } void setVec2(const char *name, float x, float y) const { glUniform2f(glGetUniformLocation(shaderProgram,name), x, y); } // ------------------------------------------------------------------------ void setVec3(const char *name, const glm::vec3 &value) const { glUniform3fv(glGetUniformLocation(shaderProgram,name), 1, &value[0]); } void setVec3(const char *name, float x, float y, float z) const { glUniform3f(glGetUniformLocation(shaderProgram,name), x, y, z); } // ------------------------------------------------------------------------ void setVec4(const char *name, const glm::vec4 &value) const { glUniform4fv(glGetUniformLocation(shaderProgram,name), 1, &value[0]); } void setVec4(const char *name, float x, float y, float z, float w) { glUniform4f(glGetUniformLocation(shaderProgram,name), x, y, z, w); } void setMat2(const char*name, const glm::mat2 &mat) const { glUniformMatrix2fv(glGetUniformLocation(shaderProgram, name), 1, GL_FALSE,glm::value_ptr(mat)); } void setMat3(const char*name, const glm::mat3 &mat){ GLuint location = glGetUniformLocation(shaderProgram, name); glUniformMatrix3fv(location,1, GL_FALSE, &mat[0][0]); } void setMat4(const char *name , const glm::mat4 &mat){ GLuint location = glGetUniformLocation(shaderProgram, name); glUniformMatrix4fv(location,1, GL_FALSE, glm::value_ptr(mat)); } GLuint shaderProgram; GLuint vertexShader; GLuint fragmentShader; GLuint geometryShader; ShaderIOType shaderIOType; string shaderName; vector <Texture*> textures; // do not release this memory, scene will manipulate this mem glm::mat4 model; glm::mat4 view; glm::mat4 projection; // ------------ direct set shader projection,view,model ---------------------------------- void setMatrix(const glm::mat4 &matModel , const glm::mat4 &matView , const glm::mat4 &matProjection){ model = matModel; view = matView; projection = matProjection; setMat4("projection", projection); setMat4("view", view); setMat4("model", model); } }; } #endif // LOADSHADER_H
集合体shader->GeometryShader.geom:
>下面的layout(points) in; 意思很重要,基础图元,代表输入的是点,那么在下面访问的时候只能gl_in[0],因为操作一个点相当于操作C++里的VAO,也类似houdini attribute wrangle(points)。
>顺理推如果layout(triangles)in; 就是我输入的是三角形,那么可以访问下面3个顶点也就是三角形的三个顶点。
gl_in[0].position
gl_in[1].position
gl_In[2].position
>同样接下来 layout (line_strip, max_verticles = 2) out; 这句话代表我要干什么,我要输出什么样的图像,这里是一条线,我要生成2个点。
#version 450 core layout (points) in; layout (line_strip, max_vertices = 2) out; uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main() { gl_Position = gl_in[0].gl_Position + projection*view*model*vec4(-.2, 0.0, 0.0, 0.0); EmitVertex(); gl_Position = gl_in[0].gl_Position + projection*view*model*vec4( 0.2, 0.0, 0.0, 0.0); EmitVertex(); EndPrimitive(); }
#version 450 core // Final Color To export out vec4 FragColor; void main() { FragColor = vec4(1,0,1,1); }
#version 450 core // INCOMING DATA layout ( location = 0 ) in vec4 v_position; // pos //layout ( location = 1 ) in vec2 v_texCoord; // st //layout ( location = 2 ) in vec3 v_normal; // st // define out data out vec2 f_TexCoord; // normal at world matrix, we direct from C++ calcalation out vec3 f_Normal; // to world matrix : mat3( transpose(inverse(model)) ) * v_normal; out vec3 f_Pos; // INCOMING THE MATRIX FROM CLIENT to transform the gl point position uniform mat4 model; uniform mat4 view; uniform mat4 projection; void main(){ // Transform the world matrix to view matrix //f_Normal = mat3(transpose(inverse(model))) * v_normal; // f_Normal at world matrix //f_TexCoord = v_texCoord; // out TexCoord //f_Pos = vec3(model *v_position); // out fragment position gl_Position = projection * view * model * v_position; }
#define GLEW_STATIC // GLEW #include <GL/glew.h> #include <cstdlib> #undef GLFW_DLL // GLFW #include <GLFW/glfw3.h> #include <iostream> #include "ALG_LoadShader.h" #include "ALG_LoadTexture.h" #include "ALG_GLFWCamera.h" #include "ALG_FrameWindow.h" #include "ALG_ModelDelegate.h" #include "ALG_SceneDelegate.h" #include "ALG_DrawGrid.h" #include <cmath> #include "ALG_OGLHelper.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <map> #include "ALG_DrawEnvBox.h" using namespace AlgebraMaster; const unsigned int SRC_WIDTH = 1400; const unsigned int SRC_HEIGHT = 720; static LoadShader SurfaceShader; void init(); void display(); void processInput(GLFWwindow *window); void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); static float lastX = float(SRC_WIDTH) / 2.0f; static float lastY = float(SRC_HEIGHT) / 2.0f; static bool firstMouse = true; static bool firstMiddowMouse = true; // timing static float deltaTime = 0.0f; // time between current frame and last frame static float lastFrame = 0.0f; // cube vao vbo static unsigned int VAO,VBO; // camera static GLFWCamera *camera; // light define static glm::vec3 lightPos(0.0f, 4.0f,-2.0f); static DrawGrid grid; static DrawEnvBox envBox; static LoadTexture cubeTex; static LoadTexture groundTex; static float testPoints[] = { -0.5f, 0.5f, // 左上 0.5f, 0.5f, // 右上 0.5f, -0.5f, // 右下 -0.5f, -0.5f // 左下 }; void init(){ camera = new GLFWCamera; camera->pos.y = 1.0f; camera->pos.z = 4.0f; // GL depth zbuffer glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); SurfaceShader.load( "shaders/SurfaceShader.vert", "shaders/SurfaceShader.frag", "shaders/GeometryShader.geom"); CreateGeometryBuffer(VAO,VBO); glBufferData(GL_ARRAY_BUFFER,sizeof(testPoints),&testPoints,GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0); grid.initialize(); } // ----------- Render Loop ---------- void display(){ // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // object .vert settings glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f, 1000.0f); glm::mat4 view = camera->GetViewMatrix(); // object world transformation glm::mat4 model = glm::mat4(1.0f); grid.draw(projection,view); SurfaceShader.use(); SurfaceShader.setMatrix(model,view,projection); glBindVertexArray(VAO); glDrawArrays(GL_POINTS,0,4); } int main() { cout << sizeof(float) << endl; glfwInit(); FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT); glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback); glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback); glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback); init(); // RENDER-------------- //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); while(!glfwWindowShouldClose(FrameWindow.getWindow())){ processInput(FrameWindow.getWindow()); display(); glfwSwapBuffers(FrameWindow.getWindow()); glfwPollEvents(); } delete camera; return 0; } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { // make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays. glViewport(0, 0, width, height); } void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT); } // ROTATE VIEW DIR void mouse_callback(GLFWwindow* window, double xpos, double ypos){ int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE); int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT); int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT); // set up the camera view if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS) { if (firstMouse){ lastX = xpos; lastY = ypos; firstMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera->processMouseMove(xoffset,yoffset); } if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){ firstMouse = true; } // Move Camera Position if( middow_mouse_state == GLFW_PRESS) { if (firstMiddowMouse){ lastX = xpos; lastY = ypos; firstMiddowMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera->pos.x += xoffset*0.01f; camera->pos.y += yoffset*0.01f; } if ( middow_mouse_state == GLFW_RELEASE){ firstMiddowMouse = true; } } void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){ camera->processFov(yoffset); }
法线向量显示:
首先在vert阶段材质输出法线向量:
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; out VS_OUT { vec3 normal; } vs_out; uniform mat4 projection; uniform mat4 view; uniform mat4 model; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0); mat3 normalMatrix = mat3(transpose(inverse(view * model))); vs_out.normal = normalize(vec3(projection * vec4(normalMatrix * aNormal, 0.0))); }
然后在geometry阶段材质,注意接入是三角形,也就是可以访问三角形三个点。一个点要生成1跟线,1根线2个点, 则3个点需要3根线,6个点。
不过作者这个是做的点法线,按道理做个面法线不是个困难的事情。
#version 330 core layout (triangles) in; layout (line_strip, max_vertices = 6) out; in VS_OUT { vec3 normal; } gs_in[]; const float MAGNITUDE = 0.4; void GenerateLine(int index) { gl_Position = gl_in[index].gl_Position; EmitVertex(); gl_Position = gl_in[index].gl_Position + vec4(gs_in[index].normal, 0.0) * MAGNITUDE; EmitVertex(); EndPrimitive(); } void main() { GenerateLine(0); // point 1-> normal line GenerateLine(1); // point 2-> normal line GenerateLine(2); // point 3-> normal line }
引用原图:
CP25:利用Opengl Geometry Shader绘制坐标轴:
当然有多种绘制方法,选择用这个主要练习。
输入图元一个点,然后用这个点绘制3条线,即输出图元。最大点6个。
包装成一个最简单的头文件。
// // Created by Admin on 2020/3/5. // #ifndef TRIANGLE_ALG_DRAWORIGINGNOMON_H #define TRIANGLE_ALG_DRAWORIGINGNOMON_H #include <vector> #include "ALG_LoadShader.h" #include "ALG_OGLHelper.h" namespace AlgebraMaster { using namespace std; static float __originPt__[] = {0.0f,0.0f,0.0f}; class DrawOriginGnomon{ public: void initialize(); void draw(glm::mat4 &proj, glm::mat4 &view); LoadShader shader; unsigned int VAO; unsigned int VBO; }; void DrawOriginGnomon::initialize() { CreateGeometryBuffer(VAO,VBO); glBufferData(GL_ARRAY_BUFFER,sizeof(__originPt__),&__originPt__, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE, 3 * sizeof(float), (void*)0 ); shader.load("shaders/origin_gnomon/surface.vert", "shaders/origin_gnomon/surface.frag", "shaders/origin_gnomon/surface.geom"); } void DrawOriginGnomon::draw(glm::mat4 &proj, glm::mat4 &view) { shader.use(); shader.setMatrix(glm::mat4(1.0f),view,proj); glLineWidth(4.0f); glBindVertexArray(VAO); glDrawArrays(GL_POINTS,0,1); } } #endif //TRIANGLE_ALG_DRAWORIGINGNOMON_H
由于shader stage: vert->geometry->fragment
我想测试从geometry shader直接生成3中颜色,传递到fragment
还有我想把projection*view*model从vert里面传递到geometry里(当然直接可以把这种uniform变量写到geometry shader),有两种方式传递:
首先是vert材质:
#version 450 core layout(location=0) in vec3 aPos; uniform mat4 projection; uniform mat4 view; uniform mat4 model; out mat4 testMat; out VS_OUT{ mat4 toCameraMat; }vs_out; void main(){ mat4 pipematrix = projection * view * model; testMat = pipematrix; // only for test can transfer to geometry shader vs_out.toCameraMat = pipematrix; gl_Position = pipematrix * vec4(aPos,1.0f); }
geometry shader:
#version 450 core layout(points) in; layout(line_strip,max_vertices = 6 ) out; in mat4 testMat[]; in VS_OUT{ mat4 toCameraMat; }gs_in[]; out vec3 fColor; void main(){ // build x RED fColor = vec3(1,0,0); gl_Position = gl_in[0].gl_Position + gs_in[0].toCameraMat * vec4(0.0, 0.0, 0.0, 0.0); EmitVertex(); gl_Position = gl_in[0].gl_Position + gs_in[0].toCameraMat * vec4(1.0, 0.0, 0.0, 0.0); EmitVertex(); // build primitive EndPrimitive(); // build y GREEN fColor = vec3(0,1,0); gl_Position = gl_in[0].gl_Position + gs_in[0].toCameraMat * vec4(0.0, 0.0, 0.0, 0.0); EmitVertex(); gl_Position = gl_in[0].gl_Position + gs_in[0].toCameraMat * vec4(0.0, 1.0, 0.0, 0.0); EmitVertex(); // build primitive EndPrimitive(); // build z BLUE fColor = vec3(0,0,1); gl_Position =gl_in[0].gl_Position + testMat[0] * vec4(0.0, 0.0, 0.0, 0.0); // 注意这里使用的testMat 和 gs_in[0].toCameraMat 完全一样! EmitVertex(); gl_Position =gl_in[0].gl_Position + testMat[0] * vec4(0.0, 0.0, 1.0, 0.0); EmitVertex(); // build primitive EndPrimitive(); }
fragment:fragment的颜色注意是直接从geometry shader来的。
#version 450 core out vec4 FragColor; in vec3 fColor; void main() { FragColor = vec4(fColor, 1.0); }
#define GLEW_STATIC // GLEW #include <GL/glew.h> #include <cstdlib> #undef GLFW_DLL // GLFW #include <GLFW/glfw3.h> #include <iostream> #include "ALG_LoadShader.h" #include "ALG_LoadTexture.h" #include "ALG_GLFWCamera.h" #include "ALG_FrameWindow.h" #include "ALG_ModelDelegate.h" #include "ALG_SceneDelegate.h" #include "ALG_DrawGrid.h" #include <cmath> #include "ALG_OGLHelper.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <map> #include "ALG_DrawEnvBox.h" #include "ALG_DrawOriginGnomon.h" using namespace AlgebraMaster; const unsigned int SRC_WIDTH = 1400; const unsigned int SRC_HEIGHT = 720; static LoadShader SurfaceShader; void init(); void display(); void processInput(GLFWwindow *window); void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); static float lastX = float(SRC_WIDTH) / 2.0f; static float lastY = float(SRC_HEIGHT) / 2.0f; static bool firstMouse = true; static bool firstMiddowMouse = true; // timing static float deltaTime = 0.0f; // time between current frame and last frame static float lastFrame = 0.0f; // cube vao vbo static unsigned int VAO,VBO; // camera static GLFWCamera *camera; // light define static glm::vec3 lightPos(0.0f, 4.0f,-2.0f); static DrawGrid grid; static DrawEnvBox envBox; static DrawOriginGnomon originGnomon; static LoadTexture cubeTex; static LoadTexture groundTex; static float testPoints[] = { -0.5f, 0.5f, // 左上 0.5f, 0.5f, // 右上 0.5f, -0.5f, // 右下 -0.5f, -0.5f // 左下 }; void init(){ camera = new GLFWCamera; camera->pos.y = 1.0f; camera->pos.z = 4.0f; // GL depth zbuffer glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); SurfaceShader.load( "shaders/SurfaceShader.vert", "shaders/SurfaceShader.frag", "shaders/GeometryShader.geom"); CreateGeometryBuffer(VAO,VBO); glBufferData(GL_ARRAY_BUFFER,sizeof(testPoints),&testPoints,GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0); grid.initialize(); originGnomon.initialize(); } // ----------- Render Loop ---------- void display(){ // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // object .vert settings glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f, 1000.0f); glm::mat4 view = camera->GetViewMatrix(); // object world transformation glm::mat4 model = glm::mat4(1.0f); grid.draw(projection,view); originGnomon.draw(projection,view); } int main() { cout << sizeof(float) << endl; glfwInit(); FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT); glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback); glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback); glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback); init(); // RENDER-------------- //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); while(!glfwWindowShouldClose(FrameWindow.getWindow())){ processInput(FrameWindow.getWindow()); display(); glfwSwapBuffers(FrameWindow.getWindow()); glfwPollEvents(); } delete camera; return 0; } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { // make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays. glViewport(0, 0, width, height); } void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT); } // ROTATE VIEW DIR void mouse_callback(GLFWwindow* window, double xpos, double ypos){ int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE); int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT); int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT); // set up the camera view if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS) { if (firstMouse){ lastX = xpos; lastY = ypos; firstMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera->processMouseMove(xoffset,yoffset); } if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){ firstMouse = true; } // Move Camera Position if( middow_mouse_state == GLFW_PRESS) { if (firstMiddowMouse){ lastX = xpos; lastY = ypos; firstMiddowMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera->pos.x += xoffset*0.01f; camera->pos.y += yoffset*0.01f; } if ( middow_mouse_state == GLFW_RELEASE){ firstMiddowMouse = true; } } void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){ camera->processFov(yoffset); }
CP26: Opengl Instance:
还是借用以前的纳米模型那张,当前文件夹结构:
注意场景的scene.json加入了从全局材质赋予每一个材质。详细见scene.json
Mesh的类也修改了,因为要在main.cpp中分析贴图单元,所以把Mesh类的贴图单元创建部分单独立了一个函数。
#ifndef MESH_H #define MESH_H #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <string> #include <vector> #include "ALG_LoadShader.h" #include <GL/glew.h> #include "ALG_TextureDelegate.h" #include "ALG_Vertex.h" namespace AlgebraMaster { using namespace std; struct Mesh { public: Mesh()= default; //* constructor */ Mesh(const vector<Vertex> &vts, const vector<unsigned int>ids); void allocateTextureChannelFromShader(const LoadShader &rhs_shader); // rendering data vector<Vertex> vertices; vector<unsigned int> indices; // ogl unsigned int VAO,VBO,EBO; // vertex array buffer //* this method need called manually */ virtual void setupMesh(); // ogl draw virtual void draw(); // shader LoadShader shader; // get mat from outside void assignMaterial(const LoadShader & rhs_shader); }; Mesh::Mesh(const vector<Vertex> &vts, const vector<unsigned int>ids):vertices(vts),indices(ids){ } void Mesh::assignMaterial(const LoadShader &rhs_shader) { // shader attach shader.fragmentShader = rhs_shader.fragmentShader; shader.vertexShader = rhs_shader.vertexShader; shader.geometryShader = rhs_shader.geometryShader; shader.shaderProgram = rhs_shader.shaderProgram; // matrix attach shader.projection = rhs_shader.projection; shader.view = rhs_shader.view; shader.model = rhs_shader.model; // texture attach shader.textures = rhs_shader.textures; } void Mesh::allocateTextureChannelFromShader(const LoadShader &rhs_shader) { string mat_prefix = "material."; for(auto &tex: rhs_shader.textures) { switch (tex->texType) { case Texture::BASECOLOR_MAP:{ glActiveTexture(tex->texChannel); glBindTexture(GL_TEXTURE_2D, tex->id); string texchanName = mat_prefix + "diffuse_map"; shader.setInt(texchanName.c_str(),tex->textureUnitID); break; } case Texture::SPECULAR_MAP:{ glActiveTexture(tex->texChannel); glBindTexture(GL_TEXTURE_2D, tex->id); string texchanName = mat_prefix + "specular_map"; shader.setInt(texchanName.c_str(),tex->textureUnitID); break; } case Texture::EMISSION_MAP:{ string texchanName = mat_prefix + "emission_map"; shader.setInt(texchanName.c_str(),tex->textureUnitID); break; } case Texture::BUMP_MAP:{ string texchanName = mat_prefix + "bump_map"; shader.setInt(texchanName.c_str(),tex->textureUnitID); break; } case Texture::NORMAL_MAP:{ string texchanName = mat_prefix + "normal_map"; shader.setInt(texchanName.c_str(),tex->textureUnitID); break; } case Texture::IOR_MAP:{ string texchanName = mat_prefix + "ior_map"; shader.setInt(texchanName.c_str(),tex->textureUnitID); break; } case Texture::OPACITY_MAP:{ string texchanName = mat_prefix + "opacity_map"; shader.setInt(texchanName.c_str(),tex->textureUnitID); break; } case Texture::DISPLACE_MAP:{ string texchanName = mat_prefix + "displace_map"; shader.setInt(texchanName.c_str(),tex->textureUnitID); break; } default: break; } // end of switch } // end of for each textures string haveDfName = mat_prefix + "have_diffuse_map"; string haveSpecName = mat_prefix + "have_specular_map"; string haveEmissionName = mat_prefix + "have_emission_map"; shader.setInt(haveDfName.c_str(), rhs_shader.haveTypeTexmap(Texture::BASECOLOR_MAP)); shader.setInt(haveSpecName.c_str(), rhs_shader.haveTypeTexmap(Texture::SPECULAR_MAP)); shader.setInt(haveEmissionName.c_str(), rhs_shader.haveTypeTexmap(Texture::EMISSION_MAP)); } // opengl draw the mesh void Mesh::draw() { this->shader.use(); shader.setMatrix(shader.model,shader.view,shader.projection); allocateTextureChannelFromShader(this->shader); // draw mesh glBindVertexArray(VAO); glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0); glBindVertexArray(0); // always good practice to set everything back to defaults once configured. glActiveTexture(GL_TEXTURE0); } // init our mesh data void Mesh::setupMesh() { glCreateVertexArrays(1,&VAO); // vertex array object glCreateBuffers(1,&VBO); // vertex buffer object glCreateBuffers(1,&EBO); // vertex element array buffer object glBindVertexArray(VAO); // bind vertex array glBindBuffer(GL_ARRAY_BUFFER,VBO); // bind vertex buffer glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), &vertices[0], GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW); // vertex attributes // position glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)0); // normal glEnableVertexAttribArray(1); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 3*sizeof(float)) ); //tex glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 6*sizeof(float)) ); //tangent glEnableVertexAttribArray(3); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 8*sizeof(float)) ); // bitangent glEnableVertexAttribArray(4); glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), (void*)( 11*sizeof(float)) ); glBindVertexArray(0); } } // end of namespace #endif // MESH_H
// // Created by Admin on 2020/3/7. // #ifndef TRIANGLE_ALG_RANDOM_H #define TRIANGLE_ALG_RANDOM_H #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> #include <random> #include <iostream> #include <vector> #include <iostream> #include <limits> #include <random> namespace AlgebraMaster { using namespace std; // ------------- Float 0-1 Random gen------------------------ struct RandomFloatBase{ RandomFloatBase(int num, int seed=1){ } // datas vector<float> values; default_random_engine e; uniform_real_distribution<double> u; float operator[] (int index)const{ return values[index]; } float &operator[] (int index){ return values[index]; } friend ostream & operator << (ostream &os , const RandomFloatBase &rv){ for(auto &v:rv.values){ cout << v <<" "; } cout << " "; return os; } }; struct Random01:public RandomFloatBase{ Random01(int num,int seed=1); }; Random01::Random01(int num,int seed): RandomFloatBase(num, seed){ e.seed(seed); u = uniform_real_distribution<double>(0.0,1.0); for(int i=0;i<num;i++){ values.emplace_back(u(e)); } } // ------------- Float 0-1 Random gen------------------------ // ------------- Float -1 - 1 Random gen------------------------ struct RandomN1P1:public RandomFloatBase{ RandomN1P1(int num,int seed=1); }; RandomN1P1::RandomN1P1(int num,int seed): RandomFloatBase(num, seed){ e.seed(seed); u = uniform_real_distribution<double>(-1.0,1.0); for(int i=0;i<num;i++){ values.emplace_back(u(e)); } } } // namespace end #endif //TRIANGLE_ALG_RANDOM_H
// // Created by Admin on 2020/2/23. // #ifndef TRIANGLE_ALG_SCENEDELEGATE_H #define TRIANGLE_ALG_SCENEDELEGATE_H #include <iostream> #include <json.hpp> #include <string> #include <fstream> #include <iomanip> #include <vector> #include "ALG_LoadShader.h" #include "ALG_ModelDelegate.h" #include "ALG_LoadTexture.h" #include "ALG_MeshDelegate.h" // texture struct namespace AlgebraMaster{ // namespace using namespace std; using json = nlohmann::json; // bool checkJsonError(json &j,string msg); bool checkJsonError(json &j,string msg) { if (j.is_null()) { cout << "ERROR JSON:" << msg<<endl; return true; } return false; } template <typename T> void FreeSTLMemory(T & container); template <typename T> void FreeSTLMemory(T & container){ // release mats mem for(auto &c: container){ delete c; } container.clear(); } Texture *CreateTexture(const LoadTexture &textureLoader, const string &relativeTexturePath, Texture::Type type, unsigned int textureChannel, unsigned int textureUnitID); Texture *CreateTexture(const LoadTexture &textureLoader, const string &relativeTexturePath, Texture::Type type, unsigned int textureChannel, unsigned int textureUnitID) { // create texture object auto *texture = new Texture; // Create our texture object texture->id = textureLoader.getTextureID(); // Assign GL_TextureID to our texture object texture->texType = type; // set texture type texture->path = relativeTexturePath; // set texture path is relative texture->texChannel = textureChannel; texture->textureUnitID = textureUnitID; //current unique texture unit return texture; } //* scene description from json object/ class Scene{ public: Scene(); virtual ~Scene(); void read(const string &path); void save(const string &path)const; virtual void draw(); string getSceneName()const; void setSceneName(const string &name); Texture * getTextureByPath(const string &path){ for(auto &t: allTextures){ if(t->path == path)return t; } return nullptr; } vector<LoadShader *> allShaders; vector<Texture*> allTextures; // all texture from json file , this index will as GL_activeTexture(TEXTURE0+i) LoadShader* getShaderByName(const string &name){ for(auto &m : allShaders){ if(m->shaderName == name) return m; } return nullptr; } void debugShaders(){ for(auto &s: allShaders){ cout <<"Scene::debugShaders debug shader pool have:" << s->shaderName <<endl; } } void parseInitialize(); // read mesh void parseModel(); void parseMats(); void parseAssignMats(); void setMatrix(glm::mat4 &proj , glm::mat4 & view , glm::mat4 model = glm::mat4(1.0f)); //override all model mats void assignMaterial(LoadShader &shader){ for(auto &m : allModels){ m->assignMaterial(shader); } } vector<Model*> allModels; private: // * scene description json obj */ json j; // proj string project_dir; // bool textureIsLoaded(const string &texturePath); public: static int currentActiveTextureChannel; static int currentTextureLoaderIndex; }; int Scene::currentActiveTextureChannel = GL_TEXTURE0; int Scene::currentTextureLoaderIndex = 0; // ------------------ DEFINE FUNCTION -------------------------- Scene::Scene(){ } Scene::~Scene() { // release mats mem cout << "---------------Memory Release---------------------- "; cout << "free model's mem "; FreeSTLMemory(allModels); // cout << "free all textures mem "; FreeSTLMemory(allTextures); // cout << "free all shaders mem "; FreeSTLMemory(allShaders); cout << "---------------Memory Release---------------------- "; } bool Scene::textureIsLoaded(const string &texturePath) { bool isLoaded = false; for(auto &tex: allTextures){ if (tex->path == texturePath){ isLoaded = true; } } return isLoaded; } void Scene::setMatrix(glm::mat4 &proj , glm::mat4 &view , glm::mat4 model) { for(auto &mod :allModels){ for(auto &loc: mod->getLocations()) { loc->mesh->shader.setMatrix(model, view, proj); } } } // Read File void Scene::read(const string &path) { ifstream in(path.c_str()); in >> j; } // Write File void Scene::save(const string &path) const{ // write prettified JSON to another file ofstream o(path.c_str()); o << setw(4) << j << std::endl; } string Scene::getSceneName() const { auto name = j["name"]; if( name){ return name; } return "ERROR SCENE NAME"; } void Scene::setSceneName(const string &name) { j["name"] = name; } void Scene::draw() { for(auto &m : allModels){ m->draw(); } } void Scene::parseInitialize() { string temp_proj_dir = j["project_dir"]; temp_proj_dir += "/"; project_dir = temp_proj_dir; } void Scene::parseModel() { cout << j["models"] <<endl; for(string path :j["models"]){ auto *model = new Model; string absPath = project_dir + path; cout << "Scene Parse Read mesh:" << absPath <<endl; model->readMesh(absPath); this->allModels.emplace_back(model); } } void Scene::parseMats() { json globalVertFileObj = j["global_vert_file"]; json globalFragFileObj = j["global_frag_file"]; json globalGeomFileObj = j["global_geom_file"]; // Get global shader file path string globalVertRelFilePath = globalVertFileObj.get<string>(); string globalFragRelFilePath = globalFragFileObj.get<string>(); string globalGeomRelFilePath = globalGeomFileObj.get<string>(); json mats = j["mats"]; for (auto& mat : mats.items()) { json matNameObject = mat.key(); // json mat name json matContentObject = mat.value(); // json tex json shaderDefineObject = matContentObject["shader_define"]; json codeTypeObject = shaderDefineObject["code_type"]; json fragCodeObject = shaderDefineObject["frag_code"]; json vertCodeObject = shaderDefineObject["vert_code"]; // Get may be used local file to create shader json vertFileObject = shaderDefineObject["vert_file"]; // ----------- INIT shader pointer--------------------- auto *shader = new LoadShader; // ----------- INIT shader pointer--------------------- bool jsonIsError = false; // if is error , create default mat jsonIsError = checkJsonError(shaderDefineObject,"Can not find key ->shader_define ,create default color shader"); if(jsonIsError) { shader->asSimpleShader(); return; } jsonIsError = checkJsonError(codeTypeObject,"Can not find key ->code_type ,create default color shader"); if(jsonIsError){ shader->asSimpleShader(); return; } jsonIsError = checkJsonError(fragCodeObject,"Can not find key ->frag_code ,create default color shader"); if(jsonIsError){ shader->asSimpleShader(); return; } jsonIsError = checkJsonError(vertCodeObject,"Can not find key ->vert_code ,create default color shader"); if(jsonIsError){ shader->asSimpleShader(); return; } // JSON shader_define values string std_strMatName = matNameObject.get<string>(); // mat name int codeType = codeTypeObject.get<int>(); string fragCode = fragCodeObject.get<string>(); string vertCode = vertCodeObject.get<string>(); cout << "system create mat:" << std_strMatName << " codeType:" <<codeType <<endl; switch (codeType) { case 0: { shader->asSimpleShader(); shader->shaderName = std_strMatName; break; } case 1: { shader->asSimpleTextureShader(); shader->shaderName = std_strMatName; break; } case 3: { shader->fromSrc(vertCode,fragCode); shader->shaderName = std_strMatName; break; } case 5:{ shader->load(globalVertRelFilePath.c_str(), globalFragRelFilePath.c_str()); shader->shaderName = std_strMatName; break; } default: // create in line shader shader->asSimpleShader(); shader->shaderName = std_strMatName; break; } // shader param define json paramDefineObject = matContentObject["params_define"]; for(auto ¶ms: paramDefineObject.items()) { json paramNameObject = params.key(); json valueObject = params.value(); // may be relative texture path , or shader value string paramName = paramNameObject.get<string>(); if(paramName == "diffuse") { string texRelativePath = valueObject.get<string>(); string texAbsPath = project_dir + texRelativePath; // create texture loader LoadTexture textureLoader; textureLoader.load(texAbsPath.c_str()); // if texture load error, pass this loading if (!textureLoader.loadStatus) continue; // if this texture have loaded if (textureIsLoaded(texRelativePath)) { shader->textures.emplace_back(getTextureByPath(texRelativePath)); // make connection with pair shader continue; } unsigned int texChannel = Scene::currentActiveTextureChannel; unsigned int textureUnitID = Scene::currentTextureLoaderIndex; //current unique texture unit Texture *tex = CreateTexture(textureLoader,texRelativePath, Texture::BASECOLOR_MAP, texChannel, textureUnitID); cout << "OPENGL->register <diffuse> texture:" << texRelativePath <<" ID:"<<tex->id<< " channel:"<<tex->texChannel<< " unit:"<<tex->textureUnitID <<endl; Scene::currentTextureLoaderIndex+=1; Scene::currentActiveTextureChannel+=1; allTextures.emplace_back(tex); shader->textures.emplace_back(tex);// make connection with pair shader } if(paramName == "specular") { string texRelativePath = valueObject.get<string>(); string texAbsPath = project_dir + texRelativePath; // create texture loader LoadTexture textureLoader; textureLoader.load(texAbsPath.c_str()); // if texture load error, pass this loading if (!textureLoader.loadStatus) continue; // if this texture have loaded if (textureIsLoaded(texRelativePath)){ shader->textures.emplace_back(getTextureByPath(texRelativePath)); // make connection with pair shader continue; } unsigned int texChannel = Scene::currentActiveTextureChannel; unsigned int textureUnitID = Scene::currentTextureLoaderIndex; //current unique texture unit Texture *tex = CreateTexture(textureLoader,texRelativePath, Texture::SPECULAR_MAP, texChannel, textureUnitID); cout << "OPENGL->register <specular> texture:" << texRelativePath <<" ID:"<<tex->id<< " channel:"<<tex->texChannel<< " unit:"<<tex->textureUnitID <<endl; Scene::currentTextureLoaderIndex+=1; Scene::currentActiveTextureChannel+=1; allTextures.emplace_back(tex); shader->textures.emplace_back(tex);// make connection with pair shader } } // end of mat param settings allShaders.emplace_back(shader); // place shader in our container }//end of loop material } void Scene::parseAssignMats() { // loop all model cout << ">> -------------- Parse Assign Mat Start--------------------- "; json matTree = j["assignMaterial"]; for(auto &tree: matTree.items()){ json locationPWDObject = tree.key(); json locationMatNameObject = tree.value(); string locationPWD = locationPWDObject.get<string>(); string locationMatName = locationMatNameObject.get<string>(); LoadShader *shader = getShaderByName(locationMatName); if (!shader){ cout << "ERROR Try to assign:"<< locationPWD <<",But can not find material in material pool:" << locationMatName <<endl; continue; } // loop all model, find the location for(auto &model: allModels){ SceneLocation *loc = model->getLocationByPath(locationPWD); loc->mesh->assignMaterial(*shader); cout << "assign:" << shader->shaderName << " to:" << loc->pwd <<endl; } } cout << ">> -------------- Parse Assign Mat End--------------------- "; } }// end of namespace #endif //TRIANGLE_ALG_SCENEDELEGATE_H
// // Created by Admin on 2020/2/23. // #ifndef TRIANGLE_ALG_SCENEDELEGATE_H #define TRIANGLE_ALG_SCENEDELEGATE_H #include <iostream> #include <json.hpp> #include <string> #include <fstream> #include <iomanip> #include <vector> #include "ALG_LoadShader.h" #include "ALG_ModelDelegate.h" #include "ALG_LoadTexture.h" #include "ALG_MeshDelegate.h" // texture struct namespace AlgebraMaster{ // namespace using namespace std; using json = nlohmann::json; // bool checkJsonError(json &j,string msg); bool checkJsonError(json &j,string msg) { if (j.is_null()) { cout << "ERROR JSON:" << msg<<endl; return true; } return false; } template <typename T> void FreeSTLMemory(T & container); template <typename T> void FreeSTLMemory(T & container){ // release mats mem for(auto &c: container){ delete c; } container.clear(); } Texture *CreateTexture(const LoadTexture &textureLoader, const string &relativeTexturePath, Texture::Type type, unsigned int textureChannel, unsigned int textureUnitID); Texture *CreateTexture(const LoadTexture &textureLoader, const string &relativeTexturePath, Texture::Type type, unsigned int textureChannel, unsigned int textureUnitID) { // create texture object auto *texture = new Texture; // Create our texture object texture->id = textureLoader.getTextureID(); // Assign GL_TextureID to our texture object texture->texType = type; // set texture type texture->path = relativeTexturePath; // set texture path is relative texture->texChannel = textureChannel; texture->textureUnitID = textureUnitID; //current unique texture unit return texture; } //* scene description from json object/ class Scene{ public: Scene(); virtual ~Scene(); void read(const string &path); void save(const string &path)const; virtual void draw(); string getSceneName()const; void setSceneName(const string &name); Texture * getTextureByPath(const string &path){ for(auto &t: allTextures){ if(t->path == path)return t; } return nullptr; } vector<LoadShader *> allShaders; vector<Texture*> allTextures; // all texture from json file , this index will as GL_activeTexture(TEXTURE0+i) LoadShader* getShaderByName(const string &name){ for(auto &m : allShaders){ if(m->shaderName == name) return m; } return nullptr; } void debugShaders(){ for(auto &s: allShaders){ cout <<"Scene::debugShaders debug shader pool have:" << s->shaderName <<endl; } } void parseInitialize(); // read mesh void parseModel(); void parseMats(); void parseAssignMats(); void setMatrix(glm::mat4 &proj , glm::mat4 & view , glm::mat4 model = glm::mat4(1.0f)); //override all model mats void assignMaterial(LoadShader &shader){ for(auto &m : allModels){ m->assignMaterial(shader); } } vector<Model*> allModels; private: // * scene description json obj */ json j; // proj string project_dir; // bool textureIsLoaded(const string &texturePath); public: static int currentActiveTextureChannel; static int currentTextureLoaderIndex; }; int Scene::currentActiveTextureChannel = GL_TEXTURE0; int Scene::currentTextureLoaderIndex = 0; // ------------------ DEFINE FUNCTION -------------------------- Scene::Scene(){ } Scene::~Scene() { // release mats mem cout << "---------------Memory Release---------------------- "; cout << "free model's mem "; FreeSTLMemory(allModels); // cout << "free all textures mem "; FreeSTLMemory(allTextures); // cout << "free all shaders mem "; FreeSTLMemory(allShaders); cout << "---------------Memory Release---------------------- "; } bool Scene::textureIsLoaded(const string &texturePath) { bool isLoaded = false; for(auto &tex: allTextures){ if (tex->path == texturePath){ isLoaded = true; } } return isLoaded; } void Scene::setMatrix(glm::mat4 &proj , glm::mat4 &view , glm::mat4 model) { for(auto &mod :allModels){ for(auto &loc: mod->getLocations()) { loc->mesh->shader.setMatrix(model, view, proj); } } } // Read File void Scene::read(const string &path) { ifstream in(path.c_str()); in >> j; } // Write File void Scene::save(const string &path) const{ // write prettified JSON to another file ofstream o(path.c_str()); o << setw(4) << j << std::endl; } string Scene::getSceneName() const { auto name = j["name"]; if( name){ return name; } return "ERROR SCENE NAME"; } void Scene::setSceneName(const string &name) { j["name"] = name; } void Scene::draw() { for(auto &m : allModels){ m->draw(); } } void Scene::parseInitialize() { string temp_proj_dir = j["project_dir"]; temp_proj_dir += "/"; project_dir = temp_proj_dir; } void Scene::parseModel() { cout << j["models"] <<endl; for(string path :j["models"]){ auto *model = new Model; string absPath = project_dir + path; cout << "Scene Parse Read mesh:" << absPath <<endl; model->readMesh(absPath); this->allModels.emplace_back(model); } } void Scene::parseMats() { json globalVertFileObj = j["global_vert_file"]; json globalFragFileObj = j["global_frag_file"]; json globalGeomFileObj = j["global_geom_file"]; // Get global shader file path string globalVertRelFilePath = globalVertFileObj.get<string>(); string globalFragRelFilePath = globalFragFileObj.get<string>(); string globalGeomRelFilePath = globalGeomFileObj.get<string>(); json mats = j["mats"]; for (auto& mat : mats.items()) { json matNameObject = mat.key(); // json mat name json matContentObject = mat.value(); // json tex json shaderDefineObject = matContentObject["shader_define"]; json codeTypeObject = shaderDefineObject["code_type"]; json fragCodeObject = shaderDefineObject["frag_code"]; json vertCodeObject = shaderDefineObject["vert_code"]; // Get may be used local file to create shader json vertFileObject = shaderDefineObject["vert_file"]; // ----------- INIT shader pointer--------------------- auto *shader = new LoadShader; // ----------- INIT shader pointer--------------------- bool jsonIsError = false; // if is error , create default mat jsonIsError = checkJsonError(shaderDefineObject,"Can not find key ->shader_define ,create default color shader"); if(jsonIsError) { shader->asSimpleShader(); return; } jsonIsError = checkJsonError(codeTypeObject,"Can not find key ->code_type ,create default color shader"); if(jsonIsError){ shader->asSimpleShader(); return; } jsonIsError = checkJsonError(fragCodeObject,"Can not find key ->frag_code ,create default color shader"); if(jsonIsError){ shader->asSimpleShader(); return; } jsonIsError = checkJsonError(vertCodeObject,"Can not find key ->vert_code ,create default color shader"); if(jsonIsError){ shader->asSimpleShader(); return; } // JSON shader_define values string std_strMatName = matNameObject.get<string>(); // mat name int codeType = codeTypeObject.get<int>(); string fragCode = fragCodeObject.get<string>(); string vertCode = vertCodeObject.get<string>(); cout << "system create mat:" << std_strMatName << " codeType:" <<codeType <<endl; switch (codeType) { case 0: { shader->asSimpleShader(); shader->shaderName = std_strMatName; break; } case 1: { shader->asSimpleTextureShader(); shader->shaderName = std_strMatName; break; } case 3: { shader->fromSrc(vertCode,fragCode); shader->shaderName = std_strMatName; break; } case 5:{ shader->load(globalVertRelFilePath.c_str(), globalFragRelFilePath.c_str()); shader->shaderName = std_strMatName; break; } default: // create in line shader shader->asSimpleShader(); shader->shaderName = std_strMatName; break; } // shader param define json paramDefineObject = matContentObject["params_define"]; for(auto ¶ms: paramDefineObject.items()) { json paramNameObject = params.key(); json valueObject = params.value(); // may be relative texture path , or shader value string paramName = paramNameObject.get<string>(); if(paramName == "diffuse") { string texRelativePath = valueObject.get<string>(); string texAbsPath = project_dir + texRelativePath; // create texture loader LoadTexture textureLoader; textureLoader.load(texAbsPath.c_str()); // if texture load error, pass this loading if (!textureLoader.loadStatus) continue; // if this texture have loaded if (textureIsLoaded(texRelativePath)) { shader->textures.emplace_back(getTextureByPath(texRelativePath)); // make connection with pair shader continue; } unsigned int texChannel = Scene::currentActiveTextureChannel; unsigned int textureUnitID = Scene::currentTextureLoaderIndex; //current unique texture unit Texture *tex = CreateTexture(textureLoader,texRelativePath, Texture::BASECOLOR_MAP, texChannel, textureUnitID); cout << "OPENGL->register <diffuse> texture:" << texRelativePath <<" ID:"<<tex->id<< " channel:"<<tex->texChannel<< " unit:"<<tex->textureUnitID <<endl; Scene::currentTextureLoaderIndex+=1; Scene::currentActiveTextureChannel+=1; allTextures.emplace_back(tex); shader->textures.emplace_back(tex);// make connection with pair shader } if(paramName == "specular") { string texRelativePath = valueObject.get<string>(); string texAbsPath = project_dir + texRelativePath; // create texture loader LoadTexture textureLoader; textureLoader.load(texAbsPath.c_str()); // if texture load error, pass this loading if (!textureLoader.loadStatus) continue; // if this texture have loaded if (textureIsLoaded(texRelativePath)){ shader->textures.emplace_back(getTextureByPath(texRelativePath)); // make connection with pair shader continue; } unsigned int texChannel = Scene::currentActiveTextureChannel; unsigned int textureUnitID = Scene::currentTextureLoaderIndex; //current unique texture unit Texture *tex = CreateTexture(textureLoader,texRelativePath, Texture::SPECULAR_MAP, texChannel, textureUnitID); cout << "OPENGL->register <specular> texture:" << texRelativePath <<" ID:"<<tex->id<< " channel:"<<tex->texChannel<< " unit:"<<tex->textureUnitID <<endl; Scene::currentTextureLoaderIndex+=1; Scene::currentActiveTextureChannel+=1; allTextures.emplace_back(tex); shader->textures.emplace_back(tex);// make connection with pair shader } } // end of mat param settings allShaders.emplace_back(shader); // place shader in our container }//end of loop material } void Scene::parseAssignMats() { // loop all model cout << ">> -------------- Parse Assign Mat Start--------------------- "; json matTree = j["assignMaterial"]; for(auto &tree: matTree.items()){ json locationPWDObject = tree.key(); json locationMatNameObject = tree.value(); string locationPWD = locationPWDObject.get<string>(); string locationMatName = locationMatNameObject.get<string>(); LoadShader *shader = getShaderByName(locationMatName); if (!shader){ cout << "ERROR Try to assign:"<< locationPWD <<",But can not find material in material pool:" << locationMatName <<endl; continue; } // loop all model, find the location for(auto &model: allModels){ SceneLocation *loc = model->getLocationByPath(locationPWD); loc->mesh->assignMaterial(*shader); cout << "assign:" << shader->shaderName << " to:" << loc->pwd <<endl; } } cout << ">> -------------- Parse Assign Mat End--------------------- "; } }// end of namespace #endif //TRIANGLE_ALG_SCENEDELEGATE_H
#define GLEW_STATIC // GLEW #include <GL/glew.h> #include <cstdlib> #undef GLFW_DLL // GLFW #include <GLFW/glfw3.h> #include <iostream> #include "ALG_LoadShader.h" #include "ALG_LoadTexture.h" #include "ALG_GLFWCamera.h" #include "ALG_FrameWindow.h" #include "ALG_ModelDelegate.h" #include "ALG_SceneDelegate.h" #include "ALG_DrawGrid.h" #include "ALG_DrawOriginGnomon.h" #include <cmath> #include "ALG_Random.h" #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> using namespace AlgebraMaster; const unsigned int SRC_WIDTH = 1400; const unsigned int SRC_HEIGHT = 720; static GLuint cubeVAO,VBO; static GLuint lightVAO; //VBO stays the same; the vertices are the same for the light object which is also a 3D cube static LoadShader SurfaceShader; void init(); void display(); void processInput(GLFWwindow *window); void framebuffer_size_callback(GLFWwindow* window, int width, int height); // framezize void mouse_callback(GLFWwindow* window, double xpos, double ypos); // Maya Alt+LeftMouse void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); // camera static GLFWCamera *camera; static float lastX = float(SRC_WIDTH) / 2.0f; static float lastY = float(SRC_HEIGHT) / 2.0f; static bool firstMouse = true; static bool firstMiddowMouse = true; // timing static float deltaTime = 0.0f; // time between current frame and last frame static float lastFrame = 0.0f; // light define static glm::vec3 lightPos(0.0f, 4.0f,-2.0f); static Scene scene; static DrawGrid grid; static DrawOriginGnomon gnomon; const int amount = 10000; void init(){ camera = new GLFWCamera; camera->pos.y = 5.0f; camera->pos.z = 25.0f; // GL depth zbuffer glEnable(GL_DEPTH_TEST); SurfaceShader.load("shaders/standard_surface/SurfaceShader.vert","shaders/standard_surface/SurfaceShader.frag"); scene.read("scene/scene.json"); scene.parseInitialize(); scene.parseModel(); scene.parseMats(); scene.parseAssignMats(); grid.initialize(); gnomon.initialize(); // Instance Array building: auto *modelMatrices = new glm::mat4[amount]; RandomN1P1 xPosSet(amount, 1); RandomN1P1 zPosSet(amount, 2); RandomN1P1 rotAmount(amount,3); Random01 scaleAmount(amount,4); //cout << scaleAmount <<endl; for(int i=0;i<amount;i++) { // new translate glm::mat4 model(1.0f); model = glm::translate(model,glm::vec3(xPosSet[i]*100, 0.0, zPosSet[i]*100 ) ); // new rot glm::mat4 rot(1.0f); rot = glm::rotate(rot,glm::radians(rotAmount[i]*360) , glm::vec3(0.0,1.0,0.0)); // R S T order glm::mat4 scale(1.0f); scale = glm::scale( scale,glm::vec3(scaleAmount[i]) ); modelMatrices[i] = model * scale * rot ; } //object share one mem buffer of instance unsigned int buffer; glCreateBuffers(1, &buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer); glBufferData(GL_ARRAY_BUFFER, amount * sizeof(glm::mat4), &modelMatrices[0], GL_STATIC_DRAW); for(auto &model: scene.allModels){ for(auto &loc: model->locations) { glBindVertexArray(loc->mesh->VAO); glEnableVertexAttribArray(10); glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0); glEnableVertexAttribArray(11); glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4))); glEnableVertexAttribArray(12); glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(2 * sizeof(glm::vec4))); glEnableVertexAttribArray(13); glVertexAttribPointer(13, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(3 * sizeof(glm::vec4))); glVertexAttribDivisor(10, 1); glVertexAttribDivisor(11, 1); glVertexAttribDivisor(12, 1); glVertexAttribDivisor(13, 1); glBindVertexArray(0); } } delete [] modelMatrices; } // ----------- Render Loop ---------- void display(){ // per-frame time logic // -------------------- float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; glClearColor(0.2f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // object .vert settings glm::mat4 projection = glm::perspective(glm::radians(camera->fov),float(SRC_WIDTH) / float(SRC_HEIGHT),0.1f, 1000.0f); glm::mat4 view = camera->GetViewMatrix(); // object world transformation glm::mat4 model = glm::mat4(1.0f); scene.setMatrix(projection,view,model); for(auto &m: scene.allModels){ for(auto &loc: m->locations){ glBindVertexArray(loc->mesh->VAO); loc->mesh->shader.use(); loc->mesh->shader.setInt("useInstance", 1); loc->mesh->shader.setMatrix(model,view,projection); loc->mesh->allocateTextureChannelFromShader(loc->mesh->shader); //loc->mesh->draw(); //glDrawElements(GL_TRIANGLES, loc->mesh->indices.size(), GL_UNSIGNED_INT, 0); glDrawElementsInstanced(GL_TRIANGLES, loc->mesh->indices.size(), GL_UNSIGNED_INT, 0, amount); glBindVertexArray(0); } } grid.draw(projection,view); gnomon.draw(projection,view); } int main() { glfwInit(); FrameWindow FrameWindow(SRC_WIDTH,SRC_HEIGHT); glfwSetFramebufferSizeCallback(FrameWindow.getWindow(), framebuffer_size_callback); glfwSetCursorPosCallback(FrameWindow.getWindow(),mouse_callback); glfwSetScrollCallback(FrameWindow.getWindow(), scroll_callback); init(); // RENDER-------------- while(!glfwWindowShouldClose(FrameWindow.getWindow())){ processInput(FrameWindow.getWindow()); display(); glfwSwapBuffers(FrameWindow.getWindow()); glfwPollEvents(); } delete camera; return 0; } void framebuffer_size_callback(GLFWwindow* window, int width, int height) { // make sure the viewport matches the new window dimensions; note that width and // height will be significantly larger than specified on retina displays. glViewport(0, 0, width, height); } void processInput(GLFWwindow *window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) glfwSetWindowShouldClose(window, true); if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::FORWARD); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::BACKWARD); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::LEFT); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) camera->processKeyboardMove(deltaTime,GLFWCamera::RIGHT); } // ROTATE VIEW DIR void mouse_callback(GLFWwindow* window, double xpos, double ypos){ int middow_mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_MIDDLE); int mouse_state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT); int key_state = glfwGetKey(window,GLFW_KEY_LEFT_ALT); // set up the camera view if( mouse_state == GLFW_PRESS && key_state== GLFW_PRESS) { if (firstMouse){ lastX = xpos; lastY = ypos; firstMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera->processMouseMove(xoffset,yoffset); } if (key_state == GLFW_RELEASE || mouse_state == GLFW_RELEASE){ firstMouse = true; } // Move Camera Position if( middow_mouse_state == GLFW_PRESS) { if (firstMiddowMouse){ lastX = xpos; lastY = ypos; firstMiddowMouse = false; } float xoffset = xpos - lastX; float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top lastX = xpos; lastY = ypos; camera->pos.x += xoffset*0.01f; camera->pos.y += yoffset*0.01f; } if ( middow_mouse_state == GLFW_RELEASE){ firstMiddowMouse = true; } } void scroll_callback(GLFWwindow *window, double xoffset, double yoffset){ camera->processFov(yoffset); }
#version 450 core // INCOMING DATA layout ( location = 0 ) in vec4 v_position; // pos layout ( location = 1 ) in vec3 v_normal; // norm layout ( location = 2 ) in vec2 v_texCoord; // st layout ( location = 10 ) in mat4 v_instanceMatrix; // instancer matrix , because have 4 * 4 row , so location 4 5 6 will use to construct this matrix // define out data out vec2 f_TexCoord; // normal at world matrix, we direct from C++ calcalation out vec3 f_Normal; // to world matrix : mat3( transpose(inverse(model)) ) * v_normal; out vec3 f_Pos; // INCOMING THE MATRIX FROM CLIENT to transform the gl point position uniform mat4 model; uniform mat4 view; uniform mat4 projection; // if use Instance Matrix uniform bool useInstance; void main(){ // Transform the world matrix to view matrix if (useInstance){ gl_Position = projection * view * v_instanceMatrix * model * v_position; f_Normal = mat3(transpose(inverse(v_instanceMatrix*model))) * v_normal; // f_Normal at world matrix } else{ gl_Position = projection * view * model * v_position; f_Normal = mat3(transpose(inverse(model))) * v_normal; // f_Normal at world matrix } //gl_Position = projection * view * model * v_position; f_TexCoord = v_texCoord; // out TexCoord f_Pos = vec3(model *v_position); // out fragment position }
#version 450 core // Final Color To export out vec4 FragColor; // from vert shader in vec3 f_Normal; in vec2 f_TexCoord; in vec3 f_Pos; // fragment position struct Material { float Kd; // diffuse mult float kS; // specular mult float shininess; // phong pow(,shine) sampler2D diffuse_map; sampler2D specular_map; sampler2D emission_map; bool have_diffuse_map; bool have_specular_map; bool have_emission_map; }; uniform vec3 viewPos; uniform Material material; void main() { vec4 df_tex = vec4(1,0,0,0); vec4 spec_tex = vec4(0,1,0,0); int test = int(material.have_diffuse_map); if(material.have_diffuse_map){df_tex=texture(material.diffuse_map, f_TexCoord);} if(material.have_specular_map){spec_tex=texture(material.specular_map, f_TexCoord);} FragColor = vec4(df_tex.rgb,1.0); }
由于我写的场景描述,到main中依然很轻松的访问绘制过程。
for(auto &m: scene.allModels){ for(auto &loc: m->locations){ glBindVertexArray(loc->mesh->VAO); loc->mesh->shader.use(); loc->mesh->shader.setInt("useInstance", 1); loc->mesh->shader.setMatrix(model,view,projection); loc->mesh->allocateTextureChannelFromShader(loc->mesh->shader); //loc->mesh->draw(); //glDrawElements(GL_TRIANGLES, loc->mesh->indices.size(), GL_UNSIGNED_INT, 0); glDrawElementsInstanced(GL_TRIANGLES, loc->mesh->indices.size(), GL_UNSIGNED_INT, 0, amount); glBindVertexArray(0); } }