-OPENGL5 Model Import & Scene Graph & Blend Opacity-

ASSIMP构建大纲:

因为递归的原因有必要把大纲还原,类似katana和maya大纲一样

以maya为例:(输出的时候别导出obj,fbx可以保护层级,abc也可以,但是现在assimp不支持,回头可以用abc api 搞一个)

所以我在函数原型加入一个pwd

void processNode(aiNode * node, const aiScene* scene,string pwd);
#include <iostream>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <string>
using namespace std;

void processNode(aiNode * node, const aiScene* scene, string pwd);
int main(){
    Assimp::Importer import;
    string path = "maya.fbx";
    const aiScene * scene = import.ReadFile(path, aiProcess_Triangulate | aiProcess_FlipUVs);
    if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
    {
        cout << "ERROR::ASSIMP::" << import.GetErrorString() << endl;

    }

    string directory = path.substr(0, path.find_last_of('/'));
    cout << directory << endl;

    // Get Root Node
    aiNode * node = scene->mRootNode;
    processNode(node,scene,"/");





    return 0;
}

void processNode(aiNode * node, const aiScene* scene,string pwd){

    cout << ">>LOOP At Node:" << pwd <<" WORLD MATRIX:" << endl;
    aiMatrix4x4 mat =  node->mTransformation;
    cout << "{
";
    cout << "	" <<mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << endl;
    cout << "	" <<mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << endl;
    cout << "	" <<mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << endl;
    cout << "	" <<mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4 << endl;
    cout << "}
";

    for(unsigned int i = 0; i < node->mNumMeshes; i++)
    {
        aiMesh *mesh = scene->mMeshes[node->mMeshes[i]];

        // mesh points
        cout <<">>Num points:" <<mesh->mNumVertices<< endl;

        // Dump materials infos
        aiMaterial *mat = scene->mMaterials[mesh->mMaterialIndex];
        cout << ">>Get Mesh Name: "<<mesh->mName.C_Str()<< " <->  MaterialName: " << mat->GetName().C_Str()  << endl;
        cout << ">>start dumping the texture:
";
        cout << "{
";
        for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_DIFFUSE); i++)
        {
            aiString str;
            mat->GetTexture(aiTextureType_DIFFUSE, i, &str);
            cout << "	diffuseTexture: "<<str.C_Str() << endl;
        }
        for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_NORMALS); i++)
        {
            aiString str;
            mat->GetTexture(aiTextureType_NORMALS, i, &str);
            cout << "	NormalTexture: "<<str.C_Str() << endl;
        }
        for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_AMBIENT); i++)
        {
            aiString str;
            mat->GetTexture(aiTextureType_AMBIENT, i, &str);
            cout << "	AmbientTexture: "<<str.C_Str() << endl;
        }
        for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_OPACITY); i++)
        {
            aiString str;
            mat->GetTexture(aiTextureType_OPACITY, i, &str);
            cout << "	OpacityTexture: "<<str.C_Str() << endl;
        }
        for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_SPECULAR); i++)
        {
            aiString str;
            mat->GetTexture(aiTextureType_SPECULAR, i, &str);
            cout << "	SpecularTexture: "<<str.C_Str() << endl;
        }
        for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_HEIGHT); i++)
        {
            aiString str;
            mat->GetTexture(aiTextureType_HEIGHT, i, &str);
            cout << "	HeightTexture: "<<str.C_Str() << endl;
        }
        for(unsigned int i = 0; i < mat->GetTextureCount(aiTextureType_UNKNOWN); i++)
        {
            aiString str;
            mat->GetTexture(aiTextureType_HEIGHT, i, &str);
            cout << "	UnkownTexture: "<<str.C_Str() << endl;
        }
        cout << "}
";

    }

    for(unsigned int i = 0; i < node->mNumChildren; i++)
    {

        string pathName =  pwd + node->mChildren[i]->mName.C_Str();
        pathName += "/";
        processNode(node->mChildren[i], scene,pathName);
    }


    cout << "
";

}
main.cpp

DUMP:

maya.fbx
>>LOOP At Node:/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 0
    0 0 1 0
    0 0 0 1
}
>>LOOP At Node:/Geometry/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 0
    0 0 1 0
    0 0 0 1
}
>>LOOP At Node:/Geometry/part1/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 0
    0 0 1 0
    0 0 0 1
}
>>LOOP At Node:/Geometry/part1/pSphere1/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 0
    0 0 1 0
    0 0 0 1
}
>>Num points:1560
>>Get Mesh Name: pSphere1 <->  MaterialName: lambert1
>>start dumping the texture:
{
}

>>LOOP At Node:/Geometry/part1/pSphere2/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 2.17013
    0 0 1 0
    0 0 0 1
}
>>Num points:1560
>>Get Mesh Name: pSphere2 <->  MaterialName: lambert1
>>start dumping the texture:
{
}

>>LOOP At Node:/Geometry/part1/pSphere3/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 4.34026
    0 0 1 0
    0 0 0 1
}
>>Num points:1560
>>Get Mesh Name: pSphere3 <->  MaterialName: lambert1
>>start dumping the texture:
{
}

>>LOOP At Node:/Geometry/part1/pSphere4/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 6.51039
    0 0 1 0
    0 0 0 1
}
>>Num points:1560
>>Get Mesh Name: pSphere4 <->  MaterialName: lambert1
>>start dumping the texture:
{
}


>>LOOP At Node:/Geometry/part2/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 0
    0 0 1 0
    0 0 0 1
}
>>LOOP At Node:/Geometry/part2/pSphere5/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 8.68052
    0 0 1 0
    0 0 0 1
}
>>Num points:1560
>>Get Mesh Name: pSphere5 <->  MaterialName: lambert1
>>start dumping the texture:
{
}

>>LOOP At Node:/Geometry/part2/pSphere6/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 10.8507
    0 0 1 0
    0 0 0 1
}
>>Num points:1560
>>Get Mesh Name: pSphere6 <->  MaterialName: lambert1
>>start dumping the texture:
{
}

>>LOOP At Node:/Geometry/part2/pSphere7/ WORLD MATRIX:
{
    1 0 0 0
    0 1 0 13.0208
    0 0 1 0
    0 0 0 1
}
>>Num points:1560
>>Get Mesh Name: pSphere7 <->  MaterialName: lambert1
>>start dumping the texture:
{
}

额外的我定义了我的场景描述,已经修改的跪下了,每次写代码遍历场景,发现特么的完全不科学。

json用的https://github.com/nlohmann/json

CP19会实现场景分析,加载场景。CP18修改了一些系统内部逻辑设计。

{
    "name": "simple",
    "project_dir": "D:/plugin_dev/opengl/CP_18/Triangle/build/scene",
    "models": [
        "model/nanosuit.obj"
    ],
    "mats": {
        "glass": {
            "shader_define": {
                "___comment___": "type=0 is file shader; type=1 use inline color ; type=2 use inline texture; type=3 use our json code shader,this may be use in our ui ",
                "code_type": 0,
                "frag_code": "",
                "vert_code": ""
            },
            "params_define": {
                "diffuse": "model/glass_dif.png"
            }
        },
        "leg": {
            "shader_define": {
                "code_type": 0,
                "frag_code": "",
                "vert_code": ""
            },
            "params_define": {
                "diffuse": "model/leg_dif.png",
                "specular": "model/leg_showroom_spec.png"
            }
        },
        "hand": {
            "shader_define": {
                "code_type": 0,
                "frag_code": "",
                "vert_code": ""
            },
            "params_define": {
                "diffuse": "model/hand_dif.png",
                "specular": "model/hand_showroom_spec.png"
            }
        },
        "body": {
            "shader_define": {
                "code_type": 0,
                "frag_code": "",
                "vert_code": ""
            },
            "params_define": {
                "diffuse": "model/mat2_diffuse.png",
                "specular": "model/mat2_specular.png"
            }
        },
        "helmet": {
            "shader_define": {
                "code_type": 0,
                "frag_code": "",
                "vert_code": ""
            },
            "params_define": {
                "diffuse": "model/helmet_diff.png",
                "specular": "model/helmet_showroom_spec.png"
            }
        },
        "arms": {
            "shader_define": {
                "code_type": 0,
                "frag_code": "",
                "vert_code": ""
            },
            "params_define": {
                "diffuse": "model/arm_dif.png",
                "specular": "model/arm_showroom_spec.png"
            }
        }
    },
  
    "assignMaterial": {
        "/Visor": "glass",
        "/Lights": "glass",
        "/Legs": "leg",
        "/hands": "hand",
        "/Arms": "arms",
        "/Helmet": "helmet",
        "/Body": "body"
    }
}
#include <iostream>
#include <json.hpp>
#include <fstream>
using namespace std;
using json = nlohmann::json;
int main()
{
    ifstream  in("scene.json");
    json j;
    in >> j;
    cout << "scene name:" << j.at("name") << endl;
    cout << "project dir" << j.at("project_dir") <<endl;

    for(auto &m: j["models"]){
        cout << "load model:" << m.get<string>() <<endl;
    }

    cout << "
Parse Materials:
";
    // read "mats"
    json mats = j["mats"];

    for(auto &mat: mats.items()){
        json matNameObject = mat.key(); // json mat name
        json matContentObject = mat.value();  // json shader content define
        cout << "Inspect mat:" << matNameObject <<endl;

        json shaderDefineObject =  matContentObject["shader_define"];
        json paramDefineObject = matContentObject["params_define"];

        //cout << shaderDefineObject <<endl;
        //cout << paramDefineObject << endl;

        for(auto &params: paramDefineObject.items())
        {
            json paramNameObject = params.key();
            json valueObject = params.value(); // may be relative texture path , or shader value
            string pname = paramNameObject.get<string>();
            if(pname == "diffuse"){
                cout << "diffuse: " << valueObject <<endl;
            }
            if(pname == "specular"){
                cout << "specular: " << valueObject <<endl;
            }
        }
        cout << "
";

    }

    return 0;
}
cpp场景分析

