Suree, here’s the code
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import snowvertex from './snow/vertex.glsl'
import snowfragment from './snow/fragment.glsl'
import {Pane} from 'tweakpane';
//loaders and debug items
const loader = new GLTFLoader();
const textureLoader = new THREE.TextureLoader();
const pane = new Pane({title: 'Parameters',});
const f1 = pane.addFolder({title: 'May Affect Frieren',});
const f2 = pane.addFolder({title: 'Wont Affect Frieren',});
const debugObject = {
timespeed:1.0,
background: "rgb(127, 177, 184)",
}
//sizes
const sizes = {
width: window.innerWidth,
height: window.innerHeight
}
window.addEventListener('resize', () =>
{
// Update sizes
sizes.width = window.innerWidth
sizes.height = window.innerHeight
// Update camera
camera.aspect = sizes.width / sizes.height
camera.updateProjectionMatrix()
// Update renderer
renderer.setSize(sizes.width, sizes.height)
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
snowMaterial.uniforms.uPixelRatio.value = renderer.getPixelRatio()
})
//scene camera render
const scene = new THREE.Scene();
scene.background = new THREE.Color( debugObject.background )
f2.addBinding(debugObject, 'background',{label:'Color'}).on
('change', () => {scene.background.setStyle(debugObject.background)});
const camera = new THREE.PerspectiveCamera( 75, sizes.width / sizes.height, 0.01, 50 );
const renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize( sizes.width, sizes.height );
document.body.appendChild( renderer.domElement );
//controler
const controls = new OrbitControls( camera, renderer.domElement );
camera.position.set( 1, 1, 3 );
controls.update();
controls.maxDistance = 30;
//materials
const stafftext = textureLoader.load("snowstaff.webp", t => {t.flipY = false ; t.colorSpace = THREE.SRGBColorSpace})
const frierentext = textureLoader.load("snowfrieren.webp", t => {t.flipY = false ; t.colorSpace = THREE.SRGBColorSpace})
const frierenEYEtext = textureLoader.load("snowfrieren.webp", t => {t.flipY = false ; t.colorSpace = THREE.SRGBColorSpace})
const frierenMOUTHtext = textureLoader.load("snowfrieren.webp", t => {t.flipY = false ; t.colorSpace = THREE.SRGBColorSpace})
const staffmat = new THREE.MeshBasicMaterial( {map:stafftext} );
const frierenmat = new THREE.MeshBasicMaterial( {map:frierentext} );
const frierenEYEmat = new THREE.MeshBasicMaterial( {map:frierenEYEtext} );
const frierenMOUTHmat = new THREE.MeshBasicMaterial( {map:frierenMOUTHtext} );
const vertexcolors = new THREE.MeshBasicMaterial( {vertexColors:true} );
const linemat = new THREE.MeshBasicMaterial( {color:'rgb(50, 0, 50)'} );
const snowtex = textureLoader.load('particle.png');
const snowMaterial = new THREE.ShaderMaterial({
uniforms:
{
uTime: {value:0},
uPixelRatio:{value: renderer.getPixelRatio()},
uSize: {value:15},
uRadius: {value:0.5},
uTexture: {value: snowtex},
uSimple:{value: true},
},
vertexShader:snowvertex,
fragmentShader:snowfragment,
transparent:true,
depthWrite:false
});
f1.addBinding(snowMaterial.uniforms.uSize,'value',{min:1,max:50,step:1,label:'Size'}).on
('change', () => {snowbuildup()});
f2.addBinding(snowMaterial.uniforms.uRadius,'value',{min:0.01,max:3,step:0.01,label:'Wind'})
f2.addBinding(snowMaterial.uniforms.uSimple,'value',{label:'Simple'})
//loading scene
let movingsnow;
let movingsnowline;
loader.load('frieren snow scene.glb',
function ( gltf ) {
scene.add(gltf.scene);
gltf.scene.getObjectByName('bggeo').material = vertexcolors
gltf.scene.getObjectByName('bggeo_1').material = linemat
gltf.scene.getObjectByName('cubegeo').material = vertexcolors
gltf.scene.getObjectByName('cubegeo_1').material = linemat
gltf.scene.getObjectByName('staffgeo').material = staffmat
gltf.scene.getObjectByName('staffgeo_1').material = linemat
movingsnow = gltf.scene.getObjectByName('cubegeo');
movingsnowline = gltf.scene.getObjectByName('cubegeo_1');
})
//loading frieren
let mixer
let sittingAnim
let sittingColdAnim
loader.load('frieren.glb',
function ( gltf ) {
gltf.scene.getObjectByName("Cube017").material = frierenmat
gltf.scene.getObjectByName("Cube017_1").material = frierenEYEmat
gltf.scene.getObjectByName("Cube017_2").material = frierenMOUTHmat
gltf.scene.getObjectByName("Cube017_3").material = linemat
mixer = new THREE.AnimationMixer(gltf.scene)
sittingAnim = mixer.clipAction(gltf.animations[0])
sittingColdAnim = mixer.clipAction(gltf.animations[1])
sittingAnim.play()
scene.add(gltf.scene);
})
//snow particles
const snowGeometry = new THREE.BufferGeometry()
debugObject.numParticles = 1500
let positionArray
function generatesnow(n) {
positionArray = new Float32Array(n*3)
for( let i = 0; i < n; i++ ) {
positionArray[i*3+0] = rand(7)
positionArray[i*3+1] = Math.random() * 7
positionArray[i*3+2] = rand(7)
}
snowGeometry.setAttribute('position', new THREE.BufferAttribute(positionArray,3))
}
generatesnow(debugObject.numParticles);
f1.addBinding(debugObject,'numParticles',{min:1,max:20000,step:1,label:'Amount', index: 0},).on
('change', () => {
generatesnow(debugObject.numParticles)
snowbuildup()
});
const snow = new THREE.Points(snowGeometry,snowMaterial)
scene.add(snow)
// update
const clock = new THREE.Clock()
renderer.setAnimationLoop(update);
f2.addBinding(debugObject,'timespeed',{min:0.1,max:10,step:0.1,label:'Speed',index: 2})
function update() {
const DELTA = clock.getDelta()
const ELAPSED = clock.getElapsedTime()
snowMaterial.uniforms.uTime.value = ELAPSED * debugObject.timespeed
if ( mixer ) mixer.update(DELTA);
renderer.render( scene, camera );
}
//helper functions
function rand( v ) {return (v * (Math.random() - 0.5)); }
let issnowbuildup = false
function snowbuildup(){
movingsnow.morphTargetInfluences[0] = movingsnowline.morphTargetInfluences[0] =
(Math.min(Math.max(debugObject.numParticles *snowMaterial.uniforms.uSize.value, 20000), 300000)-20000) / 280000
if (issnowbuildup) {
if (movingsnow.morphTargetInfluences[0] < 0.3) {
sittingColdAnim.stop()
sittingAnim.play()
mixer.setTime(mixer.time)
frierenEYEtext.offset.set(0,0)
frierenMOUTHtext.offset.set(0,0)
issnowbuildup = false
}
}
else {
if (movingsnow.morphTargetInfluences[0] > 0.3) {
sittingAnim.stop()
sittingColdAnim.play()
mixer.setTime(mixer.time)
frierenEYEtext.offset.set(0,0.250)
frierenMOUTHtext.offset.set(0,0.3125)
issnowbuildup = true
}
}
}