增加了高级溶解效果

This commit is contained in:
hawk86104 2025-03-03 21:16:35 +08:00
parent 507f180485
commit 2cd6996965
9 changed files with 630 additions and 1 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 KiB

View File

@ -0,0 +1,43 @@
<template></template>
<script setup lang="ts">
import { watchEffect } from 'vue'
import * as THREE from 'three'
import { useTresContext, useRenderLoop } from '@tresjs/core'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass'
const { camera, renderer, scene, sizes } = useTresContext()
const params = {
threshold: 0,
strength: 0.216, //
radius: 0.2, //
}
let effectComposer = null as any
const bloomPassEffect = (scene: THREE.Scene, camera: THREE.PerspectiveCamera, renderer: THREE.WebGLRenderer, width: number, height: number) => {
//
const renderScene = new RenderPass(scene, camera)
//
const bloomPass = new UnrealBloomPass(new THREE.Vector2(width, height), params.strength, params.radius, params.threshold)
//
effectComposer = new EffectComposer(renderer)
// effectComposer.renderToScreen = false
//
effectComposer.addPass(renderScene)
effectComposer.addPass(bloomPass)
}
watchEffect(() => {
if (sizes.width.value) {
bloomPassEffect(scene.value, camera.value as any, renderer.value, sizes.width.value, sizes.height.value)
}
})
const { onLoop } = useRenderLoop()
onLoop(() => {
if (effectComposer) {
effectComposer.render()
}
})
</script>

View File

@ -0,0 +1,99 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2025-03-03 16:04:05
* @LastEditors: 地虎降天龙
* @LastEditTime: 2025-03-03 20:21:16
-->
<template>
<CustomShaderMaterial
:baseMaterial="baseMaterial"
:vertexShader="vertexShader"
:side="THREE.DoubleSide"
:fragmentShader="fragmentShader"
:uniforms="dissolveUniformData"
/>
</template>
<script setup lang="ts">
import { watch } from 'vue'
import * as THREE from 'three'
import { CustomShaderMaterial } from '@tresjs/cientos'
import snoise from '../../shaders/snoise.glsl'
const props = defineProps({
baseMaterial: {
default: new THREE.MeshPhysicalMaterial(),
},
uEdgeColor: {
default: '#4d9bff',
},
uEdge: { default: 6 },
uFreq: {
default: 0.41,
},
uAmp: { default: 20.0 },
uProgress: { default: -2.0 },
})
const dissolveUniformData = {
uEdgeColor: {
value: new THREE.Color(props.uEdgeColor),
},
uFreq: {
value: props.uFreq,
},
uAmp: {
value: props.uAmp,
},
uProgress: {
value: props.uProgress,
},
uEdge: {
value: props.uEdge,
},
} as any
const vertexShader = `
varying vec3 vPos;
void main() {
vPos = position;
}
`
const fragmentShader = `
varying vec3 vPos;
uniform float uFreq;
uniform float uAmp;
uniform float uProgress;
uniform float uEdge;
uniform vec3 uEdgeColor;
${snoise}
void main() {
float noise = snoise(vPos * uFreq) * uAmp; // calculate snoise in fragment shader for smooth dissolve edges
if(noise < uProgress) discard; // discard any fragment where noise is lower than progress
float edgeWidth = uProgress + uEdge;
if(noise > uProgress && noise < edgeWidth){
csm_DiffuseColor = vec4(vec3(uEdgeColor),noise); // colors the edge
}else{
csm_DiffuseColor = vec4(csm_DiffuseColor.xyz,1.0);
}
}
`
watch(
() => [props.uEdgeColor, props.uEdge, props.uFreq, props.uAmp, props.uProgress],
([uEdgeColor, uEdge, uFreq, uAmp, uProgress]) => {
dissolveUniformData.uEdgeColor.value.setStyle(uEdgeColor)
dissolveUniformData.uEdge.value = uEdge
dissolveUniformData.uFreq.value = uFreq
dissolveUniformData.uAmp.value = uAmp
dissolveUniformData.uProgress.value = uProgress
},
)
</script>

