> 技术文档 > Horse3D游戏引擎研发笔记(六):在QtOpenGL环境下,仿Unity的材质管理Shader绘制四边形

Horse3D游戏引擎研发笔记(六):在QtOpenGL环境下,仿Unity的材质管理Shader绘制四边形

在上一篇笔记中,我们已经实现了基于QtOpenGL的BufferGeometry管理VAO和EBO绘制四边形的功能。这一次,我们将深入探讨材质管理系统的实现,包括Shader的加载与编译、材质的创建与使用,以及如何通过材质系统绘制带有自定义Shader效果的四边形。


一、Horse3D引擎的材质管理系统

在现代三维引擎中,材质管理系统是渲染系统的核心模块之一。它负责管理模型表面的视觉效果,包括颜色、纹理、光照响应等。在Horse3D引擎中,我们参考了Unity和Three.js的材质系统设计,实现了以下功能:

  1. 材质的定义与加载:通过JSON格式的材质文件定义材质属性,包括顶点着色器、片段着色器、纹理资源等。
  2. Shader的编译与管理:支持 Shader 的动态加载与编译,通过Builder模式管理Shader程序的创建与缓存。
  3. 材质的实例化与使用:通过Material类管理材质的OpenGL状态,并提供统一的接口绑定材质进行渲染。

二、关键技术与实现细节

1. 材质文件的定义

在Horse3D中,材质通过JSON文件进行定义。以下是一个典型的材质文件示例:

