来源:互联网 更新时间:2026-07-21 07:20
想想看,最早的三角形示例里,顶点着色器和片段着色器是直接塞在C++字符串里的。能跑是能跑,但改个颜色或者加个Uniform,就得重新编译整个项目。更别提多个物体共用Shader时的重复编译问题了。
所以,干脆把“材质”抽象成引擎里的一等公民。一个材质文件,同时说清楚三件事:用哪几个着色器阶段、顶点属性怎么布局、默认Uniform值是什么(颜色、标量、向量、矩阵、纹理)。这样一来,美术或策划同学改改JSON和GLSL就好,完全不用碰C++代码,这才是真正的解耦。
.material 文件格式材质文件统一放在 Materials/ 目录下,用JSON来描述。拿三角形材质举个例子:
{"Attributes": [{ "Name": "aPos", "Dimension": 3 },{ "Name": "aTexCoord", "Dimension": 2 }],"Uniforms": [{ "Name": "u_texture", "Type": "Texture2D", "Value": "Triangle.jpeg" }],"Shaders": [{ "ShaderEnum": "Vertex", "SourceFile": "triangle.vert" },{ "ShaderEnum": "Fragment", "SourceFile": "triangle.frag" }]}
对应的片段着色器也很简单,就一个纹理采样:
uniform sampler2D u_texture;void main(){fragColor = texture(u_texture, vTexCoord);}
材质相关的代码,拆到了两个子项目里,依赖方向必须清晰:
flowchart TBsubgraph Dragon["Dragon(渲染层)"]RT[RenderThread]OB[Object3D]BR[Brush]CA[Camera]IS[IScreen]endsubgraph Diligencier["Diligencier(工具层)"]MB[MaterialBuilder]TL[TextureLoader]FK[FileKit]endsubgraph Percheron["Percheron(资源层)"]MA[Material]IU[IUniform]TX[Texture2D]endRT --> OBOB --> MAOB --> BR & CAIS --> MAMB --> MA & FK & TLTL --> TXMA --> IUIU --> TX
Material、Uniform、Texture2D 这些基础资源。.material 文件、编译Shader、加载纹理。这样分层之后,即使以后要替换构建工具链,Percheron 里的资源定义也完全不需要改动。
classDiagramIAsset <|-- MaterialIAsset <|-- ITextureITexture <|-- Texture2DMaterial o-- IUniformMaterial o-- Texture2DIUniform <|-- ColorUniformIUniform <|-- FloatUniformIUniform <|-- IntUniformIUniform <|-- Vector2UniformIUniform <|-- Vector3UniformIUniform <|-- Vector4UniformIUniform <|-- Matrix4x4UniformIUniform <|-- Texture2DUniformTexture2DUniform --> Texture2DMaterialBuilder ..> Material : buildsTextureLoader ..> Texture2D : loadsFileKit ..> MaterialBuilder : reads JSON
Material 是运行时的核心容器:
QOpenGLShaderProgram 指针(由 MaterialBuilder 缓存并复用,材质本身不拥有它)。IUniform 集合和 Texture2D 列表。bind() 负责绑定程序并遍历所有Uniform上传;release() 解绑程序并释放占用的纹理单元。IUniform 只暴露一个 useUniform(program) 接口,具体子类负责把值推到GPU:
ColorUniform、FloatUniform、Vector*Uniform、Matrix4x4Uniform:直接调用 setUniformValue。Texture2DUniform:激活指定纹理单元,绑定 QOpenGLTexture,并把采样器Uniform设为该单元索引。这样一来,Material::bind() 根本不需要知道Uniform的具体类型,统一遍历调用接口即可,扩展性极好。
MaterialBuilder 是个单例,核心职责有三项:
.material JSON;QOpenGLShaderProgram,避免重复编译;Uniforms 段为 Material 填充Uniform和纹理。相对路径统一以 .material 所在目录为基目录来解析,所以材质资源可以整体打包移动,非常方便。
FileKit::readText 负责读取文本文件(JSON、GLSL)。TextureLoader 把 QImage 转成 QOpenGLTexture,并做垂直翻转(mirrored())以匹配OpenGL坐标原点。sequenceDiagramparticipant RT as RenderThreadparticipant MB as MaterialBuilderparticipant FK as FileKitparticipant TL as TextureLoaderparticipant MA as MaterialRT->>MB: initializeMaterial(material)MB->>FK: readText(.material)FK-->>MB: JSONMB->>MB: parseShaderSourcesMB->>FK: readText(.vert / .frag)FK-->>MB: source codeMB->>MB: compileAndLinkMB-->>MA: QOpenGLShaderProgramMB->>MB: parseUniformsMB->>TL: loadTexture2D(image)TL-->>MB: Texture2DMB-->>MA: Uniforms & Textures
flowchart LRA[Object3D::render] --> B[Material::bind]B --> C[program->bind]C --> D[遍历 Uniform
useUniform 上传]D --> E[设置 u_model]E --> F[Camera::apply
u_view / u_projection]F --> G[Brush::drawGeometry]G --> H[Material::release]
渲染线程把材质和几何体组装进 Object3D 后,每帧只需要调用 Object3D::render(camera)。对于镜像地板这种需要动态纹理的Pass,再传入运行时纹理ID,由 Object3D 设置额外的 u_mirrorTexture 并绑定。
GUI线程的 IScreen 也使用材质系统,区别在于它只负责把渲染线程产出的共享纹理画到一个全屏四边形上。
MaterialBuilder 缓存 QOpenGLShaderProgram,多个 Material 共享同一份程序;Material 析构时只删自己的Uniform和纹理,避免重复释放。0, 1, 2...,在demo里够用,但后期肯定需要独立的纹理单元管理器。QImage 原点在左上角,OpenGL纹理原点在左下角,加载时一定要用 image.mirrored() 翻转,否则纹理是倒的。.material JSON 配置加载。Material 统一管理 Shader、Uniform、纹理。MaterialBuilder 提供程序缓存,避免重复编译。Material::bind/release 使用材质。.material 和 .vert/.frag 文件变化,运行时重新编译。Attributes 段的描述真正用起来,由 MaterialBuilder 驱动顶点属性布局。本系列记录 Horse3D 游戏引擎从零开始的研发过程。
职业小知识最新答案10.4
蚂蚁庄园今日课堂答题2026年10月1日
蚂蚁新村今日答案最新2026.9.30
煤提质工这一职业诞生于哪种时代背景 蚂蚁新村今日答案2026.9.24
小鸡答题今天的答案是什么2026年9月20日
蚂蚁庄园小课堂2026年9月20日最新题目答案
2026年9月21日小鸡庄园答案
蚂蚁新村今日答案9.22
蚂蚁庄园答案2026年9月23日
有鸟有鸟群纸鸢因风假势童子牵描写的是什么场景 蚂蚁新村今日答案2026.9.29
2026年9月30日蚂蚁新村答案
以下哪一项是海水的主要运动形式
蚂蚁庄园小课堂今日最新答案2026年9月21日
小鸡庄园今天答案2026.9.23
跨经度最广的大洋是
蚂蚁庄园小鸡答题今日答案2026年9月30日
蚂蚁庄园今日课堂答题2026年9月30日
蚂蚁新村今日答案最新2026.9.29
同样是极地地区,为什么南极有数千米厚的冰雪而北极没有
蚂蚁庄园小鸡答题今日答案2026年9月16日
手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc