diff --git a/README.md b/README.md index 02759ca..421ca4f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,10 @@ # NekoTeam -### 本仓库是华东理工大学2022年度大创项目。 -目前名为“游戏场景中人像三维重建和风格迁移技术”。 -预测语言:python,c#。 -希望大家靠谱。 -###### Liz 按 于2021.12.6 多事之秋。 + +# 本分支用于每周日志汇报及会议记录 + +日志内容可包括本周项目进展,学习进展等等,与项目相关均可写进去。 + +请各成员各自建一个文件夹存放各自的日志记录。 +并于每周五晚八点前提交。 + +##### 于二零二二年三月二十八日起实行 diff --git a/ljh/Log_22_4_1 b/ljh/Log_22_4_1 new file mode 100644 index 0000000..a26e177 --- /dev/null +++ b/ljh/Log_22_4_1 @@ -0,0 +1,4 @@ +完成了计算机应用能力大赛核心功能的实现,包含渲染,动作读取计算,模型读取等功能。 +完成了大赛的技术文档。 + +本次实现的核心功能有望用于实现大创最后应用阶段,即利用人体姿态追踪实现vtuber直播中的渲染部分。 diff --git a/lth/3D Multi_View Reconstruction and Model Re_Topology.pdf b/lth/3D Multi_View Reconstruction and Model Re_Topology.pdf new file mode 100644 index 0000000..4379ca8 Binary files /dev/null and b/lth/3D Multi_View Reconstruction and Model Re_Topology.pdf differ diff --git a/lth/mmd_viewer_glfw_lth.cpp b/lth/mmd_viewer_glfw_lth.cpp new file mode 100644 index 0000000..f9f75b2 --- /dev/null +++ b/lth/mmd_viewer_glfw_lth.cpp @@ -0,0 +1,1530 @@ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_STATIC +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")//不显示窗口 + + +// ******************* +// 着色器 Shader +// ******************* + + +// 创建并编译着色器 +GLuint CreateShader(GLenum shaderType, const std::string code) +//GLuint: +{ + GLuint shader = glCreateShader(shaderType);//创建着色器对象 + if (shader == 0) + { + std::cout << "Failed to create shader.\n"; + return 0; + }//错误回收 + //这段干啥的? + const char* codes[] = { code.c_str() }; + GLint codesLen[] = { (GLint)code.size() }; + glShaderSource(shader, 1, codes, codesLen); + glCompileShader(shader); + //好像是逐行导入一堆东西到一个vector + GLint infoLength; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength); + if (infoLength != 0) + { + std::vector info; + info.reserve(infoLength + 1); + info.resize(infoLength); + + GLsizei len; + glGetShaderInfoLog(shader, infoLength, &len, &info[0]); + if (info[infoLength - 1] != '\0') + { + info.push_back('\0');//push_back方法:加在后面 + } + + std::cout << &info[0] << "\n"; + } + + GLint compileStatus; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); + if (compileStatus != GL_TRUE) + { + glDeleteShader(shader); + std::cout << "Failed to compile shader.\n"; + return 0; + }//GL传回编译失败,删掉shader + + return shader; +} + +// 链接着色器程序 +GLuint CreateShaderProgram(const std::string vsFile, const std::string fsFile) +{ + mmd::TextFileReader vsFileText; + //打不开时候错误回收 + if (!vsFileText.Open(vsFile)) + { + std::cout << "Failed to open shader file. [" << vsFile << "].\n"; + return 0; + } + //把vsFileText全读到vsCode里面 + std::string vsCode = vsFileText.ReadAll(); + vsFileText.Close(); + + mmd::TextFileReader fsFileText; + //错误回收 + if (!fsFileText.Open(fsFile)) + { + std::cout << "Failed to open shader file. [" << fsFile << "].\n"; + return 0; + } + + std::string fsCode = fsFileText.ReadAll(); + fsFileText.Close(); + //以上 错误了回传0 函数供以下使用,以下创建两个shader + GLuint vs = CreateShader(GL_VERTEX_SHADER, vsCode);//vs 顶点数据 + GLuint fs = CreateShader(GL_FRAGMENT_SHADER, fsCode);//像素着色器 + if (vs == 0 || fs == 0) + //错误回收 + { + if (vs != 0) { glDeleteShader(vs); } + if (fs != 0) { glDeleteShader(fs); } + return 0; + } + //创建program对象 + GLuint prog = glCreateProgram(); + if (prog == 0) + { + glDeleteShader(vs); + glDeleteShader(fs); + std::cout << "Failed to create program.\n"; + return 0; + } + //OpenGL API glattachshader,将着色器附到program对象 + //通过调用glCompileShader成功编译着色器对象,并且通过调用glAttachShader成功地将着色器对象附加到program 对象, + // 并且通过调用glLinkProgram成功的链接program 对象之后,可以在program 对象中创建一个或多个可执行文件。(抄自csdn) + glAttachShader(prog, vs); + glAttachShader(prog, fs); + glLinkProgram(prog); + + GLint infoLength;//感觉和上面一样但是也没看懂 + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &infoLength);//OpenGL API,获取属性 + if (infoLength != 0) + { + std::vector info; + info.reserve(infoLength + 1); + info.resize(infoLength); + + GLsizei len; + glGetProgramInfoLog(prog, infoLength, &len, &info[0]); + if (info[infoLength - 1] != '\0') + { + info.push_back('\0'); + } + + std::cout << &info[0] << "\n"; + } + + GLint linkStatus; + glGetProgramiv(prog, GL_LINK_STATUS, &linkStatus);//还是API,GL_LINK_STATUS + if (linkStatus != GL_TRUE) + { + glDeleteShader(vs); + glDeleteShader(fs); + std::cout << "Failed to link shader.\n"; + return 0; + } + + glDeleteShader(vs); + glDeleteShader(fs); + return prog; +} + +struct AppContext;//一个巨tm大的结构数组 +//输入 +struct Input +{ + std::string m_modelPath; + std::vector m_vmdPaths; +}; + +///******************* +/// 模型Shader +///******************* + +struct MMDShader +{ + ~MMDShader() + { + Clear(); + } + + GLuint m_prog = 0; + + // 顶点属性 + GLint m_inPos = -1; + GLint m_inNor = -1; + GLint m_inUV = -1; + + // 蒙皮属性 + GLint m_uWV = -1; + GLint m_uWVP = -1; + + GLint m_uAmbinet = -1; + GLint m_uDiffuse = -1; + GLint m_uSpecular = -1; + GLint m_uSpecularPower = -1; + GLint m_uAlpha = -1; + + GLint m_uTexMode = -1; + GLint m_uTex = -1; + GLint m_uTexMulFactor = -1; + GLint m_uTexAddFactor = -1; + + GLint m_uSphereTexMode = -1; + GLint m_uSphereTex = -1; + GLint m_uSphereTexMulFactor = -1; + GLint m_uSphereTexAddFactor = -1; + + GLint m_uToonTexMode = -1; + GLint m_uToonTex = -1; + GLint m_uToonTexMulFactor = -1; + GLint m_uToonTexAddFactor = -1; + + GLint m_uLightColor = -1; + GLint m_uLightDir = -1; + + GLint m_uLightVP = -1; + GLint m_uShadowMapSplitPositions = -1; + GLint m_uShadowMap0 = -1; + GLint m_uShadowMap1 = -1; + GLint m_uShadowMap2 = -1; + GLint m_uShadowMap3 = -1; + GLint m_uShadowMapEnabled = -1; + + bool Setup(const AppContext& appContext); + void Clear(); +};//mmdshader,又是一个巨大的结构数组 + +struct MMDEdgeShader//mmdedgeshader,巨大的结构数组,储存边缘 +{ + ~MMDEdgeShader() + { + Clear(); + } + + GLuint m_prog = 0; + + // 顶点属性 + GLint m_inPos = -1; + GLint m_inNor = -1; + + // 蒙皮属性 + GLint m_uWV = -1; + GLint m_uWVP = -1; + GLint m_uScreenSize = -1; + GLint m_uEdgeSize = -1; + + GLint m_uEdgeColor = -1; + + bool Setup(const AppContext& appContext); + void Clear(); +}; + +struct MMDGroundShadowShader//背景?结构数组 +{ + ~MMDGroundShadowShader() + { + Clear(); + } + + GLuint m_prog = 0; + + GLint m_inPos = -1; + + GLint m_uWVP = -1; + GLint m_uShadowColor = -1; + + bool Setup(const AppContext& appContext);//转687那里 + void Clear(); +}; + +struct Texture//纹理 +{ + GLuint m_texture; + bool m_hasAlpha; +}; + +// OpenGL上下文 +struct AppContext +{ + ~AppContext() + { + Clear(); + } + + std::string m_resourceDir; + std::string m_shaderDir; + std::string m_mmdDir; + + std::unique_ptr m_mmdShader; + std::unique_ptr m_mmdEdgeShader; + std::unique_ptr m_mmdGroundShadowShader; + + glm::mat4 m_viewMat; + glm::mat4 m_projMat; + int m_screenWidth = 0; + int m_screenHeight = 0; + + glm::vec3 m_lightColor = glm::vec3(1, 1, 1); + glm::vec3 m_lightDir = glm::vec3(-0.5f, -1.0f, -0.5f); + + std::map m_textures; + GLuint m_dummyColorTex = 0; + GLuint m_dummyShadowDepthTex = 0; + + const int m_msaaSamples = 4; + + bool m_enableTransparentWindow = false; + uint32_t m_transparentFboWidth = 0; + uint32_t m_transparentFboHeight = 0; + GLuint m_transparentFboColorTex = 0; + GLuint m_transparentFbo = 0; + GLuint m_transparentFboMSAAColorRB = 0; + GLuint m_transparentFboMSAADepthRB = 0; + GLuint m_transparentMSAAFbo = 0; + GLuint m_copyTransparentWindowShader = 0; + GLint m_copyTransparentWindowShaderTex = -1; + GLuint m_copyTransparentWindowVAO = 0; + + float m_elapsed = 0.0f; + float m_animTime = 0.0f; + std::unique_ptr m_vmdCameraAnim; + + bool Setup(); + void Clear(); + + void SetupTransparentFBO(); + + Texture GetTexture(const std::string& texturePath); +}; + +// 材质 +struct Material +{ + explicit Material(const mmd::MMDMaterial& mat) + : m_mmdMat(mat) + {} + + const mmd::MMDMaterial& m_mmdMat; + GLuint m_texture = 0; + bool m_textureHasAlpha = false; + GLuint m_spTexture = 0; + GLuint m_toonTexture = 0; +}; + +// 模型 +struct Model +{ + std::shared_ptr m_mmdModel; + std::unique_ptr m_vmdAnim; + + GLuint m_posVBO = 0; + GLuint m_norVBO = 0; + GLuint m_uvVBO = 0; + GLuint m_ibo = 0; + GLenum m_indexType; + + GLuint m_mmdVAO = 0; + GLuint m_mmdEdgeVAO = 0; + GLuint m_mmdGroundShadowVAO = 0; + + std::vector m_materials; + + bool Setup(AppContext& appContext);//引用方式传参,不管形参实参了进去的就是实际的变量(好文明) + void Clear(); + + void UpdateAnimation(const AppContext& appContext); + void Update(const AppContext& appContext); + void Draw(const AppContext& appContext); +}; + + +///*************************** +/// 上下文设置 AppContext +///*************************** + + +// 向GPU写入数据 +bool AppContext::Setup() +{ + m_resourceDir = mmd::PathUtil::GetExecutablePath(); + m_resourceDir = mmd::PathUtil::GetDirectoryName(m_resourceDir); + m_resourceDir = mmd::PathUtil::Combine(m_resourceDir, "resource"); + m_shaderDir = mmd::PathUtil::Combine(m_resourceDir, "shader"); + m_mmdDir = mmd::PathUtil::Combine(m_resourceDir, "mmd"); + + m_mmdShader = std::make_unique(); + if (!m_mmdShader->Setup(*this)) + { + return false; + } + + m_mmdEdgeShader = std::make_unique(); + if (!m_mmdEdgeShader->Setup(*this)) + { + return false; + } + + m_mmdGroundShadowShader = std::make_unique(); + if (!m_mmdGroundShadowShader->Setup(*this)) + { + return false; + } + + glGenTextures(1, &m_dummyColorTex); + glBindTexture(GL_TEXTURE_2D, m_dummyColorTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenTextures(1, &m_dummyShadowDepthTex); + glBindTexture(GL_TEXTURE_2D, m_dummyShadowDepthTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 1, 1, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + glBindTexture(GL_TEXTURE_2D, 0); + + m_copyTransparentWindowShader = CreateShaderProgram( + mmd::PathUtil::Combine(m_shaderDir, "quad.vert"), + mmd::PathUtil::Combine(m_shaderDir, "copy_transparent_window.frag") + ); + + m_copyTransparentWindowShaderTex = glGetUniformLocation(m_copyTransparentWindowShader, "u_Tex"); + + glGenVertexArrays(1, &m_copyTransparentWindowVAO); + + return true; +} + +// 清除帧缓冲数据 +void AppContext::Clear() +{ + m_mmdShader.reset(); + m_mmdEdgeShader.reset(); + m_mmdGroundShadowShader.reset(); + + for (auto& tex : m_textures) + { + glDeleteTextures(1, &tex.second.m_texture); + } + m_textures.clear(); + + if (m_dummyColorTex != 0) { glDeleteTextures(1, &m_dummyColorTex); } + if (m_dummyShadowDepthTex != 0) { glDeleteTextures(1, &m_dummyShadowDepthTex); } + m_dummyColorTex = 0; + m_dummyShadowDepthTex = 0; + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + if (m_transparentFbo != 0) { glDeleteFramebuffers(1, &m_transparentFbo); } + if (m_transparentMSAAFbo != 0) { glDeleteFramebuffers(1, &m_transparentMSAAFbo); } + if (m_transparentFboColorTex != 0) { glDeleteTextures(1, &m_transparentFboColorTex); } + if (m_transparentFboMSAAColorRB != 0) { glDeleteRenderbuffers(1, &m_transparentFboMSAAColorRB); } + if (m_transparentFboMSAADepthRB != 0) { glDeleteRenderbuffers(1, &m_transparentFboMSAADepthRB); } + if (m_copyTransparentWindowShader != 0) { glDeleteProgram(m_copyTransparentWindowShader); } + if (m_copyTransparentWindowVAO != 0) { glDeleteVertexArrays(1, &m_copyTransparentWindowVAO); } + + m_vmdCameraAnim.reset(); +} + +// 帧缓存设置 +void AppContext::SetupTransparentFBO() +{ + if (m_transparentFbo == 0) + { + glGenFramebuffers(1, &m_transparentFbo); + glGenFramebuffers(1, &m_transparentMSAAFbo); + glGenTextures(1, &m_transparentFboColorTex); + glGenRenderbuffers(1, &m_transparentFboMSAAColorRB); + glGenRenderbuffers(1, &m_transparentFboMSAADepthRB); + } + + if ((m_screenWidth != m_transparentFboWidth) || (m_screenHeight != m_transparentFboHeight)) + { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindTexture(GL_TEXTURE_2D, m_transparentFboColorTex); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA, + m_screenWidth, + m_screenHeight, + 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr + ); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, m_transparentFbo); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_transparentFboColorTex, 0); + if (GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER)) + { + std::cout << "Faile to bind framebuffer.\n"; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindRenderbuffer(GL_RENDERBUFFER, m_transparentFboMSAAColorRB); + //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, m_screenWidth, m_screenHeight); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_RGBA, m_screenWidth, m_screenHeight); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindRenderbuffer(GL_RENDERBUFFER, m_transparentFboMSAADepthRB); + //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, m_screenWidth, m_screenHeight); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_DEPTH24_STENCIL8, m_screenWidth, m_screenHeight); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, m_transparentMSAAFbo); + //glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_transparentFboColorTex, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_transparentFboMSAAColorRB); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_transparentFboMSAADepthRB); + auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (GL_FRAMEBUFFER_COMPLETE != status) + { + std::cout << "Faile to bind framebuffer.\n"; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + m_transparentFboWidth = m_screenWidth; + m_transparentFboHeight = m_screenHeight; + } + + glBindFramebuffer(GL_FRAMEBUFFER, m_transparentMSAAFbo); + glEnable(GL_MULTISAMPLE); +} + +///******************* +/// 纹理 Texture +///******************* + +// 纹理 +Texture AppContext::GetTexture(const std::string & texturePath) +{ + auto it = m_textures.find(texturePath); + if (it == m_textures.end()) + { + stbi_set_flip_vertically_on_load(true); + mmd::File file; + if (!file.Open(texturePath)) + { + return Texture{ 0, false }; + } + int x, y, comp; + int ret = stbi_info_from_file(file.GetFilePointer(), &x, &y, &comp); + if (ret == 0) + { + return Texture{ 0, false }; + } + + GLuint tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + + int reqComp = 0; + bool hasAlpha = false; + if (comp != 4) + { + uint8_t* image = stbi_load_from_file(file.GetFilePointer(), &x, &y, &comp, STBI_rgb); + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, image); + stbi_image_free(image); + hasAlpha = false; + } + else + { + uint8_t* image = stbi_load_from_file(file.GetFilePointer(), &x, &y, &comp, STBI_rgb_alpha); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); + stbi_image_free(image); + hasAlpha = true; + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, 0); + + m_textures[texturePath] = Texture{ tex, hasAlpha }; + + return m_textures[texturePath]; + } + else + { + return (*it).second; + } +} + +/// ************** +/// MMDShader +/// ************** + + +bool MMDShader::Setup(const AppContext& appContext) +{ + m_prog = CreateShaderProgram( + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd.vert"), + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd.frag") + ); + if (m_prog == 0) + { + return false; + } + + // 顶点属性 + m_inPos = glGetAttribLocation(m_prog, "in_Pos"); + m_inNor = glGetAttribLocation(m_prog, "in_Nor"); + m_inUV = glGetAttribLocation(m_prog, "in_UV"); + + // 蒙皮数据 + m_uWV = glGetUniformLocation(m_prog, "u_WV"); + m_uWVP = glGetUniformLocation(m_prog, "u_WVP"); + + m_uAmbinet = glGetUniformLocation(m_prog, "u_Ambient"); + m_uDiffuse = glGetUniformLocation(m_prog, "u_Diffuse"); + m_uSpecular = glGetUniformLocation(m_prog, "u_Specular"); + m_uSpecularPower = glGetUniformLocation(m_prog, "u_SpecularPower"); + m_uAlpha = glGetUniformLocation(m_prog, "u_Alpha"); + + m_uTexMode = glGetUniformLocation(m_prog, "u_TexMode"); + m_uTex = glGetUniformLocation(m_prog, "u_Tex"); + m_uTexMulFactor = glGetUniformLocation(m_prog, "u_TexMulFactor"); + m_uTexAddFactor = glGetUniformLocation(m_prog, "u_TexAddFactor"); + + m_uSphereTexMode = glGetUniformLocation(m_prog, "u_SphereTexMode"); + m_uSphereTex = glGetUniformLocation(m_prog, "u_SphereTex"); + m_uSphereTexMulFactor = glGetUniformLocation(m_prog, "u_SphereTexMulFactor"); + m_uSphereTexAddFactor = glGetUniformLocation(m_prog, "u_SphereTexAddFactor"); + + m_uToonTexMode = glGetUniformLocation(m_prog, "u_ToonTexMode"); + m_uToonTex = glGetUniformLocation(m_prog, "u_ToonTex"); + m_uToonTexMulFactor = glGetUniformLocation(m_prog, "u_ToonTexMulFactor"); + m_uToonTexAddFactor = glGetUniformLocation(m_prog, "u_ToonTexAddFactor"); + + m_uLightColor = glGetUniformLocation(m_prog, "u_LightColor"); + m_uLightDir = glGetUniformLocation(m_prog, "u_LightDir"); + + m_uLightVP = glGetUniformLocation(m_prog, "u_LightWVP"); + m_uShadowMapSplitPositions = glGetUniformLocation(m_prog, "u_ShadowMapSplitPositions"); + m_uShadowMap0 = glGetUniformLocation(m_prog, "u_ShadowMap0"); + m_uShadowMap1 = glGetUniformLocation(m_prog, "u_ShadowMap1"); + m_uShadowMap2 = glGetUniformLocation(m_prog, "u_ShadowMap2"); + m_uShadowMap3 = glGetUniformLocation(m_prog, "u_ShadowMap3"); + m_uShadowMapEnabled = glGetUniformLocation(m_prog, "u_ShadowMapEnabled"); + + return true; +} + +void MMDShader::Clear() +{ + if (m_prog != 0) { glDeleteProgram(m_prog); } + m_prog = 0; +} + +/// ***************** +/// MMDEdgeShader +/// ***************** + +bool MMDEdgeShader::Setup(const AppContext& appContext) +{ + m_prog = CreateShaderProgram( + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd_edge.vert"), + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd_edge.frag") + ); + if (m_prog == 0) + { + return false; + } + + // 顶点属性 + m_inPos = glGetAttribLocation(m_prog, "in_Pos"); + m_inNor = glGetAttribLocation(m_prog, "in_Nor"); + + // 蒙皮属性 + m_uWV = glGetUniformLocation(m_prog, "u_WV"); + m_uWVP = glGetUniformLocation(m_prog, "u_WVP"); + m_uScreenSize = glGetUniformLocation(m_prog, "u_ScreenSize"); + m_uEdgeSize = glGetUniformLocation(m_prog, "u_EdgeSize"); + m_uEdgeColor = glGetUniformLocation(m_prog, "u_EdgeColor"); + + return true; +} + +void MMDEdgeShader::Clear() +{ + if (m_prog != 0) { glDeleteProgram(m_prog); } + m_prog = 0; +} + +/// ************************* +/// MMDGroundShadowShader +/// ************************* + +bool MMDGroundShadowShader::Setup(const AppContext& appContext) +{ + m_prog = CreateShaderProgram( + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd_ground_shadow.vert"), + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd_ground_shadow.frag") + ); + if (m_prog == 0) + { + return false; + } + + // 顶点数据 + m_inPos = glGetAttribLocation(m_prog, "in_Pos"); + + // 蒙皮数据 + m_uWVP = glGetUniformLocation(m_prog, "u_WVP"); + m_uShadowColor = glGetUniformLocation(m_prog, "u_ShadowColor"); + + return true; +} + +void MMDGroundShadowShader::Clear() +{ + if (m_prog != 0) { glDeleteProgram(m_prog); } + m_prog = 0; +} + +/// ********* +/// Model +/// ********* + +bool Model::Setup(AppContext& appContext) +{ + if (m_mmdModel == nullptr) + { + return false; + } + + // 设置顶点缓冲 + size_t vtxCount = m_mmdModel->GetVertexCount(); + glGenBuffers(1, &m_posVBO); + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vtxCount, nullptr, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenBuffers(1, &m_norVBO); + glBindBuffer(GL_ARRAY_BUFFER, m_norVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vtxCount, nullptr, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenBuffers(1, &m_uvVBO); + glBindBuffer(GL_ARRAY_BUFFER, m_uvVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * vtxCount, nullptr, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + size_t idxSize = m_mmdModel->GetIndexElementSize(); + size_t idxCount = m_mmdModel->GetIndexCount(); + glGenBuffers(1, &m_ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, idxSize * idxCount, m_mmdModel->GetIndices(), GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + if (idxSize == 1) + { + m_indexType = GL_UNSIGNED_BYTE; + } + else if (idxSize == 2) + { + m_indexType = GL_UNSIGNED_SHORT; + } + else if (idxSize == 4) + { + m_indexType = GL_UNSIGNED_INT; + } + else + { + return false; + } + + // 设置顶点数组对象 + glGenVertexArrays(1, &m_mmdVAO); + glBindVertexArray(m_mmdVAO); + + const auto& mmdShader = appContext.m_mmdShader; + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO); + glVertexAttribPointer(mmdShader->m_inPos, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0); + glEnableVertexAttribArray(mmdShader->m_inPos); + + glBindBuffer(GL_ARRAY_BUFFER, m_norVBO); + glVertexAttribPointer(mmdShader->m_inNor, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0); + glEnableVertexAttribArray(mmdShader->m_inNor); + + glBindBuffer(GL_ARRAY_BUFFER, m_uvVBO); + glVertexAttribPointer(mmdShader->m_inUV, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2), (const void*)0); + glEnableVertexAttribArray(mmdShader->m_inUV); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + + glBindVertexArray(0); + + // 设置边缘顶点数组对象 + glGenVertexArrays(1, &m_mmdEdgeVAO); + glBindVertexArray(m_mmdEdgeVAO); + + const auto& mmdEdgeShader = appContext.m_mmdEdgeShader; + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO); + glVertexAttribPointer(mmdEdgeShader->m_inPos, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0); + glEnableVertexAttribArray(mmdEdgeShader->m_inPos); + + glBindBuffer(GL_ARRAY_BUFFER, m_norVBO); + glVertexAttribPointer(mmdEdgeShader->m_inNor, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0); + glEnableVertexAttribArray(mmdEdgeShader->m_inNor); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + + glBindVertexArray(0); + + // 设置阴影顶点数组对象 + glGenVertexArrays(1, &m_mmdGroundShadowVAO); + glBindVertexArray(m_mmdGroundShadowVAO); + + const auto& mmdGroundShadowShader = appContext.m_mmdGroundShadowShader; + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO); + glVertexAttribPointer(mmdGroundShadowShader->m_inPos, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0); + glEnableVertexAttribArray(mmdGroundShadowShader->m_inPos); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + + glBindVertexArray(0); + + // 设置材质数据 + for (size_t i = 0; i < m_mmdModel->GetMaterialCount(); i++) + { + const auto& mmdMat = m_mmdModel->GetMaterials()[i]; + Material mat(mmdMat); + if (!mmdMat.m_texture.empty()) + { + auto tex = appContext.GetTexture(mmdMat.m_texture); + mat.m_texture = tex.m_texture; + mat.m_textureHasAlpha = tex.m_hasAlpha; + } + if (!mmdMat.m_spTexture.empty()) + { + auto tex = appContext.GetTexture(mmdMat.m_spTexture); + mat.m_spTexture = tex.m_texture; + } + if (!mmdMat.m_toonTexture.empty()) + { + auto tex = appContext.GetTexture(mmdMat.m_toonTexture); + mat.m_toonTexture = tex.m_texture; + } + m_materials.emplace_back(std::move(mat)); + } + + return true; +} + +// 清理数据 +void Model::Clear() +{ + if (m_posVBO != 0) { glDeleteBuffers(1, &m_posVBO); } + if (m_norVBO != 0) { glDeleteBuffers(1, &m_norVBO); } + if (m_uvVBO != 0) { glDeleteBuffers(1, &m_uvVBO); } + if (m_ibo != 0) { glDeleteBuffers(1, &m_ibo); } + m_posVBO = 0; + m_norVBO = 0; + m_uvVBO = 0; + m_ibo = 0; + + if (m_mmdVAO != 0) { glDeleteVertexArrays(1, &m_mmdVAO); } + if (m_mmdEdgeVAO != 0) { glDeleteVertexArrays(1, &m_mmdEdgeVAO); } + if (m_mmdGroundShadowVAO != 0) { glDeleteVertexArrays(1, &m_mmdGroundShadowVAO); } + m_mmdVAO = 0; + m_mmdEdgeVAO = 0; + m_mmdGroundShadowVAO = 0; +} + +void Model::UpdateAnimation(const AppContext& appContext) +{ + m_mmdModel->BeginAnimation(); + m_mmdModel->UpdateAllAnimation(m_vmdAnim.get(), appContext.m_animTime * 30.0f, appContext.m_elapsed); + m_mmdModel->EndAnimation(); +} + +void Model::Update(const AppContext& appContext) +{ + m_mmdModel->Update(); + + size_t vtxCount = m_mmdModel->GetVertexCount(); + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3) * vtxCount, m_mmdModel->GetUpdatePositions()); + glBindBuffer(GL_ARRAY_BUFFER, m_norVBO); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3) * vtxCount, m_mmdModel->GetUpdateNormals()); + glBindBuffer(GL_ARRAY_BUFFER, m_uvVBO); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec2) * vtxCount, m_mmdModel->GetUpdateUVs()); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +// 渲染 +void Model::Draw(const AppContext& appContext) +{ + const auto& view = appContext.m_viewMat; + const auto& proj = appContext.m_projMat; + + auto world = glm::mat4(1.0f); + auto wv = view * world; + auto wvp = proj * view * world; + auto wvit = glm::mat3(view * world); + wvit = glm::inverse(wvit); + wvit = glm::transpose(wvit); + + glActiveTexture(GL_TEXTURE0 + 3); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyShadowDepthTex); + glActiveTexture(GL_TEXTURE0 + 4); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyShadowDepthTex); + glActiveTexture(GL_TEXTURE0 + 5); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyShadowDepthTex); + glActiveTexture(GL_TEXTURE0 + 6); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyShadowDepthTex); + + glEnable(GL_DEPTH_TEST); + + // 渲染模型 + size_t subMeshCount = m_mmdModel->GetSubMeshCount(); + for (size_t i = 0; i < subMeshCount; i++) + { + const auto& subMesh = m_mmdModel->GetSubMeshes()[i]; + const auto& shader = appContext.m_mmdShader; + const auto& mat = m_materials[subMesh.m_materialID]; + const auto& mmdMat = mat.m_mmdMat; + + if (mat.m_mmdMat.m_alpha == 0) + { + continue; + } + + glUseProgram(shader->m_prog); + glBindVertexArray(m_mmdVAO); + + glUniformMatrix4fv(shader->m_uWV, 1, GL_FALSE, &wv[0][0]); + glUniformMatrix4fv(shader->m_uWVP, 1, GL_FALSE, &wvp[0][0]); + + bool alphaBlend = true; + + glUniform3fv(shader->m_uAmbinet, 1, &mmdMat.m_ambient[0]); + glUniform3fv(shader->m_uDiffuse, 1, &mmdMat.m_diffuse[0]); + glUniform3fv(shader->m_uSpecular, 1, &mmdMat.m_specular[0]); + glUniform1f(shader->m_uSpecularPower, mmdMat.m_specularPower); + glUniform1f(shader->m_uAlpha, mmdMat.m_alpha); + + glActiveTexture(GL_TEXTURE0 + 0); + glUniform1i(shader->m_uTex, 0); + if (mat.m_texture != 0) + { + // 设置透明度 + if (!mat.m_textureHasAlpha) + { + glUniform1i(shader->m_uTexMode, 1); + } + else + { + glUniform1i(shader->m_uTexMode, 2); + } + glUniform4fv(shader->m_uTexMulFactor, 1, &mmdMat.m_textureMulFactor[0]); + glUniform4fv(shader->m_uTexAddFactor, 1, &mmdMat.m_textureAddFactor[0]); + glBindTexture(GL_TEXTURE_2D, mat.m_texture); + } + else + { + glUniform1i(shader->m_uTexMode, 0); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyColorTex); + } + + glActiveTexture(GL_TEXTURE0 + 1); + glUniform1i(shader->m_uSphereTex, 1); + if (mat.m_spTexture != 0) + { + if (mmdMat.m_spTextureMode == mmd::MMDMaterial::SphereTextureMode::Mul) + { + glUniform1i(shader->m_uSphereTexMode, 1); + } + else if (mmdMat.m_spTextureMode == mmd::MMDMaterial::SphereTextureMode::Add) + { + glUniform1i(shader->m_uSphereTexMode, 2); + } + glUniform4fv(shader->m_uSphereTexMulFactor, 1, &mmdMat.m_spTextureMulFactor[0]); + glUniform4fv(shader->m_uSphereTexAddFactor, 1, &mmdMat.m_spTextureAddFactor[0]); + glBindTexture(GL_TEXTURE_2D, mat.m_spTexture); + } + else + { + glUniform1i(shader->m_uSphereTexMode, 0); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyColorTex); + } + + glActiveTexture(GL_TEXTURE0 + 2); + glUniform1i(shader->m_uToonTex, 2); + if (mat.m_toonTexture != 0) + { + glUniform4fv(shader->m_uToonTexMulFactor, 1, &mmdMat.m_toonTextureMulFactor[0]); + glUniform4fv(shader->m_uToonTexAddFactor, 1, &mmdMat.m_toonTextureAddFactor[0]); + glUniform1i(shader->m_uToonTexMode, 1); + glBindTexture(GL_TEXTURE_2D, mat.m_toonTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else + { + glUniform1i(shader->m_uToonTexMode, 0); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyColorTex); + } + + glm::vec3 lightColor = appContext.m_lightColor; + glm::vec3 lightDir = appContext.m_lightDir; + glm::mat3 viewMat = glm::mat3(appContext.m_viewMat); + lightDir = viewMat * lightDir; + glUniform3fv(shader->m_uLightDir, 1, &lightDir[0]); + glUniform3fv(shader->m_uLightColor, 1, &lightColor[0]); + + if (mmdMat.m_bothFace) + { + glDisable(GL_CULL_FACE); + } + else + { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + } + + if (appContext.m_enableTransparentWindow) + { + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + if (alphaBlend) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + glDisable(GL_BLEND); + } + } + + glUniform1i(shader->m_uShadowMapEnabled, 0); + glUniform1i(shader->m_uShadowMap0, 3); + glUniform1i(shader->m_uShadowMap1, 4); + glUniform1i(shader->m_uShadowMap2, 5); + glUniform1i(shader->m_uShadowMap3, 6); + + size_t offset = subMesh.m_beginIndex * m_mmdModel->GetIndexElementSize(); + glDrawElements(GL_TRIANGLES, subMesh.m_vertexCount, m_indexType, (GLvoid*)offset); + + glActiveTexture(GL_TEXTURE0 + 2); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 0); + glBindTexture(GL_TEXTURE_2D, 0); + + glUseProgram(0); + } + + glActiveTexture(GL_TEXTURE0 + 3); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 4); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 5); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 6); + glBindTexture(GL_TEXTURE_2D, 0); + + // 渲染描边 + glm::vec2 screenSize(appContext.m_screenWidth, appContext.m_screenHeight); + for (size_t i = 0; i < subMeshCount; i++) + { + const auto& subMesh = m_mmdModel->GetSubMeshes()[i]; + int matID = subMesh.m_materialID; + const auto& shader = appContext.m_mmdEdgeShader; + const auto& mat = m_materials[subMesh.m_materialID]; + const auto& mmdMat = mat.m_mmdMat; + + if (!mmdMat.m_edgeFlag) + { + continue; + } + if (mmdMat.m_alpha == 0.0f) + { + continue; + } + + glUseProgram(shader->m_prog); + glBindVertexArray(m_mmdEdgeVAO); + + glUniformMatrix4fv(shader->m_uWV, 1, GL_FALSE, &wv[0][0]); + glUniformMatrix4fv(shader->m_uWVP, 1, GL_FALSE, &wvp[0][0]); + glUniform2fv(shader->m_uScreenSize, 1, &screenSize[0]); + glUniform1f(shader->m_uEdgeSize, mmdMat.m_edgeSize); + glUniform4fv(shader->m_uEdgeColor, 1, &mmdMat.m_edgeColor[0]); + + bool alphaBlend = true; + + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + + if (appContext.m_enableTransparentWindow) + { + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + if (alphaBlend) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + glDisable(GL_BLEND); + } + } + + size_t offset = subMesh.m_beginIndex * m_mmdModel->GetIndexElementSize(); + glDrawElements(GL_TRIANGLES, subMesh.m_vertexCount, m_indexType, (GLvoid*)offset); + + glBindVertexArray(0); + glUseProgram(0); + } + + // 阴影渲染 + glEnable(GL_POLYGON_OFFSET_FILL); + glPolygonOffset(-1, -1); + auto plane = glm::vec4(0, 1, 0, 0); + auto light = -appContext.m_lightDir; + auto shadow = glm::mat4(1); + + shadow[0][0] = plane.y * light.y + plane.z * light.z; + shadow[0][1] = -plane.x * light.y; + shadow[0][2] = -plane.x * light.z; + shadow[0][3] = 0; + + shadow[1][0] = -plane.y * light.x; + shadow[1][1] = plane.x * light.x + plane.z * light.z; + shadow[1][2] = -plane.y * light.z; + shadow[1][3] = 0; + + shadow[2][0] = -plane.z * light.x; + shadow[2][1] = -plane.z * light.y; + shadow[2][2] = plane.x * light.x + plane.y * light.y; + shadow[2][3] = 0; + + shadow[3][0] = -plane.w * light.x; + shadow[3][1] = -plane.w * light.y; + shadow[3][2] = -plane.w * light.z; + shadow[3][3] = plane.x * light.x + plane.y * light.y + plane.z * light.z; + + auto wsvp = proj * view * shadow * world; + + auto shadowColor = glm::vec4(0.4f, 0.2f, 0.2f, 0.7f); + if (appContext.m_enableTransparentWindow) + { + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + + glStencilFuncSeparate(GL_FRONT_AND_BACK, GL_NOTEQUAL, 1, 1); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glEnable(GL_STENCIL_TEST); + } + else + { + if (shadowColor.a < 1.0f) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glStencilFuncSeparate(GL_FRONT_AND_BACK, GL_NOTEQUAL, 1, 1); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glEnable(GL_STENCIL_TEST); + } + else + { + glDisable(GL_BLEND); + } + } + glDisable(GL_CULL_FACE); + + for (size_t i = 0; i < subMeshCount; i++) + { + const auto& subMesh = m_mmdModel->GetSubMeshes()[i]; + int matID = subMesh.m_materialID; + const auto& mat = m_materials[subMesh.m_materialID]; + const auto& mmdMat = mat.m_mmdMat; + const auto& shader = appContext.m_mmdGroundShadowShader; + + if (!mmdMat.m_groundShadow) + { + continue; + } + if (mmdMat.m_alpha == 0.0f) + { + continue; + } + + glUseProgram(shader->m_prog); + glBindVertexArray(m_mmdGroundShadowVAO); + + glUniformMatrix4fv(shader->m_uWVP, 1, GL_FALSE, &wsvp[0][0]); + glUniform4fv(shader->m_uShadowColor, 1, &shadowColor[0]); + + size_t offset = subMesh.m_beginIndex * m_mmdModel->GetIndexElementSize(); + glDrawElements(GL_TRIANGLES, subMesh.m_vertexCount, m_indexType, (GLvoid*)offset); + + glBindVertexArray(0); + glUseProgram(0); + } + + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); +} + +void Usage() +{ + std::cout << "app [-model ] [-vmd ]\n"; + std::cout << "e.g. app -model model1.pmx -vmd anim1_1.vmd -vmd anim1_2.vmd -model model2.pmx\n"; +} + +bool SampleMain(std::vector& args) +{ + Input currentInput; + std::vector inputModels; + bool enableTransparentWindow = false; + for (auto argIt = args.begin(); argIt != args.end(); ++argIt) + { + const auto& arg = (*argIt); + if (arg == "-model") + { + if (!currentInput.m_modelPath.empty()) + { + inputModels.emplace_back(currentInput); + } + + ++argIt; + if (argIt == args.end()) + { + Usage(); + return false; + } + currentInput = Input(); + currentInput.m_modelPath = (*argIt); + } + else if (arg == "-vmd") + { + if (currentInput.m_modelPath.empty()) + { + Usage(); + return false; + } + + ++argIt; + if (argIt == args.end()) + { + Usage(); + return false; + } + currentInput.m_vmdPaths.push_back((*argIt)); + } + else if (arg == "-transparent") + { + enableTransparentWindow = true; + } + } + if (!currentInput.m_modelPath.empty()) + { + inputModels.emplace_back(currentInput); + } + + // 初始化glfw + if (!glfwInit()) + { + return false; + } + AppContext appContext; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_SAMPLES, appContext.m_msaaSamples); + glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); + glfwWindowHint(GLFW_FLOATING, GLFW_TRUE); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); + + + + if (enableTransparentWindow) + { + glfwWindowHint(GLFW_SAMPLES, 0); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GL_TRUE); + } + + auto window = glfwCreateWindow(1280, 800, "11", nullptr, nullptr); + if (window == nullptr) + { + return false; + } + + glfwMakeContextCurrent(window); + + if (gl3wInit() != 0) + { + return false; + } + + glfwSwapInterval(0); + glEnable(GL_MULTISAMPLE); + + // 错误处理 + if (!appContext.Setup()) + { + std::cout << "Failed to setup AppContext.\n"; + return false; + } + + appContext.m_enableTransparentWindow = enableTransparentWindow; + + // 加载模型 + std::vector models; + for (const auto& input : inputModels) + { + Model model; + auto ext = mmd::PathUtil::GetExt(input.m_modelPath); + if (ext == "pmd") + { + auto pmdModel = std::make_unique(); + if (!pmdModel->Load(input.m_modelPath, appContext.m_mmdDir)) + { + std::cout << "Failed to load pmd file.\n"; + return false; + } + model.m_mmdModel = std::move(pmdModel); + } + else if (ext == "pmx") + { + auto pmxModel = std::make_unique(); + if (!pmxModel->Load(input.m_modelPath, appContext.m_mmdDir)) + { + std::cout << "Failed to load pmx file.\n"; + return false; + } + model.m_mmdModel = std::move(pmxModel); + } + else + { + std::cout << "Unknown file type. [" << ext << "]\n"; + return false; + } + model.m_mmdModel->InitializeAnimation(); + + // 加载动作 + auto vmdAnim = std::make_unique(); + if (!vmdAnim->Create(model.m_mmdModel)) + { + std::cout << "Failed to create VMDAnimation.\n"; + return false; + } + for (const auto& vmdPath : input.m_vmdPaths) + { + mmd::VMDFile vmdFile; + if (!mmd::ReadVMDFile(&vmdFile, vmdPath.c_str())) + { + std::cout << "Failed to read VMD file.\n"; + return false; + } + if (!vmdAnim->Add(vmdFile)) + { + std::cout << "Failed to add VMDAnimation.\n"; + return false; + } + if (!vmdFile.m_cameras.empty()) + { + auto vmdCamAnim = std::make_unique(); + if (!vmdCamAnim->Create(vmdFile)) + { + std::cout << "Failed to create VMDCameraAnimation.\n"; + } + appContext.m_vmdCameraAnim = std::move(vmdCamAnim); + } + } + vmdAnim->SyncPhysics(0.0f); + + model.m_vmdAnim = std::move(vmdAnim); + + model.Setup(appContext); + + models.emplace_back(std::move(model)); + } + + double fpsTime = mmd::GetTime(); + int fpsFrame = 0; + double saveTime = mmd::GetTime(); + + + while (!glfwWindowShouldClose(window)) + { + double time = mmd::GetTime(); + double elapsed = time - saveTime; + if (elapsed > 1.0 / 30.0) + { + elapsed = 1.0 / 30.0; + } + saveTime = time; + appContext.m_elapsed = float(elapsed); + appContext.m_animTime += float(elapsed); + + if (enableTransparentWindow) + { + appContext.SetupTransparentFBO(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + else + { + //glClearColor(0.0f, 0.8f, 0.75f, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + + int width, height; + glfwGetFramebufferSize(window, &width, &height); + appContext.m_screenWidth = width; + appContext.m_screenHeight = height; + + glViewport(0, 0, width, height); + + // 摄像机设置 + if (appContext.m_vmdCameraAnim) + { + appContext.m_vmdCameraAnim->Evaluate(appContext.m_animTime * 30.0f); + const auto mmdCam = appContext.m_vmdCameraAnim->GetCamera(); + mmd::MMDLookAtCamera lookAtCam(mmdCam); + appContext.m_viewMat = glm::lookAt(lookAtCam.m_eye, lookAtCam.m_center, lookAtCam.m_up); + appContext.m_projMat = glm::perspectiveFovRH(mmdCam.m_fov, float(width), float(height), 1.0f, 10000.0f); + } + else + { + appContext.m_viewMat = glm::lookAt(glm::vec3(0, 10, 50), glm::vec3(0, 10, 0), glm::vec3(0, 1, 0)); + appContext.m_projMat = glm::perspectiveFovRH(glm::radians(30.0f), float(width), float(height), 1.0f, 10000.0f); + } + + for (auto& model : models) + { + // 更新动作 + model.UpdateAnimation(appContext); + + // 更新顶点 + model.Update(appContext); + + // 渲染 + model.Draw(appContext); + } + + if (enableTransparentWindow) + { + glDisable(GL_MULTISAMPLE); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, appContext.m_transparentFbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, appContext.m_transparentMSAAFbo); + glDrawBuffer(GL_BACK); + glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + glDisable(GL_DEPTH_TEST); + glBindVertexArray(appContext.m_copyTransparentWindowVAO); + glUseProgram(appContext.m_copyTransparentWindowShader); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, appContext.m_transparentFboColorTex); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + glUseProgram(0); + glBindTexture(GL_TEXTURE_2D, 0); + } + + glfwSwapBuffers(window); + glfwPollEvents(); + + // 帧率显示 + { + fpsFrame++; + double time = mmd::GetTime(); + double deltaTime = time - fpsTime; + if (deltaTime > 1.0) + { + double fps = double(fpsFrame) / deltaTime; + std::cout << fps << " fps\n"; + fpsFrame = 0; + fpsTime = time; + } + } + } + + appContext.Clear(); + + glfwTerminate(); + + return true; +} + +#if _WIN32 +#include +#include +#endif + +int main(int argc, char** argv) +{ + if (argc < 2) + { + Usage(); + return 1; + } + + std::vector args(argc); + + { + WCHAR* cmdline = GetCommandLineW(); + int wArgc; + WCHAR** wArgs = CommandLineToArgvW(cmdline, &wArgc); + for (int i = 0; i < argc; i++) + { + args[i] = mmd::ToUtf8String(wArgs[i]); + } + } + + if (!SampleMain(args)) + { + std::cout << "Failed to run.\n"; + return 1; + } + + return 0; +} diff --git a/lth/week1_apr1.md b/lth/week1_apr1.md new file mode 100644 index 0000000..392e3bf --- /dev/null +++ b/lth/week1_apr1.md @@ -0,0 +1,5 @@ +#### ~~总算把作业补完了我要死了~~ +# week1 log +  刚把被易思在线炸了的python修好,还得修复pytorch...我******你个东方仿真 +# todo +  开始标注释&复习c diff --git a/wrj/mmd_viewer_glfw.cpp b/wrj/mmd_viewer_glfw.cpp new file mode 100644 index 0000000..72ba4b6 --- /dev/null +++ b/wrj/mmd_viewer_glfw.cpp @@ -0,0 +1,1522 @@ +#include +#include + +#include +#include +#include +#include + +#include +#include + +#define STB_IMAGE_IMPLEMENTATION +#define STB_IMAGE_STATIC +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")//不显示窗口 + + +// ******************* +// 着色器 Shader +// ******************* + + +// 创建并编译着色器 +GLuint CreateShader(GLenum shaderType, const std::string code)//无符号四字节整型 +{ + GLuint shader = glCreateShader(shaderType); + if (shader == 0) + { + std::cout << "Failed to create shader.\n"; + return 0; + } + const char* codes[] = { code.c_str() }; + GLint codesLen[] = { (GLint)code.size() };//有符号四字节整型 + glShaderSource(shader, 1, codes, codesLen);//替换着色器中的代码,创建加载shader脚本源码 + glCompileShader(shader);//编译shader脚本源码 + + GLint infoLength; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);//检测着色器编译是否成功 + if (infoLength != 0) + { + std::vector info; + info.reserve(infoLength + 1);//调整容量大小 + info.resize(infoLength);//调整vector大小 + + GLsizei len; + glGetShaderInfoLog(shader, infoLength, &len, &info[0]);//返回shader对象的日志信息 + if (info[infoLength - 1] != '\0') + { + info.push_back('\0'); + } + + std::cout << &info[0] << "\n"; + } + + GLint compileStatus; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);//查询编译结果 + if (compileStatus != GL_TRUE) + { + glDeleteShader(shader); + std::cout << "Failed to compile shader.\n"; + return 0; + } + + return shader; +} + +// 链接着色器程序 +GLuint CreateShaderProgram(const std::string vsFile, const std::string fsFile) +{ + mmd::TextFileReader vsFileText; + if (!vsFileText.Open(vsFile)) + { + std::cout << "Failed to open shader file. [" << vsFile << "].\n"; + return 0; + } + std::string vsCode = vsFileText.ReadAll(); + vsFileText.Close(); + + mmd::TextFileReader fsFileText; + if (!fsFileText.Open(fsFile)) + { + std::cout << "Failed to open shader file. [" << fsFile << "].\n"; + return 0; + } + std::string fsCode = fsFileText.ReadAll(); + fsFileText.Close(); + + GLuint vs = CreateShader(GL_VERTEX_SHADER, vsCode); + GLuint fs = CreateShader(GL_FRAGMENT_SHADER, fsCode); + if (vs == 0 || fs == 0) + { + if (vs != 0) { glDeleteShader(vs); }//删除一个shader对象 + if (fs != 0) { glDeleteShader(fs); } + return 0; + } + + GLuint prog = glCreateProgram();//创建着色器程序对象 + if (prog == 0) + { + glDeleteShader(vs); + glDeleteShader(fs); + std::cout << "Failed to create program.\n"; + return 0; + } + glAttachShader(prog, vs);//附加一个shader对象到程序对象 + glAttachShader(prog, fs); + glLinkProgram(prog);//链接一个程序对象 + + GLint infoLength; + glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &infoLength);//返回程序对象参数 + if (infoLength != 0) + { + std::vector info; + info.reserve(infoLength + 1); + info.resize(infoLength); + + GLsizei len; + glGetProgramInfoLog(prog, infoLength, &len, &info[0]); + if (info[infoLength - 1] != '\0') + { + info.push_back('\0'); + } + + std::cout << &info[0] << "\n"; + } + + GLint linkStatus; + glGetProgramiv(prog, GL_LINK_STATUS, &linkStatus); + if (linkStatus != GL_TRUE) + { + glDeleteShader(vs); + glDeleteShader(fs); + std::cout << "Failed to link shader.\n"; + return 0; + } + + glDeleteShader(vs); + glDeleteShader(fs); + return prog; +} + +struct AppContext; + +struct Input +{ + std::string m_modelPath; + std::vector m_vmdPaths; +}; + +///******************* +/// 模型Shader +///******************* + +struct MMDShader +{ + ~MMDShader() + { + Clear(); + } + + GLuint m_prog = 0; + + // 顶点属性 + GLint m_inPos = -1; + GLint m_inNor = -1; + GLint m_inUV = -1; + + // 蒙皮属性 + GLint m_uWV = -1; + GLint m_uWVP = -1; + + GLint m_uAmbinet = -1; + GLint m_uDiffuse = -1; + GLint m_uSpecular = -1; + GLint m_uSpecularPower = -1; + GLint m_uAlpha = -1; + + GLint m_uTexMode = -1; + GLint m_uTex = -1; + GLint m_uTexMulFactor = -1; + GLint m_uTexAddFactor = -1; + + GLint m_uSphereTexMode = -1; + GLint m_uSphereTex = -1; + GLint m_uSphereTexMulFactor = -1; + GLint m_uSphereTexAddFactor = -1; + + GLint m_uToonTexMode = -1; + GLint m_uToonTex = -1; + GLint m_uToonTexMulFactor = -1; + GLint m_uToonTexAddFactor = -1; + + GLint m_uLightColor = -1; + GLint m_uLightDir = -1; + + GLint m_uLightVP = -1; + GLint m_uShadowMapSplitPositions = -1; + GLint m_uShadowMap0 = -1; + GLint m_uShadowMap1 = -1; + GLint m_uShadowMap2 = -1; + GLint m_uShadowMap3 = -1; + GLint m_uShadowMapEnabled = -1; + + bool Setup(const AppContext& appContext); + void Clear(); +}; + +struct MMDEdgeShader//边缘 +{ + ~MMDEdgeShader() + { + Clear(); + } + + GLuint m_prog = 0; + + // 顶点属性 + GLint m_inPos = -1; + GLint m_inNor = -1; + + // 蒙皮属性 + GLint m_uWV = -1; + GLint m_uWVP = -1; + GLint m_uScreenSize = -1; + GLint m_uEdgeSize = -1; + + GLint m_uEdgeColor = -1; + + bool Setup(const AppContext& appContext); + void Clear(); +}; + +struct MMDGroundShadowShader//背景 +{ + ~MMDGroundShadowShader() + { + Clear(); + } + + GLuint m_prog = 0; + + GLint m_inPos = -1;//顶点属性 + + GLint m_uWVP = -1;//蒙皮属性 + GLint m_uShadowColor = -1; + + bool Setup(const AppContext& appContext); + void Clear(); +}; + +struct Texture +{ + GLuint m_texture; + bool m_hasAlpha; +}; + +// OpenGL上下文 +struct AppContext +{ + ~AppContext() + { + Clear(); + } + + std::string m_resourceDir; + std::string m_shaderDir; + std::string m_mmdDir; + + std::unique_ptr m_mmdShader; + std::unique_ptr m_mmdEdgeShader; + std::unique_ptr m_mmdGroundShadowShader; + + glm::mat4 m_viewMat; + glm::mat4 m_projMat; + int m_screenWidth = 0; + int m_screenHeight = 0; + + glm::vec3 m_lightColor = glm::vec3(1, 1, 1); + glm::vec3 m_lightDir = glm::vec3(-0.5f, -1.0f, -0.5f); + + std::map m_textures; + GLuint m_dummyColorTex = 0; + GLuint m_dummyShadowDepthTex = 0; + + const int m_msaaSamples = 4; + + bool m_enableTransparentWindow = false; + uint32_t m_transparentFboWidth = 0; + uint32_t m_transparentFboHeight = 0; + GLuint m_transparentFboColorTex = 0; + GLuint m_transparentFbo = 0; + GLuint m_transparentFboMSAAColorRB = 0; + GLuint m_transparentFboMSAADepthRB = 0; + GLuint m_transparentMSAAFbo = 0; + GLuint m_copyTransparentWindowShader = 0; + GLint m_copyTransparentWindowShaderTex = -1; + GLuint m_copyTransparentWindowVAO = 0; + + float m_elapsed = 0.0f; + float m_animTime = 0.0f; + std::unique_ptr m_vmdCameraAnim; + + bool Setup(); + void Clear(); + + void SetupTransparentFBO(); + + Texture GetTexture(const std::string& texturePath); +}; + +// 材质 +struct Material +{ + explicit Material(const mmd::MMDMaterial& mat) + : m_mmdMat(mat) + {} + + const mmd::MMDMaterial& m_mmdMat; + GLuint m_texture = 0;//纹理 + bool m_textureHasAlpha = false;//无透明通道 + GLuint m_spTexture = 0; + GLuint m_toonTexture = 0; +}; + +// 模型 +struct Model +{ + std::shared_ptr m_mmdModel; + std::unique_ptr m_vmdAnim; + + GLuint m_posVBO = 0; + GLuint m_norVBO = 0; + GLuint m_uvVBO = 0; + GLuint m_ibo = 0; + GLenum m_indexType;//枚举 + + GLuint m_mmdVAO = 0; + GLuint m_mmdEdgeVAO = 0; + GLuint m_mmdGroundShadowVAO = 0; + + std::vector m_materials; + + bool Setup(AppContext& appContext); + void Clear(); + + void UpdateAnimation(const AppContext& appContext);//更新动画 + void Update(const AppContext& appContext); + void Draw(const AppContext& appContext); +}; + + +///*************************** +/// 上下文设置 AppContext +///*************************** + + +// 向GPU写入数据 +bool AppContext::Setup() +{ + m_resourceDir = mmd::PathUtil::GetExecutablePath();//获得程序路径 + m_resourceDir = mmd::PathUtil::GetDirectoryName(m_resourceDir);//获得文件的路径名 + m_resourceDir = mmd::PathUtil::Combine(m_resourceDir, "resource"); + m_shaderDir = mmd::PathUtil::Combine(m_resourceDir, "shader"); + m_mmdDir = mmd::PathUtil::Combine(m_resourceDir, "mmd"); + + m_mmdShader = std::make_unique();//智能指针 + if (!m_mmdShader->Setup(*this)) + { + return false; + } + + m_mmdEdgeShader = std::make_unique(); + if (!m_mmdEdgeShader->Setup(*this)) + { + return false; + } + + m_mmdGroundShadowShader = std::make_unique(); + if (!m_mmdGroundShadowShader->Setup(*this)) + { + return false; + } + + //将本地数据传输到显卡纹理上 + glGenTextures(1, &m_dummyColorTex);//生成保存颜色数据的纹理 + glBindTexture(GL_TEXTURE_2D, m_dummyColorTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);//分配存储空间 + glBindTexture(GL_TEXTURE_2D, 0); + + glGenTextures(1, &m_dummyShadowDepthTex); + glBindTexture(GL_TEXTURE_2D, m_dummyShadowDepthTex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 1, 1, 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr); + glBindTexture(GL_TEXTURE_2D, 0); + + m_copyTransparentWindowShader = CreateShaderProgram( + mmd::PathUtil::Combine(m_shaderDir, "quad.vert"), + mmd::PathUtil::Combine(m_shaderDir, "copy_transparent_window.frag") + ); + + m_copyTransparentWindowShaderTex = glGetUniformLocation(m_copyTransparentWindowShader, "u_Tex");//返回统一变量的位置序号 + + glGenVertexArrays(1, &m_copyTransparentWindowVAO);//生成顶点数组对象名称 + + return true; +} + +// 清除帧缓冲数据 +void AppContext::Clear() +{ + m_mmdShader.reset(); + m_mmdEdgeShader.reset(); + m_mmdGroundShadowShader.reset(); + + for (auto& tex : m_textures) + { + glDeleteTextures(1, &tex.second.m_texture); + } + m_textures.clear(); + + if (m_dummyColorTex != 0) { glDeleteTextures(1, &m_dummyColorTex); } + if (m_dummyShadowDepthTex != 0) { glDeleteTextures(1, &m_dummyShadowDepthTex); } + m_dummyColorTex = 0; + m_dummyShadowDepthTex = 0; + + glBindFramebuffer(GL_FRAMEBUFFER, 0);//指定绑定操作的帧缓冲区目标 + if (m_transparentFbo != 0) { glDeleteFramebuffers(1, &m_transparentFbo); }//删除帧缓存 + if (m_transparentMSAAFbo != 0) { glDeleteFramebuffers(1, &m_transparentMSAAFbo); } + if (m_transparentFboColorTex != 0) { glDeleteTextures(1, &m_transparentFboColorTex); }//删除纹理 + if (m_transparentFboMSAAColorRB != 0) { glDeleteRenderbuffers(1, &m_transparentFboMSAAColorRB); }//删除渲染 + if (m_transparentFboMSAADepthRB != 0) { glDeleteRenderbuffers(1, &m_transparentFboMSAADepthRB); } + if (m_copyTransparentWindowShader != 0) { glDeleteProgram(m_copyTransparentWindowShader); } + if (m_copyTransparentWindowVAO != 0) { glDeleteVertexArrays(1, &m_copyTransparentWindowVAO); } + + m_vmdCameraAnim.reset(); +} + +// 帧缓存设置 +void AppContext::SetupTransparentFBO() +{ + if (m_transparentFbo == 0) + { + glGenFramebuffers(1, &m_transparentFbo);//创建FBO + glGenFramebuffers(1, &m_transparentMSAAFbo); + glGenTextures(1, &m_transparentFboColorTex); + glGenRenderbuffers(1, &m_transparentFboMSAAColorRB); + glGenRenderbuffers(1, &m_transparentFboMSAADepthRB); + } + + if ((m_screenWidth != m_transparentFboWidth) || (m_screenHeight != m_transparentFboHeight)) + { + glBindFramebuffer(GL_FRAMEBUFFER, 0);//绑定 + glBindTexture(GL_TEXTURE_2D, m_transparentFboColorTex); + glTexImage2D( + GL_TEXTURE_2D, 0, GL_RGBA, + m_screenWidth, + m_screenHeight, + 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr + );//挂接2D纹理到FBO + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//,为当前绑定的纹理对象设置过滤方式,将纹理像素映射成像素 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, m_transparentFbo); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_transparentFboColorTex, 0);//将纹理对象绑定到帧缓冲区 + if (GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER))//返回帧缓冲区对象的帧缓冲区完整性状态,是否帧缓冲完成 + { + std::cout << "Faile to bind framebuffer.\n"; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindRenderbuffer(GL_RENDERBUFFER, m_transparentFboMSAAColorRB); + //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, m_screenWidth, m_screenHeight); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_RGBA, m_screenWidth, m_screenHeight); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindRenderbuffer(GL_RENDERBUFFER, m_transparentFboMSAADepthRB); + //glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, m_screenWidth, m_screenHeight); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, m_msaaSamples, GL_DEPTH24_STENCIL8, m_screenWidth, m_screenHeight); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, m_transparentMSAAFbo); + //glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_transparentFboColorTex, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_transparentFboMSAAColorRB);//将renderbuffer对象附加到framebuffer对象 + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_transparentFboMSAADepthRB); + auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);+ + if (GL_FRAMEBUFFER_COMPLETE != status) + { + std::cout << "Faile to bind framebuffer.\n"; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + m_transparentFboWidth = m_screenWidth; + m_transparentFboHeight = m_screenHeight; + } + + glBindFramebuffer(GL_FRAMEBUFFER, m_transparentMSAAFbo); + glEnable(GL_MULTISAMPLE);//开启多重采样 +} + +///******************* +/// 纹理 Texture +///******************* + +// 纹理 +Texture AppContext::GetTexture(const std::string & texturePath) +{ + auto it = m_textures.find(texturePath); + if (it == m_textures.end()) + { + stbi_set_flip_vertically_on_load(true);//翻转 + mmd::File file; + if (!file.Open(texturePath)) + { + return Texture{ 0, false }; + } + int x, y, comp; + int ret = stbi_info_from_file(file.GetFilePointer(), &x, &y, &comp);// + if (ret == 0) + { + return Texture{ 0, false }; + } + + GLuint tex; + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_2D, tex); + + int reqComp = 0; + bool hasAlpha = false; + if (comp != 4) + { + uint8_t* image = stbi_load_from_file(file.GetFilePointer(), &x, &y, &comp, STBI_rgb);//从文件中加载图片 + glPixelStorei(GL_UNPACK_ALIGNMENT, 1);//对齐像素字节 + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, image);//指定二维纹理图像 + stbi_image_free(image);//释放 + hasAlpha = false; + } + else + { + uint8_t* image = stbi_load_from_file(file.GetFilePointer(), &x, &y, &comp, STBI_rgb_alpha); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); + stbi_image_free(image); + hasAlpha = true; + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glBindTexture(GL_TEXTURE_2D, 0); + + m_textures[texturePath] = Texture{ tex, hasAlpha }; + + return m_textures[texturePath]; + } + else + { + return (*it).second; + } +} + +/// ************** +/// MMDShader +/// ************** + + +bool MMDShader::Setup(const AppContext& appContext) +{ + m_prog = CreateShaderProgram( + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd.vert"), + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd.frag") + ); + if (m_prog == 0) + { + return false; + } + + // 顶点属性 + m_inPos = glGetAttribLocation(m_prog, "in_Pos");//返回属性变量的位置 + m_inNor = glGetAttribLocation(m_prog, "in_Nor"); + m_inUV = glGetAttribLocation(m_prog, "in_UV"); + + // 蒙皮数据 + m_uWV = glGetUniformLocation(m_prog, "u_WV");// + m_uWVP = glGetUniformLocation(m_prog, "u_WVP"); + + m_uAmbinet = glGetUniformLocation(m_prog, "u_Ambient");//返回统一变量的位置//环境光 + m_uDiffuse = glGetUniformLocation(m_prog, "u_Diffuse");//漫反射光 + m_uSpecular = glGetUniformLocation(m_prog, "u_Specular");//镜面反射光 + m_uSpecularPower = glGetUniformLocation(m_prog, "u_SpecularPower");// + m_uAlpha = glGetUniformLocation(m_prog, "u_Alpha"); + + m_uTexMode = glGetUniformLocation(m_prog, "u_TexMode"); + m_uTex = glGetUniformLocation(m_prog, "u_Tex"); + m_uTexMulFactor = glGetUniformLocation(m_prog, "u_TexMulFactor"); + m_uTexAddFactor = glGetUniformLocation(m_prog, "u_TexAddFactor"); + + m_uSphereTexMode = glGetUniformLocation(m_prog, "u_SphereTexMode"); + m_uSphereTex = glGetUniformLocation(m_prog, "u_SphereTex"); + m_uSphereTexMulFactor = glGetUniformLocation(m_prog, "u_SphereTexMulFactor"); + m_uSphereTexAddFactor = glGetUniformLocation(m_prog, "u_SphereTexAddFactor"); + + m_uToonTexMode = glGetUniformLocation(m_prog, "u_ToonTexMode"); + m_uToonTex = glGetUniformLocation(m_prog, "u_ToonTex"); + m_uToonTexMulFactor = glGetUniformLocation(m_prog, "u_ToonTexMulFactor"); + m_uToonTexAddFactor = glGetUniformLocation(m_prog, "u_ToonTexAddFactor"); + + m_uLightColor = glGetUniformLocation(m_prog, "u_LightColor"); + m_uLightDir = glGetUniformLocation(m_prog, "u_LightDir"); + + m_uLightVP = glGetUniformLocation(m_prog, "u_LightWVP"); + m_uShadowMapSplitPositions = glGetUniformLocation(m_prog, "u_ShadowMapSplitPositions"); + m_uShadowMap0 = glGetUniformLocation(m_prog, "u_ShadowMap0"); + m_uShadowMap1 = glGetUniformLocation(m_prog, "u_ShadowMap1"); + m_uShadowMap2 = glGetUniformLocation(m_prog, "u_ShadowMap2"); + m_uShadowMap3 = glGetUniformLocation(m_prog, "u_ShadowMap3"); + m_uShadowMapEnabled = glGetUniformLocation(m_prog, "u_ShadowMapEnabled"); + + return true; +} + +void MMDShader::Clear() +{ + if (m_prog != 0) { glDeleteProgram(m_prog); } + m_prog = 0; +} + +/// ***************** +/// MMDEdgeShader +/// ***************** + +bool MMDEdgeShader::Setup(const AppContext& appContext) +{ + m_prog = CreateShaderProgram( + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd_edge.vert"), + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd_edge.frag") + ); + if (m_prog == 0) + { + return false; + } + + // 顶点属性 + m_inPos = glGetAttribLocation(m_prog, "in_Pos"); + m_inNor = glGetAttribLocation(m_prog, "in_Nor"); + + // 蒙皮属性 + m_uWV = glGetUniformLocation(m_prog, "u_WV"); + m_uWVP = glGetUniformLocation(m_prog, "u_WVP"); + m_uScreenSize = glGetUniformLocation(m_prog, "u_ScreenSize"); + m_uEdgeSize = glGetUniformLocation(m_prog, "u_EdgeSize"); + m_uEdgeColor = glGetUniformLocation(m_prog, "u_EdgeColor"); + + return true; +} + +void MMDEdgeShader::Clear() +{ + if (m_prog != 0) { glDeleteProgram(m_prog); } + m_prog = 0; +} + +/// ************************* +/// MMDGroundShadowShader +/// ************************* + +bool MMDGroundShadowShader::Setup(const AppContext& appContext) +{ + m_prog = CreateShaderProgram( + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd_ground_shadow.vert"), + mmd::PathUtil::Combine(appContext.m_shaderDir, "mmd_ground_shadow.frag") + ); + if (m_prog == 0) + { + return false; + } + + // 顶点数据 + m_inPos = glGetAttribLocation(m_prog, "in_Pos"); + + // 蒙皮数据 + m_uWVP = glGetUniformLocation(m_prog, "u_WVP"); + m_uShadowColor = glGetUniformLocation(m_prog, "u_ShadowColor"); + + return true; +} + +void MMDGroundShadowShader::Clear() +{ + if (m_prog != 0) { glDeleteProgram(m_prog); } + m_prog = 0; +} + +/// ********* +/// Model +/// ********* + +bool Model::Setup(AppContext& appContext) +{ + if (m_mmdModel == nullptr) + { + return false; + } + + // 设置顶点缓冲 + size_t vtxCount = m_mmdModel->GetVertexCount(); + glGenBuffers(1, &m_posVBO);//生成缓冲区 + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO);//绑定缓冲区对象 + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vtxCount, nullptr, GL_DYNAMIC_DRAW);//创建并初始化缓冲区对象的数据存储 + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenBuffers(1, &m_norVBO); + glBindBuffer(GL_ARRAY_BUFFER, m_norVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * vtxCount, nullptr, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenBuffers(1, &m_uvVBO); + glBindBuffer(GL_ARRAY_BUFFER, m_uvVBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec2) * vtxCount, nullptr, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + size_t idxSize = m_mmdModel->GetIndexElementSize(); + size_t idxCount = m_mmdModel->GetIndexCount(); + glGenBuffers(1, &m_ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, idxSize * idxCount, m_mmdModel->GetIndices(), GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + //顶点规范 + if (idxSize == 1) + { + m_indexType = GL_UNSIGNED_BYTE; + } + else if (idxSize == 2) + { + m_indexType = GL_UNSIGNED_SHORT; + } + else if (idxSize == 4) + { + m_indexType = GL_UNSIGNED_INT; + } + else + { + return false; + } + + // 设置顶点数组对象 + glGenVertexArrays(1, &m_mmdVAO);//生成顶点数组对象 + glBindVertexArray(m_mmdVAO);//绑定顶点数组对象 + + const auto& mmdShader = appContext.m_mmdShader; + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO); + glVertexAttribPointer(mmdShader->m_inPos, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0);//定义通用顶点属性数据的数组 + glEnableVertexAttribArray(mmdShader->m_inPos);//启用通用顶点 + + glBindBuffer(GL_ARRAY_BUFFER, m_norVBO); + glVertexAttribPointer(mmdShader->m_inNor, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0); + glEnableVertexAttribArray(mmdShader->m_inNor); + + glBindBuffer(GL_ARRAY_BUFFER, m_uvVBO); + glVertexAttribPointer(mmdShader->m_inUV, 2, GL_FLOAT, GL_FALSE, sizeof(glm::vec2), (const void*)0); + glEnableVertexAttribArray(mmdShader->m_inUV); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + + glBindVertexArray(0); + + // 设置边缘顶点数组对象 + glGenVertexArrays(1, &m_mmdEdgeVAO); + glBindVertexArray(m_mmdEdgeVAO); + + const auto& mmdEdgeShader = appContext.m_mmdEdgeShader; + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO); + glVertexAttribPointer(mmdEdgeShader->m_inPos, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0); + glEnableVertexAttribArray(mmdEdgeShader->m_inPos); + + glBindBuffer(GL_ARRAY_BUFFER, m_norVBO); + glVertexAttribPointer(mmdEdgeShader->m_inNor, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0); + glEnableVertexAttribArray(mmdEdgeShader->m_inNor); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + + glBindVertexArray(0); + + // 设置阴影顶点数组对象 + glGenVertexArrays(1, &m_mmdGroundShadowVAO); + glBindVertexArray(m_mmdGroundShadowVAO); + + const auto& mmdGroundShadowShader = appContext.m_mmdGroundShadowShader; + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO); + glVertexAttribPointer(mmdGroundShadowShader->m_inPos, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec3), (const void*)0); + glEnableVertexAttribArray(mmdGroundShadowShader->m_inPos); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ibo); + + glBindVertexArray(0); + + // 设置材质数据 + for (size_t i = 0; i < m_mmdModel->GetMaterialCount(); i++) + { + const auto& mmdMat = m_mmdModel->GetMaterials()[i]; + Material mat(mmdMat); + if (!mmdMat.m_texture.empty()) + { + auto tex = appContext.GetTexture(mmdMat.m_texture); + mat.m_texture = tex.m_texture; + mat.m_textureHasAlpha = tex.m_hasAlpha; + } + if (!mmdMat.m_spTexture.empty()) + { + auto tex = appContext.GetTexture(mmdMat.m_spTexture); + mat.m_spTexture = tex.m_texture; + } + if (!mmdMat.m_toonTexture.empty()) + { + auto tex = appContext.GetTexture(mmdMat.m_toonTexture); + mat.m_toonTexture = tex.m_texture; + } + m_materials.emplace_back(std::move(mat)); + } + + return true; +} + +// 清理数据 +void Model::Clear() +{ + if (m_posVBO != 0) { glDeleteBuffers(1, &m_posVBO); }//删除缓冲区 + if (m_norVBO != 0) { glDeleteBuffers(1, &m_norVBO); } + if (m_uvVBO != 0) { glDeleteBuffers(1, &m_uvVBO); } + if (m_ibo != 0) { glDeleteBuffers(1, &m_ibo); } + m_posVBO = 0; + m_norVBO = 0; + m_uvVBO = 0; + m_ibo = 0; + + if (m_mmdVAO != 0) { glDeleteVertexArrays(1, &m_mmdVAO); }//删除顶点数组 + if (m_mmdEdgeVAO != 0) { glDeleteVertexArrays(1, &m_mmdEdgeVAO); } + if (m_mmdGroundShadowVAO != 0) { glDeleteVertexArrays(1, &m_mmdGroundShadowVAO); } + m_mmdVAO = 0; + m_mmdEdgeVAO = 0; + m_mmdGroundShadowVAO = 0; +} + +void Model::UpdateAnimation(const AppContext& appContext) +{ + m_mmdModel->BeginAnimation(); + m_mmdModel->UpdateAllAnimation(m_vmdAnim.get(), appContext.m_animTime * 30.0f, appContext.m_elapsed); + m_mmdModel->EndAnimation(); +} + +void Model::Update(const AppContext& appContext) +{ + m_mmdModel->Update(); + + size_t vtxCount = m_mmdModel->GetVertexCount(); + glBindBuffer(GL_ARRAY_BUFFER, m_posVBO); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3) * vtxCount, m_mmdModel->GetUpdatePositions());//更新缓冲区对象的数据存储的子集 + glBindBuffer(GL_ARRAY_BUFFER, m_norVBO); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3) * vtxCount, m_mmdModel->GetUpdateNormals()); + glBindBuffer(GL_ARRAY_BUFFER, m_uvVBO); + glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec2) * vtxCount, m_mmdModel->GetUpdateUVs()); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +// 渲染 +void Model::Draw(const AppContext& appContext) +{ + const auto& view = appContext.m_viewMat; + const auto& proj = appContext.m_projMat; + + auto world = glm::mat4(1.0f); + auto wv = view * world; + auto wvp = proj * view * world; + auto wvit = glm::mat3(view * world); + wvit = glm::inverse(wvit);//求逆矩阵 + wvit = glm::transpose(wvit);//求矩阵的转置 + + glActiveTexture(GL_TEXTURE0 + 3);//激活纹理单元 + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyShadowDepthTex);//绑定纹理 + glActiveTexture(GL_TEXTURE0 + 4); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyShadowDepthTex); + glActiveTexture(GL_TEXTURE0 + 5); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyShadowDepthTex); + glActiveTexture(GL_TEXTURE0 + 6); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyShadowDepthTex); + + glEnable(GL_DEPTH_TEST);//启用功能,进行深度比较并更新深度缓冲区 + + // 渲染模型 + size_t subMeshCount = m_mmdModel->GetSubMeshCount(); + for (size_t i = 0; i < subMeshCount; i++) + { + const auto& subMesh = m_mmdModel->GetSubMeshes()[i]; + const auto& shader = appContext.m_mmdShader; + const auto& mat = m_materials[subMesh.m_materialID]; + const auto& mmdMat = mat.m_mmdMat; + + if (mat.m_mmdMat.m_alpha == 0) + { + continue; + } + + glUseProgram(shader->m_prog);//使用程序对象作为当前渲染的一部分 + glBindVertexArray(m_mmdVAO); + + glUniformMatrix4fv(shader->m_uWV, 1, GL_FALSE, &wv[0][0]);// + glUniformMatrix4fv(shader->m_uWVP, 1, GL_FALSE, &wvp[0][0]); + + bool alphaBlend = true; + + glUniform3fv(shader->m_uAmbinet, 1, &mmdMat.m_ambient[0]);//指定当前程序对象的统一变量的值 + glUniform3fv(shader->m_uDiffuse, 1, &mmdMat.m_diffuse[0]); + glUniform3fv(shader->m_uSpecular, 1, &mmdMat.m_specular[0]); + glUniform1f(shader->m_uSpecularPower, mmdMat.m_specularPower); + glUniform1f(shader->m_uAlpha, mmdMat.m_alpha); + + glActiveTexture(GL_TEXTURE0 + 0); + glUniform1i(shader->m_uTex, 0);// + if (mat.m_texture != 0) + { + // 设置透明度 + if (!mat.m_textureHasAlpha) + { + glUniform1i(shader->m_uTexMode, 1); + } + else + { + glUniform1i(shader->m_uTexMode, 2); + } + glUniform4fv(shader->m_uTexMulFactor, 1, &mmdMat.m_textureMulFactor[0]); + glUniform4fv(shader->m_uTexAddFactor, 1, &mmdMat.m_textureAddFactor[0]); + glBindTexture(GL_TEXTURE_2D, mat.m_texture); + } + else + { + glUniform1i(shader->m_uTexMode, 0); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyColorTex); + } + + glActiveTexture(GL_TEXTURE0 + 1); + glUniform1i(shader->m_uSphereTex, 1); + if (mat.m_spTexture != 0) + { + if (mmdMat.m_spTextureMode == mmd::MMDMaterial::SphereTextureMode::Mul) + { + glUniform1i(shader->m_uSphereTexMode, 1); + } + else if (mmdMat.m_spTextureMode == mmd::MMDMaterial::SphereTextureMode::Add) + { + glUniform1i(shader->m_uSphereTexMode, 2); + } + glUniform4fv(shader->m_uSphereTexMulFactor, 1, &mmdMat.m_spTextureMulFactor[0]); + glUniform4fv(shader->m_uSphereTexAddFactor, 1, &mmdMat.m_spTextureAddFactor[0]); + glBindTexture(GL_TEXTURE_2D, mat.m_spTexture); + } + else + { + glUniform1i(shader->m_uSphereTexMode, 0); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyColorTex); + } + + glActiveTexture(GL_TEXTURE0 + 2); + glUniform1i(shader->m_uToonTex, 2); + if (mat.m_toonTexture != 0) + { + glUniform4fv(shader->m_uToonTexMulFactor, 1, &mmdMat.m_toonTextureMulFactor[0]); + glUniform4fv(shader->m_uToonTexAddFactor, 1, &mmdMat.m_toonTextureAddFactor[0]); + glUniform1i(shader->m_uToonTexMode, 1); + glBindTexture(GL_TEXTURE_2D, mat.m_toonTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);//设置纹理参数GLint + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else + { + glUniform1i(shader->m_uToonTexMode, 0); + glBindTexture(GL_TEXTURE_2D, appContext.m_dummyColorTex); + } + + glm::vec3 lightColor = appContext.m_lightColor; + glm::vec3 lightDir = appContext.m_lightDir; + glm::mat3 viewMat = glm::mat3(appContext.m_viewMat); + lightDir = viewMat * lightDir; + glUniform3fv(shader->m_uLightDir, 1, &lightDir[0]); + glUniform3fv(shader->m_uLightColor, 1, &lightColor[0]); + + if (mmdMat.m_bothFace) + { + glDisable(GL_CULL_FACE);//禁用功能,禁止多边形剔除 + } + else + { + glEnable(GL_CULL_FACE);//启用多边形剔除 + glCullFace(GL_BACK);//指定是否可以剔除前面或后面的多边形 + } + + if (appContext.m_enableTransparentWindow) + { + glEnable(GL_BLEND);//启用将计算片段颜色值与颜色缓冲区中的值混合 + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);//分别指定RGB和alpha分量的像素计算 + } + else + { + if (alphaBlend) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//指定像素算术 + } + else + { + glDisable(GL_BLEND); + } + } + + glUniform1i(shader->m_uShadowMapEnabled, 0); + glUniform1i(shader->m_uShadowMap0, 3); + glUniform1i(shader->m_uShadowMap1, 4); + glUniform1i(shader->m_uShadowMap2, 5); + glUniform1i(shader->m_uShadowMap3, 6); + + size_t offset = subMesh.m_beginIndex * m_mmdModel->GetIndexElementSize(); + glDrawElements(GL_TRIANGLES, subMesh.m_vertexCount, m_indexType, (GLvoid*)offset);//从数组数据中渲染图元 + + glActiveTexture(GL_TEXTURE0 + 2); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 0); + glBindTexture(GL_TEXTURE_2D, 0); + + glUseProgram(0);//使用程序对象作为当前渲染状态的一部分 + } + + glActiveTexture(GL_TEXTURE0 + 3); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 4); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 5); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0 + 6); + glBindTexture(GL_TEXTURE_2D, 0); + + // 渲染描边 + glm::vec2 screenSize(appContext.m_screenWidth, appContext.m_screenHeight); + for (size_t i = 0; i < subMeshCount; i++) + { + const auto& subMesh = m_mmdModel->GetSubMeshes()[i]; + int matID = subMesh.m_materialID; + const auto& shader = appContext.m_mmdEdgeShader; + const auto& mat = m_materials[subMesh.m_materialID]; + const auto& mmdMat = mat.m_mmdMat; + + if (!mmdMat.m_edgeFlag) + { + continue; + } + if (mmdMat.m_alpha == 0.0f) + { + continue; + } + + glUseProgram(shader->m_prog); + glBindVertexArray(m_mmdEdgeVAO); + + glUniformMatrix4fv(shader->m_uWV, 1, GL_FALSE, &wv[0][0]); + glUniformMatrix4fv(shader->m_uWVP, 1, GL_FALSE, &wvp[0][0]); + glUniform2fv(shader->m_uScreenSize, 1, &screenSize[0]); + glUniform1f(shader->m_uEdgeSize, mmdMat.m_edgeSize); + glUniform4fv(shader->m_uEdgeColor, 1, &mmdMat.m_edgeColor[0]); + + bool alphaBlend = true; + + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + + if (appContext.m_enableTransparentWindow) + { + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + if (alphaBlend) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else + { + glDisable(GL_BLEND); + } + } + + size_t offset = subMesh.m_beginIndex * m_mmdModel->GetIndexElementSize(); + glDrawElements(GL_TRIANGLES, subMesh.m_vertexCount, m_indexType, (GLvoid*)offset); + + glBindVertexArray(0); + glUseProgram(0); + } + + // 阴影渲染 + glEnable(GL_POLYGON_OFFSET_FILL);//将偏移添加到由光栅化生产的多边形片段的深度值 + glPolygonOffset(-1, -1);//设置用于计算深度值的比例和单位 + auto plane = glm::vec4(0, 1, 0, 0); + auto light = -appContext.m_lightDir; + auto shadow = glm::mat4(1); + + shadow[0][0] = plane.y * light.y + plane.z * light.z; + shadow[0][1] = -plane.x * light.y; + shadow[0][2] = -plane.x * light.z; + shadow[0][3] = 0; + + shadow[1][0] = -plane.y * light.x; + shadow[1][1] = plane.x * light.x + plane.z * light.z; + shadow[1][2] = -plane.y * light.z; + shadow[1][3] = 0; + + shadow[2][0] = -plane.z * light.x; + shadow[2][1] = -plane.z * light.y; + shadow[2][2] = plane.x * light.x + plane.y * light.y; + shadow[2][3] = 0; + + shadow[3][0] = -plane.w * light.x; + shadow[3][1] = -plane.w * light.y; + shadow[3][2] = -plane.w * light.z; + shadow[3][3] = plane.x * light.x + plane.y * light.y + plane.z * light.z; + + auto wsvp = proj * view * shadow * world; + + auto shadowColor = glm::vec4(0.4f, 0.2f, 0.2f, 0.7f); + if (appContext.m_enableTransparentWindow) + { + glEnable(GL_BLEND); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); + + glStencilFuncSeparate(GL_FRONT_AND_BACK, GL_NOTEQUAL, 1, 1);//设置模板测试的前端和后端功能和参考值 + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);//设置正面和背面模板测试操作 + glEnable(GL_STENCIL_TEST);//进行模板测试并更新模板缓冲区 + } + else + { + if (shadowColor.a < 1.0f) + { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//指定像素运算 + + glStencilFuncSeparate(GL_FRONT_AND_BACK, GL_NOTEQUAL, 1, 1); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + glEnable(GL_STENCIL_TEST); + } + else + { + glDisable(GL_BLEND); + } + } + glDisable(GL_CULL_FACE); + + for (size_t i = 0; i < subMeshCount; i++) + { + const auto& subMesh = m_mmdModel->GetSubMeshes()[i]; + int matID = subMesh.m_materialID; + const auto& mat = m_materials[subMesh.m_materialID]; + const auto& mmdMat = mat.m_mmdMat; + const auto& shader = appContext.m_mmdGroundShadowShader; + + if (!mmdMat.m_groundShadow) + { + continue; + } + if (mmdMat.m_alpha == 0.0f) + { + continue; + } + + glUseProgram(shader->m_prog); + glBindVertexArray(m_mmdGroundShadowVAO); + + glUniformMatrix4fv(shader->m_uWVP, 1, GL_FALSE, &wsvp[0][0]); + glUniform4fv(shader->m_uShadowColor, 1, &shadowColor[0]); + + size_t offset = subMesh.m_beginIndex * m_mmdModel->GetIndexElementSize(); + glDrawElements(GL_TRIANGLES, subMesh.m_vertexCount, m_indexType, (GLvoid*)offset); + + glBindVertexArray(0); + glUseProgram(0); + } + + glDisable(GL_POLYGON_OFFSET_FILL); + glDisable(GL_STENCIL_TEST); + glDisable(GL_BLEND); +} + +void Usage() +{ + std::cout << "app [-model ] [-vmd ]\n"; + std::cout << "e.g. app -model model1.pmx -vmd anim1_1.vmd -vmd anim1_2.vmd -model model2.pmx\n"; +} + +bool SampleMain(std::vector& args) +{ + Input currentInput; + std::vector inputModels; + bool enableTransparentWindow = false; + for (auto argIt = args.begin(); argIt != args.end(); ++argIt) + { + const auto& arg = (*argIt); + if (arg == "-model") + { + if (!currentInput.m_modelPath.empty()) + { + inputModels.emplace_back(currentInput); + } + + ++argIt; + if (argIt == args.end()) + { + Usage(); + return false; + } + currentInput = Input(); + currentInput.m_modelPath = (*argIt); + } + else if (arg == "-vmd") + { + if (currentInput.m_modelPath.empty()) + { + Usage(); + return false; + } + + ++argIt; + if (argIt == args.end()) + { + Usage(); + return false; + } + currentInput.m_vmdPaths.push_back((*argIt)); + } + else if (arg == "-transparent") + { + enableTransparentWindow = true; + } + } + if (!currentInput.m_modelPath.empty()) + { + inputModels.emplace_back(currentInput); + } + + // 初始化glfw + if (!glfwInit()) + { + return false; + } + AppContext appContext; + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);//设置窗口提示参数 + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_SAMPLES, appContext.m_msaaSamples); + glfwWindowHint(GLFW_DECORATED, GLFW_FALSE); + glfwWindowHint(GLFW_FLOATING, GLFW_TRUE); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE); + + + + if (enableTransparentWindow) + { + glfwWindowHint(GLFW_SAMPLES, 0); + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GL_TRUE); + } + + auto window = glfwCreateWindow(1280, 800, "11", nullptr, nullptr); + if (window == nullptr) + { + return false; + } + + glfwMakeContextCurrent(window);//绑定当前线程的content为window + + if (gl3wInit() != 0) + { + return false; + } + + glfwSwapInterval(0);//设置swap间隔 + glEnable(GL_MULTISAMPLE);//使用多个片元采样来计算最终的像素颜色 + + // 错误处理 + if (!appContext.Setup()) + { + std::cout << "Failed to setup AppContext.\n"; + return false; + } + + appContext.m_enableTransparentWindow = enableTransparentWindow; + + // 加载模型 + std::vector models; + for (const auto& input : inputModels) + { + Model model; + auto ext = mmd::PathUtil::GetExt(input.m_modelPath); + if (ext == "pmd") + { + auto pmdModel = std::make_unique(); + if (!pmdModel->Load(input.m_modelPath, appContext.m_mmdDir)) + { + std::cout << "Failed to load pmd file.\n"; + return false; + } + model.m_mmdModel = std::move(pmdModel); + } + else if (ext == "pmx") + { + auto pmxModel = std::make_unique(); + if (!pmxModel->Load(input.m_modelPath, appContext.m_mmdDir)) + { + std::cout << "Failed to load pmx file.\n"; + return false; + } + model.m_mmdModel = std::move(pmxModel); + } + else + { + std::cout << "Unknown file type. [" << ext << "]\n"; + return false; + } + model.m_mmdModel->InitializeAnimation(); + + // 加载动作 + auto vmdAnim = std::make_unique(); + if (!vmdAnim->Create(model.m_mmdModel)) + { + std::cout << "Failed to create VMDAnimation.\n"; + return false; + } + for (const auto& vmdPath : input.m_vmdPaths) + { + mmd::VMDFile vmdFile; + if (!mmd::ReadVMDFile(&vmdFile, vmdPath.c_str())) + { + std::cout << "Failed to read VMD file.\n"; + return false; + } + if (!vmdAnim->Add(vmdFile)) + { + std::cout << "Failed to add VMDAnimation.\n"; + return false; + } + if (!vmdFile.m_cameras.empty()) + { + auto vmdCamAnim = std::make_unique(); + if (!vmdCamAnim->Create(vmdFile)) + { + std::cout << "Failed to create VMDCameraAnimation.\n"; + } + appContext.m_vmdCameraAnim = std::move(vmdCamAnim); + } + } + vmdAnim->SyncPhysics(0.0f); + + model.m_vmdAnim = std::move(vmdAnim); + + model.Setup(appContext); + + models.emplace_back(std::move(model)); + } + + double fpsTime = mmd::GetTime(); + int fpsFrame = 0; + double saveTime = mmd::GetTime(); + + + while (!glfwWindowShouldClose(window))//检查glfw是否被指示关闭 + { + double time = mmd::GetTime(); + double elapsed = time - saveTime; + if (elapsed > 1.0 / 30.0) + { + elapsed = 1.0 / 30.0; + } + saveTime = time; + appContext.m_elapsed = float(elapsed); + appContext.m_animTime += float(elapsed); + + if (enableTransparentWindow)// + { + appContext.SetupTransparentFBO(); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + else + { + //glClearColor(0.0f, 0.8f, 0.75f, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + + int width, height; + glfwGetFramebufferSize(window, &width, &height);//改变窗口大小 + appContext.m_screenWidth = width; + appContext.m_screenHeight = height; + + glViewport(0, 0, width, height); + + // 摄像机设置 + if (appContext.m_vmdCameraAnim) + { + appContext.m_vmdCameraAnim->Evaluate(appContext.m_animTime * 30.0f); + const auto mmdCam = appContext.m_vmdCameraAnim->GetCamera(); + mmd::MMDLookAtCamera lookAtCam(mmdCam); + appContext.m_viewMat = glm::lookAt(lookAtCam.m_eye, lookAtCam.m_center, lookAtCam.m_up); + appContext.m_projMat = glm::perspectiveFovRH(mmdCam.m_fov, float(width), float(height), 1.0f, 10000.0f); + } + else + { + appContext.m_viewMat = glm::lookAt(glm::vec3(0, 10, 50), glm::vec3(0, 10, 0), glm::vec3(0, 1, 0)); + appContext.m_projMat = glm::perspectiveFovRH(glm::radians(30.0f), float(width), float(height), 1.0f, 10000.0f); + } + + for (auto& model : models) + { + // 更新动作 + model.UpdateAnimation(appContext); + + // 更新顶点 + model.Update(appContext); + + // 渲染 + model.Draw(appContext); + } + + if (enableTransparentWindow) + { + glDisable(GL_MULTISAMPLE); + glBindFramebuffer(GL_FRAMEBUFFER, 0);//绑定一个缓冲区对象 + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, appContext.m_transparentFbo); + glBindFramebuffer(GL_READ_FRAMEBUFFER, appContext.m_transparentMSAAFbo); + glDrawBuffer(GL_BACK);// + glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);//将像素快从读取的帧缓冲区复制到绘制帧缓冲区 + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + glDisable(GL_DEPTH_TEST); + glBindVertexArray(appContext.m_copyTransparentWindowVAO); + glUseProgram(appContext.m_copyTransparentWindowShader); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, appContext.m_transparentFboColorTex); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + glBindVertexArray(0); + glUseProgram(0); + glBindTexture(GL_TEXTURE_2D, 0); + } + + glfwSwapBuffers(window); + glfwPollEvents();//立即处理已到位的事件 + + // 帧率显示 + { + fpsFrame++; + double time = mmd::GetTime(); + double deltaTime = time - fpsTime; + if (deltaTime > 1.0) + { + double fps = double(fpsFrame) / deltaTime; + std::cout << fps << " fps\n"; + fpsFrame = 0; + fpsTime = time; + } + } + } + + appContext.Clear(); + + glfwTerminate();//销毁窗口释放资源,初始化 + + return true; +} + +#if _WIN32 +#include +#include +#endif + +int main(int argc, char** argv) +{ + if (argc < 2) + { + Usage(); + return 1; + } + + std::vector args(argc); + + { + WCHAR* cmdline = GetCommandLineW(); + int wArgc; + WCHAR** wArgs = CommandLineToArgvW(cmdline, &wArgc); + for (int i = 0; i < argc; i++) + { + args[i] = mmd::ToUtf8String(wArgs[i]); + } + } + + if (!SampleMain(args)) + { + std::cout << "Failed to run.\n"; + return 1; + } + + return 0; +} diff --git a/wrj/rizhi.txt b/wrj/rizhi.txt new file mode 100644 index 0000000..77fff4a --- /dev/null +++ b/wrj/rizhi.txt @@ -0,0 +1,5 @@ +第一周 +对机器学习有初步了解 +完成了gui的框架,现在可以使用gui调用动画程序,播放mmd。 +gui的说明文档正在编写中 +了解git的使用 \ No newline at end of file diff --git a/yhn/20220401.md b/yhn/20220401.md new file mode 100644 index 0000000..9b9a12c --- /dev/null +++ b/yhn/20220401.md @@ -0,0 +1,54 @@ +# 日志NO.1 + +## 概要 + +- 使用tkinter制作GUI +- 开始学习git的使用 +- 文档编写 + +## GUI制作 + +> 以下内容由每次提交的信息修改而来。 + +完成了gui的框架,现在可以使用gui调用动画程序,播放mmd。 + +增加了reload按钮,修改了界面默认的位置。现在界面默认会出现在屏幕中央。 + +优化了代码结构,将主窗口构建相关代码转移到类中,使用更多易于更改的部分,现在增加了constants.py存放常量。优化了文件结构,增加了assets文件夹存放软件使用的素材,制作并增加了简单的按钮图案,并增加了使窗口透明的代码(未启用)。 + +修改了组件布局方式,增加了背景图层,并添加了简单的背景图。增加了按钮在鼠标悬停时的样式变化,提高交互舒适度。 + +增加了constants.py中的内容,现在所有图片可以通过更改路径常量轻松更改。 + +修改了背景,增加了标签底色和按钮底色两个常量。 + +修复了启动失败后再次点击启动按钮无反应的bug,现在找不到文件后会删除对应的下拉栏选项,下拉栏更新后会自动选择第一项。 + + + +不得不说,又学习了好多tkinter的知识,确实是一个非常不错的gui制作方法。但是并不能制作出很漂亮的gui,制作过程也比较繁琐费力。 + +据liz了解到了Electron,看起来是很强大的东西,但是还没有开始学习。 + + + +下一个版本希望能在gui中加入校验文件完整性的功能,似乎是通过文件哈希值校验的方式实现。但是还没有开始学习。 + + + +## Git使用 + +开始使用git管理代码。初步学习了git的简单操作。 + +现在加入了NekoTeam的Github,进行了第一次clone和提交! + +此外,还在本地编写GUI相关代码时,使用了git来记录和控制每一次的版本变更。非常好用! + + + +## 文档编写 + +gui的说明文档基本编写完成。 + +##### yhn 2022.4.1 + diff --git a/yhn/20220408.md b/yhn/20220408.md new file mode 100644 index 0000000..a4e49fc --- /dev/null +++ b/yhn/20220408.md @@ -0,0 +1,24 @@ +# 日志NO.2 + +## 概要 + +- GUI完善 +- 其它 + +## GUI完善 + +V1.20版本加入了校验文件完整性的功能。 + +使用的是hashlib模块的m5d功能生成带有文件特征值的JSON文件。 + +在新加入的hashcheck.py中,包含部分校验代码以及生成校验索引JSON文件的代码。通过修改其中主程序部分的代码,以及头部的一些值,可以以这个文件为主程序,直接进行索引文件的生成和检验。 + +GUI程序中不包含生成校验索引文件的功能。 + +现在在启动程序时,会自动检验resource目录和assets目录下的内容。如果文件被删除或篡改,将会发出报错并终止程序。 + +## 其它 + +本来想加注释但是看不懂,寄。 + +##### yhn2022.4.8 \ No newline at end of file