Texture splatting with Three.js
Challenge accepted!
First, you can write a vertex shader that takes a grayscale image and uses it as a heightmap, and includes a varying float (called vAmount
below) to pass to the fragment shader to determine the texture(s) to display(blend) at that point.
uniform sampler2D bumpTexture;
uniform float bumpScale;
varying float vAmount;
varying vec2 vUV;
void main()
{
vUV = uv;
vec4 bumpData = texture2D( bumpTexture, uv );
vAmount = bumpData.r; // assuming map is grayscale it doesn't matter if you use r, g, or b.
// move the position along the normal
vec3 newPosition = position + normal * bumpScale * vAmount;
gl_Position = projectionMatrix * modelViewMatrix * vec4( newPosition, 1.0 );
}
Next comes the fragment shader, which can include however many textures you need for different elevations, and there is a great built-in function called smoothstep
that makes smooth transitions much easier to calculate.
An example of code for such a fragment shader:
uniform sampler2D oceanTexture;
uniform sampler2D sandyTexture;
uniform sampler2D grassTexture;
uniform sampler2D rockyTexture;
uniform sampler2D snowyTexture;
varying vec2 vUV;
varying float vAmount;
void main()
{
vec4 water = (smoothstep(0.01, 0.25, vAmount) - smoothstep(0.24, 0.26, vAmount)) * texture2D( oceanTexture, vUV * 10.0 );
vec4 sandy = (smoothstep(0.24, 0.27, vAmount) - smoothstep(0.28, 0.31, vAmount)) * texture2D( sandyTexture, vUV * 10.0 );
vec4 grass = (smoothstep(0.28, 0.32, vAmount) - smoothstep(0.35, 0.40, vAmount)) * texture2D( grassTexture, vUV * 20.0 );
vec4 rocky = (smoothstep(0.30, 0.50, vAmount) - smoothstep(0.40, 0.70, vAmount)) * texture2D( rockyTexture, vUV * 20.0 );
vec4 snowy = (smoothstep(0.50, 0.65, vAmount)) * texture2D( snowyTexture, vUV * 10.0 );
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) + water + sandy + grass + rocky + snowy;
}
Then you can use a THREE.ShaderMaterial
to use this for a given mesh. The above code is implemented at http://stemkoski.github.io/Three.js/Shader-Heightmap-Textures.html and produces a result like this:
Hope this helps you get started. Happy coding!
Setting texture to geometry in Three.js
This really not that hard to understand, let me walk you through the logic.
In your case, you don't want to use a displacement map. So, you need to set up a varying height
on your vertexShader to map your vertices up-coordinates [0,1] to your fragmentShader.
//vertexShader:
varying vec2 vUV;
varying float height;
void main() {
vUV = uv;
float maxPosition = 30.0; // this is an example value.
height = max( 0.0, min(1.0, position.y/maxPosition ) ); // assuming +y is up
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
Now you can access height
from your fragmentShader and use that information to select where you want your transitions to occur.
uniform sampler2D grassTexture;
uniform sampler2D snowTexture;
varying vec2 vUV;
varying float height;
void main(){
vec4 grass = (1.0 - smoothstep( 0.48, 0.52, height)) * texture2D( grassTexture, vUV);
vec4 snow = (smoothstep(0.48, 0.52, height) - 0.0) * texture2D( snowTexture, vUV);
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0) + grass + snow;
}
The link provided uses function smoothstep to make a gradual transition between the textures. We can create transitions using the follow pattern ( a - b ) * textureColor
.
In this case, a
controls when the texture starts to contribute to the fragment color. b
controls when the texture stops contributing.
In other words, your grass texture will have already started contributing at every height, so we map a
to 1.0. It stops contributing around 0.5, so we give b
a smooth fade-out as it approaches that 0.5.
Your snow texture, on the other hand, will only start contributing around 0.5. So, we give a
a smooth fade-in as it approaches 0.5. It will never stop contributing, so we set b
as 0.0.
Hope this clears things up for you.
ThreeJS: First shader attempt - blending two textures
You have run into the following issue:
https://github.com/mrdoob/three.js/issues/8016
Just assign your textures after you have merge the uniforms.
https://jsfiddle.net/r4nmf2wt/1/
three.js R112
three.js: rendering 3d text with custom texture
Here is an example of 3D text with a texture applied:
http://stemkoski.github.io/Three.js/Text3D-Textures.html
Hope it helps!
Related Topics
Word Wrap a Link So It Doesn't Overflow Its Parent Div Width
How to Use Nth-Child for Styling with a Table with Rowspan
How to Stretch a Background Image to Cover The Entire HTML Element
How to Write Content That Screen Readers Will Ignore
Question Mark Characters Display Within Text. Why Is This
Export Stored Procedure Result Set to Excel in Ssms
Emulate Ie7 for Ie8 But Not for Ie9 Using "X-Ua-Compatible"
How to Send Mail with a Subject Using a Mailto Url
How to Display Excel Sheet in HTML Page
Angular2 Without Hash in The Url
How to Change Border Color of Textarea on: Focus
CSS: Display:Block; Vs Display:Table;
HTML Form Redirect After Submit
R Shiny Selectedinput Inside Renderdatatable Cells
How to Implement Responsive Web Design and Its Best Practices