爱站seo工具包官网,模板建站源码,宁波企业自助建站,什么是4c品牌建设模型大家好#xff01;我是 [数擎AI]#xff0c;一位热爱探索新技术的前端开发者#xff0c;在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情#xff0c;欢迎关注我的文章#xff0c;我们一起成长、进步#xff01; 开发领域#xff1a;前端开发 | AI… 大家好我是 [数擎AI]一位热爱探索新技术的前端开发者在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情欢迎关注我的文章我们一起成长、进步 开发领域前端开发 | AI 应用 | Web3D | 元宇宙 技术栈JavaScript、React、ThreeJs、WebGL、Go 经验经验6 年 前端开发经验专注于图形渲染和 AI 技术 开源项目AI简历、元宇宙、数字孪生 源码地址 https://github.com/dezhizhang/shadertoy 演示地址 https://shader.shuqin.cc/xx3fdh
在本文中我们将深入探讨如何使用 Three.js 和 GLSLOpenGL Shading Language编写一个火焰效果的着色器。通过这个教程你将学习如何创建动态的火焰效果以及如何将它应用到 3D 渲染中。
着色器简介
着色器是图形渲染管线中的一个重要组成部分负责处理图形渲染过程中每个像素的颜色计算。通常着色器分为两个主要部分
顶点着色器Vertex Shader用于处理每个顶点的位置和属性。片段着色器Fragment Shader用于计算每个像素的颜色和纹理。
在这个示例中我们将重点关注如何编写片段着色器来模拟火焰的视觉效果。
火焰着色器的结构
我们的火焰着色器由以下几个部分组成
Uniforms这部分包含了着色器所需的外部变量如时间、分辨率等。顶点着色器负责传递 UV 坐标给片段着色器。片段着色器执行火焰效果的核心计算包括噪声生成、分形布朗运动FBM等。
以下是整个着色器的代码实现
const flameShader {uniforms: {time: { value: 0 },resolution: { value: new THREE.Vector2() }},vertexShader: varying vec2 vUv;void main() {vUv uv;gl_Position projectionMatrix * modelViewMatrix * vec4(position, 1.0);},fragmentShader: precision highp float;#define NUM_OCTAVES 5varying vec2 vUv;uniform float time;uniform vec2 resolution;// 生成随机数float rand(vec2 n) {return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);}// 生成噪声float noise(vec2 p) {vec2 ip floor(p);vec2 u fract(p);u u * u * (3.0 - 2.0 * u);float res mix(mix(rand(ip), rand(ip vec2(1.0, 0.0)), u.x),mix(rand(ip vec2(0.0, 1.0)), rand(ip vec2(1.0, 1.0)), u.x),u.y);return res * res;}// 分形布朗运动float fbm(vec2 x) {float v 0.0;float a 0.5;vec2 shift vec2(100);mat2 rot mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.5));for (int i 0; i NUM_OCTAVES; i) {v a * noise(x);x rot * x * 2.0 shift;a * 0.5;}return v;}void main() {vec2 shake vec2(sin(time * 1.5) * 0.01, cos(time * 2.7) * 0.01);vec2 fragCoord vUv * resolution;vec2 p ((fragCoord shake * resolution) - resolution * 0.5) / resolution.y;p * mat2(8.0, -6.0, 6.0, 8.0);vec2 v;vec4 o vec4(0.0);float f 3.0 fbm(p vec2(time * 7.0, 0.0));for (float i 0.0; i 50.0; i) {v p cos(i * i (time p.x * 0.1) * 0.03 i * vec2(11.0, 9.0)) * 5.0 vec2(sin(time * 4.0 i) * 0.005, cos(time * 4.5 - i) * 0.005);float tailNoise fbm(v vec2(time, i)) * (1.0 - (i / 50.0));vec4 currentContribution (cos(sin(i) * vec4(1.0, 2.0, 3.0, 1.0)) 1.0)* exp(sin(i * i time)) / length(max(v, vec2(v.x * f * 0.02, v.y)));float thinnessFactor smoothstep(0.0, 1.0, i / 50.0);o currentContribution * (1.0 tailNoise * 2.0) * thinnessFactor;}o tanh(pow(o / 1e2, vec4(1.5)));gl_FragColor o;}
};着色器解析
1. 顶点着色器
顶点着色器的任务非常简单它将 UV 坐标传递给片段着色器并根据模型视图矩阵和投影矩阵计算每个顶点的位置。
void main() {vUv uv;gl_Position projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}2. 片段着色器
随机数生成与噪声我们通过 rand 函数生成一个伪随机数结合 noise 函数生成了基础的噪声用于创建火焰的动态效果。
分形布朗运动FBM使用多个频率和振幅的噪声叠加生成复杂的纹理和动态效果这使得火焰的效果更加自然。
动态效果通过 time 控制火焰的变化使用不同的参数让火焰不断变化模拟出自然的火焰流动。
3. 渲染火焰效果
通过循环并叠加每一层的噪声和贡献我们可以模拟火焰的扩散和衰退。使用 exp 和 tanh 函数对输出进行平滑处理使得最终的火焰效果看起来更加柔和自然。
如何使用该着色器 创建一个材质 使用 THREE.ShaderMaterial 创建一个自定义材质将上述着色器代码传递给它。 设置 time 和 resolution time 是一个动态变化的值用来驱动火焰的动画效果。resolution 则表示画布的尺寸影响渲染的比例。 应用到对象上 创建一个平面或其他几何体并将自定义的火焰材质应用到该几何体上。
const material new THREE.ShaderMaterial({uniforms: flameShader.uniforms,vertexShader: flameShader.vertexShader,fragmentShader: flameShader.fragmentShader
});完整代码
import * as THREE from three;// 使用示例
const camera new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
const scene new THREE.Scene();const renderer new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);document.body.appendChild(renderer.domElement);const flameShader {uniforms: {time: { value: 0 },resolution: { value: new THREE.Vector2() }},vertexShader: varying vec2 vUv;void main() {vUv uv;gl_Position projectionMatrix * modelViewMatrix * vec4(position, 1.0);},fragmentShader: precision highp float;#define NUM_OCTAVES 5varying vec2 vUv;uniform float time;uniform vec2 resolution;float rand(vec2 n) { return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);}float noise(vec2 p) {vec2 ip floor(p);vec2 u fract(p);u u*u*(3.0-2.0*u);float res mix(mix(rand(ip), rand(ipvec2(1.0,0.0)), u.x),mix(rand(ipvec2(0.0,1.0)), rand(ipvec2(1.0,1.0)), u.x), u.y);return res*res;}float fbm(vec2 x) {float v 0.0;float a 0.5;vec2 shift vec2(100);mat2 rot mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.50));for (int i 0; i NUM_OCTAVES; i) {v a * noise(x);x rot * x * 2.0 shift;a * 0.5;}return v;}void main() {vec2 shake vec2(sin(time * 1.5) * 0.01, cos(time * 2.7) * 0.01);vec2 fragCoord vUv * resolution;vec2 p ((fragCoord shake * resolution) - resolution * 0.5) / resolution.y;p * mat2(8.0, -6.0, 6.0, 8.0);vec2 v;vec4 o vec4(0.0);float f 3.0 fbm(p vec2(time * 7.0, 0.0));for(float i 0.0; i 50.0; i) {v p cos(i*i (time p.x*0.1)*0.03 i*vec2(11.0,9.0)) *5.0 vec2(sin(time*4.0 i)*0.005, cos(time*4.5 - i)*0.005);float tailNoise fbm(v vec2(time, i)) * (1.0 - (i/50.0));vec4 currentContribution (cos(sin(i)*vec4(1.0,2.0,3.0,1.0)) 1.0) * exp(sin(i*i time)) / length(max(v, vec2(v.x*f*0.02, v.y)));float thinnessFactor smoothstep(0.0, 1.0, i/50.0);o currentContribution * (1.0 tailNoise*2.0) * thinnessFactor;}o tanh(pow(o/1e2, vec4(1.5)));gl_FragColor o;}
};const mesh new THREE.Mesh(new THREE.PlaneGeometry(2, 2),new THREE.ShaderMaterial({...flameShader,blending: THREE.AdditiveBlending,transparent: true})
);scene.add(mesh);function animate() {mesh.material.uniforms.time.value performance.now() / 1000;mesh.material.uniforms.resolution.value.set(window.innerWidth, window.innerHeight);requestAnimationFrame(animate);renderer.render(scene, camera);
}animate();
总结
通过本文的介绍你可以了解如何使用 Three.js 和 GLSL 创建一个动态的火焰效果。这个效果是基于噪声和分形布朗运动的模拟了自然界火焰的动态变化。你可以根据自己的需要调整参数进一步优化火焰效果。
如果你也对shader和AI感兴趣欢迎关注我们公众号数擎Ai