Made another update
-
patches
array renamed toplugins
- Added addPlugin, removePlugin and hasPlugin to material prototypes
- Ensures plugins/callbacks aren’t assigned multiple times
- A frame callback can be defined, called once per frame, like in the following example to update a global time variable
- If a
requires
array with plugins/callbacks is defined, it will add these and make sure the they added only once. This is usefull for shared ones like in this example, separating the noise code.
Notes:
- If you use post-processing or otherwise call renderer.render() more than once per frame set
THREE.MaterialCallback.auto = false;
and callTHREE.MaterialCallback.frame();
whenever your actual loop starts.
Here is an example for a grass waving in wind plugin
It also doesn’t require you to modify the normals in advance. This is just a simple example, you could make it much more advanced, such as using some kind of global wind map, define a mass property per object for how much it gets influenced etc.
https://codepen.io/Fyrestar/pen/PMyZpR
Used the fiddle from Backface Directional Lighting as template.
The plugin:
const GrassPlugin = {
time: 0,
frame: function() {
this.time += 0.025;
},
render: function( object, uniforms, context ) {
context.set( uniforms.uTime, this.time );
context.set( uniforms.uSize, object.waveLength );
},
compile: function( shader ) {
shader.uniforms.uSize = {
value: 0
};
shader.uniforms.uTime = {
value: 0
};
shader.fragmentShader = shader.fragmentShader.replace(
'#include <normal_fragment_begin>',
'vec3 normal = normalize( vNormal );'
);
shader.vertexShader = shader.vertexShader.replace('#include <common>', `
#include <common>
#ifndef uTime
uniform float uTime;
#endif
uniform float uSize;
float rand(float n){return fract(sin(n) * 43758.5453123);}
float noise(float p){
float fl = floor(p);
float fc = fract(p);
return mix(rand(fl), rand(fl + 1.0), fc);
}
float noise(vec2 n) {
const vec2 d = vec2(0.0, 1.0);
vec2 b = floor(n), f = smoothstep(vec2(0.0), vec2(1.0), fract(n));
return mix(mix(rand(b), rand(b + d.yx), f.x), mix(rand(b + d.xy), rand(b + d.yy), f.x), f.y);
}
`);
shader.vertexShader = shader.vertexShader.replace('#include <beginnormal_vertex>', `
#include <beginnormal_vertex>
objectNormal = vec3(0.0, 1.0, 0.0);
`);
shader.vertexShader = shader.vertexShader.replace('#include <project_vertex>', `
vec4 GRASS_world = modelMatrix * vec4( transformed, 1.0 );
transformed.xz += uv.y * ( noise(GRASS_world.xz + uTime ) * uSize );
#include <project_vertex>
`);
}
};