After conducting some research and putting in the work, I have come to the conclusion that utilizing the THREE.ShaderMaterial
is the optimal choice for completing this particular task. Thanks to the availability of
/extras/renderers/plugins/SpritePlugin
, I was able to grasp the concept of shaping and positioning sprites using vertex shaders. Although I still have a few lingering questions, I am content with the solution I have found.
To start off, I created a basic plane geometry:
var geometry = new THREE.PlaneGeometry( 1, 1 );
Which I then utilized in a mesh with a ShaderMaterial
:
uniforms = {
cur_time: {type:"f", value:1.0},
beg_time:{type:"f", value:1.0},
scale:{type: "v3", value:new THREE.Vector3()}
};
var material = new THREE.ShaderMaterial( {
uniforms: uniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
transparent: true,
blending:THREE.AdditiveBlending // Additive blending gives a realistic blast effect!!!
} );
var mesh = new THREE.Mesh( geometry, material );
Below are my shader implementations:
Vertex shader:
varying vec2 vUv;
uniform vec3 scale;
void main() {
vUv = uv;
float rotation = 0.0;
vec3 alignedPosition = vec3(position.x * scale.x, position.y * scale.y, position.z*scale.z);
vec2 pos = alignedPosition.xy;
vec2 rotatedPosition;
rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;
rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;
vec4 finalPosition;
finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );
finalPosition.xy += rotatedPosition;
finalPosition = projectionMatrix * finalPosition;
gl_Position = finalPosition;
}
The vertex shader was adapted from the original Sprite Plugin source code with minor modifications. Interestingly, changing +=
to =
resulted in the sprite sticking to the screen, causing a considerable amount of time to be spent figuring this out.
Followed by the fragment shader:
uniform float cur_time;
uniform float beg_time;
varying vec2 vUv;
void main() {
float full_time = 5000.;
float time_left = cur_time - beg_time;
float expl_step0 = 0.;
float expl_step1 = 0.3;
float expl_max = 1.;
float as0 = 0.;
float as1 = 1.;
float as2 = 0.;
float time_perc = clamp( (time_left / full_time), 0., 1. ) ;
float alphap;
alphap = mix(as0,as1, smoothstep(expl_step0, expl_step1, time_perc));
alphap = mix(alphap,as2, smoothstep(expl_step1, expl_max, time_perc));
// Rest of the shader code...
}
This example showcases a multipoint gradient that is animated based on time. There is certainly room for optimization and enhancements to make it even more visually appealing. However, the current implementation is close to what I had envisioned.
With further fine-tuning and creativity, this project has the potential to be truly captivating.