demos
This commit is contained in:
@@ -278,6 +278,130 @@ export function useParticleSystem() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建增强型火焰发射器 - 用于大型中心火焰效果
|
||||||
|
*/
|
||||||
|
function createIntenseFireEmitter(
|
||||||
|
scene: THREE.Scene,
|
||||||
|
position: THREE.Vector3,
|
||||||
|
emissionRate = 50,
|
||||||
|
spreadRadius = 2,
|
||||||
|
) {
|
||||||
|
const texture = createFlameTexture()
|
||||||
|
const particles: Particle[] = []
|
||||||
|
let emissionCounter = 0
|
||||||
|
|
||||||
|
function emit() {
|
||||||
|
for (let i = 0; i < emissionRate; i++) {
|
||||||
|
const particlePos = position.clone()
|
||||||
|
|
||||||
|
// 在圆形区域内随机分布
|
||||||
|
const angle = Math.random() * Math.PI * 2
|
||||||
|
const radius = Math.random() * spreadRadius
|
||||||
|
particlePos.x += Math.cos(angle) * radius
|
||||||
|
particlePos.z += Math.sin(angle) * radius
|
||||||
|
|
||||||
|
// 多样化的火焰颜色
|
||||||
|
const colorVariation = Math.random()
|
||||||
|
let color: number
|
||||||
|
if (colorVariation < 0.3) {
|
||||||
|
color = 0xFFFFFF // 白色(最热)
|
||||||
|
}
|
||||||
|
else if (colorVariation < 0.6) {
|
||||||
|
color = 0xFFDD00 // 黄色
|
||||||
|
}
|
||||||
|
else if (colorVariation < 0.85) {
|
||||||
|
color = 0xFF8800 // 橙色
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
color = 0xFF2200 // 红色
|
||||||
|
}
|
||||||
|
|
||||||
|
// 粒子大小和速度变化
|
||||||
|
const sizeVariation = 0.3 + Math.random() * 0.5
|
||||||
|
const speedVariation = 0.05 + Math.random() * 0.1
|
||||||
|
|
||||||
|
const particle = createParticle(texture, particlePos, {
|
||||||
|
color,
|
||||||
|
opacity: 0.6 + Math.random() * 0.3,
|
||||||
|
size: sizeVariation,
|
||||||
|
velocity: new THREE.Vector3(
|
||||||
|
(Math.random() - 0.5) * 0.08,
|
||||||
|
speedVariation,
|
||||||
|
(Math.random() - 0.5) * 0.08,
|
||||||
|
),
|
||||||
|
maxAge: 40 + Math.floor(Math.random() * 30),
|
||||||
|
})
|
||||||
|
scene.add(particle.sprite)
|
||||||
|
particles.push(particle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
// 更新现有粒子
|
||||||
|
for (let i = particles.length - 1; i >= 0; i--) {
|
||||||
|
const particle = particles[i]
|
||||||
|
if (!particle)
|
||||||
|
continue
|
||||||
|
|
||||||
|
// 自定义更新逻辑以增强视觉效果
|
||||||
|
particle.sprite.position.add(particle.velocity)
|
||||||
|
|
||||||
|
// 添加轻微的湍流效果
|
||||||
|
particle.velocity.x += (Math.random() - 0.5) * 0.002
|
||||||
|
particle.velocity.z += (Math.random() - 0.5) * 0.002
|
||||||
|
|
||||||
|
particle.age++
|
||||||
|
|
||||||
|
// 更新大小和透明度
|
||||||
|
const lifeRatio = particle.age / particle.maxAge
|
||||||
|
const initialSize = 0.3
|
||||||
|
// 火焰先变大后缩小
|
||||||
|
const sizeFactor = Math.sin(lifeRatio * Math.PI) * 2 + 1
|
||||||
|
particle.sprite.scale.setScalar(initialSize * sizeFactor)
|
||||||
|
|
||||||
|
// 透明度渐变
|
||||||
|
particle.sprite.material.opacity = 0.8 * (1 - lifeRatio * lifeRatio)
|
||||||
|
|
||||||
|
// 颜色渐变(从亮到暗)
|
||||||
|
const material = particle.sprite.material as THREE.SpriteMaterial
|
||||||
|
if (lifeRatio > 0.5) {
|
||||||
|
const darkening = (lifeRatio - 0.5) * 2
|
||||||
|
material.color.lerp(new THREE.Color(0x440000), darkening * 0.5)
|
||||||
|
}
|
||||||
|
|
||||||
|
const shouldRemove = particle.age >= particle.maxAge
|
||||||
|
|
||||||
|
if (shouldRemove) {
|
||||||
|
scene.remove(particle.sprite)
|
||||||
|
particle.sprite.material.dispose()
|
||||||
|
particles.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 控制发射频率
|
||||||
|
emissionCounter++
|
||||||
|
if (emissionCounter >= 1) {
|
||||||
|
emit()
|
||||||
|
emissionCounter = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function stop() {
|
||||||
|
particles.forEach((particle) => {
|
||||||
|
scene.remove(particle.sprite)
|
||||||
|
particle.sprite.material.dispose()
|
||||||
|
})
|
||||||
|
particles.length = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
update,
|
||||||
|
stop,
|
||||||
|
particles,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createSmokeTexture,
|
createSmokeTexture,
|
||||||
createFlameTexture,
|
createFlameTexture,
|
||||||
@@ -285,5 +409,6 @@ export function useParticleSystem() {
|
|||||||
updateParticle,
|
updateParticle,
|
||||||
createEmitter,
|
createEmitter,
|
||||||
createFlameEmitter,
|
createFlameEmitter,
|
||||||
|
createIntenseFireEmitter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,6 +304,19 @@ function spreadFire() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 移除初始着火点的火焰
|
||||||
|
function removeInitialFire() {
|
||||||
|
// 找到并移除 pingt01_0019_pCylinder10001 的火焰发射器
|
||||||
|
for (let i = flameEmitters.length - 1; i >= 0; i--) {
|
||||||
|
const { emitter, mesh } = flameEmitters[i]
|
||||||
|
if (mesh && mesh.name === 'pingt01_0019_pCylinder10001') {
|
||||||
|
emitter.stop()
|
||||||
|
flameEmitters.splice(i, 1)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 创建中心大火效果
|
// 创建中心大火效果
|
||||||
function createCenterFire() {
|
function createCenterFire() {
|
||||||
if (!model)
|
if (!model)
|
||||||
@@ -311,6 +324,9 @@ function createCenterFire() {
|
|||||||
|
|
||||||
const particleUtils = useParticleSystem()
|
const particleUtils = useParticleSystem()
|
||||||
|
|
||||||
|
// 先移除初始着火点
|
||||||
|
removeInitialFire()
|
||||||
|
|
||||||
// 移除所有小火焰发射器
|
// 移除所有小火焰发射器
|
||||||
flameEmitters.forEach(({ emitter }) => {
|
flameEmitters.forEach(({ emitter }) => {
|
||||||
emitter.stop()
|
emitter.stop()
|
||||||
@@ -323,23 +339,41 @@ function createCenterFire() {
|
|||||||
const modelCenter = modelBox.getCenter(new THREE.Vector3())
|
const modelCenter = modelBox.getCenter(new THREE.Vector3())
|
||||||
const modelSize = modelBox.getSize(new THREE.Vector3())
|
const modelSize = modelBox.getSize(new THREE.Vector3())
|
||||||
|
|
||||||
// 在中心创建大型火焰发射器
|
// 在中心创建大型火焰发射器 - 使用增强版
|
||||||
centerFireEmitter = particleUtils.createFlameEmitter(
|
centerFireEmitter = particleUtils.createIntenseFireEmitter(
|
||||||
scene,
|
scene,
|
||||||
new THREE.Vector3(modelCenter.x, modelBox.min.y + modelSize.y * 0.3, modelCenter.z),
|
new THREE.Vector3(modelCenter.x, modelBox.min.y, modelCenter.z),
|
||||||
30, // 大量粒子
|
80, // 更多粒子
|
||||||
|
modelSize.x * 0.5, // 扩散范围
|
||||||
)
|
)
|
||||||
|
|
||||||
// 添加多个位置的火焰,模拟整体燃烧
|
// 添加多层火焰效果,模拟整体燃烧
|
||||||
|
const layers = [
|
||||||
|
{ y: modelBox.min.y, count: 60, spread: modelSize.x * 0.4 },
|
||||||
|
{ y: modelBox.min.y + modelSize.y * 0.3, count: 50, spread: modelSize.x * 0.3 },
|
||||||
|
{ y: modelBox.min.y + modelSize.y * 0.6, count: 40, spread: modelSize.x * 0.2 },
|
||||||
|
]
|
||||||
|
|
||||||
|
layers.forEach((layer) => {
|
||||||
|
const emitter = particleUtils.createIntenseFireEmitter(
|
||||||
|
scene,
|
||||||
|
new THREE.Vector3(modelCenter.x, layer.y, modelCenter.z),
|
||||||
|
layer.count,
|
||||||
|
layer.spread,
|
||||||
|
)
|
||||||
|
flameEmitters.push({ emitter, mesh: null })
|
||||||
|
})
|
||||||
|
|
||||||
|
// 四周添加火焰柱
|
||||||
const positions = [
|
const positions = [
|
||||||
new THREE.Vector3(modelBox.min.x, modelBox.min.y + 1, modelCenter.z),
|
new THREE.Vector3(modelBox.min.x, modelBox.min.y, modelCenter.z),
|
||||||
new THREE.Vector3(modelBox.max.x, modelBox.min.y + 1, modelCenter.z),
|
new THREE.Vector3(modelBox.max.x, modelBox.min.y, modelCenter.z),
|
||||||
new THREE.Vector3(modelCenter.x, modelBox.min.y + 1, modelBox.min.z),
|
new THREE.Vector3(modelCenter.x, modelBox.min.y, modelBox.min.z),
|
||||||
new THREE.Vector3(modelCenter.x, modelBox.min.y + 1, modelBox.max.z),
|
new THREE.Vector3(modelCenter.x, modelBox.min.y, modelBox.max.z),
|
||||||
]
|
]
|
||||||
|
|
||||||
positions.forEach((pos) => {
|
positions.forEach((pos) => {
|
||||||
const emitter = particleUtils.createFlameEmitter(scene, pos, 20)
|
const emitter = particleUtils.createIntenseFireEmitter(scene, pos, 40, modelSize.x * 0.15)
|
||||||
flameEmitters.push({ emitter, mesh: null })
|
flameEmitters.push({ emitter, mesh: null })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user