ShaderMaterial(着色器材质)
ShaderMaterial
使用自定义 shader 渲染的材质。 shader 是一个用 GLSL 编写的小程序 ,在 GPU 上运行。 您可能需要使用自定义 shader,如果你要:
- 要实现内置 materials 之外的效果。
- 将许多对象组合成单个 BufferGeometry 以提高性能。
使用 ShaderMaterial 时需要注意以下注意事项:
- ShaderMaterial 只有使用 WebGLRenderer 才可以绘制正常, 因为 vertexShader 和 fragmentShader 属性中 GLSL 代码必须使用 WebGL 来编译并运行在 GPU 中。
- 从 THREE r72 开始,不再支持在 ShaderMaterial 中直接分配属性。 必须使用 BufferGeometry 实例,使用 BufferAttribute 实例来定义自定义属性。
- 从 THREE r77 开始,WebGLRenderTarget 或 WebGLCubeRenderTarget 实例不再被用作 uniforms。 必须使用它们的 texture 属性。
- 内置 attributes 和 uniforms 与代码一起传递到 shaders。 如果您不希望 WebGLProgram 向 shader 代码添加任何内容,则可以使用 RawShaderMaterial 而不是此类。
- 您可以使用指令#pragma unroll_loop_start,#pragma unroll_loop_end 以便通过 shader 预处理器在 GLSL 中展开 for 循环。 该指令必须放在循环的正上方。循环格式必须与定义的标准相对应。
- 循环必须标准化 normalized。
- 循环变量必须是 i。
顶点着色器和片元着色器
您可以为每种材质指定两种不同类型的 shaders:
- 顶点着色器首先运行; 它接收 attributes, 计算/操纵每个单独顶点的位置,并将其他数据(varyings)传递给片元着色器。
- 片元(或像素)着色器后运行; 它设置渲染到屏幕的每个单独的“片元”(像素)的颜色。
shader 中有三种类型的变量: uniforms, attributes, 和 varyings:
- Uniforms 是所有顶点都具有相同的值的变量。 比如灯光,雾,和阴影贴图就是被储存在 uniforms 中的数据。 uniforms 可以通过顶点着色器和片元着色器来访问。
- Attributes 与每个顶点关联的变量。例如,顶点位置,法线和顶点颜色都是存储在 attributes 中的数据。attributes 只 可以在顶点着色器中访问。
- Varyings 是从顶点着色器传递到片元着色器的变量。对于每一个片元,每一个 varying 的值将是相邻顶点值的平滑插值。
注意:在 shader 内部,uniforms 和 attributes 就像常量;你只能使用 JavaScript 代码通过缓冲区来修改它们的值。
内置 attributes 和 uniforms
WebGLRenderer 默认情况下为 shader 提供了许多 attributes 和 uniforms; 这些变量定义在 shader 程序编译时被自动添加到片元着色器和顶点着色器代码的前面,你不需要自己声明它们。 这些变量的描述请参见 WebGLProgram。
这些 uniforms 或 attributes(例如,那些和照明,雾等相关的)要求属性设置在材质上, 以便 WebGLRenderer 来拷贝合适的值到 GPU 中。 如果你想在自己的 shader 中使用这些功能,请确保设置这些标志。
如果你不希望 WebGLProgram 向你的 shader 代码中添加任何东西, 你可以使用 RawShaderMaterial 而不是这个类。
自定义 attributes 和 uniforms
自定义 attributes 和 uniforms 必须在 GLSL 着色器代码中声明(在 vertexShader 和/或 fragmentShader 中)。 自定义 uniforms 必须定义为 ShaderMaterial 的 uniforms 属性, 而任何自定义 attributes 必须通过 BufferAttribute 实例来定义。 注意 varyings 只需要在 shader 代码中声明(而不必在材质中)。
要声明一个自定义属性,更多细节请参考 BufferGeometry 页面, 以及 BufferAttribute 页面关于 BufferAttribute 接口。
当创建 attributes 时,您创建的用来保存属性数据的每个类型化数组(typed array)必须是您的数据类型大小的倍数。 比如,如果你的属性是一个 THREE.Vector3 类型,并且在你的缓存几何模型 BufferGeometry 中有 3000 个顶点, 那么你的类型化数组的长度必须是 3000 * 3,或者 9000(一个顶点一个值)。每个数据类型的尺寸如下表所示:
GLSL 类型 | JavaScript 类型 | 尺寸 |
---|---|---|
float | Number | 1 |
vec2 | THREE.Vector2 | 2 |
vec3 | THREE.Vector3 | 3 |
vec3 | THREE.Color 3 | 3 |
vec4 | THREE.Vector4 | 4 |
请注意,属性缓冲区 不会 在其值更改时自动刷新。要更新自定义属性, 需要在模型的 BufferAttribute 中设置 needsUpdate 为 true。
要声明一个自定义的 Uniform,使用 uniforms 属性:
uniforms: {
time: { value: 1.0 },
resolution: { value: new THREE.Vector2() }
}
在 Object3D.onBeforeRender 中,建议根据 object 和 camera 来更新自定义 Uniform 的值。 因为 Material 可以被 meshes,Scene 的 matrixWorld 以及 Camera 共享, 会在 WebGLRenderer.render 中更新,并会对拥有私有 cameras 的 scene 的渲染造成影响。
构造器
parameters : Object
parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。 材质的任何属性都可以从此处传入(包括从 Material 继承的任何属性)。
属性
共有属性请参见其基类 Material。
.clipping : Boolean
定义此材质是否支持剪裁; 如果渲染器传递clippingPlanes uniform,则为true。默认值为false。
.defaultAttributeValues : Object
当渲染的几何体不包含这些属性但材质包含这些属性时,这些默认值将传递给shaders。这可以避免在缓冲区数据丢失时出错。
this.defaultAttributeValues = {
'color': [ 1, 1, 1 ],
'uv': [ 0, 0 ],
'uv2': [ 0, 0 ]
};
.defines : Object
使用 #define 指令在GLSL代码为顶点着色器和片段着色器定义自定义常量;每个键/值对产生一行定义语句:
defines: {
FOO: 15,
BAR: true
}
这将在GLSL代码中产生如下定义语句:
#define FOO 15
#define BAR true
.extensions : Object
一个有如下属性的对象:
this.extensions = {
derivatives: false, // set to use derivatives
fragDepth: false, // set to use fragment depth values
drawBuffers: false, // set to use draw buffers
shaderTextureLOD: false // set to use shader texture LOD
};
.fog : Boolean
定义材质颜色是否受全局雾设置的影响; 如果将fog uniforms传递给shader,则为true。默认值为false。
.fragmentShader : String
片元着色器的GLSL代码。这是shader程序的实际代码。在上面的例子中, vertexShader 和 fragmentShader 代码是从DOM(HTML文档)中获取的; 它也可以作为一个字符串直接传递或者通过AJAX加载。
.glslVersion : String
Defines the GLSL version of custom shader code. Only relevant for WebGL 2 in order to define whether to specify GLSL 3.0 or not. Valid values are THREE.GLSL1 or THREE.GLSL3. Default is null.
.index0AttributeName : String
如果设置,则调用gl.bindAttribLocation 将通用顶点索引绑定到属性变量。默认值未定义。
.isShaderMaterial : Boolean
Read-only flag to check if a given object is of type ShaderMaterial.
.lights : Boolean
材质是否受到光照的影响。默认值为 false。如果传递与光照相关的uniform数据到这个材质,则为true。默认是false。
.linewidth : Float
控制线框宽度。默认值为1。
由于OpenGL Core Profile与大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。
.flatShading : Boolean
定义材质是否使用平面着色进行渲染。默认值为false。
.uniforms : Object
如下形式的对象:
{ "uniform1": { value: 1.0 }, "uniform2": { value: 2 } }
指定要传递给shader代码的uniforms;键为uniform的名称,值(value)是如下形式:
{ value: 1.0 }
这里 value 是uniform的值。名称必须匹配 uniform 的name,和GLSL代码中的定义一样。 注意,uniforms逐帧被刷新,所以更新uniform值将立即更新GLSL代码中的相应值。
.uniformsNeedUpdate : Boolean
Can be used to force a uniform update while changing uniforms in Object3D.onBeforeRender(). Default is false.
.vertexColors : Boolean
定义是否使用顶点着色。默认为false。
.vertexShader : String
顶点着色器的GLSL代码。这是shader程序的实际代码。 在上面的例子中,vertexShader 和 fragmentShader 代码是从DOM(HTML文档)中获取的; 它也可以作为一个字符串直接传递或者通过AJAX加载。
.wireframe : Boolean
将几何体渲染为线框(通过GL_LINES而不是GL_TRIANGLES)。默认值为false(即渲染为平面多边形)。
.wireframeLinewidth : Float
控制线框宽度。默认值为1。
由于OpenGL Core Profile与大多数平台上WebGL渲染器的限制,无论如何设置该值,线宽始终为1。
方法
共有方法请参见其基类Material。
.clone () : ShaderMaterial this : ShaderMaterial
创建该材质的一个浅拷贝。需要注意的是,vertexShader和fragmentShader使用引用拷贝; attributes的定义也是如此; 这意味着,克隆的材质将共享相同的编译WebGLProgram; 但是,uniforms 是 值拷贝,这样对不同的材质我们可以有不同的uniforms变量。