Log:

21:36:39: Starting D:plugin_devopenglJSON_CP_01JSON_Scene_ParseJSON_Scene_Parse.exe ...
scene name:"simple"
project dir"D:/plugin_dev/opengl/CP_18/Triangle/build/scene"
load model:model/nanosuit.obj

Parse Materials:
Inspect mat:"arms"
diffuse: "model/arm_dif.png"
specular: "model/arm_showroom_spec.png"

Inspect mat:"body"
diffuse: "model/mat2_diffuse.png"
specular: "model/mat2_specular.png"

Inspect mat:"glass"
diffuse: "model/glass_dif.png"

Inspect mat:"hand"
diffuse: "model/hand_dif.png"
specular: "model/hand_showroom_spec.png"

Inspect mat:"helmet"
diffuse: "model/helmet_diff.png"
specular: "model/helmet_showroom_spec.png"

Inspect mat:"leg"
diffuse: "model/leg_dif.png"
specular: "model/leg_showroom_spec.png"

21:36:39: D:plugin_devopenglJSON_CP_01JSON_Scene_ParseJSON_Scene_Parse.exe exited with code 0

CP18:

locations debug;

//
// Created by admin on 2020/2/21.
//

#ifndef TRIANGLE_ALG_MODELDELEGATE_H
#define TRIANGLE_ALG_MODELDELEGATE_H
#include <string>
#include <vector>
#include "ALG_MeshDelegate.h"
#include "ALG_LoadShader.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>


namespace AlgebraMaster
{
using namespace std;


// helper method for exchange aiMatrix to glm matrix
void exchange_matrix_data(glm::mat4 &DesMatrix,const aiMatrix4x4 & srcAssimpMat);

// ----------------------- SCENE LOCATION --------------------------------
struct SceneLocation{
    // function
    SceneLocation();
    ~SceneLocation();

    // vars
    string pwd;
    glm::mat4 worldTransform;
    string type; // group or Mesh
    Mesh *mesh;
};

SceneLocation::SceneLocation():pwd(""),worldTransform(1.0f),type("group"),mesh(nullptr){
}
SceneLocation::~SceneLocation() {
    if(mesh)
        delete mesh;
}

// ----------------------- SCENE LOCATION --------------------------------




// ----------------------- SCENE Model --------------------------------
class Model{
public:
    //* Read Mesh from path */
    Model() = default;
    explicit Model(const string& path);
    ~Model();

    void readMesh(const string& path);
    //* overwrite all mesh material */
    void assignMaterial(const LoadShader &shader);
    //* paint mesh in opengl */
    void draw();
    //* get the locations */
    vector<SceneLocation*> getLocations();

    // use default shader
    inline void useSimpleShader(){
        cout << "Model Used basic shader that should call useSimpleShaderMatrix() in render loop !
";
        for(auto &loc :locations){
            loc->mesh->shader.asSimpleShader();
        }
    }
    inline void useSimpleShaderMatrix(glm::mat4 &proj, glm::mat4 &view, glm::mat4 &model){
        for(auto &loc :locations){
            loc->mesh->shader.use();
            loc->mesh->shader.setMat4("projection", proj);
            loc->mesh->shader.setMat4("view", view);
            loc->mesh->shader.setMat4("model", model);

        }
    }
    inline void debugLocations(){
        cout << "debug locations:
";
        cout << "{
";
        for(auto&loc : locations){
            cout <<"	SceneGraph:" <<loc->pwd <<"	Type:" <<loc->type << endl;
        }
        cout << "}
";
    }



private:

    // vars
    vector<SceneLocation*> locations;
    string directory; // the mesh location at filesystem path


    // functions from assimp to our struct
    void processNode(aiNode *assimpNode,const aiScene* assimpScene, string pwd);
    Mesh* processMesh(aiMesh *assimpMesh, const aiScene *assimpScene);

};



// constructor
Model::Model(const string &path) {
    readMesh(path);
}
Model::~Model() {
    for(auto & location : locations){
        delete location;
    }
    locations.clear();
}

vector<SceneLocation *> Model::getLocations() {
    return this->locations;
}

void Model::draw(){
    for_each(locations.begin(),locations.end(),[](SceneLocation* l){l->mesh->draw();});
}
void Model::assignMaterial(const LoadShader &shader) {
    for(auto & location : locations){
        location->mesh->assignMaterial(shader);
    }
}

void Model::readMesh(const string &path)
{
    Assimp::Importer import;
    const aiScene * scene = import.ReadFile(path.c_str(),
            aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
    // check error
    if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){
        cout << "ERROR::ASSIMP:: " << import.GetErrorString() << endl;
        return ;
    }
    // retrieve the directory path of the filepath
    directory = path.substr(0, path.find_last_of('/'));

    // process ASSIMP's root node recursively
    processNode(scene->mRootNode, scene,"/");

}

void Model::processNode(aiNode *assimpNode, const aiScene *assimpScene, string pwd) {
    // process each mesh located at the current node
    aiMatrix4x4 mat =  assimpNode->mTransformation;
    auto *location = new SceneLocation;
    location->pwd = pwd;
    if (assimpNode->mNumMeshes<=0)
        location->type = "group";
    else
        location->type = "mesh";
    location->pwd = pwd;
    exchange_matrix_data(location->worldTransform,mat);

    // loop this node's meshs
    for(unsigned int i = 0; i < assimpNode->mNumMeshes; i++)
    {
        // the node object only contains indices to index the actual objects in the scene.
        // the scene contains all the data, node is just to keep stuff organized (like relations between nodes).
        aiMesh* assimpMesh = assimpScene->mMeshes[assimpNode->mMeshes[i]];
        Mesh* mesh = processMesh(assimpMesh,assimpScene);
        location->mesh = mesh;
        this->locations.emplace_back(location);
    }
    // after we've processed all of the meshes (if any) we then recursively process each of the children nodes
    for(unsigned int i = 0; i < assimpNode->mNumChildren; i++)
    {
        string pathName =  pwd + assimpNode->mChildren[i]->mName.C_Str();
        pathName += "/";
        processNode(assimpNode->mChildren[i], assimpScene,pathName);
    }

}
Mesh* Model::processMesh(aiMesh *assimpMesh, const aiScene *assimpScene)
{
    // our mesh interface pointer
    Mesh *mesh = new Mesh;
    // construct mesh data from assimpMesh
    for(unsigned int i =0; i <assimpMesh->mNumVertices;i++){
        Vertex vertex;
        vertex.position.x= assimpMesh->mVertices[i].x;
        vertex.position.y= assimpMesh->mVertices[i].y;
        vertex.position.z= assimpMesh->mVertices[i].z;
        vertex.normal.x = assimpMesh->mNormals[i].x;
        vertex.normal.y = assimpMesh->mNormals[i].y;
        vertex.normal.z = assimpMesh->mNormals[i].z;
        // tex
        if(assimpMesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
        {
            // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
            // use models where a vertex can have multiple texture coordinates so we always take the first set (0).
            vertex.texCoords.x = assimpMesh->mTextureCoords[0][i].x;
            vertex.texCoords.y = assimpMesh->mTextureCoords[0][i].y;
        }
        else{
            vertex.texCoords.x = 0.0f;
            vertex.texCoords.y = 0.0f;
        }
        // tangent
        vertex.tangent.x = assimpMesh->mTangents[i].x;
        vertex.tangent.y = assimpMesh->mTangents[i].y;
        vertex.tangent.z = assimpMesh->mTangents[i].z;
        // bitangent
        vertex.biTangent.x = assimpMesh->mBitangents[i].x;
        vertex.biTangent.y = assimpMesh->mBitangents[i].y;
        vertex.biTangent.z = assimpMesh->mBitangents[i].z;
        mesh->vertices.emplace_back(vertex);
    }
    // indices
    for(int i=0; i<assimpMesh->mNumFaces; i++){
        aiFace face = assimpMesh->mFaces[i];
        for(int j=0;j<face.mNumIndices;j++){
            mesh->indices.emplace_back(face.mIndices[j]);
        }
    }
    mesh->setupMesh();
    return mesh;

}
// ----------------------- SCENE Model --------------------------------




// ---- Helper
void exchange_matrix_data(glm::mat4 &DesMatrix,const aiMatrix4x4 & srcAssimpMat){

    DesMatrix[0].x = srcAssimpMat.a1;
    DesMatrix[0].y = srcAssimpMat.a2;
    DesMatrix[0].z = srcAssimpMat.a3;
    DesMatrix[0].w = srcAssimpMat.a4;

    DesMatrix[1].x = srcAssimpMat.b1;
    DesMatrix[1].y = srcAssimpMat.b2;
    DesMatrix[1].z = srcAssimpMat.b3;
    DesMatrix[1].w = srcAssimpMat.b4;

    DesMatrix[2].x = srcAssimpMat.c1;
    DesMatrix[2].y = srcAssimpMat.c2;
    DesMatrix[2].z = srcAssimpMat.c3;
    DesMatrix[2].w = srcAssimpMat.c4;

    DesMatrix[3].x = srcAssimpMat.d1;
    DesMatrix[3].y = srcAssimpMat.d2;
    DesMatrix[3].z = srcAssimpMat.d3;
    DesMatrix[3].w = srcAssimpMat.d4;
}


} // end of namespace

#endif //TRIANGLE_ALG_MODELDELEGATE_H
ALG_ModelDelegate.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>




namespace AlgebraMaster{


using namespace std;
// Shaders



struct LoadShader
{
    enum ShaderIOType{FILE,INLINE_DEFAULT_PROJECTION };
    void compileShaderProgram(){
        // create shader program and check it
        GLint success;
        GLchar infoLog[512];
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram,vertexShader);
        glAttachShader(shaderProgram,fragmentShader);
        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 shaders as they're linked into our program now and no longer necessery
        glDeleteShader( vertexShader );
        glDeleteShader( fragmentShader );
    }
    void compileVertexShader(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 compileFragmentShader(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;
        }
    }



