Shaders
Note: This documentation is for the old 0.2.0 version of A-Frame. Check out the documentation for the current 1.6.0 version
Shaders (in A-Frame) are responsible for creating the material for the base material component. A-Frame ships with a couple of built-in shading models: standard
and flat
.
We can register custom shaders to implement different visual effects and materials. We have available the materials provided by three.js, including THREE.ShaderMaterial. With THREE.ShaderMaterial, we can provide our own GLSL vertex and fragment shaders (small programs that run on the GPU), and we can define a schema for their uniforms and attributes just as we would with component schemas. The shader’s schema will extend the base material component’s schema, and as a result we can pass values from markup directly to the shader.
Built-in Shading Models
A-Frame ships with a couple of built-in shading models.
Standard Shading Model
The standard shading model is the default shader for the material component. It is a physically-based shading model that uses THREE.MeshStandardMaterial under the hood. The standard shading model can be explicitly specified by setting the shader
to be standard
in the material component (i.e., material="shader: standard"
).
Properties
Property | Description | Default Value |
---|---|---|
color | Base diffuse color. | #fff |
height | Height of video (in pixels), if defining a video texture. | 360 |
envMap | Environment cubemap texture for reflections. Can be a selector to |
None |
fog | Whether or not material is affected by fog. | true |
metalness | How metallic the material is from 0 to 1 . |
0.5 |
repeat | How many times a texture (defined by src ) repeats in the X and Y direction. |
1 1 |
roughness | How rough the material is from 0 to 1 . A rougher material will scatter reflected light in more directions than a smooth material. |
0.5 |
width | Width of video (in pixels), if defining a video texture. | 640 |
src | Image or video texture map. Can either be a selector to an <img> or <video> , or an inline URL. |
None |
Physically-Based Shading
Physically based shading is a recent trend in rendering systems where materials behave realistically to lighting conditions. Appearance is a result of the interaction between the incoming light and the properties of the material.
To achieve realism, the diffuse color
(can be supplied through the base material component), metalness
, roughness
properties of the material must accurately be controlled, often based on real-world material studies. Some people have compiled charts of realistic values for different kinds of materials that can be used as a starting point.
For example, for a tree bark material, as an estimation, we might set:
<a-entity geometry="primitive: cylinder" |
For basic scenes, physically based materials are generally not needed. In that case, we want to specify flat shading for better performance.
Environment Maps
The envMap
property defines what environment the material reflects. This also works together with plain textures. Though unlike regular texture maps, the envMap
property takes a cubemap, six images put together to form a cube. The cubemap is wrapped around the entity and applied as a texture. Note that cubemaps can not yet be defined for regular textures.
If shader is set to standard
, which it is by default, the clarity of the reflection depends on the metalness
, and roughness
properties.
<a-scene> |
Flat Shading Model
Since materials default to physically based shading, materials will factor in light when we might not want them to. To specify flat shading, useful for displaying media like images or videos, we can define the shader
property to be flat
. The flat shading model can be specified by setting the shader
to be flat
in the material component:
<a-entity geometry="primitive: plane" material="src: #cat-image; shader: flat"> |
Properties
Property | Description | Default Value |
---|---|---|
color | Base diffuse color. | #fff |
fog | Whether or not material is affected by fog. | true |
height | Height of video (in pixels), if defining a video texture. | 360 |
repeat | How many times a texture (defined by src ) repeats in the X and Y direction. |
1 1 |
src | Image or video texture map. Can either be a selector to an <img> or <video> , or an inline URL. |
None |
width | Width of video (in pixels), if defining a video texture. | 640 |
Registering a Custom Shader
We register a shader with AFRAME.registerShader
, passing in a schema. We can then either pass vertex and fragment shaders for use with THREE.ShaderMaterial, or we can override the A-Frame shader initialization and pass in our own material.
Schema
Shader schemas are similar to component schemas. The schema will extend the base material component schema. If we are creating a custom shader by passing in vertex and fragment shaders, we can specify uniforms and attributes:
AFRAME.registerShader('hello-world-shader', { |
Shader Uniform and Attribute Types
Type | Description |
---|---|
color | Built-in convenience (vec3) uniform type. Will take colors in multiple formats and automatically convert them to vec3 format (e.g., ‘red’ -> THREE.Vector3(1, 0, 0) ) |
number | Maps to GLSL float . |
time | Built-in convenience (float) uniform type. If specified, the material component will continuously update the shader with the global scene time. |
vec2 | Maps to GLSL vec2 . |
vec3 | Maps to GLSL vec3 . |
vec4 | Maps to GLSL vec4 . |
Standard Component Properties
If we just want to create a custom material THREE.Material, we can define component properties as usual:
AFRAME.registerShader('custom-material', { |
Creating a Custom Shader
Under the hood, custom shaders use THREE.ShaderMaterial. We register a shader with AFRAME.registerShader
while defining a schema, a vertex shader, and a fragment shader:
AFRAME.registerShader('hello-world-shader', { |
To use the shader, we set the material component’s shader
property to the name of a registered shader. Then we pass the define shader uniforms and attributes as properties:
<a-entity geometry="primitive: box" |
Creating a Custom Material
By default, shaders will try to create a THREE.ShaderMaterial. We can override the init
and update
handlers of the shader and setting this.material
to work with our own custom material:
AFRAME.registerShader('line-dashed', { |
Shader API Reference
Like components, shaders have a schema and lifecycle handlers.
Property | Description |
---|---|
schema | Defines properties, uniforms, attributes that the shader will use to extend the material component. |
init | Lifecycle handler called once during shader initialization. Used to create the material. |
update | Lifecycle handler called once during shader initialization and when data is updated. Used to update the material or shader. |