three火焰
引入着色器
import vertex from './fireA.vert?raw'
import fragment from './fireA.frag?raw'
const fireTex = new THREE.TextureLoader().load("/public/mo-Image/fire/Fire copy.png");
let fireAState = reactive({
fireScale: 2,
magnitude: 1,
lacunarity: 2.0,
gain: 1.0,
})
const fireShader = {
defines: {
ITERATIONS: '20',
OCTIVES: '3'
},
uniforms: {
fireScale: { type: 'f', value: fireAState.fireScale },
offsetPositin: { type: 'f', value: [0, 0, 0] },
fireTex: { type: 't', value: fireTex },
color: { type: 'c', value: new THREE.Color(0x0ff) },
time: { type: 'f', value: 0.0 },
seed: { type: 'f', value: Math.random() * 19.19 },
invModelMatrix: { type: 'm4', value: new THREE.Matrix4() },
scale: { type: 'v3', value: new THREE.Vector3(1, 1, 1) },
noiseScale: { type: 'v4', value: new THREE.Vector4(1, 2, 1, 0.3) },
magnitude: { type: 'f', value: fireAState.magnitude },
lacunarity: { type: 'f', value: fireAState.lacunarity },
gain: { type: 'f', value: fireAState.gain }
},
/* 1、着色器 */
/*
vertexShader: vertex, // 顶点着色器
fragmentShader:fragment, // 片元着色器
*/
/* 2、着色器 */
vertexShader: [
"varying vec3 vWorldPos;",
"uniform float fireScale;",
"uniform vec3 offsetPositin;",
"varying vec3 vUnCameraPosition;",
"void main() {",
"gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);",
"vWorldPos = (modelMatrix * vec4(position, 1.0)).xyz;",
"vUnCameraPosition=cameraPosition-offsetPositin;",
"vWorldPos.x=vWorldPos.x-offsetPositin.x;",
"vWorldPos.y=vWorldPos.y-offsetPositin.y-.46*fireScale;",
"vWorldPos.z=vWorldPos.z-offsetPositin.z;",
"vWorldPos=vWorldPos/fireScale;",
"}"
].join("\n"),
fragmentShader: [
"uniform vec3 color;",
"uniform float time;",
"uniform float seed;",
"uniform mat4 invModelMatrix;",
"uniform vec3 scale;",
"uniform vec4 noiseScale;",
"uniform float magnitude;",
"uniform float lacunarity;",
"uniform float gain;",
"uniform sampler2D fireTex;",
"varying vec3 vWorldPos;",
// GLSL simplex noise function by ashima / https://github.com/ashima/webgl-noise/blob/master/src/noise3D.glsl
// -------- simplex noise
"vec3 mod289(vec3 x) {",
"return x - floor(x * (1.0 / 289.0)) * 289.0;",
"}",
"vec4 mod289(vec4 x) {",
"return x - floor(x * (1.0 / 289.0)) * 289.0;",
"}",
"vec4 permute(vec4 x) {",
"return mod289(((x * 34.0) + 1.0) * x);",
"}",
"vec4 taylorInvSqrt(vec4 r) {",
"return 1.79284291400159 - 0.85373472095314 * r;",
"}",
"float snoise(vec3 v) {",
"const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);",
"const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);",
// First corner
"vec3 i = floor(v + dot(v, C.yyy));",
"vec3 x0 = v - i + dot(i, C.xxx);",
// Other corners
"vec3 g = step(x0.yzx, x0.xyz);",
"vec3 l = 1.0 - g;",
"vec3 i1 = min(g.xyz, l.zxy);",
"vec3 i2 = max(g.xyz, l.zxy);",
// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
"vec3 x1 = x0 - i1 + C.xxx;",
"vec3 x2 = x0 - i2 + C.yyy;", // 2.0*C.x = 1/3 = C.y
"vec3 x3 = x0 - D.yyy;", // -1.0+3.0*C.x = -0.5 = -D.y
// Permutations
"i = mod289(i); ",
"vec4 p = permute(permute(permute( ",
"i.z + vec4(0.0, i1.z, i2.z, 1.0))",
"+ i.y + vec4(0.0, i1.y, i2.y, 1.0)) ",
"+ i.x + vec4(0.0, i1.x, i2.x, 1.0));",
// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
"float n_ = 0.142857142857;", // 1.0/7.0
"vec3 ns = n_ * D.wyz - D.xzx;",
"vec4 j = p - 49.0 * floor(p * ns.z * ns.z);", // mod(p,7*7)
"vec4 x_ = floor(j * ns.z);",
"vec4 y_ = floor(j - 7.0 * x_);", // mod(j,N)
"vec4 x = x_ * ns.x + ns.yyyy;",
"vec4 y = y_ * ns.x + ns.yyyy;",
"vec4 h = 1.0 - abs(x) - abs(y);",
"vec4 b0 = vec4(x.xy, y.xy);",
"vec4 b1 = vec4(x.zw, y.zw);",
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
"vec4 s0 = floor(b0) * 2.0 + 1.0;",
"vec4 s1 = floor(b1) * 2.0 + 1.0;",
"vec4 sh = -step(h, vec4(0.0));",
"vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;",
"vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;",
"vec3 p0 = vec3(a0.xy, h.x);",
"vec3 p1 = vec3(a0.zw, h.y);",
"vec3 p2 = vec3(a1.xy, h.z);",
"vec3 p3 = vec3(a1.zw, h.w);",
//Normalise gradients
"vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));",
"p0 *= norm.x;",
"p1 *= norm.y;",
"p2 *= norm.z;",
"p3 *= norm.w;",
// Mix final noise value
"vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);",
"m = m * m;",
"return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));",
"}",
// simplex noise --------
"float turbulence(vec3 p) {",
"float sum = 0.0;",
"float freq = 1.0;",
"float amp = 1.0;",
"for(int i = 0; i < OCTIVES; i++) {",
"sum += abs(snoise(p * freq)) * amp;",
"freq *= lacunarity;",
"amp *= gain;",
"}",
"return sum;",
"}",
"vec4 samplerFire (vec3 p, vec4 scale) {",
"vec2 st = vec2(sqrt(dot(p.xz, p.xz)), p.y);",
"if(st.x <= 0.0 || st.x >= 1.0 || st.y <= 0.0 || st.y >= 1.0) return vec4(0.0);",
"p.y -= (seed + time) * scale.w;",
"p *= scale.xyz;",
"st.y += sqrt(st.y) * magnitude * turbulence(p);",
"if(st.y <= 0.0 || st.y >= 1.0) return vec4(0.0);",
"return texture2D(fireTex, st);",
"}",
"vec3 localize(vec3 p) {",
"return (invModelMatrix * vec4(p, 1.0)).xyz;",
"}",
"void main() {",
"vec3 rayPos = vWorldPos;",
"vec3 rayDir = normalize(rayPos - cameraPosition);",
"float rayLen = 0.0288 * length(scale.xyz);",
"vec4 col = vec4(0.0);",
"for(int i = 0; i < ITERATIONS; i++) {",
"rayPos += rayDir * rayLen;",
"vec3 lp = localize(rayPos);",
"lp.y += 0.5;",
"lp.xz *= 2.0;",
"col += samplerFire(lp, noiseScale);",
"}",
"col.a = col.r;",
"gl_FragColor = col;",
"}",
].join("\n"),
transparent: true,
depthWrite: true,
depthTest: true,
side: THREE.DoubleSide//双面显示
}
创建物体容器
const geometry = new THREE.BoxGeometry(3, 3, 3);
const material = new THREE.ShaderMaterial(fireShader)
const cube = new THREE.Mesh(geometry, material);
const antions = ()=> {
fireShader.uniforms.time.value += 0.01;
requestAnimationFrame(antions)
}
若有着色器遮挡
其一、关闭logarithmicDepthBuffer可以解决遮挡问题,但可能会导致闪烁问题
let renderer = new THREE.WebGLRenderer({
// alpha: true,
antialias: true,
logarithmicDepthBuffer: false
})
其二、修改顶点着色器和片元着色器、在顶点着色器中添加:`${ShaderChunk.logdepthbuf_pars_vertex}`和`${ShaderChunk.logdepthbuf_vertex}`、
在片元着色器中添加`${ShaderChunk.logdepthbuf_pars_fragment}`。
这样可以确保ShaderMaterial正确处理深度信息,避免被遮挡2。