    LoadShader(){

    }
    void asSimpleShader()
    {
        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 vec4 myColor;
"
                                         "uniform mat4 model;
"
                                         "uniform mat4 view;
"
                                         "uniform mat4 projection;
"
                                         "void main()
"
                                         "{
"
                                         "gl_Position = projection *   view * model * v_position;
"
                                         "myColor = vec4(v_normal , 1);
"
                                         "}";



        const char* fragmentShaderSource = "#version 450 core
"
                                           "out vec4 fColor;
"
                                           "in vec4 myColor;
"
                                           "void main()
"
                                           "{
"
                                           "fColor = myColor;
"
                                           "}
";




        shaderIOType = INLINE_DEFAULT_PROJECTION;
        compileVertexShader(vertexShaderSource);
        compileFragmentShader(fragmentShaderSource);
        compileShaderProgram();
    }


    void setShaderName(const string &name){
        shaderName = name;
    }

    LoadShader(const char*vertPath, const char* fragPath){
        load(vertPath,fragPath);
        shaderIOType = 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;
    }

    void _loadVertexShader(const char *path){

        // read shader code
        auto handle = _readFile(path);
        const char * shaderCode = handle.c_str();
        compileVertexShader(shaderCode);

    }

    void _loadFragmentShader(const char *path){
        // read shader code
        auto handle = _readFile(path);
        const char * shaderCode = handle.c_str();
        compileFragmentShader(shaderCode);
    }

    void load(const char* vertShaderPath, const char* fragShaderPath){
        shaderIOType = FILE;
        _loadVertexShader(vertShaderPath);
        _loadFragmentShader(fragShaderPath);
        // create shader program and check it
        compileShaderProgram();
    }

    void use(){
        glUseProgram(shaderProgram);
    }

    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;
    ShaderIOType shaderIOType;
    string shaderName;
};



}


#endif // LOADSHADER_H
ALG_LoadShader.h
#ifndef WINDOW_H
#define WINDOW_H


#define GLEW_STATIC
#include <GL/glew.h>

#undef GLFW_DLL
#include <GLFW/glfw3.h>





class FrameWindow
{
public:
    FrameWindow(int width,int height,const char*title="OpenGL");
    virtual ~FrameWindow();
    GLFWwindow *getWindow();
private:
     GLFWwindow *window;
     int w;
     int h;
};

FrameWindow::FrameWindow(int width,int height,const char*title){
    w = width;
    h = height;
    glewInit();
    glfwInit();
    window = glfwCreateWindow(width,height,title,NULL,NULL);
    glfwMakeContextCurrent(window);


}
FrameWindow::~FrameWindow(){
    glfwDestroyWindow(window);
    glfwTerminate();
}
GLFWwindow * FrameWindow::getWindow(){
    return window;
}

#endif // WINDOW_H
ALG_FrameWindow.h
#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>
namespace AlgebraMaster
{

using namespace std;



struct Vertex{
    glm::vec3 position;
    glm::vec3 normal;
    glm::vec2 texCoords;
    glm::vec3 tangent;
    glm::vec3 biTangent;
};
struct Texture{
    // Reference houdini principledshader
    enum Type {
        BASECOLOR_MAP, SPECULAR_MAP, EMISSION_MAP,
        BUMP_MAP, NORMAL_MAP, IOR_MAP,
        OPACITY_MAP, DISPLACE_MAP,
        CHAN_TEX0,CHAN_TEX1,CHAN_TEX2,CHAN_TEX3,
        CHAN_TEX4,CHAN_TEX5,CHAN_TEX6,CHAN_TEX7,
        CHAN_TEX8,CHAN_TEX9_CHAN_TEX10
    };
    unsigned int id;
    string path;
    Type texType;
};

struct Mesh
{
public:
    Mesh()= default;
    //* constructor */
    Mesh(const vector<Vertex> &vts,
            const vector<unsigned int>ids,
            const vector<Texture> &texs);
    // rendering data
    vector<Vertex> vertices;
    vector<unsigned int> indices;
    vector<Texture> textures;
    // ogl
    unsigned int VAO,VBO,EBO; // vertex array buffer

    //* this method need called manually */
    void setupMesh();

