Three.js Wind Turbine IoT Visualization with Shaders, Animations, and Bloom Effects
This article demonstrates how to build a Three.js‑based wind turbine IoT visualization system, covering the tech stack, shader creation, clipping and tween animations, material handling, custom Bézier curves, gear animations, and bloom lighting effects, with full source code examples.
The article describes a Three.js project that visualizes a wind turbine IoT system, showcasing various shader effects, animations, and rendering techniques.
Technology stack : three.js 0.165.0, Vite 4.3.2, Node.js v18.19.0.
Shader creation includes a vertex shader and a fragment shader that generate a dynamic bubble effect. The source code is kept intact:
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
} varying vec2 vUv;
uniform vec2 u_center;
void main() {
vec3 bubbleColor = vec3(0.9, 0.9, 0.9);
vec2 center = u_center;
float distanceToCenter = distance(vUv, center);
float alpha = smoothstep(0.1, 0.0, distanceToCenter);
gl_FragColor = vec4(bubbleColor, alpha);
}A THREE.ShaderMaterial is created with these shaders and a uniform u_center that is animated each frame:
export const bubbleMaterial = new THREE.ShaderMaterial({
vertexShader: vertexShader,
fragmentShader: fragmentShader,
transparent: true,
depthTest: true,
depthWrite: false,
uniforms: {
u_center: { value: new THREE.Vector2(0.3, 0.3) }
},
});
// Update center position each frame
let t = performance.now() * 0.001;
bubbleMaterial.uniforms.u_center.value.x = Math.sin(t) * 0.5 + 0.5;
bubbleMaterial.uniforms.u_center.value.y = Math.cos(t) * 0.5 + 0.5;Clipping animation uses THREE.Plane and tweens the constant value to reveal the model:
const wind = windGltf.scene;
const boxInfo = wind.userData.box3Info;
const max = boxInfo.worldPosition.z + boxInfo.max.z;
const min = boxInfo.worldPosition.z + boxInfo.min.z;
let tween = new TWEEN.Tween({ d: min - 0.2 })
.to({ d: max + 0.1 }, 2000)
.start()
.onUpdate(({ d }) => {
clippingPlane.constant = d;
});When rendering transparent gear parts, depthWrite is set to true and renderOrder is adjusted (e.g., -1 ) to keep transparent and opaque objects independent.
Custom Bézier curve animation is implemented with a CubicBezier class that interpolates a value t from 0 to 1:
export class CubicBezier {
private p0: { x: number; };
private p1: { x: number; };
private p2: { x: number; };
private p3: { x: number; };
constructor(p0: { x: number; }, p1: { x: number; }, p2: { x: number; }, p3: { x: number; }) {
this.p0 = p0;
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
}
get(t: number): { x: number; } {
const mt = 1 - t;
const mt2 = mt * mt;
const mt3 = mt2 * mt;
const t2 = t * t;
const t3 = t2 * t;
const x = mt3 * this.p0.x + 3 * mt2 * t * this.p1.x + 3 * mt * t2 * this.p2.x + t3 * this.p3.x;
return { x };
}
}The curve is used in a tween’s easing callback to control the animation speed of objects such as edgeLineGroup.scale .
Gear animation is handled by a HandleAnimation helper:
motorAnimation = new HandleAnimation(motorGltf.scene, motorGltf.animations);
motorAnimation.play('Take 001');
motorAnimation && motorAnimation.upDate();Gear expansion uses TransformControls to move the model after tweening.
Bloom (unreal) lighting is set up with RenderPass , UnrealBloomPass , and EffectComposer . Default parameters are:
const createParams = {
threshold: 0,
strength: 0.972,
radius: 0.21,
exposure: 1.55
};
const { finalComposer: F, bloomComposer: B, renderScene: R, bloomPass: BP } = unreal(scene, camera, renderer, width, height, createParams);During rendering, objects marked with object.userData.isLight = true are rendered with bloom, while others are darkened and later restored.
The article concludes with links to the full source code and a note that more utilities will be packaged into a library.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.