{ \"Attributes\": [ { \"Name\": \"a_position\", \"Dimension\": 3 }, { \"Name\": \"a_texcoord\", \"Dimension\": 2 } ], \"Uniforms\": [ { \"Name\": \"u_fragColor\", \"Type\": \"Color\", \"Value\": \"#FFFF00\" }, { \"Name\": \"u_texture_fei\", \"Type\": \"Texture2D\", \"Value\": \"Materials/Test/fei.jpg\" }, { \"Name\": \"u_texture_tang\", \"Type\": \"Texture2D\", \"Value\": \"Materials/Test/tang.jpeg\" } ], \"Shaders\": [ { \"ShaderEnum\": \"Vertex\", \"SourceFile\": \"Materials/Test/Test.vert\" }, { \"ShaderEnum\": \"Fragment\", \"SourceFile\": \"Materials/Test/Test.frag\" } ]}

该文件定义了材质的顶点属性、Uniform变量以及Shader程序。通过这种方式,我们可以灵活地配置材质的视觉效果。这一部分的设计灵感来源于Unity与OpenGL中的材质系统详解。

2. Shader程序的加载与编译

在Horse3D中,Shader程序的加载与编译通过MaterialBuilder类实现。该类采用Builder模式,负责解析材质文件、加载Shader代码、编译Shader程序并缓存编译结果。

Shader代码的解析与加载

MaterialBuilder类中,getShaderProgramCode方法负责从材质文件中提取Shader代码。通过解析Shaders数组,我们可以获取顶点着色器和片段着色器的源代码路径,并将其加载到内存中。

std::map<QOpenGLShader::ShaderTypeBit, QString> MaterialBuilder::getShaderProgramCode(const QJsonValue& shadersValue){ static std::map<QString, QOpenGLShader::ShaderTypeBit> shaderTypeMap = { { \"Vertex\", QOpenGLShader::Vertex }, { \"Fragment\", QOpenGLShader::Fragment } }; std::map<QOpenGLShader::ShaderTypeBit, QString> shaderProgramCode; for (const QJsonValue& shaderValue : shadersValue.toArray()) { const QJsonObject& shaderObject = shaderValue.toObject(); QOpenGLShader::ShaderTypeBit shaderType = shaderTypeMap[shaderObject[\"ShaderEnum\"].toString()]; QString sourcePath = QHutu::applicationDirPath(shaderObject[\"SourceFile\"].toString()); shaderProgramCode.insert(std::pair<QOpenGLShader::ShaderTypeBit, QString>(shaderType, QHutu::readTextFile(sourcePath))); } return shaderProgramCode;}

Shader程序的编译与链接

createShaderProgram方法中,我们通过QOpenGLShaderProgram类编译和链接Shader程序。具体步骤如下:

  1. 创建顶点着色器和片段着色器对象。
  2. 加载并编译Shader源代码。
  3. 将编译后的Shader添加到Shader程序中。
  4. 链接Shader程序并验证其有效性。
QOpenGLShaderProgram* MaterialBuilder::createShaderProgram(const QString& key){ std::map<QString, QOpenGLShaderProgram*>::iterator iter = m_shaderPrograms.find(key); if (iter != m_shaderPrograms.end()) { return iter->second; } std::map<QString, std::map<QOpenGLShader::ShaderTypeBit, QString>>::iterator iterator = m_shaderProgramCodes.find(key); if (iterator == m_shaderProgramCodes.end()) { return nullptr; } QOpenGLShaderProgram* shaderProgram = new QOpenGLShaderProgram(); std::map<QOpenGLShader::ShaderTypeBit, QString> shaderProgramCode = iterator->second; for (std::pair<QOpenGLShader::ShaderTypeBit, QString> shaderCode : shaderProgramCode) { QOpenGLShader* shader = new QOpenGLShader(shaderCode.first); shader->compileSourceCode(shaderCode.second); shaderProgram->addShader(shader); } bool result = shaderProgram->link() && shaderProgram->bind(); if (result) { m_shaderPrograms.insert(std::pair<QString, QOpenGLShaderProgram*>(key, shaderProgram)); } else { return nullptr; } return shaderProgram;}

通过这种方式,我们可以动态地创建和管理多个Shader程序。这一部分的实现参考了深入理解OpenGL Shader与GLSL:基础知识与优势分析。

3. 材质的创建与使用

Material类中,我们封装了材质的OpenGL状态管理功能。通过createOpenGLState方法,我们可以为当前材质创建OpenGL状态(如绑定Shader程序)。通过useMaterial方法,我们可以绑定当前材质并进行渲染。

void Material::createOpenGLState(IScreen* screen){ m_shaderProgram = MaterialBuilder::materialBuilder()->createShaderProgram(m_key);}bool Material::useMaterial(){ if (m_shaderProgram == nullptr) { return false; } m_shaderProgram->bind(); return true;}

三、绘制四边形的实现

在Horse3D中,绘制四边形的过程可以分为以下几个步骤:

1. 初始化材质与几何体

FerghanaScreen类的构造函数中,我们创建了材质和四边形对象:

Material* material;Quadrangle* quadrangle;FerghanaScreen::FerghanaScreen(QWidget* parent) : IScreen(parent){ quadrangle = new Quadrangle(); material = createMaterial(\"Materials/Test/Test.material\");}

2. 创建OpenGL状态

initializeGL方法中,我们初始化OpenGL环境,并为材质和几何体创建OpenGL状态:

void FerghanaScreen::initializeGL(){ initializeOpenGLFunctions(); glClearColor(0.2f, 0.3f, 0.3f, 1.0f); quadrangle->createOpenGLState(this); material->createOpenGLState(this);}

3. 渲染四边形

paintGL方法中,我们绑定材质并绘制四边形:

void FerghanaScreen::paintGL(){ glClear(GL_COLOR_BUFFER_BIT); material->useMaterial(); quadrangle->useGeometry(this); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);}

这一部分的实现参考了之前的开发笔记在QtOpenGL环境下,仿three.js的BufferGeometry管理VAO和EBO绘制四边形。


四、结果与分析

通过上述实现,我们可以在QtOpenGL环境下成功绘制带有自定义Shader效果的四边形。以下是本次实现的关键点总结:

  1. 材质管理系统的实现:通过Material类和MaterialBuilder类,我们实现了材质的动态加载与管理,支持Shader程序的编译与缓存。
  2. Shader程序的动态加载:通过解析JSON格式的材质文件,我们实现了Shader程序的动态加载与编译,支持灵活的Shader配置。
  3. 四边形的绘制:通过结合材质系统和几何体管理模块,我们实现了带有自定义Shader效果的四边形的绘制。

五、项目介绍

Horse渲染内核基于Qt与OpenGL开发,是一款三维引擎。本项目将不提供编辑器,以SDK的形式对外提供接口。本项目将参考Three.js与Unity等众多渲染引擎的API设计,致力于开发出一款具有竞争力的渲染引擎内核。

地址:

  • Gitee
  • GitHub

六、总结与展望

在本次开发中,我们成功实现了Horse3D引擎的材质管理系统,并通过该系统绘制了带有自定义Shader效果的四边形。这为后续的三维模型渲染奠定了基础。

未来,我们计划在以下方面进一步完善材质管理系统:

  1. 支持更多的Shader类型:如几何着色器、曲面细分着色器等。
  2. 优化Shader程序的缓存机制:通过更高效的缓存策略减少Shader编译的开销。
  3. 支持更多的材质属性:如光照模型、反射模型等。

通过不断优化和扩展,我们希望将Horse3D引擎打造成为一款具有竞争力的三维渲染引擎内核。


七、参考文献

  1. 深入理解OpenGL Shader与GLSL:基础知识与优势分析
    https://blog.csdn.net/2503_92624912/article/details/150076191

  2. Unity与OpenGL中的材质系统详解
    https://blog.csdn.net/2503_92624912/article/details/150432587

  3. Three.js 材质系统深度解析
    https://blog.csdn.net/2503_92624912/article/details/150448417

  4. 应用Builder模式在C++中进行复杂对象构建
    https://blog.csdn.net/2503_92624912/article/details/149831961

  5. Horse3D游戏引擎研发笔记(一):从使用Qt的OpenGL库绘制三角形开始
    https://blog.csdn.net/2503_92624912/article/details/150006641

  6. Horse3D游戏引擎研发笔记(二):基于QtOpenGL使用仿Three.js的BufferAttribute结构重构三角形绘制
    https://blog.csdn.net/2503_92624912/article/details/150063706

  7. Horse3D游戏引擎研发笔记(三):使用QtOpenGL的Shader编程绘制彩色三角形
    https://blog.csdn.net/2503_92624912/article/details/150114327

  8. Horse3D游戏引擎研发笔记(四):在QtOpenGL下仿three.js,封装EBO绘制四边形
    https://blog.csdn.net/2503_92624912/article/details/150235885

  9. Horse3D游戏引擎研发笔记(五):在QtOpenGL环境下,仿three.js的BufferGeometry管理VAO和EBO绘制四边形
    https://blog.csdn.net/2503_92624912/article/details/150400945

Horse3D游戏引擎研发笔记(七):在QtOpenGL环境下,使用改进的Uniform变量管理方式绘制多彩四边形 (相较于Unity、Unreal Engine与Godot引擎)

Pomian语言处理器 研发笔记(一):使用C++的正则表达式构建词法分析器