    // ogl draw
    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,
           const vector<Texture> &texs):vertices(vts),indices(ids),textures(texs){

}

void Mesh::assignMaterial(const LoadShader &rhs_shader) {
    shader.fragmentShader = rhs_shader.fragmentShader;
    shader.vertexShader = rhs_shader.vertexShader;
    shader.shaderProgram = rhs_shader.shaderProgram;
}

// opengl draw the mesh
void Mesh::draw() {
    this->shader.use();
    string mat_prefix = "material.";
    for(int i=0;i<textures.size();i++){
        glActiveTexture(GL_TEXTURE0 + i);
        switch (this->textures[i].texType)
        {
            case Texture::BASECOLOR_MAP:{
                string texchanName = mat_prefix + "diffuse_map";
                shader.setInt(texchanName.c_str(),i);
                break;
            }
            case Texture::SPECULAR_MAP:{
                string texchanName = mat_prefix + "specular_map";
                shader.setInt(texchanName.c_str(),i);
                break;
            }
            case Texture::EMISSION_MAP:{
                string texchanName = mat_prefix + "emission_map";
                shader.setInt(texchanName.c_str(),i);
                break;
            }
            case Texture::BUMP_MAP:{
                string texchanName = mat_prefix + "bump_map";
                shader.setInt(texchanName.c_str(),i);
                break;
            }
            case Texture::NORMAL_MAP:{
                string texchanName = mat_prefix + "normal_map";
                shader.setInt(texchanName.c_str(),i);
                break;
            }
            case Texture::IOR_MAP:{
                string texchanName = mat_prefix + "ior_map";
                shader.setInt(texchanName.c_str(),i);
                break;
            }
            case Texture::OPACITY_MAP:{
                string texchanName = mat_prefix + "opacity_map";
                shader.setInt(texchanName.c_str(),i);
                break;
            }
            case Texture::DISPLACE_MAP:{
                string texchanName = mat_prefix + "displace_map";
                shader.setInt(texchanName.c_str(),i);
                break;
            }
            default:
                break;

        } // end of switch
        glBindTexture(GL_TEXTURE_2D, textures[i].id); // bind current id

    } // end of for each textures


    // 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
#ifndef LOADTEXTURE_H
#define LOADTEXTURE_H
#include <GL/glew.h>

// IMP the stb image loader
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <iostream>
using namespace std;

namespace AlgebraMaster
{



class LoadTexture
{
public:
    LoadTexture()=default;
    LoadTexture(const char *fileName);
    void load(const char *fileName);
    virtual ~LoadTexture();
    inline GLuint getTextureID(){return textureID;}
    inline GLuint getImageFormat(){return format;}
private:
    GLuint textureID;
    GLenum format;
};

void LoadTexture::load(const char *fileName)
{
    glGenTextures(1, &textureID);
    int width, height, nrComponents;
    unsigned char *data = stbi_load(fileName, &width, &height, &nrComponents, 0);
    if (data)
    {
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, textureID);
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);

        stbi_image_free(data);
    }
    else
    {
        std::cout << "Texture failed to load at path: " << fileName << std::endl;
        stbi_image_free(data);
    }

}

LoadTexture::LoadTexture(const char *fileName){
    load(fileName);
}
LoadTexture::~LoadTexture(){}

}
#endif // LOADTEXTURE_H
ALG_LoadTexture.h
#ifndef GLFWCAMERA_H
#define GLFWCAMERA_H

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

namespace AlgebraMaster{



class GLFWCamera{
public:
    GLFWCamera();
    ~GLFWCamera(){}
    enum CAMERA_MOVEMENT{
        FORWARD,     // Camera move to front   ->  key:W
        BACKWARD,    // Camera move to back    ->  key:S
        LEFT,        // Camera move to left    ->  key:A
        RIGHT        // Camera move to right   ->  key:D
    };

public:
    glm::vec3 pos;   // camera world space
    glm::vec3 front;
    glm::vec3 up;

    // Euler Angles
   float yaw;
   float pitch;


   // Camera options
   float movementSpeed;
   float mouseSensitivity;
   float fov;

   void processFov(float yoffset){
       if(fov >= 1.0f && fov <= 45.0f){
           fov -= yoffset;
       }
       if(fov <=1.0f){
           fov = 1.0f;
       }
       if(fov >= 45.0f){
           fov = 45.0f;
       }
   }

   // build the matrix for lookAt
   glm::mat4 GetViewMatrix(){
       return glm::lookAt(pos , pos + front , up);
   }

   // process -Rotate the view-
   void processMouseMove(float xoffset, float yoffset);


   // process -W S A D-
   void processKeyboardMove(float delta, CAMERA_MOVEMENT moveDir);



   void updateFront(){
       glm::vec3 tempfront;
       tempfront.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
       tempfront.y = sin(glm::radians(pitch));
       tempfront.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
       this->front = glm::normalize(tempfront);
   }


};

GLFWCamera::GLFWCamera(){
    pos = glm::vec3(0.0f,0.0f,3.0f);
    up = glm::vec3(0.0f,1.0f,0.0f);
    front = glm::vec3(0.0f,0.0f,-1.0f);
    yaw = -90.0f;
    pitch = 0.0f;
    fov = 45.0f;
    movementSpeed = 4.5f;
    mouseSensitivity = 0.1f;
}

void GLFWCamera::processMouseMove(float xoffset, float yoffset)
{

    xoffset *= mouseSensitivity;
    yoffset *= mouseSensitivity;

    yaw += xoffset;
    pitch += yoffset;

    // make sure that when pitch is out of bounds, screen doesn't get flipped
    if (pitch > 89.0f)
        pitch = 89.0f;
    if (pitch < -89.0f)
        pitch = -89.0f;
    this->updateFront();
}

void GLFWCamera::processKeyboardMove(float delta, CAMERA_MOVEMENT moveDir)
{
    float vel = movementSpeed * delta;
    switch (moveDir)
    {
    case FORWARD:
        {
            pos += vel * front;
            break;
        }
    case BACKWARD:
        {
            pos -= vel * front;
            break;
        }
    case LEFT:
        {
            pos -= glm::normalize(glm::cross(front, up)) * vel;
            break;
        }
    case RIGHT:
        {
            pos += glm::normalize(glm::cross(front, up)) * vel;
        }
    default:
        break;
    }
}

}
#endif // GLFWCAMERA_H
ALG_GLFWCamera.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 <cmath>


#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);


Model nanosuit_model;
void init(){

    camera = new GLFWCamera;
    camera->pos.y = 10.0f;
    camera->pos.z = 25.0f;
    // GL depth zbuffer
    glEnable(GL_DEPTH_TEST);
    //SurfaceShader.load("shaders/SurfaceShader.vert","shaders/SurfaceShader.frag");
    nanosuit_model.readMesh("scene/model/nanosuit.obj");
    nanosuit_model.useSimpleShader();
    nanosuit_model.debugLocations();
    //nanosuit_model.assignMaterial(SurfaceShader);
}

// ----------- 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);
    nanosuit_model.useSimpleShaderMatrix(projection,view,model);



    //SurfaceShader.setMat4("projection", projection);
    //SurfaceShader.setMat4("view", view);
    //SurfaceShader.setMat4("model", model);


    nanosuit_model.draw();


}


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
cmake_minimum_required(VERSION 3.5)

project(Triangle)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# OPENGL
find_package(OpenGL REQUIRED)
include_directories(${OpenGL_INCLUDE_DIRS})
link_directories(${OpenGL_LIBRARY_DIRS})
add_definitions(${OpenGL_DEFINITIONS})

if(NOT OPENGL_FOUND)
    message(ERROR " OPENGL not found!")
endif(NOT OPENGL_FOUND)

# GLEW
set(GLEW_HOME D:/plugin_dev/libs/glew-2.1.0)
include_directories(${GLEW_HOME}/include)
link_directories(${GLEW_HOME}/lib/Release/x64)

# GLFW
set(GLFW_HOME D:/plugin_dev/libs/glfw-3.3.1.bin.WIN64)
include_directories(${GLFW_HOME}/include/)
link_directories(${GLFW_HOME}/lib-vc2019)

# STB
include_directories(D:/plugin_dev/libs/stb)

# GLM
include_directories(D:/plugin_dev/libs/GLM_include)

# Assimp
include_directories(D:/plugin_dev/libs/assimp-5.0.1_bin/win_vs2019/include)

if(CMAKE_BUILD_TYPE STREQUAL Debug)
    message(">> Cmake will use debug mode to link debug lib")
    link_directories(D:/plugin_dev/libs/assimp-5.0.1_bin/win_vs2019/Debug) # we first link the debug
    link_libraries(assimp-vc142-mtd)
else()
    link_directories(D:/plugin_dev/libs/assimp-5.0.1_bin/win_vs2019/Release) # we first link the debug
    link_libraries(assimp-vc142-mt)
endif()


#json
include_directories(D:/plugin_dev/libs/nlohmann)

# output excutable dir
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build)


# SRC FILE
FILE(
    GLOB
    SRC
    *.cpp *.h
    )

add_executable(Triangle ${SRC} ALG_SceneDelegate.h)
target_link_libraries(Triangle glew32s.lib glfw3 opengl32 )
CMakeLists

CP19:

只做了个描述diffuse贴图的,其他的通道跟灯光有关系,普通的烂灯光,烂材质懒的写。

{
  "name": "simple",
  "project_dir": "D:/plugin_dev/opengl/CP_19/Triangle/build/scene",
  "models": [
    "model/nanosuit.obj"
  ],
  "mats": {
    "glass": {
      "shader_define": {
        "___comment___1": "type=0 is default no texture shader; ",
        "___comment___2": "type=1 use inline texture; ",
        "___comment___3": "type=2 use our json code shader,this may be use in our ui  ",
        "___comment___4": "type=3 from file",
        "vert_file": "",
        "frag_file": "",
        "code_type": 1,
        "frag_code": "",
        "vert_code": ""
      },
      "params_define": {
        "diffuse": "model/glass_dif.png"
      }
    },
    "leg": {
      "shader_define": {
        "code_type": 1,
        "vert_file": "",
        "frag_file": "",
        "frag_code": "",
        "vert_code": ""
      },
      "params_define": {
        "diffuse": "model/leg_dif.png",
        "specular": "model/leg_showroom_spec.png"
      }
    },
    "hand": {
      "shader_define": {
        "code_type": 1,
        "vert_file": "",
        "frag_file": "",
        "frag_code": "",
        "vert_code": ""
      },
      "params_define": {
        "diffuse": "model/hand_dif.png",
        "specular": "model/hand_showroom_spec.png"
      }
    },
    "body": {
      "shader_define": {
        "code_type": 1,
        "vert_file": "",
        "frag_file": "",
        "frag_code": "",
        "vert_code": ""
      },
      "params_define": {
        "diffuse": "model/mat2_diffuse.png",
        "specular": "model/mat2_specular.png"
      }
    },
    "helmet": {
      "shader_define": {
        "code_type": 1,
        "vert_file": "",
        "frag_file": "",
        "frag_code": "",
        "vert_code": ""
      },
      "params_define": {
        "diffuse": "model/helmet_diff.png",
        "specular": "model/helmet_showroom_spec.png"
      }
    },
    "arms": {
      "shader_define": {
        "code_type": 1,
        "vert_file": "",
        "frag_file": "",
        "frag_code": "",
        "vert_code": ""
      },
      "params_define": {
        "diffuse": "model/arm_dif.png",
        "specular": "model/arm_showroom_spec.png"
      }
    }
  },

  "assignMaterial": {
    "/Visor": "glass",
    "/Lights": "glass",
    "/Legs": "leg",
    "/hands": "hand",
    "/Arms": "arms",
    "/Helmet": "helmet",
    "/Body": "body"
  },


  "lights": {
    "lgt1":
    {
      "shader_define":
      {
        "lightType": "pointLight",
        "code_type": 1,
        "vert_file": "",
        "frag_file": "",
        "frag_code": "",
        "vert_code": ""
      },
      "params_define":
      {
        "pos" : [0.0, 10.0, 0.0],
        "sensitive" : 1.0,
        "color": [1.0, 0.0, 0.0]
      }
    },
    "lgt2":
    {
      "shader_define":
      {
        "lightType": "pointLight",
        "vert_file": "",
        "frag_file": "",
        "code_type": 1,
        "frag_code": "",
        "vert_code": ""
      },
      "params_define":
      {
        "pos" : [0.0, 10.0, 0.0],
        "sensitive" : 1.0,
        "color": [1.0, 0.0, 0.0]
      }
    },
    "lgt3":
    {
      "shader_define":
      {
        "lightType": "dirLight",
        "code_type": 1,
        "frag_code": "",
        "vert_code": ""
      },
      "params_define":
      {
        "pos" : [0.0, 10.0, 0.0],
        "sensitive" : 1.0,
        "color": [1.0, 0.0, 0.0],
        "dir": [1.0, -1.0, 0.0]
      }
    }

  },

  "assignLights":{
    "/lights/light1": "lgt1",
    "/lights/light2": "lgt2",
    "/lights/light3": "lgt3"
  }

}
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 <cmath>


#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;
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/SurfaceShader.vert","shaders/SurfaceShader.frag");


    scene.read("scene/scene.json");
    scene.parseInitialize();
    scene.parseModel();
    scene.parseMats();
    scene.parseAssignMats();

    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);


    scene.setMatrix(projection,view,model);
    //SurfaceShader.setMatrix(model,view,projection);
    //scene.assignMaterial(SurfaceShader);

    scene.draw();


    grid.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

其他的代码可以看下面CP20。

CP20:

透明,透明只跟绘制顺序相关。

比如这个我先绘制我的网格,然后绘制我的立方体,最后对透明物体排序。

 然后开启这些脑残特性,

 // GL depth zbuffer
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

#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


uniform sampler2D diffuse_map;


void main()
{
    vec4 df = texture(diffuse_map, f_TexCoord);
    FragColor = df;
}
SurfaceShader.frag
#version 450 core
// INCOMING DATA
layout ( location = 0 ) in vec4 v_position; //  pos
//layout ( location = 1 ) in vec3 v_normal;   //  norm
layout ( location = 1 ) in vec2 v_texCoord; //  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
    gl_Position = projection *   view * model * v_position;

    //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
}
SurfaceShader.vert
//
// Created by admin on 2020/2/27.
//

#ifndef TRIANGLE_OGLHELPER_H
#define TRIANGLE_OGLHELPER_H
#define GLEW_STATIC
#include <GL/glew.h>

void CreateGeometryBuffer(unsigned int &VAO, unsigned int &VBO);


void CreateGeometryBuffer(unsigned int &VAO, unsigned int &VBO){

    glCreateVertexArrays(1, &VAO);
    glCreateBuffers(1,&VBO);
    glBindVertexArray(VAO);
    glBindBuffer(GL_ARRAY_BUFFER, VBO);

}







#endif //TRIANGLE_OGLHELPER_H
OGLHelper.h
//
// Created by admin on 2020/2/25.
//

#ifndef TRIANGLE_ALG_VERTEX_H
#define TRIANGLE_ALG_VERTEX_H
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

namespace AlgebraMaster {
    using namespace std;
    struct Vertex {
        glm::vec3 position;
        glm::vec3 normal;
        glm::vec2 texCoords;
        glm::vec3 tangent;
        glm::vec3 biTangent;
    };
}

#endif //TRIANGLE_ALG_VERTEX_H
ALG_Vertex.h
//
// Created by admin on 2020/2/25.
//

#ifndef TRIANGLE_ALG_TEXTURE_H
#define TRIANGLE_ALG_TEXTURE_H

#include <iostream>
namespace AlgebraMaster{

using namespace std;
struct Texture{
    // Reference houdini principledshader
    enum Type {
        BASECOLOR_MAP, SPECULAR_MAP, EMISSION_MAP,
        BUMP_MAP, NORMAL_MAP, IOR_MAP,
        OPACITY_MAP, DISPLACE_MAP,
        CHAN_TEX0,CHAN_TEX1,CHAN_TEX2,CHAN_TEX3,
        CHAN_TEX4,CHAN_TEX5,CHAN_TEX6,CHAN_TEX7,
        CHAN_TEX8,CHAN_TEX9_CHAN_TEX10
    };
    unsigned int id;             // glBindTexture(GL_TEXTURE_2D,id);
    unsigned int textureUnitID;  // for shaderMethod set the texture unit: gluniformli(location, texture_unit)
    string path;                 // ralative path
    Type texType;                // type
    unsigned int texChannel;     // glActiveTexture(texChannel);
};

}

#endif //TRIANGLE_ALG_TEXTURE_H
ALG_Texture.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);
        }
    }


private:
    // * scene description json obj */
    json j;
    vector<Model*> allModels;


    // 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 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"];


        auto *shader = new LoadShader;
        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 2:
            {
                shader->fromSrc(vertCode,fragCode);
                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
    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;
        }
    }
}

}// end of namespace
#endif //TRIANGLE_ALG_SCENEDELEGATE_H
ALG_SceneDelegate.h
//
// Created by admin on 2020/2/21.
//

#ifndef TRIANGLE_ALG_MODELDELEGATE_H
#define TRIANGLE_ALG_MODELDELEGATE_H
#include <string>
#include <vector>
#include "ALG_MeshDelegate.h"
#include "ALG_LoadShader.h"
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>


namespace AlgebraMaster
{
using namespace std;


// helper method for exchange aiMatrix to glm matrix
void exchange_matrix_data(glm::mat4 &DesMatrix,const aiMatrix4x4 & srcAssimpMat);

// ----------------------- SCENE LOCATION --------------------------------
struct SceneLocation{
    // function
    SceneLocation();
    ~SceneLocation();

    // vars
    string pwd;
    glm::mat4 worldTransform;
    string type; // group or Mesh
    Mesh *mesh;
};

SceneLocation::SceneLocation():pwd(""),worldTransform(1.0f),type("group"),mesh(nullptr){
}
SceneLocation::~SceneLocation() {
    if(mesh)
        delete mesh;
}

// ----------------------- SCENE LOCATION --------------------------------




// ----------------------- SCENE Model --------------------------------
class Model{
public:
    //* Read Mesh from path */
    Model() = default;
    explicit Model(const string& path);
    ~Model();

    void readMesh(const string& path);
    //* overwrite all mesh material */
    void assignMaterial(LoadShader &shader);
    //* paint mesh in opengl */
    void draw();
    //* get the locations */
    vector<SceneLocation*> &getLocations();

    //* get location by name /
    SceneLocation * getLocationByPath(const string &path);

    // use default shader
    inline void useSimpleShader(){
        cout << "Model Used basic shader that should call useSimpleShaderMatrix() in render loop !
";
        for(auto &loc :locations){
            loc->mesh->shader.asSimpleShader();
        }
    }
    inline void useSimpleShaderMatrix(glm::mat4 &proj, glm::mat4 &view, glm::mat4 &model){
        for(auto &loc :locations){
            loc->mesh->shader.use();
            loc->mesh->shader.setMat4("projection", proj);
            loc->mesh->shader.setMat4("view", view);
            loc->mesh->shader.setMat4("model", model);

        }
    }
    inline void debugLocations(){
        cout << "debug locations:
";
        cout << "{
";
        for(auto&loc : locations){
            cout <<"	SceneGraph:" <<loc->pwd <<"	Type:" <<loc->type << endl;
        }
        cout << "}
";
    }



private:

    // vars
    vector<SceneLocation*> locations;
    string directory; // the mesh location at filesystem path


    // functions from assimp to our struct
    void processNode(aiNode *assimpNode,const aiScene* assimpScene, string pwd);
    Mesh* processMesh(aiMesh *assimpMesh, const aiScene *assimpScene);

};



// constructor
Model::Model(const string &path) {
    readMesh(path);
}
Model::~Model() {
    for(auto & location : locations){
        delete location;
    }
    locations.clear();
}

vector<SceneLocation *> &Model::getLocations() {
    return this->locations;
}

SceneLocation * Model::getLocationByPath(const string &path){
    for(auto &loc: this->locations){
        if(loc->pwd == path)return loc;
    }
    return nullptr;
}

void Model::draw(){
    for(auto &loc: locations){
        loc->mesh->draw();
    }
}
void Model::assignMaterial(LoadShader &shader) {
    for(auto & location : locations){
        location->mesh->assignMaterial(shader);
    }
}

void Model::readMesh(const string &path)
{
    Assimp::Importer import;
    const aiScene * scene = import.ReadFile(path.c_str(),
            aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_CalcTangentSpace);
    // check error
    if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode){
        cout << "ERROR::ASSIMP:: " << import.GetErrorString() << endl;
        return ;
    }
    // retrieve the directory path of the filepath
    directory = path.substr(0, path.find_last_of('/'));

    // process ASSIMP's root node recursively
    processNode(scene->mRootNode, scene,"/");

    // fix location pwd end with '/', we should remove it
    for(auto &loc : locations){
        string pwd = loc->pwd;
        if (pwd[pwd.length()-1] == '/'){
            loc->pwd = string(pwd.begin(),pwd.end()-1);
        }
    }
}

void Model::processNode(aiNode *assimpNode, const aiScene *assimpScene, string pwd) {
    // process each mesh located at the current node
    aiMatrix4x4 mat =  assimpNode->mTransformation;
    auto *location = new SceneLocation;
    location->pwd = pwd;
    if (assimpNode->mNumMeshes<=0)
        location->type = "group";
    else
        location->type = "mesh";
    location->pwd = pwd;
    exchange_matrix_data(location->worldTransform,mat);

    // loop this node's meshs
    for(unsigned int i = 0; i < assimpNode->mNumMeshes; i++)
    {
        // the node object only contains indices to index the actual objects in the scene.
        // the scene contains all the data, node is just to keep stuff organized (like relations between nodes).
        aiMesh* assimpMesh = assimpScene->mMeshes[assimpNode->mMeshes[i]];
        Mesh* mesh = processMesh(assimpMesh,assimpScene);
        location->mesh = mesh;
        this->locations.emplace_back(location);
    }
    // after we've processed all of the meshes (if any) we then recursively process each of the children nodes
    for(unsigned int i = 0; i < assimpNode->mNumChildren; i++)
    {
        string pathName =  pwd + assimpNode->mChildren[i]->mName.C_Str();
        pathName += "/";
        processNode(assimpNode->mChildren[i], assimpScene,pathName);
    }

}
Mesh* Model::processMesh(aiMesh *assimpMesh, const aiScene *assimpScene)
{
    // our mesh interface pointer
    Mesh *mesh = new Mesh;
    // construct mesh data from assimpMesh
    for(unsigned int i =0; i <assimpMesh->mNumVertices;i++){
        Vertex vertex;
        vertex.position.x= assimpMesh->mVertices[i].x;
        vertex.position.y= assimpMesh->mVertices[i].y;
        vertex.position.z= assimpMesh->mVertices[i].z;
        vertex.normal.x = assimpMesh->mNormals[i].x;
        vertex.normal.y = assimpMesh->mNormals[i].y;
        vertex.normal.z = assimpMesh->mNormals[i].z;
        // tex
        if(assimpMesh->mTextureCoords[0]) // does the mesh contain texture coordinates?
        {
            // a vertex can contain up to 8 different texture coordinates. We thus make the assumption that we won't
            // use allModels where a vertex can have multiple texture coordinates so we always take the first set (0).
            vertex.texCoords.x = assimpMesh->mTextureCoords[0][i].x;
            vertex.texCoords.y = assimpMesh->mTextureCoords[0][i].y;
        }
        else{
            vertex.texCoords.x = 0.0f;
            vertex.texCoords.y = 0.0f;
        }
        // tangent
        vertex.tangent.x = assimpMesh->mTangents[i].x;
        vertex.tangent.y = assimpMesh->mTangents[i].y;
        vertex.tangent.z = assimpMesh->mTangents[i].z;
        // bitangent
        vertex.biTangent.x = assimpMesh->mBitangents[i].x;
        vertex.biTangent.y = assimpMesh->mBitangents[i].y;
        vertex.biTangent.z = assimpMesh->mBitangents[i].z;
        mesh->vertices.emplace_back(vertex);
    }
    // indices
    for(int i=0; i<assimpMesh->mNumFaces; i++){
        aiFace face = assimpMesh->mFaces[i];
        for(int j=0;j<face.mNumIndices;j++){
            mesh->indices.emplace_back(face.mIndices[j]);
        }
    }
    mesh->setupMesh();
    return mesh;

}
// ----------------------- SCENE Model --------------------------------




// ---- Helper
void exchange_matrix_data(glm::mat4 &DesMatrix,const aiMatrix4x4 & srcAssimpMat){

    DesMatrix[0].x = srcAssimpMat.a1;
    DesMatrix[0].y = srcAssimpMat.a2;
    DesMatrix[0].z = srcAssimpMat.a3;
    DesMatrix[0].w = srcAssimpMat.a4;

    DesMatrix[1].x = srcAssimpMat.b1;
    DesMatrix[1].y = srcAssimpMat.b2;
    DesMatrix[1].z = srcAssimpMat.b3;
    DesMatrix[1].w = srcAssimpMat.b4;

    DesMatrix[2].x = srcAssimpMat.c1;
    DesMatrix[2].y = srcAssimpMat.c2;
    DesMatrix[2].z = srcAssimpMat.c3;
    DesMatrix[2].w = srcAssimpMat.c4;

    DesMatrix[3].x = srcAssimpMat.d1;
    DesMatrix[3].y = srcAssimpMat.d2;
    DesMatrix[3].z = srcAssimpMat.d3;
    DesMatrix[3].w = srcAssimpMat.d4;
}


} // end of namespace

#endif //TRIANGLE_ALG_MODELDELEGATE_H
ALG_ModelDelegate.h
#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);

// 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.fragmentShader = rhs_shader.fragmentShader;
    shader.vertexShader = rhs_shader.vertexShader;
    shader.shaderProgram = rhs_shader.shaderProgram;
    shader.projection = rhs_shader.projection;
    shader.view = rhs_shader.view;
    shader.model = rhs_shader.model;
    shader.textures = rhs_shader.textures;
}