View File

@ -0,0 +1,276 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2025-03-03 20:21:59
* @LastEditors: 地虎降天龙
* @LastEditTime: 2025-03-03 21:06:10
-->
<template>
<TresPoints :geometry="meshGeo">
<TresShaderMaterial
transparent
:blending="THREE.AdditiveBlending"
:uniforms="particlesUniformData"
:vertexShader="vertexShader"
:fragmentShader="fragmentShader"
/>
</TresPoints>
</template>
<script setup lang="ts">
import { watch } from 'vue'
import * as THREE from 'three'
import { useTexture, useTresContext, useRenderLoop } from '@tresjs/core'
import snoise from '../../shaders/snoise.glsl'
const props = defineProps({
geo: {
default: new THREE.BufferGeometry(),
},
uEdge: { default: 6 },
uFreq: {
default: 0.41,
},
uAmp: { default: 20.0 },
uProgress: { default: -2.0 },
uColor: {
default: '#4d9bff',
},
uPointSize: {
default: 200,
},
particleData: {
default: {
particleSpeedFactor: 0.02, // for tweaking velocity
velocityFactor: { x: 2.5, y: 2 },
waveAmplitude: 0,
},
},
})
const meshGeo = props.geo.clone()
const pTexture = await useTexture(['./plugins/industry4/image/particle.png'])
let particleCount = meshGeo.attributes.position.count
let particleMaxOffsetArr: Float32Array // -- how far a particle can go from its initial position
let particleInitPosArr: Float32Array // store the initial position of the particles -- particle position will reset here if it exceed maxoffset
let particleCurrPosArr: Float32Array // use to update he position of the particle
let particleVelocityArr: Float32Array // velocity of each particle
let particleDistArr: Float32Array
let particleRotationArr: Float32Array
function initParticleAttributes(meshGeo: THREE.BufferGeometry) {
particleCount = meshGeo.attributes.position.count
particleMaxOffsetArr = new Float32Array(particleCount)
particleInitPosArr = new Float32Array(meshGeo.getAttribute('position').array)
particleCurrPosArr = new Float32Array(meshGeo.getAttribute('position').array)
particleVelocityArr = new Float32Array(particleCount * 3)
particleDistArr = new Float32Array(particleCount)
particleRotationArr = new Float32Array(particleCount)
for (let i = 0; i < particleCount; i++) {
let x = i * 3 + 0
let y = i * 3 + 1
let z = i * 3 + 2
particleMaxOffsetArr[i] = Math.random() * 5.5 + 1.5
particleVelocityArr[x] = Math.random() * 0.5 + 0.5
particleVelocityArr[y] = Math.random() * 0.5 + 0.5
particleVelocityArr[z] = Math.random() * 0.1
particleDistArr[i] = 0.001
particleRotationArr[i] = Math.random() * Math.PI * 2
}
meshGeo.setAttribute('aOffset', new THREE.BufferAttribute(particleMaxOffsetArr, 1))
meshGeo.setAttribute('aCurrentPos', new THREE.BufferAttribute(particleCurrPosArr, 3))
meshGeo.setAttribute('aVelocity', new THREE.BufferAttribute(particleVelocityArr, 3))
meshGeo.setAttribute('aDist', new THREE.BufferAttribute(particleDistArr, 1))
meshGeo.setAttribute('aAngle', new THREE.BufferAttribute(particleRotationArr, 1))
}
initParticleAttributes(meshGeo)
const { renderer } = useTresContext()
const particlesUniformData = {
uTexture: {
value: pTexture,
},
uPixelDensity: {
value: renderer.value.getPixelRatio(),
},
uProgress: {
value: props.uProgress,
},
uEdge: {
value: props.uEdge,
},
uAmp: {
value: props.uAmp,
},
uFreq: {
value: props.uFreq,
},
uBaseSize: {
value: props.uPointSize,
},
uColor: {
value: new THREE.Color(props.uColor),
},
} as any
const vertexShader = `
${snoise}
uniform float uPixelDensity;
uniform float uBaseSize;
uniform float uFreq;
uniform float uAmp;
uniform float uEdge;
uniform float uProgress;
varying float vNoise;
varying float vAngle;
attribute vec3 aCurrentPos;
attribute float aDist;
attribute float aAngle;
void main() {
vec3 pos = position;
float noise = snoise(pos * uFreq) * uAmp;
vNoise =noise;
vAngle = aAngle;
if( vNoise > uProgress-2.0 && vNoise < uProgress + uEdge+2.0){
pos = aCurrentPos;
}
vec4 modelPosition = modelMatrix * vec4(pos, 1.0);
vec4 viewPosition = viewMatrix * modelPosition;
vec4 projectedPosition = projectionMatrix * viewPosition;
gl_Position = projectedPosition;
float size = uBaseSize * uPixelDensity;
size = size / (aDist + 1.0);
gl_PointSize = size / -viewPosition.z;
}
`
const fragmentShader = `
uniform vec3 uColor;
uniform float uEdge;
uniform float uProgress;
uniform sampler2D uTexture;
varying float vNoise;
varying float vAngle;
void main(){
if( vNoise < uProgress ) discard;
if( vNoise > uProgress + uEdge) discard;
vec2 coord = gl_PointCoord;
coord = coord - 0.5; // get the coordinate from 0-1 ot -0.5 to 0.5
coord = coord * mat2(cos(vAngle),sin(vAngle) , -sin(vAngle), cos(vAngle)); // apply the rotation transformaion
coord = coord + 0.5; // reset the coordinate to 0-1
vec4 texture = texture2D(uTexture,coord);
gl_FragColor = vec4(vec3(uColor.xyz * texture.xyz),1.0);
}
`
function calculateWaveOffset(idx: number) {
const posx = particleCurrPosArr[idx * 3 + 0]
const posy = particleCurrPosArr[idx * 3 + 1]
let xwave1 = Math.sin(posy * 2) * (0.8 + props.particleData.waveAmplitude)
let ywave1 = Math.sin(posx * 2) * (0.6 + props.particleData.waveAmplitude)
let xwave2 = Math.sin(posy * 5) * (0.2 + props.particleData.waveAmplitude)
let ywave2 = Math.sin(posx * 1) * (0.9 + props.particleData.waveAmplitude)
let xwave3 = Math.sin(posy * 8) * (0.8 + props.particleData.waveAmplitude)
let ywave3 = Math.sin(posx * 5) * (0.6 + props.particleData.waveAmplitude)
let xwave4 = Math.sin(posy * 3) * (0.8 + props.particleData.waveAmplitude)
let ywave4 = Math.sin(posx * 7) * (0.6 + props.particleData.waveAmplitude)
let xwave = xwave1 + xwave2 + xwave3 + xwave4
let ywave = ywave1 + ywave2 + ywave3 + ywave4
return { xwave, ywave }
}
function updateVelocity(idx: number) {
let vx = particleVelocityArr[idx * 3 + 0]
let vy = particleVelocityArr[idx * 3 + 1]
let vz = particleVelocityArr[idx * 3 + 2]
vx *= props.particleData.velocityFactor.x
vy *= props.particleData.velocityFactor.y
let { xwave, ywave } = calculateWaveOffset(idx)
vx += xwave
vy += ywave
vx *= Math.abs(props.particleData.particleSpeedFactor)
vy *= Math.abs(props.particleData.particleSpeedFactor)
vz *= Math.abs(props.particleData.particleSpeedFactor)
return { vx, vy, vz }
}
function updateParticleAttriutes() {
for (let i = 0; i < particleCount; i++) {
let x = i * 3 + 0
let y = i * 3 + 1
let z = i * 3 + 2
let { vx, vy, vz } = updateVelocity(i)
particleCurrPosArr[x] += vx
particleCurrPosArr[y] += vy
particleCurrPosArr[z] += vz
const vec1 = new THREE.Vector3(particleInitPosArr[x], particleInitPosArr[y], particleInitPosArr[z])
const vec2 = new THREE.Vector3(particleCurrPosArr[x], particleCurrPosArr[y], particleCurrPosArr[z])
const dist = vec1.distanceTo(vec2)
particleDistArr[i] = dist
particleRotationArr[i] += 0.01
if (dist > particleMaxOffsetArr[i]) {
particleCurrPosArr[x] = particleInitPosArr[x]
particleCurrPosArr[y] = particleInitPosArr[y]
particleCurrPosArr[z] = particleInitPosArr[z]
}
}
meshGeo.setAttribute('aOffset', new THREE.BufferAttribute(particleMaxOffsetArr, 1))
meshGeo.setAttribute('aCurrentPos', new THREE.BufferAttribute(particleCurrPosArr, 3))
meshGeo.setAttribute('aVelocity', new THREE.BufferAttribute(particleVelocityArr, 3))
meshGeo.setAttribute('aDist', new THREE.BufferAttribute(particleDistArr, 1))
meshGeo.setAttribute('aAngle', new THREE.BufferAttribute(particleRotationArr, 1))
}
const { onLoop } = useRenderLoop()
onLoop(() => {
updateParticleAttriutes()
})
watch(
() => [props.uColor, props.uEdge, props.uFreq, props.uAmp, props.uProgress, props.uPointSize],
([uColor, uEdge, uFreq, uAmp, uProgress, uPointSize]) => {
particlesUniformData.uColor.value.setStyle(uColor)
particlesUniformData.uEdge.value = uEdge
particlesUniformData.uFreq.value = uFreq
particlesUniformData.uAmp.value = uAmp
particlesUniformData.uProgress.value = uProgress
particlesUniformData.uBaseSize.value = uPointSize
},
)
</script>

View File

@ -0,0 +1,17 @@
<template>
<TresGroup>
<TresMesh :geometry="knotGeometry">
<material color="#636363" :metalness="2" :roughness="0" v-bind="$attrs" />
</TresMesh>
<Suspense>
<particlesPoints :geo="knotGeometry" v-bind="$attrs" :uColor="$attrs.uEdgeColor" />
</Suspense>
</TresGroup>
</template>
<script setup lang="ts">
import * as THREE from 'three'
import material from './material.vue'
import particlesPoints from './particlesPoints.vue'
const knotGeometry = new THREE.TorusKnotGeometry(3, 1, 64, 8, 2, 3)
</script>

View File

@ -4,7 +4,7 @@
* @Autor: 地虎降天龙
* @Date: 2023-11-10 16:11:27
* @LastEditors: 地虎降天龙
* @LastEditTime: 2024-05-31 16:19:18
* @LastEditTime: 2025-03-03 21:14:58
*/
export default {
@ -57,6 +57,13 @@ export default {
name: 'dissolveEffect',
title: '溶解特效',
},
{
src: 'plugins/industry4/preview/dissolveEffectPlus.png',
type: 'img',
name: 'dissolveEffectPlus',
title: '高级溶解特效',
referenceSource: { title: 'JatinChopra', url: 'https://github.com/JatinChopra/emissive-dissolve-effect' },
},
{
src: 'plugins/industry4/preview/alternator.png',
type: 'img',

View File

@ -0,0 +1,112 @@
<!--
* @Description:
* @Version: 1.668
* @Autor: 地虎降天龙
* @Date: 2025-03-03 15:58:09
* @LastEditors: 地虎降天龙
* @LastEditTime: 2025-03-03 21:14:08
-->
<template>
<TresCanvas v-bind="tcConfig">
<TresPerspectiveCamera :position="[15, 15, 15]" :fov="45" :near="0.1" :far="10000" :look-at="[0, 0, 0]" />
<OrbitControls enableDamping />
<torusKnot v-bind="torusKnotConfigState" :color="meshConfig.torusKnotColor" />
<Suspense>
<skyBoxDmesh texture="https://opensource-1314935952.cos.ap-nanjing.myqcloud.com/images/skyBox/workshop_blur.jpg" />
</Suspense>
<bloomPass />
</TresCanvas>
</template>
<script setup lang="ts">
import { reactive } from 'vue'
import * as THREE from 'three'
import { OrbitControls } from '@tresjs/cientos'
import { skyBoxDmesh } from 'PLS/skyBox'
import { Pane } from 'tweakpane'
import torusKnot from '../components/dissolveEffectPlus/torusKnot.vue'
import bloomPass from '../components/dissolveEffectPlus/bloomPass.vue'
const tcConfig = {
clearColor: '#201919',
windowSize: true,
toneMapping: THREE.ACESFilmicToneMapping,
toneMappingExposure: 0.8,
renderMode: 'manual',
}
const torusKnotConfigState = reactive({
uEdgeColor: '#ff784d',
uEdge: 6,
uFreq: 0.41,
uAmp: 20.0,
uProgress: -4.9,
uPointSize: 576,
particleData: {
particleSpeedFactor: 0.02,
velocityFactor: { x: 2.5, y: 2 },
waveAmplitude: 0,
},
})
const meshConfig = reactive({
torusKnotColor: '#7a8c87',
})
const paneControl = new Pane({
title: '参数',
expanded: true,
})
paneControl.addBinding(meshConfig, 'torusKnotColor', { label: 'torusKnotColor' })
paneControl.addBinding(torusKnotConfigState, 'uEdgeColor', { label: '边缘颜色' })
paneControl.addBinding(torusKnotConfigState, 'uEdge', {
label: '边缘宽度',
min: 0,
max: 9.0,
step: 0.01,
})
paneControl.addBinding(torusKnotConfigState, 'uFreq', {
label: '密度',
min: 0.002,
max: 2.0,
step: 0.002,
})
paneControl.addBinding(torusKnotConfigState, 'uAmp', {
label: '幅度',
min: 3,
max: 22,
step: 0.01,
})
paneControl.addBinding(torusKnotConfigState, 'uProgress', {
label: '进度',
min: -25,
max: 20.0,
step: 0.1,
})
paneControl.addBinding(torusKnotConfigState, 'uPointSize', {
label: '粒子大小',
min: 10,
max: 800,
step: 5,
})
paneControl.addBinding(torusKnotConfigState.particleData, 'particleSpeedFactor', {
label: '粒子速度',
min: 0.0001,
max: 0.1,
step: 0.0001,
})
paneControl.addBinding(torusKnotConfigState.particleData, 'velocityFactor', {
picker: 'inline',
label: '粒子飘逸方向',
expanded: true,
x: { min: -10, max: 10, step: 0.01 },
y: { min: -10, max: 10, step: 0.01 },
})
paneControl.addBinding(torusKnotConfigState.particleData, 'waveAmplitude', {
label: '粒子扰动幅度',
min: 0,
max: 5,
step: 0.01,
})
</script>

View File

@ -0,0 +1,75 @@
vec4 permute(vec4 x) {
return mod(((x * 34.0) + 1.0) * x, 289.0);
}
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 * C
vec3 x1 = x0 - i1 + 1.0 * C.xxx;
vec3 x2 = x0 - i2 + 2.0 * C.xxx;
vec3 x3 = x0 - 1. + 3.0 * C.xxx;
// Permutations
i = mod(i, 289.0);
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
// ( N*N points uniformly over a square, mapped onto an octahedron.)
float n_ = 1.0 / 7.0; // N=7
vec3 ns = n_ * D.wyz - D.xzx;
vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,N*N)
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 = 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)));
}