first commit
This commit is contained in:
3
docs/mcguide/16-美术/7-材质与着色器/README.md
Normal file
3
docs/mcguide/16-美术/7-材质与着色器/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 前言
|
||||
|
||||
本教程将向大家讲解游戏中常见的一些对象是使用什么材质进行渲染,该材质中又是声明了哪个shader;在不同的shader中,我们能够使用哪些uniform常量;另外也将详细介绍材质的配置方式。
|
||||
170
docs/mcguide/16-美术/7-材质与着色器/Shader使用简介.md
Normal file
170
docs/mcguide/16-美术/7-材质与着色器/Shader使用简介.md
Normal file
@@ -0,0 +1,170 @@
|
||||
---
|
||||
front: https://nie.res.netease.com/r/pic/20220408/3541655a-7205-4609-b118-be8d6dbb84bd.png
|
||||
hard: 入门
|
||||
time: 15分钟
|
||||
selection: true
|
||||
---
|
||||
|
||||
# Shader使用简介
|
||||
|
||||
## 前言
|
||||
|
||||
本文将介绍MC游戏中使用的Shader的基本编写与使用方式
|
||||
|
||||
## 定义
|
||||
|
||||
游戏中的对象使用什么Shader定义于材质文件中,例如以下材质定义:
|
||||
```json
|
||||
{
|
||||
"materials": {
|
||||
"version": "1.0.0",
|
||||
|
||||
"terrain_base": {
|
||||
"vertexShader": "shaders/renderchunk.vertex",
|
||||
"vrGeometryShader": "shaders/renderchunk.geometry",
|
||||
"fragmentShader": "shaders/renderchunk.fragment",
|
||||
|
||||
...(省略无关代码)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
在移动端,我们只需要关注 vertexShader 与 fragmentShader:
|
||||
```json
|
||||
vertexShader: 顶点着色器,后缀名不做要求,通常命名为vertex
|
||||
fragmentShader: 像素着色器,后缀名不做要求,通常命名为fragment
|
||||
```
|
||||
|
||||
## 语法
|
||||
|
||||
MC中的Shader使用Opengl语言进行编写。因为Opengl具有不个版本,越高级的版本能使用的特性越多,但兼容的设备就越少。为了让shader在不同版本中都生效,建议若使用一些高版本Opengl特性的时候加上如下判断,并提供一份针对低版本的实现:
|
||||
```opengl
|
||||
#if __VERSION__ >= 300
|
||||
_centroid varying vec4 uv; //关键字_centroid表示使用质心采样,是3.0才支持的语法,上面300表示OpenGL 3.0,若为310,则代表OpenGL 3.1版本。
|
||||
#else
|
||||
varying vec4 uv;
|
||||
#endif
|
||||
```
|
||||
本教程不涉及opengl的基础教程,开发者可自行学习。
|
||||
|
||||
## 材质中的宏
|
||||
|
||||
材质defines字段中定义的值在shader中可以进行使用
|
||||
```json
|
||||
"terrain_blend_far:terrain_blend": {
|
||||
"+defines": [ "FOG" ]
|
||||
}
|
||||
```
|
||||
这里定义了FOG字段,则在Shader中可以用ifdef或者ifndef进行判断并执行一些逻辑处理:
|
||||
```opengl
|
||||
#ifndef FOG
|
||||
color.rgb += FOG_COLOR.rgb * 0.000001;
|
||||
#endif
|
||||
```
|
||||
宏的使用不像传统shader中的if else语句,宏是编译器的,运行时不会产生分支语句,所以不会对性能有额外影响。
|
||||
|
||||
## 头文件
|
||||
|
||||
为了代码的复用性,我们通常会把多个shader都可能用到的代码抽取出来,此时只要把他们声明为以.h结尾的头文件,放在shaders/glsl目录下, 例如uniformWorldConstants.h。则在其它shader中要使用这个文件中的代码,只需要调用include即可
|
||||
```opengl
|
||||
#include "uniformWorldConstants.h"
|
||||
```
|
||||
|
||||

|
||||
|
||||
## Uniform
|
||||
|
||||
在shader中除了使用顶点属性以外,引擎还会通过uniform变量向shader中传递很多有用的数据,大部份shader都依赖一些uniform变量进行计算。引擎中的uniform变量定义在各个.h头文件中,下面将对常用的头文件及其中的uniform变量进行说明。
|
||||
|
||||
### uniformWorldConstants.h
|
||||
|
||||
生效时机:在渲染场景对象的shader中可以使用,里面包含当前场景相机对应的变换矩阵
|
||||
```opengl
|
||||
MAT4 WORLDVIEWPROJ : mvp矩阵乘积,用于把模型空间的坐标转化为裁剪空间坐标
|
||||
MAT4 WORLD : 世界矩阵,用于把模型空间的坐标转化为世界坐标
|
||||
MAT4 WORLDVIEW : mv矩阵乘积,用于把模型空间的坐标转化为视口空间的坐标
|
||||
MAT4 PROJ : 投影矩阵,用于把视口空间的坐标转化为裁剪空间坐标
|
||||
```
|
||||
|
||||
### uniformPerFrameConstants.h
|
||||
|
||||
生效时机:每帧更新,所有shader中都可以使用
|
||||
```opengl
|
||||
vec3 VIEW_POS : 相机位置
|
||||
float TIME : 游戏启动到现在经过的时间,可以用于做一些动画,为了避免无限增长带来较大浮点误差,会取模210,处理数值边界的时候需要注意
|
||||
vec4 FOG_COLOR : 雾的颜色
|
||||
vec2 FOG_CONTROL : 雾生效的距离,FOG_CONTROL.x为最短距离,FOG_CONTROL.y为最远距离
|
||||
float RENDER_DISTANCE : 可渲染的最远距离
|
||||
```
|
||||
|
||||
### uniformRenderChunkConstants.h
|
||||
|
||||
生效时机:渲染地形
|
||||
```opengl
|
||||
POS4 CHUNK_ORIGIN_AND_SCALE : 基于玩家视角的Chunk的局部位置
|
||||
POS4 CHUNK_WORLD_POS_MOD_VALUE : 基于世界坐标的Chunk的世界位置,但由于MC地图很大,所以这里数值会取模128
|
||||
float RENDER_CHUNK_FOG_ALPHA : Chunk雾效的透明度
|
||||
```
|
||||
|
||||
### uniformShaderConstants.h
|
||||
|
||||
生效时机:所有shader中都可以使用
|
||||
```opengl
|
||||
vec4 CURRENT_COLOR : 受群系等因素影响,场景中渲染的对象会对应的明亮两种颜色,这个为明亮的颜色。其它系统也可能复用此值作一些颜色传递
|
||||
vec4 DARKEN : 受群系等因素影响,场景中渲染的对象会对应的明亮两种颜色,这个为暗的颜色。其它系统也可能复用此值作一些颜色传递
|
||||
vec3 TEXTURE_DIMENSIONS :当前渲染使用的第一张贴图的尺寸,常为图集贴图,x,y,z分别为宽,高,当前所处在mipmap的哪一级。常用于做抗锯齿处理
|
||||
float HUD_OPACITY : 一些ui渲染的透明度会变化,使用此值进行控制
|
||||
```
|
||||
|
||||
### uniformWeatherConstants.h
|
||||
|
||||
生效时机:渲染天气元素的时候生效
|
||||
```opengl
|
||||
vec4 POSITION_OFFSET : 当前天气渲染用的面片的坐标偏移
|
||||
vec4 VELOCITY : 风速
|
||||
vec4 ALPHA : 存储当前的光照缩放值
|
||||
vec4 VIEW_POSITION : 相对于相机的位置
|
||||
vec4 SIZE_SCALE : 粒子大小的缩放值,粒子会根据投影,速度进行一定缩放
|
||||
vec4 FORWARD :当前视角的前向位置,一般用于把粒子往前放推一点,保证在相机前面
|
||||
vec4 UV_INFO : 渲染时候的贴图的uv
|
||||
vec4 PARTICLE_BOX : 播放粒子的区域大小
|
||||
```
|
||||
|
||||
### util.h
|
||||
|
||||
封装了搞锯齿的采样函数texture2D_AA
|
||||
|
||||
## 兼容性
|
||||
|
||||
### 浮点精度
|
||||
|
||||
不同平台浮点数的精度略有差异,有小数点的话最多只能精确到小数点后三位,比如0.001跟0.002是能区分出来的,但0.0011跟0.0012可能在某些平台会被判断是相等的。
|
||||
|
||||
另外,浮点判断相等也尽量不要用 == 或者 != 符号。比如一些开发者可能判断alpha值不为1的时候做一些操作,会这样写:
|
||||
```opengl
|
||||
if(color.a != 1.0){
|
||||
// do something
|
||||
}
|
||||
```
|
||||
正确的应该这样写:
|
||||
```opengl
|
||||
if(color.a < 0.999){
|
||||
// do something
|
||||
}
|
||||
```
|
||||
同理,判断不为0的话也不应该这样写:
|
||||
```opengl
|
||||
if(color.a != 0.0){
|
||||
// do something
|
||||
}
|
||||
```
|
||||
正确的应该这样写:
|
||||
```opengl
|
||||
if(color.a > 0.001){
|
||||
// do something
|
||||
}
|
||||
```
|
||||
|
||||
### 纹理采样
|
||||
|
||||
在shader中使用texture2D对纹理采样进行采样应该只写在片段着色器中,因为IOS平台不支持在顶点着色器中进行纹理采样。
|
||||
BIN
docs/mcguide/16-美术/7-材质与着色器/images/entity_static.png
Normal file
BIN
docs/mcguide/16-美术/7-材质与着色器/images/entity_static.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
BIN
docs/mcguide/16-美术/7-材质与着色器/images/fancy_switch.png
Normal file
BIN
docs/mcguide/16-美术/7-材质与着色器/images/fancy_switch.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/mcguide/16-美术/7-材质与着色器/images/material_head.png
Normal file
BIN
docs/mcguide/16-美术/7-材质与着色器/images/material_head.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.6 KiB |
BIN
docs/mcguide/16-美术/7-材质与着色器/images/material_list.png
Normal file
BIN
docs/mcguide/16-美术/7-材质与着色器/images/material_list.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.6 KiB |
BIN
docs/mcguide/16-美术/7-材质与着色器/images/shader_headfiles.png
Normal file
BIN
docs/mcguide/16-美术/7-材质与着色器/images/shader_headfiles.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
273
docs/mcguide/16-美术/7-材质与着色器/材质的分类.md
Normal file
273
docs/mcguide/16-美术/7-材质与着色器/材质的分类.md
Normal file
@@ -0,0 +1,273 @@
|
||||
---
|
||||
front:
|
||||
hard: 入门
|
||||
time: 分钟
|
||||
---
|
||||
|
||||
# 材质的分类
|
||||
|
||||
## 前言
|
||||
|
||||
本文将介绍MC游戏中常用的材质,若开发者需要修改某些对象的表现效果,则可参考此文修改对应的材质和Shader。
|
||||
以下材质基于data\resource_packs\vanilla\materials目录之下
|
||||
|
||||
## 天空
|
||||
|
||||
### sky.material 材质文件
|
||||
|
||||
#### sun_moon
|
||||
|
||||
太阳和月亮
|
||||
|
||||
#### stars
|
||||
|
||||
星星
|
||||
|
||||
#### cubemap
|
||||
|
||||
用于渲染天空的六个面组成的天空盒
|
||||
|
||||
#### skyplane
|
||||
|
||||
用于渲染上方天空的颜色。游戏里面最上方会放置一个超大圆型网格,平行于地面
|
||||
|
||||
#### end_sky
|
||||
|
||||
用于渲染末地上方天空的颜色与贴图。游戏里面最上方会放置一个超大圆型网格,平行于地面
|
||||
|
||||
### fancy.material 、 sad.material 材质文件
|
||||
|
||||
#### clouds
|
||||
|
||||
云
|
||||
|
||||
## 地形方块(放置在地上的方块)
|
||||
|
||||
### terrain.material 材质文件
|
||||
|
||||
#### terrain_opaque
|
||||
|
||||
不透明地形方块
|
||||
|
||||
##### terrain_far
|
||||
|
||||
不透明地形方块在远处的时候会使用该材质进行渲染
|
||||
|
||||
#### terrain_blend
|
||||
|
||||
半透明地形方块材质,例如水,玻璃等
|
||||
|
||||
##### terrain_blend_far
|
||||
|
||||
半透明方块在远处的时候会使用该材质进行渲染
|
||||
|
||||
#### terrain_alpha
|
||||
|
||||
一些局部有全透明区域,而且正反面都需要渲染的方块材质,引擎中用到的有铁砧,竹子,铁轨,药水,仙人掌,珊瑚,农作物等等。
|
||||
|
||||
##### terrain_alpha_single_side
|
||||
|
||||
一些局部有全透明区域,但开启了背面裁剪只渲染一个面的材质,引擎中用到的有信标,胡萝卜,红石比较器,堆肥箱,门,蘑菇等等。
|
||||
|
||||
#### terrain_doubleside
|
||||
|
||||
目前用于渲染床
|
||||
|
||||
#### terrain_opaque_seasons
|
||||
|
||||
目前用于渲染上面覆盖有雪的不透明树叶
|
||||
|
||||
##### terrain_seasons_far
|
||||
|
||||
目前用于渲染远处上面覆盖有雪的不透明树叶
|
||||
|
||||
#### terrain_alpha_seasons
|
||||
|
||||
目前用于渲染上面覆盖有雪的半透明树叶
|
||||
|
||||
##### terrain_seasons_far_alpha
|
||||
|
||||
目前用于渲染渲染上面覆盖有雪的半透明树叶
|
||||
|
||||
### barrier.material 材质文件
|
||||
|
||||
#### barrier
|
||||
|
||||
屏障方块
|
||||
|
||||
### portal.material 材质文件
|
||||
|
||||
#### portal_base
|
||||
|
||||
末地传送门
|
||||
|
||||
## 非地形方块与实体(手持或者独立在场景中的)
|
||||
|
||||
### entity.material 材质文件
|
||||
|
||||
#### entity_static
|
||||
|
||||
静态实体
|
||||
|
||||
#### entity_flat_color_line
|
||||
|
||||
用于渲染钓鱼竿的线
|
||||
|
||||
#### entity_loyalty_rope
|
||||
|
||||
用于渲染拴绳
|
||||
|
||||
#### opaque_block 、 opaque_block_color 、 opaque_block_color_uv2
|
||||
|
||||
不透明方块渲染
|
||||
|
||||
#### alpha_block 、 alpha_block_color
|
||||
|
||||
带透明区域的方块
|
||||
|
||||
#### map
|
||||
|
||||
地图渲染
|
||||
|
||||
#### entity_alphablend 、 entity_alphablend_nocolor
|
||||
|
||||
带透明度混合的实体对象
|
||||
|
||||
#### item_in_hand 、 item_in_hand_multicolor_tint 、 item_in_hand_entity_alphatest_color 、 item_in_hand_glint
|
||||
|
||||
用于各种手持物品的渲染
|
||||
|
||||
#### moving_block 、 moving_block_seasons 、 moving_block_alpha_seasons 、 moving_block_alpha_single_side 、 moving_block_alpha 、 moving_block_double_side 、 moving_block_blend
|
||||
|
||||
用于渲染会动态变化的方块
|
||||
|
||||
### 网易扩展 entity.material 材质文件内容
|
||||
|
||||
文件位于data、resource_packs、vanilla_netease、materials目录下,主要是添加了骨骼模型渲染用的材质
|
||||
|
||||
#### 带有vip字眼的资源
|
||||
|
||||
通常为会员材质中使用到的资源,一般效果较好,Shader实现较复杂,可供学习参考
|
||||
|
||||
#### entity_for_skeleton 、 entity_for_skeleton_cpu
|
||||
|
||||
用于渲染普通的不透明骨骼模型
|
||||
|
||||
#### entity_for_skeleton_hide_cpu 、 entity_for_skeleton_hide
|
||||
|
||||
用于表现实体隐藏状态,效果是渲染纯色的半透明模型
|
||||
|
||||
#### entity_for_skeleton_alpha_cpu 、 entity_for_skeleton_alpha
|
||||
|
||||
用于渲染带透明度的骨骼模型
|
||||
|
||||
#### entity_for_skeleton_bright 、 entity_for_skeleton_bloom 、 entity_for_skeleton_glint、 entity_for_skeleton_bloom_glint
|
||||
|
||||
某些骨骼模型会使用到各种特殊效果,例如高光,辉光,扫光效果。
|
||||
|
||||
#### entity_for_skeleton_frame_ani
|
||||
|
||||
用于实现骨骼模型序列帧动画
|
||||
|
||||
## 粒子
|
||||
|
||||
### particles.material 材质文件
|
||||
|
||||
#### particles_opaque
|
||||
|
||||
引擎原生的不透明粒子
|
||||
|
||||
#### particles_alpha
|
||||
|
||||
引擎原生的开启了透明度裁剪的粒子
|
||||
|
||||
#### particles_blend
|
||||
|
||||
引擎原生的带透明度的粒子
|
||||
|
||||
#### particles_effects
|
||||
|
||||
引擎原生带有特效UV变动效果的开启了透明度裁剪的粒子
|
||||
|
||||
#### common_particle、common_particle_add、common_particle_add_texture、common_particle_blend、common_particle_blend_texture
|
||||
|
||||
网易粒子系统,自定义粒子特效基本都是使用这些,功能与上述原生粒子相对应。
|
||||
|
||||
## 阴影
|
||||
|
||||
### shadows.material 材质文件
|
||||
|
||||
阴影的渲染使用了Stencil蒙版技术
|
||||
|
||||
#### shadow_front 、 shadow_back
|
||||
|
||||
在蒙板标记阴影的位置,未进行实际渲染
|
||||
|
||||
### shadow_overlay
|
||||
|
||||
对蒙板中被标记的位置进行真正的渲染
|
||||
|
||||
## UI
|
||||
|
||||
### ui3D.material 材质文件
|
||||
|
||||
包含场景中对象相关的一些特殊UI,或者天气相关UI的材质
|
||||
|
||||
#### selection_XXX
|
||||
|
||||
带有selection字眼的基本上都是选中方块或者实体后这个选中效果的渲染
|
||||
|
||||
#### selection_box
|
||||
|
||||
开启轮廓选择后指向某个对象会显示线框
|
||||
|
||||
#### name_tag、name_tag_depth_tested
|
||||
|
||||
实体头顶名字背景
|
||||
|
||||
#### sign_text、name_text_depth_tested
|
||||
|
||||
实体头顶名字文字
|
||||
|
||||
#### rain
|
||||
|
||||
雨
|
||||
|
||||
#### snow
|
||||
|
||||
雪
|
||||
|
||||
#### lightning
|
||||
|
||||
闪电
|
||||
|
||||
### ui.material 材质文件
|
||||
|
||||
UI界面上使用的UI材质
|
||||
|
||||
由于很多UI会使用相同的材质,每个材质可能会在多处进行使用,这里不一一列举每一处地方,这里只举例几个常见UI界面对象使用到的材质
|
||||
|
||||
#### 物品快捷栏
|
||||
|
||||
ui_textured_and_glcolor
|
||||
|
||||
#### 摇杆,上方的菜单按钮,右上方的移动,潜行,飞行等按钮,右下角的跳跃按钮
|
||||
|
||||
ui_texture_and_color
|
||||
|
||||
#### 背包或物品快捷栏中的物品图标
|
||||
|
||||
ui_item
|
||||
|
||||
#### 屏幕中心的十字光标
|
||||
|
||||
ui_crosshair
|
||||
|
||||
#### 加载场景的背景图
|
||||
|
||||
ui_cubemap
|
||||
|
||||
#### UI上的文字
|
||||
|
||||
ui_text
|
||||
|
||||
558
docs/mcguide/16-美术/7-材质与着色器/材质配置说明.md
Normal file
558
docs/mcguide/16-美术/7-材质与着色器/材质配置说明.md
Normal file
@@ -0,0 +1,558 @@
|
||||
---
|
||||
front:
|
||||
hard: 入门
|
||||
time: 分钟
|
||||
---
|
||||
|
||||
# 材质配置说明
|
||||
|
||||
## 前言
|
||||
|
||||
本文将详细介绍材质文件的结构与配置方式。
|
||||
|
||||
## 加载的材质文件列表
|
||||
|
||||
材质文件存放于资源包的materials文件夹下,我们打开resource_packs\vanilla\materials目录,可看到包含有下面这些文件,这些是原生微软定义的材质文件:
|
||||
|
||||

|
||||
|
||||
而resource_packs\vanilla_netease\materials目录下的材质文件,则是网易对微软材质文件的修改与扩充。
|
||||
|
||||
下面我们就先以原生微软的材质文件进行讲解,首先,目录下面的文件基本都是以".material"为后缀的文件,除此之外,还有3个重要的json文件,分别是common.json,fancy.json,sad.json。
|
||||
|
||||
我们先来看看sad.json和fancy.json,他们是用于控制画质表现的,内部各自定义了一个材质文件列表,fancy.json通常比sad.json会多定义几个材质文件和可能会为某些材质文件多添加了一些额外的宏,shader中可通过对这些宏的判断做特殊的处理:
|
||||
|
||||
sad.json:
|
||||
```json
|
||||
[
|
||||
{"path":"materials/sad.material"},
|
||||
{"path":"materials/entity.material"},
|
||||
{"path":"materials/terrain.material"},
|
||||
{"path":"materials/portal.material"},
|
||||
{"path":"materials/barrier.material"},
|
||||
{"path":"materials/wireframe.material"}
|
||||
]
|
||||
```
|
||||
|
||||
fancy.json:
|
||||
```json
|
||||
[
|
||||
{"path":"materials/fancy.material", "+defines":["FANCY"]},
|
||||
{"path":"materials/entity.material", "+defines":["FANCY"]},
|
||||
{"path":"materials/terrain.material", "+defines":["FANCY"]},
|
||||
{"path":"materials/hologram.material"},
|
||||
{"path":"materials/portal.material", "+defines":["FANCY"]},
|
||||
{"path":"materials/barrier.material"},
|
||||
{"path":"materials/wireframe.material"}
|
||||
]
|
||||
```
|
||||
可见fancy.json比sad.json多定义了fancy.material,hologram.material材质文件,另外也为多个材质文件定义了FANCY宏。
|
||||
游戏内 设置/视频/精美贴图 这个开关就是控制sad与fancy的切换。当精美贴图开关打开时,fancy.json中的材质文件就会生效,而关闭时,sad.json的材质文件就会生效:
|
||||
|
||||

|
||||
|
||||
为了实现更好的表现效果,fancy.json中的材质文件通常具有较复杂的运算,而sad.json中的材质则通常以牺牲一点渲染表现去换取更好的性能。
|
||||
开发者若需要编写计算较为复杂shader,则建议同时编写一个低消耗的版本,然后分别把他们定义在fancy与sad内。让玩家在游戏中通过精美贴图选项自行控制是否开启相应效果。
|
||||
|
||||
接下来再看看common.json:
|
||||
```json
|
||||
[
|
||||
{"path":"materials/particles.material"},
|
||||
{"path":"materials/shadows.material"},
|
||||
{"path":"materials/sky.material"},
|
||||
{"path":"materials/ui.material"},
|
||||
{"path":"materials/ui3D.material"},
|
||||
{"path":"materials/portal.material"},
|
||||
{"path":"materials/barrier.material"},
|
||||
{"path":"materials/wireframe.material"}
|
||||
]
|
||||
```
|
||||
|
||||
相比于sad与fancy可互相切换。common.json中定义的材质文件进入游戏后都将被加载。除了在common.json, sad.json, fancy.json中声明的材质文件,其余的材质文件并不会被加载。
|
||||
|
||||
## 材质语法
|
||||
|
||||
我们使用其中一个材质文件entity.material来进行讲解,打开文件,我们可以看到文件是以materials开头,然后定义了版本号version为1.0.0,这些都是固定格式,标识了这个材质文件的解析方式,我们可以暂时不理会不修改:
|
||||
|
||||

|
||||
|
||||
接下来讲解材质中字段的格式,我们用entity.material中定义的第一个材质来看:
|
||||
|
||||

|
||||
|
||||
可以看到材质里面每一个字段的定义都是键值对的形式,例如:
|
||||
```json
|
||||
[
|
||||
"vertexShader": "shaders/entity.vertex",
|
||||
]
|
||||
```
|
||||
冒号左边代表键为vertexShader,右边代表值为shaders/entity.vertex;
|
||||
|
||||
另外还有列表形式的定义:
|
||||
```json
|
||||
[
|
||||
"vertexFields": [
|
||||
{ "field": "Position" },
|
||||
{ "field": "Normal" },
|
||||
{ "field": "UV0" }
|
||||
],
|
||||
]
|
||||
```
|
||||
用符号[ ]声明是列表,然后里面是每个子元素的json定义。
|
||||
|
||||
## 材质所有的属性字段概况
|
||||
|
||||
我们把所有字段按功能分到以下几类中:
|
||||
|
||||
### 渲染状态
|
||||
|
||||
#### states
|
||||
|
||||
配置渲染环境,可以有以下的值:
|
||||
```json
|
||||
EnableAlphaToCoverage :半透明对象顺序无关渲染方式的一种,支持MSAA的环境下这个开关才有用,开启后物体边缘会根据透明度作更精确的柔和和过渡,也可用于有大量网格交错重叠的一些复杂场景。
|
||||
Wireframe : 绘制线框模式
|
||||
Blending : 开启颜色混合模式,常用于渲染半透明对象。声明这个之后通常也需要声明混合因子blendSrc,blendDst
|
||||
|
||||
DisableColorWrite : 不往颜色缓冲区写入颜色值,RGBA通道均不写入
|
||||
DisableAlphaWrite : 不往颜色缓冲区写入透明度alpha值,允许写入RGB值
|
||||
DisableRGBWrite : 不往颜色缓冲区写入透明度RGB值,允许写入Alpha值
|
||||
|
||||
DisableDepthTest : 关闭深度测试
|
||||
DisableDepthWrite : 关闭深度写入
|
||||
|
||||
DisableCulling : 同时渲染正面和反面
|
||||
InvertCulling :使用正面裁剪。默认情况下为背面裁剪,声明这个之后则渲染背面,裁剪掉正面
|
||||
|
||||
StencilWrite :开启蒙版写入
|
||||
EnableStencilTest : 开启蒙版测试
|
||||
```
|
||||
|
||||
### 着色器路径
|
||||
|
||||
#### vertexShader
|
||||
|
||||
顶点着色器的路径,通常为shaders/XXX.vertex。
|
||||
|
||||
#### vrGeometryShader 或 geometryShader
|
||||
|
||||
几何着色器的路径,通常为shaders/XXX.geometry,移动端用不到,无须考虑修改。
|
||||
|
||||
#### fragmentShader
|
||||
|
||||
片段着色器的路径,通常为shaders/XXX.fragment。
|
||||
|
||||
### Shader宏定义
|
||||
|
||||
#### defines
|
||||
|
||||
为使用到的Shader定义宏。为了代码的复用,我们很多不同的材质会使用相同的shader。此时若想shader里面某处根据当前材质执行不一样的逻辑,则可以通过材质defines声明的宏去做判断。
|
||||
我们可以用下面entity_for_skeleton这个材质做说明,这里可以看出定义了USE_SKINNING,USE_OVERLAY,NETEASE_SKINNING三个宏。
|
||||
```json
|
||||
"entity_for_skeleton": {
|
||||
"vertexShader": "shaders/entity.vertex",
|
||||
"vrGeometryShader": "shaders/entity.geometry",
|
||||
"fragmentShader": "shaders/entity.fragment",
|
||||
"+defines": [ "USE_SKINNING", "USE_OVERLAY", "NETEASE_SKINNING" ],
|
||||
"vertexFields": [
|
||||
{ "field": "Position" },
|
||||
{ "field": "Normal" },
|
||||
{ "field": "BoneId0" },
|
||||
{ "field": "UV0" }
|
||||
],
|
||||
"msaaSupport": "Both",
|
||||
"+samplerStates": [
|
||||
{
|
||||
"samplerIndex": 0,
|
||||
"textureFilter": "Point"
|
||||
}
|
||||
]
|
||||
},
|
||||
```
|
||||
|
||||
再看顶点着色器entity.vertex中会有通过#ifdef,#else,#endif来对宏进行判断并执行不同的逻辑分支,宏的这些判断语句是编译期处理的,不像传统shader中的if else,编译期处理的在实际运行中不会产生逻辑分支,性能不会因分支而下降。另外,下面可以看出宏也可以做多层的判断,先判断NETEASE_SKINNING宏,在内部执行逻辑中又有LARGE_VERTEX_SHADER_UNIFORMS宏的判断:
|
||||
```json
|
||||
#ifdef NETEASE_SKINNING
|
||||
MAT4 boneMat = transpose(mat3x4ToMat4(BONES_70[int(BONEID_0)]));
|
||||
entitySpacePosition = boneMat * POSITION;
|
||||
entitySpaceNormal = boneMat * NORMAL;
|
||||
#else
|
||||
#if defined(LARGE_VERTEX_SHADER_UNIFORMS)
|
||||
entitySpacePosition = BONES[int(BONEID_0)] * POSITION;
|
||||
entitySpaceNormal = BONES[int(BONEID_0)] * NORMAL;
|
||||
#else
|
||||
entitySpacePosition = BONE * POSITION;
|
||||
entitySpaceNormal = BONE * NORMAL;
|
||||
#endif
|
||||
#endif
|
||||
```
|
||||
|
||||
### 运行时状态
|
||||
|
||||
#### depth 深度测试
|
||||
|
||||
##### depthFunc
|
||||
|
||||
深度检测通过函数,可以使用以下的值:
|
||||
```json
|
||||
Always : 总是通过
|
||||
Equal : 深度值与缓冲区值相等时通过
|
||||
NotEqual :深度值与缓冲区值不相等时通过
|
||||
Less :深度值小于缓冲区值时通过
|
||||
Greater :深度值大于缓冲区值时通过
|
||||
GreaterEqual :深度值大于等于缓冲区值时通过
|
||||
LessEqual :深度值小于等于缓冲区值时通过
|
||||
```
|
||||
|
||||
相关联的states渲染环境配置:
|
||||
```json
|
||||
DisableDepthTest : 关闭深度测试
|
||||
DisableDepthWrite : 关闭深度写入
|
||||
```
|
||||
|
||||
#### Stencil 蒙版测试
|
||||
|
||||
##### stencilRef
|
||||
与蒙版缓冲区比较或要被写入的值
|
||||
|
||||
##### stencilRefOverride
|
||||
是否使用缓冲区当前的值作为stencilRef,支持0或1:
|
||||
```json
|
||||
1 : 使用配置的stencilRef,若配置了stencilRef则stencilRefOverride自动取1
|
||||
0 : 使用缓冲区当前的值作为stencilRef,此情况下不配置stencilRef
|
||||
```
|
||||
|
||||
##### stencilReadMask
|
||||
蒙版缓冲区的值与stencilRef值在比较前均会先与stencilReadMask进行位与运算
|
||||
|
||||
##### stencilWriteMask
|
||||
stencilRef值在写入蒙版缓冲区前会与stencilWriteMask进行位与运算
|
||||
|
||||
##### frontFace, backFace
|
||||
配置网格正面或反面使用什么蒙版测试函数,另外,判断的顺序为先蒙版检测,再深度检测,需要配置以下操作:
|
||||
```json
|
||||
stencilFunc : stencilRef与蒙版缓冲区比较时使用的方法,支持下面的值:
|
||||
Always : 总是通过
|
||||
Equal : stencilRef与缓冲区值相等时通过
|
||||
NotEqual :stencilRef与缓冲区值不相等时通过
|
||||
Less :stencilRef小于缓冲区值时通过
|
||||
Greater :stencilRef大于缓冲区值时通过
|
||||
GreaterEqual :stencilRef大于等于缓冲区值时通过
|
||||
LessEqual :stencilRef小于等于缓冲区值时通过
|
||||
|
||||
stencilFailOp :stencilFunc比较函数返回失败的时候执行的处理,支持下面的值:
|
||||
Keep : 保留缓冲区原本数值
|
||||
Replace : 往缓冲区写入 stencilRef位与stencilWriteMask 的值
|
||||
|
||||
stencilDepthFailOp : stencilFunc比较函数返回成功, 但深度测试失败的时候执行的处理,支持下面的值:
|
||||
Keep : 保留缓冲区原本数值
|
||||
Replace : 往缓冲区写入 stencilRef位与stencilWriteMask 的值
|
||||
|
||||
stencilPassOp : stencilFunc比较函数返回成功,而且深度测试成功的时候执行的处理,支持下面的值:
|
||||
Keep : 保留缓冲区原本数值
|
||||
Replace : 往缓冲区写入 stencilRef位与stencilWriteMask 的值
|
||||
```
|
||||
|
||||
相关联的states渲染环境配置:
|
||||
```json
|
||||
StencilWrite :开启蒙版写入
|
||||
EnableStencilTest : 开启蒙版测试
|
||||
```
|
||||
|
||||
最后我们看一段例子:
|
||||
```json
|
||||
"shadow_back": {
|
||||
"+states": [
|
||||
"StencilWrite",
|
||||
"DisableColorWrite",
|
||||
"DisableDepthWrite",
|
||||
"InvertCulling",
|
||||
"EnableStencilTest"
|
||||
],
|
||||
|
||||
"vertexShader": "shaders/position.vertex",
|
||||
"vrGeometryShader": "shaders/position.geometry",
|
||||
"fragmentShader": "shaders/flat_white.fragment",
|
||||
|
||||
"frontFace": {
|
||||
"stencilFunc": "Always",
|
||||
"stencilFailOp": "Keep",
|
||||
"stencilDepthFailOp": "Keep",
|
||||
"stencilPassOp": "Replace"
|
||||
},
|
||||
|
||||
"backFace": {
|
||||
"stencilFunc": "Always",
|
||||
"stencilFailOp": "Keep",
|
||||
"stencilDepthFailOp": "Keep",
|
||||
"stencilPassOp": "Replace"
|
||||
},
|
||||
|
||||
"stencilRef": 1,
|
||||
"stencilReadMask": 255,
|
||||
"stencilWriteMask": 1,
|
||||
|
||||
"vertexFields": [
|
||||
{ "field": "Position" }
|
||||
],
|
||||
"msaaSupport": "Both"
|
||||
}
|
||||
```
|
||||
例子中 StencilWrite 代表支持蒙版缓冲区的写入,EnableStencilTest代表开启蒙版测试,frontFace的配置代表正面渲染的时候蒙版测试总是通过,深度测试不通过则保持缓冲区值不变,若深度测试也通过则会往缓冲区写入 stencil位与stencilWriteMask 的值,即 1 & 1 = 1值。backFace的配置也是类似。
|
||||
|
||||
#### Blend 半透明对象颜色混合
|
||||
|
||||
半透明对象的渲染需要配置混合因子,最终输出的rgb颜色值 = 当前颜色值 * 源混合因子 + 缓冲区中的颜色值 * 目标混合因子
|
||||
|
||||
##### blendSrc
|
||||
源混合因子
|
||||
|
||||
##### blendDst
|
||||
目标混合因子
|
||||
|
||||
##### alphaSrc
|
||||
计算alpha时的源混合因子,通常不配置取默认值
|
||||
|
||||
##### alphaDst
|
||||
计算alpha时的目标混合因子,通常不配置取默认值
|
||||
|
||||
---
|
||||
|
||||
混合因子总共可以取下面的值:
|
||||
```json
|
||||
DestColor : 缓冲区颜色值
|
||||
SourceColor : 当前颜色值
|
||||
Zero : (0,0,0)
|
||||
One : (1,1,1)
|
||||
OneMinusDestColor : (1,1,1) - 缓冲区颜色值
|
||||
OneMinusSrcColor : (1,1,1) - 当前颜色值
|
||||
SourceAlpha : 当前颜色中的alpha值
|
||||
DestAlpha : 缓冲区颜色中的alpha值
|
||||
OneMinusSrcAlpha : 1 - 当前颜色值中的alpha值
|
||||
```
|
||||
|
||||
在引擎中,默认值为:
|
||||
```json
|
||||
blendSrc :SourceAlpha
|
||||
blendDst :OneMinusSrcAlpha
|
||||
alphaSrc :One
|
||||
alphaDst :OneMinusSrcAlpha
|
||||
```
|
||||
|
||||
相关联的states渲染环境配置:
|
||||
```json
|
||||
Blending : 开启颜色混合模式,常用于渲染半透明对象。声明这个之后通常也需要声明混合因子blendSrc,blendDst
|
||||
DisableColorWrite : 不往颜色缓冲区写入颜色值,RGBA通道均不写入
|
||||
DisableAlphaWrite : 不往颜色缓冲区写入透明度alpha值,允许写入RGB值
|
||||
DisableRGBWrite : 不往颜色缓冲区写入透明度RGB值,允许写入Alpha值
|
||||
```
|
||||
|
||||
#### sample 纹理采样
|
||||
|
||||
##### samplerStates
|
||||
配置采样状态,值为一个列表,根据需要采样的纹理个数为每一个纹理进行配置,通常若顶点属性中声明了UV0, UV1,代表需要采样两个纹理,这里则需要配置两个元素。下面看子元素的定义:
|
||||
```json
|
||||
{
|
||||
"samplerIndex": 0,
|
||||
"textureFilter": "Point",
|
||||
"textureWrap": "Repeat"
|
||||
}
|
||||
```
|
||||
|
||||
每个属性的定义如下:
|
||||
###### samplerIndex
|
||||
数字,代表当前正在设置第几张纹理的属性,由0开始
|
||||
|
||||
###### textureFilter
|
||||
纹理过滤模式(默认为Point),当实际显示的纹理贴图相比于原图进行了放大或缩小时,新的分辨率贴图与原分辨率贴图上像素点的映射关系,可以有以下的值:
|
||||
```json
|
||||
Point : 点采样
|
||||
Bilinear : 双线性采样
|
||||
Trilinear : 三线性采样
|
||||
MipMapBilinear : MipMap双线性采样
|
||||
TexelAA :纹素抗锯齿(不是所有设备都支持,不建议使用)
|
||||
PCF :通过比较函数进行采样(不是所有设备都支持,不建议使用)
|
||||
```
|
||||
|
||||
###### textureWrap
|
||||
纹理包裹模式,控制uv若在[0,1]之外的时候应该采样到什么样的纹理,可以有如下的值:
|
||||
```json
|
||||
Repeat : 重复,即把值求模到[0,1]之间进行采样
|
||||
Clamp : 边缘采样,采样最靠近的边缘的值,即1.1比较靠近1,则取1;-0.1比较靠近0,则取0。
|
||||
```
|
||||
|
||||
|
||||
#### vertex 顶点属性
|
||||
|
||||
##### vertexFields
|
||||
顶点属性,用于声明使用这个材质进行渲染的网格每个顶点保存有什么属性,由美术制作资源的时候决定,可能用到的有以下的值:
|
||||
```json
|
||||
Position : 模型空间坐标
|
||||
Color : 颜色
|
||||
Normal : 法线
|
||||
UV0 :纹理采样坐标
|
||||
UV1 :纹理采样坐标
|
||||
UV2 :纹理采样坐标
|
||||
BoneId0 : 骨骼ID,骨骼模型中用到
|
||||
```
|
||||
|
||||
#### rasterizer 光栅化环境配置
|
||||
|
||||
##### msaaSupport
|
||||
配置MSAA(多重采样抗锯齿)的支持(引擎中的默认值为NonMSAA)
|
||||
```json
|
||||
NonMSAA : 在没有开启MSAA的时候材质允许使用
|
||||
MSAA : 在开启MSAA的时候材质允许使用
|
||||
Both :无论是否开启MSAA,材质都允许使用。通常使用这个值就可以了。
|
||||
```
|
||||
|
||||
##### 深度偏移
|
||||
|
||||
深度偏移主要用于解决z-fighting问题,即当两个物体深度相近,则渲染时可能会出现某些帧显示这个物体,某些帧显示另一个物体这种闪烁现象。深度偏移的原理是把其中一个对象往深度大或者小的方向偏移一下,使他们的深度不再一样。
|
||||
可配置以下四个变量:
|
||||
```json
|
||||
depthBias
|
||||
slopeScaledDepthBias
|
||||
depthBiasOGL
|
||||
slopeScaledDepthBiasOGL
|
||||
```
|
||||
|
||||
具体偏移的深度为:
|
||||
```json
|
||||
offset = (slopeScaledDepthBias * m) + (depthBias * r)
|
||||
```
|
||||
在OGL平台上则为:
|
||||
```json
|
||||
offset = (slopeScaledDepthBiasOGL * m) + (depthBiasOGL * r)
|
||||
```
|
||||
|
||||
m是多边形的深度的斜率(在光栅化阶段计算得出)中的最大值。一个多边形越是与近裁剪面平行,m就越接近0。
|
||||
r是能产生在窗口坐标系的深度值中可分辨的差异的最小值,r是由具体实现OpenGL的平台指定的一个常量。
|
||||
|
||||
---
|
||||
相关联的states渲染环境配置:
|
||||
```json
|
||||
Wireframe : 绘制线框模式
|
||||
DisableCulling : 同时渲染正面和反面
|
||||
InvertCulling :使用正面裁剪。默认情况下为背面裁剪,声明这个之后则渲染背面,裁剪掉正面
|
||||
```
|
||||
|
||||
#### primitive 图元
|
||||
|
||||
##### primitiveMode
|
||||
图元渲染模式(引擎中的默认值为TriangleList):
|
||||
```json
|
||||
None : 不渲染,正常情况下不会为这个值
|
||||
QuadList :四边形模式
|
||||
TriangleList : 每三个顶点绘制一个三角形的模式,例如第一个三角形使用顶点v0,v1,v2,第二个使用v3,v4,v5
|
||||
TriangleStrip : 每一个顶点会与前两个出现的顶点构成三角形,结构复杂一点,但会节省数据量
|
||||
LineList : 每两个顶点绘制一条线段
|
||||
Line : 每一个顶点会与前一个出现的一个顶点构成线段。
|
||||
```
|
||||
|
||||
### 材质变体
|
||||
|
||||
#### variants
|
||||
用于快速基于大部分相同定义实现多种子材质。看下面entity_static这个实际例子:
|
||||
```json
|
||||
"entity_static": {
|
||||
"vertexShader": "shaders/entity.vertex",
|
||||
"vrGeometryShader": "shaders/entity.geometry",
|
||||
"fragmentShader": "shaders/entity.fragment",
|
||||
"vertexFields": [
|
||||
{ "field": "Position" },
|
||||
{ "field": "Normal" },
|
||||
{ "field": "UV0" }
|
||||
],
|
||||
"variants": [
|
||||
{
|
||||
"skinning": {
|
||||
"+defines": [ "USE_SKINNING" ],
|
||||
"vertexFields": [
|
||||
{ "field": "Position" },
|
||||
{ "field": "BoneId0" },
|
||||
{ "field": "Normal" },
|
||||
{ "field": "UV0" }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"skinning_color": {
|
||||
"+defines": [ "USE_SKINNING", "USE_OVERLAY" ],
|
||||
"+states": [ "Blending" ],
|
||||
"vertexFields": [
|
||||
{ "field": "Position" },
|
||||
{ "field": "BoneId0" },
|
||||
{ "field": "Color" },
|
||||
{ "field": "Normal" },
|
||||
{ "field": "UV0" }
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"msaaSupport": "Both",
|
||||
"+samplerStates": [
|
||||
{
|
||||
"samplerIndex": 0,
|
||||
"textureFilter": "Point"
|
||||
}
|
||||
]
|
||||
},
|
||||
```
|
||||
variants即为材质变体的声明,上述声明了skinning和skinning_color两个子变体,子变体中对外部某些字段进行了改写。实际使用中,相当于快速定义了两个材质,本体和变体间用点"."连接,两个材质分别为entity_static.skinning和entity_static.skinning_color。
|
||||
|
||||
除此之外,后续如果有其它材质继承自entity_static,比如entity_dynamic,则此材质也会同时继承有此两种变体,分别为entity_dynamic.skinning和entity_dynamic.skinning_color。
|
||||
|
||||
|
||||
## 材质合并规则
|
||||
|
||||
不同目录文件中声明了同一材质时的,在加载后会根据以下规则进行合并:
|
||||
1.通常情况下后加载的文件的材质的字段会覆盖之前加载的
|
||||
2.以下字段特殊,除了替换以外,还支持使用"+"添加与使用"-"删除属性的操作:
|
||||
```json
|
||||
defines
|
||||
states
|
||||
samplerStates
|
||||
```
|
||||
|
||||
举一个的例子,例如包体文件中声明了这么一材质(省略无关代码),定义了三个宏:
|
||||
```json
|
||||
"testMat": {
|
||||
"defines": [ "MACRO_1", "MACRO_2", "MACRO_3" ],
|
||||
}
|
||||
```
|
||||
|
||||
此时,一个Mod也声明了此材质,定义了另外三个宏:
|
||||
```json
|
||||
"testMat": {
|
||||
"defines": [ "MACRO_4", "MACRO_5", "MACRO_6" ],
|
||||
}
|
||||
```
|
||||
上述情况下,最终运行时相当于defines字段被覆盖,实际运行时生效的宏只有: MACRO_4, MACRO_5, MACRO_6
|
||||
|
||||
若MOD中定义的时候使用了"+"符号:
|
||||
```json
|
||||
"testMat": {
|
||||
"+defines": [ "MACRO_4", "MACRO_5", "MACRO_6" ],
|
||||
}
|
||||
```
|
||||
相当于在原来的基础上添加定义,则实际运行时生效的宏有: MACRO_1, MACRO_2, MACRO_3, MACRO_4, MACRO_5, MACRO_6
|
||||
|
||||
若MOD中定义的时候使用了"-"符号:
|
||||
```json
|
||||
"testMat": {
|
||||
"-defines": [ "MACRO_3"],
|
||||
}
|
||||
```
|
||||
相当于在原来的基础上删除某些定义,则实际运行时生效的宏只有: MACRO_1, MACRO_2
|
||||
|
||||
若多个文件都对同一材质进行了定义,而且分别涉及有覆盖,添加,删除操作,则依次生效的顺序为:
|
||||
先执行所有的覆盖操作,再执行所有的添加操作,最后执行所有的删除操作。
|
||||
|
||||
即如果有其中一个材质文件声明删除MACRO_3操作:
|
||||
```json
|
||||
"testMat": {
|
||||
"-defines": [ "MACRO_3"],
|
||||
}
|
||||
```
|
||||
则无论其它文件怎么覆盖,添加MACRO_3,最终合成后这一个材质一定不会有MACRO_3宏。
|
||||
Reference in New Issue
Block a user