This translation is community contributed and may not be up to date. We only maintain the English version of the documentation. Read this manual in English
材质用以表达可视元素 (sprite, tilemap, font, GUI node, model 等等) 应该如何被渲染.
材质包含 tags, 用来在渲染过程中作为选择渲染对象的依据. 材质还具有 shader programs 这是通过显卡驱动编译好并上传至显卡每帧渲染时要使用的程序.
要创建材质, 在 Assets 浏览器里目标文件夹上 右键点击 然后选择 New... ▸ Material. (还可以从菜单选择 File ▸ New... , 再选择 Material). 给材质命名并点击 Ok.
新材质会在 材质编辑器 里打开.
材质文件包含以下信息:
render.enable_material()
也是使用这个名称. 此名称不能与其他名称重名.render.predicate()
来收集需要渲染的组件. 如何渲染请见 Render documentation. 每个项目最多可以使用32个标签.Shader 属性 (也叫 vertex streams), 是一个 GPU 从内存获取顶点来渲染几何图形的机制. 顶点着色器使用 attribute
关键字指定一系列流而且多数情况下 Defold 在流名称上自动创建并绑定数据. 然而, 有些情况下你会想传递顶点数据来实现一个引擎没有的特效. 顶点属性有如下配置:
SEMANTIC_TYPE_COLOR
会在编辑器中显示一个颜色拾取器, 同时数据会从引擎原样发送至着色器.
SEMANTIC_TYPE_NONE
默认语义类型. 除了给属性传送材质数据到顶点缓存以外没有其他效果.SEMANTIC_TYPE_POSITION
给属性创建每个顶点位置数据. 可以连同坐标空间一起告诉引擎位置应该如何计算.SEMANTIC_TYPE_TEXCOORD
给属性创建每个顶点的纹理坐标.SEMANTIC_TYPE_PAGE_INDEX
给属性创建每个顶点的页码.SEMANTIC_TYPE_COLOR
决定编辑器如何解释属性. 如果属性被配置为颜色语义, 则会在检视面板上显示一个颜色拾取器.材质系统会在运行时基于特定属性名给属性分配默认语义: position, texcoord0, page_index. 如果材质中有这些名字, 则默认语义类型会覆盖你在材质编辑器的手动配置!
TYPE_BYTE
有符号 8 位值TYPE_UNSIGNED_BYTE
无符号 8 位值TYPE_SHORT
有符号 16 位短值TYPE_UNSIGNED_SHORT
无符号 16 位短值TYPE_INT
有符号整数TYPE_UNSIGNED_INT
无符号整数TYPE_FLOAT
浮点值vec4
有四个元素, 一个 float
有一个元素. 注意: 即使在着色器里制定了属性是一个 vec4
, 你还是能给它指定元素更少的值, 这可以帮助减少内存占用.自定义属性也可以在 CPU 和 GPU 上帮助减少内存占用, 方法是重构流以使用更小的数据类型, 或更少的元素.
与用户自定义着色器常量类似, 你也可以通过调用 go.get, go.set 和 go.animate 在运行时更新顶点属性:
go.set("#sprite", "tint", vmath.vector4(1,0,0,1))
go.animate("#sprite", "tint", go.PLAYBACK_LOOP_PINGPONG, vmath.vector4(1,0,0,1), go.EASING_LINEAR, 2)
更新顶点属性有一些注意事项, 组件是否可以使用该值取决于属性的语义类型. 比如, sprite 组件支持 SEMANTIC_TYPE_POSITION
所以如果你更新有该语义类型的属性, 该组件将忽略覆盖的值, 因为语义类型规定数据应始终由 sprites 位置生成.
目前仅 sprite 组件支持在运行时设置自定义顶点数据.
着色器常量, 或称 “uniforms” 是从引擎传输给顶点和片元着色器程序的数据. 要使用常量,您可以在材质文件中将其定义为一个 顶点常量 属性或 片元常量 属性.需要在着色器程序中定义相应的 uniform
变量.材质中可以设置以下常量:
sprite
, model
, spine
, particlefx
和 tilemap
) 的 .set_constant()
和 .reset_constant()
函数来改变其值. 改变单个组件实例的材质参数会 打破合批增加drawcall.举例:
go.set("#sprite", "tint", vmath.vector4(1,0,0,1))
go.animate("#sprite", "tint", go.PLAYBACK_LOOP_PINGPONG, vmath.vector4(1,0,0,1), go.EASING_LINEAR, 2)
举例:
go.set("#sprite", "m", vmath.matrix4())
sidenote
要使 CONSTANT_TYPE_USER
或 CONSTANT_TYPE_MATRIX4
类型的常量能使用 go.get()
和 go.set()
存取, 在着色器程序中必须使用到该常量. 如果常量在材质中定义了却没在着色器程序中使用, 它将被自动删除无法在运行时使用.
:::
采样器用于从纹理 (瓷砖图源或者图集) 中取得颜色数据. 颜色数据用于在着色器程序中参与计算.
Sprite, tilemap, GUI 和 particle effect 组件自动获得 sampler2D
集. 着色程序里第一个声明的 sampler2D
与可视组件所引用的图片自动绑定. 也就是说这些组件不用特地指定材质文件. 而且目前这些组件只支持一个纹理. (如需在着色器中使用多纹理, 可以使用 render.enable_texture()
在渲染脚本中手动设置采样器.)
-- mysprite.fp
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D MY_SAMPLER;
void main()
{
gl_FragColor = texture2D(MY_SAMPLER, var_texcoord0.xy);
}
在材质文件中添加取样器名就指定了一个采样器. 要是材质文件里没有指定, 会使用项目全局设置里的 graphics 设置.
对于3D模型组件, 还要在材质文件里设置采样器属性. 之后编辑器会让你选择使用该材质的3D模型纹理:
-- mymodel.fp
varying mediump vec2 var_texcoord0;
uniform lowp sampler2D TEXTURE_1;
uniform lowp sampler2D TEXTURE_2;
void main()
{
lowp vec4 color1 = texture2D(TEXTURE_1, var_texcoord0.xy);
lowp vec4 color2 = texture2D(TEXTURE_2, var_texcoord0.xy);
gl_FragColor = color1 * color2;
}
sampler2D
变量名相匹配.WRAP_MODE_REPEAT
[0,1] 范围之外重复纹理.WRAP_MODE_MIRRORED_REPEAT
[0,1] 范围之外重复纹理, 但是再次重复时使用镜像的纹理.WRAP_MODE_CLAMP_TO_EDGE
把大于 1.0 的值设置为 1.0, 小于 0.0 的值设置为 0.0—也就是说边缘的纹理会扩展开去.Default
使用 game.project
文件里 Graphics
下的 Default Texture Min Filter
和 Default Texture Mag Filter
作为默认过滤选项.FILTER_MODE_NEAREST
使用位于像素中心最近的图素.FILTER_MODE_LINEAR
使用位于像素中心最近的的2x2图素矩阵的加权线性平均值.FILTER_MODE_NEAREST_MIPMAP_NEAREST
使用位于单个mipmap上最近的图素值.FILTER_MODE_NEAREST_MIPMAP_LINEAR
在最近的两个mipmap中选出最近的两个图素再进行线性插值.FILTER_MODE_LINEAR_MIPMAP_NEAREST
在单个mipmap里线性插值.FILTER_MODE_LINEAR_MIPMAP_LINEAR
使用线性插值分别计算两个mipmap再把两个结果进行线性插值.渲染管线工作时, 默认会从系统常量缓存中拉取数据. 也可以建立自定义缓存再把着色器参数在渲染脚本里填充进缓存里去:
self.constants = render.constant_buffer() -- <1>
self.constants.tint = vmath.vector4(1, 0, 0, 1) -- <2>
...
render.draw(self.my_pred, {constants = self.constants}) -- <3>
tint
常量为白色注意常量缓存就是一个普通的 Lua 表, 只是不能使用 pairs()
或 ipairs()
来进行迭代.
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB