Materials describe how an object responds to illumination by lights. Lights can emit diffuse, ambient, or specular light components (often known as "terms"), and the properties of a material describe how (or whether) an object will reflect those terms.
The most common material properties control the reflection of those three terms, and share their names:
###diffuse
This is the primary color of an object as it would appear in pure white light, in the absence of highlights. By default: diffuse: white
.
lights:
light1:
type: point
position: [1,1,2.4]
ambient: white
diffuse: white
specular: white
stylename:
material:
diffuse: 0.5
ambient: 0
specular: 0
###ambient
This is is the color of the object in the presence of ambient light. By default, the ambient color will be the same as the diffuse
value, unless otherwise specified.
lights:
light1:
type: point
position: [1,1,2.4]
ambient: white
diffuse: white
specular: white
stylename:
material:
emission: 0
ambient: 0.5
diffuse: 0
specular: 0
shininess: 0.2
###specular
In our lighting model, "specular" is the "highlight" color of a material. It can be thought of as the reflection of the light source itself on the surface of an object. The shininess
parameter controls the size of the highlight: larger numbers produce smaller highlights, which makes the object appear shinier.
By default, these are set to specular: 0
and shininess: 0.2
lights:
light1:
type: point
position: [1,1,2.4]
ambient: white
diffuse: white
specular: white
stylename:
material:
diffuse: 0.0
ambient: 0
specular: 0.5
shininess: 2.0
###emission
When an emission
color is set, the object will take on that color independent of any lights, including ambient, as though it is glowing (although it will not illuminate neighboring objects, as it is not a true light source). By default, it is set to emission: 0
.
lights:
light1:
type: point
position: [1,1,2.4]
ambient: 0
diffuse: 0
specular: 0
stylename:
material:
emission: [.9,.9,.9]
ambient: 0
diffuse: 0.0
Material properties can be controlled with pixel-level detail when used with texture maps.
Textures are loaded by setting the texture
parameter to the url of an image:
material:
diffuse:
texture: ./images/grid.jpg
###Mapping
When using a texture, you must specify one of four mapping
modes, which determine the method used to apply the texture to an object. In every case, texture coordinates are applied to the vertices of the geometry, and the image is drawn according to those coordinates.
UV mapping is related to the size and proportions of the geometry. With this method, a bounding box is applied to contiguous surfaces, and texture coordinates are applied to the corners of the bounding box. In the following example, this grid image is applied to each polygon. On larger shapes, the UVs are tiled, resulting in a tiled image.
material:
diffuse:
texture: ./material/grid.jpg
mapping: uv
###mapping: planar
Planar mapping uses only 2D world coordinates. As you can see the pattern is constant across surfaces that face up but is stretched on the sides of geometries.
material:
diffuse:
texture: /material/grid.jpg
mapping: planar
scale: 0.01
###mapping: triplanar
This is similar to planar
, but along all three world-space axes. Where a face does not point directly along one axis, the result will be a blend of more than one axis; thus it is computationally more expensive.
material:
diffuse:
texture: /material/grid.jpg
mapping: triplanar
scale: 0.01
###mapping: spheremap
A "spherical environment map", or "spheremap", is an unusual kind of mapping which is dependent on camera position. It uses a texture to color faces depending on their relative angle to the camera. You can think of a spheremap as a hemisphere over the scene, on which the texture has been painted – each polygon in the scene is colored depending on the part of the texture at which it points.
In this example, all polygons which face straight toward the camera will be given the color at the center of the spheremap's texture: white. All polys which face south will be tinted blue, east green, west red, north yellow, and so on.
material:
diffuse:
texture: /material/sem.jpg
mapping: spheremap
###Other properties
Each texture
can also have the following properties:
-
scale
: use foruv
,planar
andtriplanar
. This scales the value of the texture coordinates. Usually, bigger values result in smaller textures. Can be a single float value, or a two/three dimensional value. By default:scale: [1,1]
-
amount
: is a three dimensional vector or single float number that multiply the value of the texture in order to modulate the amount of brightness of the texture. By default:amount: [1,1,1]
The normal
of a polygon is a three-dimensional vector describing the direction that it is considered to be facing. The direction that a 3D plane is facing may seem obvious, but most 3D engines allow a polygon's apparent direction to be changed without modifying the geometry, which is useful in many situations.
Tangram's polygon model assigns normals to the vertices at the corners of a polygon when the geometry is constructed, and these values are interpolated across the face of the polygon to calculate the normal at any given point. This information is used as part of the diffuse and specular lighting calculations.
The material
implementation allows you to modify these normals with a "normal map" texture
, using the mapping
modes uv
, planar
, or triplanar
. This can produce the illusion of far greater detail than exists in the model itself.
Here is an example of a normal map, produced with a third-party 3D application:
And here is the normal map assigned with the uv
mapping to the building layer:
material:
normal:
texture: /material/rock.jpg
mapping: uv
ambient: 0.8
diffuse: 1
specular: 0
#Composition
Any of these material
properties is magical on its own, but even more sophisticated effects become possible when combining them. You will need to experiment to find the right combination to produce the effect that you want.
This example modifies the normal values of the water layer with a glsl shader
, then applies a spheremap
to it:
material:
ambient: .7
diffuse:
texture: /material/sky.jpg
mapping: spheremap
shaders:
blocks:
global: |
vec3 random3(vec3 c) {
float j = 4096.0*sin(dot(c,vec3(17.0, 59.4, 15.0)));
vec3 r;
r.z = fract(512.0*j);
j *= .125;
r.x = fract(512.0*j);
j *= .125;
r.y = fract(512.0*j);
return r-0.5;
}
const float F3 = 0.3333333;
const float G3 = 0.1666667;
float snoise(vec3 p) {
vec3 s = floor(p + dot(p, vec3(F3)));
vec3 x = p - s + dot(s, vec3(G3));
vec3 e = step(vec3(0.0), x - x.yzx);
vec3 i1 = e*(1.0 - e.zxy);
vec3 i2 = 1.0 - e.zxy*(1.0 - e);
vec3 x1 = x - i1 + G3;
vec3 x2 = x - i2 + 2.0*G3;
vec3 x3 = x - 1.0 + 3.0*G3;
vec4 w, d;
w.x = dot(x, x);
w.y = dot(x1, x1);
w.z = dot(x2, x2);
w.w = dot(x3, x3);
w = max(0.6 - w, 0.0);
d.x = dot(random3(s), x);
d.y = dot(random3(s + i1), x1);
d.z = dot(random3(s + i2), x2);
d.w = dot(random3(s + 1.0), x3);
w *= w;
w *= w;
d *= w;
return dot(d, vec4(52.0));
}
normal: |
normal += snoise(vec3(worldPosition().xy*0.08,u_time*.5))*0.02;