/** * FakeFlame material component by Anderson Mancini - Jan 2024. */ import React, { useMemo, useRef } from 'react' import { shaderMaterial } from '@react-three/drei' import { extend, useFrame } from '@react-three/fiber' import { Color, DoubleSide, AdditiveBlending } from 'three' export default function FakeFlame({ falloff = 3, glowInternalRadius = 1.0, glowColor = 'orange', glowSharpness = 1.0 , isBoosting,}) { const FakeFlame = useMemo(() => { return shaderMaterial( { falloffAmount: falloff, glowInternalRadius: glowInternalRadius, glowColor: new Color(glowColor), glowSharpness: glowSharpness, time: 0, isBoosting: isBoosting, }, /*GLSL */ ` varying vec3 vNormal; varying vec2 vUv; uniform float time; float random2D(vec2 value) { return fract(sin(dot(value.xy, vec2(12.9898,78.233))) * 43758.5453123); } void main() { // Position vec4 modelPosition = modelMatrix * vec4(position, 1.0); vec4 modelNormal = modelMatrix * vec4(normal, 0.0); // Glitch float glitchTime = time + modelPosition.y; float glitchStrength = sin(glitchTime) + sin(glitchTime * .05) + sin(glitchTime * .36); glitchStrength /= 2.0; glitchStrength = smoothstep(0.2, 0.8, glitchStrength); glitchStrength *= 0.05; modelPosition.x += (random2D(modelNormal.xx + time) - 0.5) * glitchStrength; modelPosition.x += (random2D(modelNormal.xx - time) - 0.2) * glitchStrength; modelPosition.y += sin(smoothstep(0.3, vUv.y - 2.2, position.y) * 2.) * sin(time * 48.); modelPosition.z += sin(smoothstep(0., vUv.x - 0.8, position.z) * 2.) * sin(time * 24.) * .6; gl_Position = projectionMatrix * viewMatrix * modelPosition; vUv = uv; }`, /*GLSL */ ` uniform vec3 glowColor; uniform float falloffAmount; uniform float glowSharpness; uniform float glowInternalRadius; uniform float time; uniform bool isBoosting; varying vec2 vUv; vec2 hash( vec2 p ) { p = vec2( dot(p,vec2(127.1,311.7)), dot(p,vec2(269.5,183.3)) ); return -1.0 + 2.0*fract(sin(p)*43758.5453123); } float noise( in vec2 p ) { const float K1 = 0.366025404; // (sqrt(3)-1)/2; const float K2 = 0.211324865; // (3-sqrt(3))/6; vec2 i = floor( p + (p.x+p.y)*K1 ); vec2 a = p - i + (i.x+i.y)*K2; vec2 o = (a.x>a.y) ? vec2(1.0,0.0) : vec2(0.0,1.0); vec2 b = a - o + K2; vec2 c = a - 1.0 + 2.0*K2; vec3 h = max( 0.5-vec3(dot(a,a), dot(b,b), dot(c,c) ), 0.0 ); vec3 n = h*h*h*h*vec3( dot(a,hash(i+0.0)), dot(b,hash(i+o)), dot(c,hash(i+1.0))); return dot( n, vec3(70.0) ); } float fbm(vec2 uv) { float f; mat2 m = mat2( 1.6, 1.2, -1.2, 1.6 ); f = 0.5000*noise( uv ); uv = m*uv; f += 0.2500*noise( uv ); uv = m*uv; // f += 0.1250*noise( uv ); uv = m*uv; // f += 0.0625*noise( uv ); uv = m*uv; f = 0.5 + 0.5*f; return f; } // #define BLUE_FLAME // #define GREEN_FLAME void main() { vec2 q = vUv; q.x *= 2.; q.y *= 2.; float strength = floor(q.x+1.5); float T3 = max(2.,2.25*strength)*time * 3.; q.x = mod(q.x,1.)-0.5; q.y -= 0.05; float n = fbm(strength*q + vec2(0,T3)); float c = 0.7 - 0.01 * pow( max( 0., length(q*vec2(1.8+q.y*1.5,.75) ) - n * max( 0., q.y+.25 ) ),.2 ); // float c1 = n * c * fract((1.9-pow(0.15*vUv.y,2.))) * 2.; float c1 = n * c * (pow(1.90*vUv.y,2.)); c1=clamp(c1,0.,1.); vec3 col = smoothstep(0.1, 0.8, vec3(c1, c1*c1*c1, c1*c1*c1*c1*c1*c1)); #ifdef BLUE_FLAME col = col.zyx; #endif #ifdef GREEN_FLAME col = 0.85*col.yxz; #endif if (isBoosting) { gl_FragColor = vec4(col, 1.0); } else { gl_FragColor = vec4(col, 0.0); } #include #include }` ) }, [falloff, glowInternalRadius, glowColor, glowSharpness, isBoosting]) extend({ FakeFlame }) useFrame((state, delta) => { ref.current.time += delta }) const ref = useRef() return ( ) }