// opengl draw the mesh
void Mesh::draw() {
    this->shader.use();
    shader.setMatrix(shader.model,shader.view,shader.projection);

    string mat_prefix = "material.";
    for(auto &tex: shader.textures)
    {
        glActiveTexture(tex->texChannel);
        switch (tex->texType)
        {
            case Texture::BASECOLOR_MAP:{
                string texchanName = mat_prefix + "diffuse_map";
                shader.setInt(texchanName.c_str(),tex->textureUnitID);
                break;
            }
            case Texture::SPECULAR_MAP:{
                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
        glBindTexture(GL_TEXTURE_2D, tex->id); // bind current id

    } // end of for each textures


    // 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
#ifndef LOADTEXTURE_H
#define LOADTEXTURE_H
#include <GL/glew.h>

// IMP the stb image loader
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <iostream>
using namespace std;

namespace AlgebraMaster
{



class LoadTexture
{
public:
    LoadTexture();
    LoadTexture(const char *fileName);
    void load(const char *fileName);
    virtual ~LoadTexture();
    inline GLuint getTextureID()const{return textureID;}
    inline GLuint getImageFormat()const{return format;}
    GLuint textureID;
    GLenum format;
    bool loadStatus;
};

LoadTexture::LoadTexture() {
    loadStatus = false;
}


void LoadTexture::load(const char *fileName)
{
    glGenTextures(1, &textureID);
    int width, height, nrComponents;
    unsigned char *data = stbi_load(fileName, &width, &height, &nrComponents, 0);
    if (data)
    {
        if (nrComponents == 1)
            format = GL_RED;
        else if (nrComponents == 3)
            format = GL_RGB;
        else if (nrComponents == 4)
            format = GL_RGBA;

        glBindTexture(GL_TEXTURE_2D, textureID);
        glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
        glGenerateMipmap(GL_TEXTURE_2D);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);

        stbi_image_free(data);
        loadStatus = true;
    }
    else
    {
        loadStatus = false;
        std::cout << "Texture failed to load at path: " << fileName << std::endl;
        stbi_image_free(data);
    }

}

LoadTexture::LoadTexture(const char *fileName){
    loadStatus = false;
    load(fileName);
}
LoadTexture::~LoadTexture(){}

}
#endif // LOADTEXTURE_H
ALG_LoadTexture.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(0.5f, 0.5f, 0.5f , 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(){
        // create shader program and check it
        GLint success;
        GLchar infoLog[512];
        shaderProgram = glCreateProgram();
        glAttachShader(shaderProgram,vertexShader);
        glAttachShader(shaderProgram,fragmentShader);
        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(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 compileFragmentShader(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();
    }

    LoadShader(){

    }
    ~LoadShader(){

    }

    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();
    }


    void setShaderName(const string &name){
        shaderName = name;
    }

    LoadShader(const char*vertPath, const char* fragPath){
        load(vertPath,fragPath);
        shaderIOType = 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;
    }

    void _loadVertexShader(const char *path){

        // read shader code
        auto handle = _readFile(path);
        const char * shaderCode = handle.c_str();
        compileVertexShader(shaderCode);

    }

    void _loadFragmentShader(const char *path){
        // read shader code
        auto handle = _readFile(path);
        const char * shaderCode = handle.c_str();
        compileFragmentShader(shaderCode);
    }

    void load(const char* vertShaderPath, const char* fragShaderPath){
        shaderIOType = FILE;
        _loadVertexShader(vertShaderPath);
        _loadFragmentShader(fragShaderPath);
        // create shader program and check it
        compileShaderProgram();
    }

    void use(){
        glUseProgram(shaderProgram);
    }

    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;
    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;

    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
ALG_LoadShader.h
//
// Created by admin on 2020/2/25.
//
#define GLEW_STATIC
// GLEW
#include <GL/glew.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <GL/glew.h>
#include "ALG_MathFunction.h"
#include "ALG_LoadShader.h"
namespace AlgebraMaster{

// x line
static float points[] = {
        -10.0f,0.0f,0.0f,
        10.0f,0.0f,0.0f
};


class DrawGrid{
public:
    void initialize();
    void draw(glm::mat4 &proj, glm::mat4 &view);
    // members
    GLuint VAO,VBO;
    LoadShader shader;
};

void DrawGrid::initialize() {

    glCreateVertexArrays(1, &VAO);
    glCreateBuffers(1,&VBO);
    glBindVertexArray(VAO);

    glBindBuffer(GL_ARRAY_BUFFER,VBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);

    // position
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);

    shader.asSimpleShader();
}

void DrawGrid::draw(glm::mat4 &proj, glm::mat4 &view) {
    glEnable(GL_LINE_SMOOTH);
    shader.use();
    shader.setMat4("projection",proj);
    shader.setMat4("view",view);
    glLineWidth(1.0f);
    glBindVertexArray(VAO);

    // Draw X line
    glm::mat4 model(1.0f);
    shader.setMat4("model",model);
    glDrawArrays(GL_LINES,0, 2);


    // Draw Z line
    glm::mat4 rot(1.0f);
    rot = glm::rotate(rot,glm::radians(90.0f),glm::vec3(0.0f, 1.0f, 0.0f ) );
    shader.setMat4("model",rot);
    glDrawArrays(GL_LINES,0, 2);


    // offset line on x




    //  Z positive dir
    for(int i=1;i<11;i++){
        // offset line on z
        glm::mat4 model(1.0f);
        glBindVertexArray(VAO);
        model = glm::translate(model,glm::vec3(0.0f, 0.0f, i ) );
        shader.setMat4("model",model);
        glDrawArrays(GL_LINES,0, 2);

    }
    // Z negative dir
    for(int i=1;i<11;i++){
        // offset line on z
        glm::mat4 model(1.0f);
        glBindVertexArray(VAO);
        model = glm::translate(model,glm::vec3(0.0f, 0.0f, -i ) );
        shader.setMat4("model",model);
        glDrawArrays(GL_LINES,0, 2);
        // offset line on x
    }

    // X positive dir
    for(int i=1;i<11;i++){
        glBindVertexArray(VAO);
        // offset line on x
        glm::mat4 rot(1.0f);
        rot = glm::rotate(rot,glm::radians(90.0f),glm::vec3(0.0f, 1.0f, 0.0f ) );

        glm::mat4 trans(1.0f);
        trans = glm::translate(trans,glm::vec3(i,0.0f,0.0f));

        shader.setMat4("model",trans*rot);
        glDrawArrays(GL_LINES,0, 2);
        // offset line on x
    }

    // X negative dir
    for(int i=1;i<11;i++){
        // offset line on x
        glm::mat4 rot(1.0f);
        rot = glm::rotate(rot,glm::radians(90.0f),glm::vec3(0.0f, 1.0f, 0.0f ) );
        glm::mat4 trans(1.0f);
        trans = glm::translate(trans,glm::vec3(-i,0.0f,0.0f));
        shader.setMat4("model",trans*rot);
        glDrawArrays(GL_LINES,0, 2);

        // offset line on x
    }

    glDisable(GL_LINE_SMOOTH);
}
}// end of namespace






#ifndef TRIANGLE_ALG_DRAWGRID_H
#define TRIANGLE_ALG_DRAWGRID_H





#endif //TRIANGLE_ALG_DRAWGRID_H
ALG_DrawGrid.h
#ifndef WINDOW_H
#define WINDOW_H
#undef GLFW_DLL
#include <GLFW/glfw3.h>

#define GLEW_STATIC
#include <GL/glew.h>


namespace AlgebraMaster{


class FrameWindow
{
public:
    FrameWindow(int width,int height,const char*title="日格朗拉Never Fake");
    virtual ~FrameWindow();
    GLFWwindow *getWindow();
private:
     GLFWwindow *window;
     int w;
     int h;
};

FrameWindow::FrameWindow(int width,int height,const char*title){
    w = width;
    h = height;
    glfwInit();
    window = glfwCreateWindow(width,height,title,NULL,NULL);
    glfwMakeContextCurrent(window);
    glewInit();

}
FrameWindow::~FrameWindow(){
    glfwDestroyWindow(window);
    glfwTerminate();
}
GLFWwindow * FrameWindow::getWindow(){
    return window;
}
}
#endif // WINDOW_H
ALG_FrameWindow.h
#ifndef GLFWCAMERA_H
#define GLFWCAMERA_H

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

namespace AlgebraMaster{



class GLFWCamera{
public:
    GLFWCamera();
    ~GLFWCamera(){}
    enum CAMERA_MOVEMENT{
        FORWARD,     // Camera move to front   ->  key:W
        BACKWARD,    // Camera move to back    ->  key:S
        LEFT,        // Camera move to left    ->  key:A
        RIGHT        // Camera move to right   ->  key:D
    };

public:
    glm::vec3 pos;   // camera world space
    glm::vec3 front;
    glm::vec3 up;

    // Euler Angles
   float yaw;
   float pitch;


   // Camera options
   float movementSpeed;
   float mouseSensitivity;
   float fov;

   void processFov(float yoffset){
       if(fov >= 1.0f && fov <= 45.0f){
           fov -= yoffset;
       }
       if(fov <=1.0f){
           fov = 1.0f;
       }
       if(fov >= 45.0f){
           fov = 45.0f;
       }
   }

   // build the matrix for lookAt
   glm::mat4 GetViewMatrix(){
       return glm::lookAt(pos , pos + front , up);
   }

   // process -Rotate the view-
   void processMouseMove(float xoffset, float yoffset);


   // process -W S A D-
   void processKeyboardMove(float delta, CAMERA_MOVEMENT moveDir);



   void updateFront(){
       glm::vec3 tempfront;
       tempfront.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
       tempfront.y = sin(glm::radians(pitch));
       tempfront.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
       this->front = glm::normalize(tempfront);
   }


};

GLFWCamera::GLFWCamera(){
    pos = glm::vec3(0.0f,0.0f,3.0f);
    up = glm::vec3(0.0f,1.0f,0.0f);
    front = glm::vec3(0.0f,0.0f,-1.0f);
    yaw = -90.0f;
    pitch = 0.0f;
    fov = 45.0f;
    movementSpeed = 4.5f;
    mouseSensitivity = 0.1f;
}

void GLFWCamera::processMouseMove(float xoffset, float yoffset)
{

    xoffset *= mouseSensitivity;
    yoffset *= mouseSensitivity;

    yaw += xoffset;
    pitch += yoffset;

    // make sure that when pitch is out of bounds, screen doesn't get flipped
    if (pitch > 89.0f)
        pitch = 89.0f;
    if (pitch < -89.0f)
        pitch = -89.0f;
    this->updateFront();
}

void GLFWCamera::processKeyboardMove(float delta, CAMERA_MOVEMENT moveDir)
{
    float vel = movementSpeed * delta;
    switch (moveDir)
    {
    case FORWARD:
        {
            pos += vel * front;
            break;
        }
    case BACKWARD:
        {
            pos -= vel * front;
            break;
        }
    case LEFT:
        {
            pos -= glm::normalize(glm::cross(front, up)) * vel;
            break;
        }
    case RIGHT:
        {
            pos += glm::normalize(glm::cross(front, up)) * vel;
        }
    default:
        break;
    }
}

}
#endif // GLFWCAMERA_H
ALG_GLFWCamera.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 <cmath>
#include "OGLHelper.h"

#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <map>
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);


// 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);



// Geometry

static DrawGrid grid;

static float cubeVertices[] = {
    // positions          // texture Coords
           -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,
            0.5f, -0.5f, -0.5f,  1.0f, 0.0f,
            0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
            0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
           -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
           -0.5f, -0.5f, -0.5f,  0.0f, 0.0f,

           -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
            0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 1.0f,
           -0.5f,  0.5f,  0.5f,  0.0f, 1.0f,
           -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,

           -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
           -0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
           -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
           -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
           -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
           -0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

            0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
            0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
            0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
            0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
            0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 0.0f,

           -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,
            0.5f, -0.5f, -0.5f,  1.0f, 1.0f,
            0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
            0.5f, -0.5f,  0.5f,  1.0f, 0.0f,
           -0.5f, -0.5f,  0.5f,  0.0f, 0.0f,
           -0.5f, -0.5f, -0.5f,  0.0f, 1.0f,

           -0.5f,  0.5f, -0.5f,  0.0f, 1.0f,
            0.5f,  0.5f, -0.5f,  1.0f, 1.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
            0.5f,  0.5f,  0.5f,  1.0f, 0.0f,
           -0.5f,  0.5f,  0.5f,  0.0f, 0.0f,
           -0.5f,  0.5f, -0.5f,  0.0f, 1.0f
};



static float planeVertices[] = {
        // positions          // texture Coords
        5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f,  5.0f,  0.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,

        5.0f, -0.5f,  5.0f,  2.0f, 0.0f,
        -5.0f, -0.5f, -5.0f,  0.0f, 2.0f,
        5.0f, -0.5f, -5.0f,  2.0f, 2.0f
};
static float transparentVertices[] = {
        // positions         // texture Coords (swapped y coordinates because texture is flipped upside down)
        0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
        0.0f, -0.5f,  0.0f,  0.0f,  1.0f,
        1.0f, -0.5f,  0.0f,  1.0f,  1.0f,

        0.0f,  0.5f,  0.0f,  0.0f,  0.0f,
        1.0f, -0.5f,  0.0f,  1.0f,  1.0f,
        1.0f,  0.5f,  0.0f,  1.0f,  0.0f
};

static vector<glm::vec3> windows
{
    glm::vec3(-1.5f, 0.0f, -0.48f),
    glm::vec3( 1.5f, 0.0f, 0.51f),
    glm::vec3( 0.0f, 0.0f, 0.7f),
    glm::vec3(-0.3f, 0.0f, -2.3f),
    glm::vec3( 0.5f, 0.0f, -0.6f)
};



// cube vao vbo
static unsigned int cubeVAO,cubeVBO;
static unsigned int planeVAO,planeVBO;
static unsigned int transparentVAO,transparentVBO;
static LoadTexture texture1;
static LoadTexture texture2;
static LoadTexture texture3;

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");


    glGenVertexArrays(1, &cubeVAO);
    glGenBuffers(1, &cubeVBO);
    glBindVertexArray(cubeVAO);
    glBindBuffer(GL_ARRAY_BUFFER, cubeVBO);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), &cubeVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));


    CreateGeometryBuffer(planeVAO, planeVBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(planeVertices),&planeVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));


    CreateGeometryBuffer(transparentVAO, transparentVBO);
    glBufferData(GL_ARRAY_BUFFER,sizeof(transparentVertices),&transparentVertices, GL_STATIC_DRAW);
    glEnableVertexAttribArray(0);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(1);
    glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));


    glBindVertexArray(0);

    cout << "cube VAO:" << cubeVAO <<endl;
    texture1.load("texture/marble.jpg");
    texture2.load("texture/metal.png");
    texture3.load("texture/window.png");




    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);
    // render cube
    SurfaceShader.setInt("diffuse_map", 1);
    SurfaceShader.use();
    SurfaceShader.setMat4("projection", projection);
    SurfaceShader.setMat4("view", view);
    model = glm::translate(model, glm::vec3(-1.0f, 0.0f, -1.0f));
    SurfaceShader.setMat4("model", model);


    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,texture1.textureID);
    glBindVertexArray(cubeVAO);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    model = glm::mat4(1.0f);
    model = glm::translate(model, glm::vec3(2.0f, 0.0f, 0.0f));
    SurfaceShader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 36);



    // floor
    glBindVertexArray(planeVAO);
    glBindTexture(GL_TEXTURE_2D, texture2.getTextureID());
    model = glm::mat4(1.0f);
    SurfaceShader.setMat4("model", model);
    glDrawArrays(GL_TRIANGLES, 0, 6);

    std::map<float, glm::vec3> sorted;
    for (unsigned int i = 0; i < windows.size(); i++)
    {
        float distance = glm::length(camera->pos - windows[i]);  // cal distance between camera and window position
        sorted[distance] = windows[i];
    }
    // windows (from furthest to nearest)
    glBindVertexArray(transparentVAO);
    glBindTexture(GL_TEXTURE_2D, texture3.getTextureID());
    for (std::map<float, glm::vec3>::reverse_iterator it = sorted.rbegin(); it != sorted.rend(); ++it)
    {
       model = glm::mat4(1.0f);
       model = glm::translate(model, it->second);
       SurfaceShader.setMat4("model", model);
       glDrawArrays(GL_TRIANGLES, 0, 6);
    }




}


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

面剔除:

比较简单:

默认glEnable(GL_CULL_FACE); 是剔除后面

剔除front-face

glEnable(GL_CULL_FACE);

glFrontFace(GL_CW);  把顺时针的排序定为frontface,实际上默认这个CW应该是背面,CCW才是前面。现在相当于把真正的<前面>和<后面>调换顺序了。

glCullFace(GL_BACK);  现在裁剪后面,其实在目前情况下是 前面,视窗上看相当于把前面裁剪了

   

也可以这样剔除front-face:默认情况下,逆时针的排序代表front-face

原文地址:https://www.cnblogs.com/gearslogy/p/12350580.html