-OPENGL7 Geometry & Instance-

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
View Code

集合体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);
}
SurfaceShader.frag
#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;

}
SurfaceShader.vert
#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);
}
main.cpp

法线向量显示:

首先在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
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);
}
main.cpp

 

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
ALG_MeshDelegate.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
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 &params: 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
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 &params: 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
scene.json
#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);
}
main.cpp
#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
}
SurfaceShader.vert
#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);
}
SurfaceShader.frag

由于我写的场景描述,到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);
        }
    }
原文地址:https://www.cnblogs.com/gearslogy/p/12411367.html