Legacy Shader 主要函数与结构体
CCVertInput[^1]
为对接骨骼动画与数据解压流程,我们提供了
CCVertInput
工具函数,它有general
和standard
两个版本,内容如下:glsl// 位于 ‘input.chunk’ 的通用顶点着色器输入 #define CCVertInput(position) \ CCDecode(position); \ #if CC_USE_MORPH \ applyMorph(position); \ #endif \ #if CC_USE_SKINNING \ CCSkin(position); \ #endif \ #pragma // 空 ‘pragma’ 技巧,在编译时消除尾随分号 // 位于 ‘input-standard.chunk’ 的标准顶点着色器输入 #define CCVertInput(In) \ CCDecode(In); \ #if CC_USE_MORPH \ applyMorph(In); \ #endif \ #if CC_USE_SKINNING \ CCSkin(In); \ #endif \ #pragma // 空 ‘pragma’ 技巧,在编译时消除尾随分号
如果只需要获取 顶点位置信息,可以使用 general 版本,那么顶点着色器函数开头的代码示例如下:
glsl#include <legacy/input> vec4 vert () { vec3 position; CCVertInput(position); // ... 对位置信息做自定义操作 }
如果还需要法线等信息,可使用
standard
版本,像下面这样写:glsl#include <legacy/input-standard> vec4 vert () { StandardVertInput In; CCVertInput(In); // ... 此时 ‘In.position’ 初始化完毕,并且可以在顶点着色器中使用 }
上面的示例代码中,StandardVertInput
对象 In
会返回模型空间的顶点位置(position
)、法线(normal
)和切空间(tangent
)信息,并对骨骼动画模型做完蒙皮计算。
StandardVertInput
结构体的定义如下:
struct StandardVertInput {
highp vec4 position;
vec3 normal;
vec4 tangent;
};
注意:引用头文件后,不要在 Shader 内重复声明这些 attributes(
a_position
、a_normal
、a_tangent
等)。对于其他顶点数据(如 uv 等)还是需要声明 attributes 后再使用。
如果要对接引擎动态 Mesh 合批和几何体实例化(GPU Instancing),需要包含 cc-local-batch
头文件,通过 CCGetWorldMatrix
工具函数获取世界矩阵,示例如下:
mat4 matWorld;
CCGetWorldMatrix(matWorld);
mat4 matWorld, matWorldIT;
CCGetWorldMatrixFull(matWorld, matWorldIT);
更多细节,请参考 Cocos Shader 内置全局 Uniform。
CCFragOutput
Cocos Shader 提供了 CCFragOutput
工具函数用以简化片元着色器的输出,可用于直接返回片元着色器所需要的值,代码示例如下:
#include <legacy/output>
vec4 frag () {
vec4 o = vec4(0.0);
// ... 编写片元着实代码
return CCFragOutput(o);
}
CCFragOutput
会根据管线状态来决定是否需要做 ToneMap
转码处理,这样中间的颜色计算就不必区分当前渲染管线是否为 HDR 流程。
代码示例如下:
vec4 CCFragOutput (vec4 color) {
#if CC_USE_HDR
color.rgb = ACESToneMap(color.rgb);
#endif
color.rgb = LinearToSRGB(color.rgb);
return color;
}
特别注意:
如果采用 CCFragOutput
作为片元输出,中间的颜色运算必须转到 Linear
空间,因为 CCFragOutput
认为传入的参数是在 Linear
空间的,总是会进行 LinearToSRGB
转码。
CCFragOutput
函数一般不需要自己实现,它只起到与渲染管线对接的作用,且对于这种含有光照计算的输出,因为计算结果已经在 HDR 范围,所以应该包含 output-standard
而非 output
头文件。
如需包含标准的 PBR 光照计算,可使用 StandardSurface
结构体与函数 CCStandardShadingBase
一起构成 PBR 着色流程。
StandardSurface
结构体内容如下:
struct StandardSurface {
// albedo
vec4 albedo;
// these two need to be in the same coordinate system
vec3 position;
vec3 normal;
// emissive
vec3 emissive;
// light map
vec3 lightmap;
float lightmap_test;
// PBR params
float roughness;
float metallic;
float occlusion;
};
代码示例如下:
#include <legacy/shading-standard-base>
#include <legacy/output-standard>
void surf (out StandardSurface s) {
// fill in your data here
}
vec4 frag () {
StandardSurface s; surf(s);
vec4 color = CCStandardShadingBase(s);
return CCFragOutput(color);
}
也可以参考 builtin-standard.effect
中,使用 surf
函数与 CC_STANDARD_SURFACE_ENTRY()
宏组合。
CC_STANDARD_SURFACE_ENTRY()
是一个 wrapper,会根据渲染状态,利用 surf
函数构建出一个可用于片元的 main
函数,代码示例如下:
CCProgram shader-fs %{
#include <legacy/standard-surface-entry>
void surf (out StandardSurface s) {
// fill in your data here
}
CC_STANDARD_SURFACE_ENTRY()
}%
StandardSurface
StandardSurface 为 PBR 材质信息结构体,记录了一个像素需要进行光照计算的表面信息。 Lagecy Shader 中的 surf 函数主要用于填充,它会在光照阶段被使用。
struct StandardSurface {
// albedo
vec4 albedo;
// these two need to be in the same coordinate system
HIGHP_VALUE_STRUCT_DEFINE(vec3, position);
vec3 normal;
// emissive
vec3 emissive;
// light map
vec3 lightmap;
float lightmap_test;
// PBR params
float roughness;
float metallic;
float occlusion;
float specularIntensity;
#if CC_RECEIVE_SHADOW
vec2 shadowBias;
#endif
};
ToonSurface
struct ToonSurface {
vec4 baseColor;
vec4 specular;
// these two need to be in the same coordinate system
HIGHP_VALUE_STRUCT_DEFINE(vec3, position);
vec3 normal;
// shading params
vec3 shade1;
vec3 shade2;
vec3 emissive;
float baseStep;
float baseFeather;
float shadeStep;
float shadeFeather;
float shadowCover;
#if CC_RECEIVE_SHADOW
vec2 shadowBias;
#endif
};
和 StandardSurface 一样,ToonSurface 也是用于记录像素表面信息,只是它是卡通材质专用的结构体。
[^1]: 不包含粒子、Sprite、后期效果等不基于 Mesh 渲染的 Shader。