From 35ea79078d5ec47b34e5e21ac110aa84ae73e6a8 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Sun, 24 Jul 2022 18:41:49 -0400 Subject: [PATCH 01/16] rewrite water --- index.js | 4918 ++++-------------------------------------------------- 1 file changed, 301 insertions(+), 4617 deletions(-) diff --git a/index.js b/index.js index db8c4d8..8ca76b2 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ import metaversefile from 'metaversefile'; // import { useSyncExternalStore } from 'react'; import * as THREE from 'three'; +import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js'; // import { terrainVertex, terrainFragment } from './shaders/terrainShader.js'; // import biomeSpecs from './biomes.js'; @@ -25,7 +26,10 @@ const { const sounds = useSound(); const soundFiles = sounds.getSoundFiles(); -let reflectionSsrPass = null; +const waterWorldPosition = new THREE.Vector3(); + +let webaWaterPass = null; +let foamPass = null; const baseUrl = import.meta.url.replace(/(\/)[^\/\\]*$/, '$1'); const textureLoader = new THREE.TextureLoader(); @@ -71,29 +75,21 @@ flowmapTexture.wrapS = flowmapTexture.wrapT = THREE.RepeatWrapping; // const localVector = new THREE.Vector3(); const localVector2 = new THREE.Vector3(); -// const localVector3 = new THREE.Vector3(); -// const localVector4 = new THREE.Vector3(); +const localVector3D = new THREE.Vector3(); +const localVector3D2 = new THREE.Vector3(); const localQuaternion = new THREE.Quaternion(); const localMatrix = new THREE.Matrix4(); const localMatrix2 = new THREE.Matrix4(); -// const localColor = new THREE.Color(); const localSphere = new THREE.Sphere(); -// const localBox = new THREE.Box3(); - -// const zeroVector = new THREE.Vector3(); -// const procGenManager = useProcGenManager(); const chunkWorldSize = procGenManager.chunkSize; -const terrainSize = chunkWorldSize * 4; const chunkRadius = Math.sqrt(chunkWorldSize * chunkWorldSize * 3); -const numLods = 1; const bufferSize = 20 * 1024 * 1024; const defaultNumNods = 3; const defaultMinLodRange = 2; -// const textureLoader = new THREE.TextureLoader(); const abortError = new Error('chunk disposed'); abortError.isAbortError = true; const fakeMaterial = new THREE.MeshBasicMaterial({ @@ -107,24 +103,12 @@ class ChunkRenderData { } } -// const textureUrls = { Base_Color: `${baseUrl}Vol_36_3_Water_Base_Color.png`, }; const textureNames = Object.keys(textureUrls); -/* const biomesPngTexturePrefix = `/images/stylized-textures/png/`; -const biomesKtx2TexturePrefix = `/images/land-textures/`; -const neededTexturePrefixes = (() => { - const neededTexturePrefixesSet = new Set(); - for (const biomeSpec of biomeSpecs) { - const [name, colorHex, textureName] = biomeSpec; - neededTexturePrefixesSet.add(textureName); - } - const neededTexturePrefixes = Array.from(neededTexturePrefixesSet); - return neededTexturePrefixes; -})(); -const texturesPerRow = Math.ceil(Math.sqrt(neededTexturePrefixes.length)); */ + const { BatchedMesh, GeometryAllocator } = useInstancing(); class WaterMesh extends BatchedMesh { @@ -154,15 +138,6 @@ class WaterMesh extends BatchedMesh { ); const {geometry} = allocator; - const lightMapper = procGenInstance.getLightMapper(); - // lightMapper.addEventListener('update', e => { - // const {coord} = e.data; - // material.uniforms.uLightBasePosition.value.copy(coord); - // material.uniforms.uLightBasePosition.needsUpdate = true; - // }); - - - const material = new THREE.ShaderMaterial({ defines: { DEPTH_PACKING: 1, @@ -172,48 +147,30 @@ class WaterMesh extends BatchedMesh { uTime: { value: 0 }, - uUJump: { - type: "f", - value: 0.24 - }, - uVJump: { - type: "f", - value: 0.208 - }, - uTiling: { - type: "f", - value: 2 - }, - uSpeed: { - type: "f", - value: 0.5 - }, - uFlowStrength: { - type: "f", - value: 0.25 - }, - uFlowOffset: { - type: "f", - value: -1.5 - }, sunPosition: { value: new THREE.Vector3(200.0, 1.0, -600.) }, - playerPosition: { - value: new THREE.Vector3() + tDudv: { + value: null + }, + tDepth: { + value: null }, - playerDirection: { - value: new THREE.Vector3() + cameraNear: { + value: 0 }, - waterDerivativeHeightTexture: { - value: waterDerivativeHeightTexture + cameraFar: { + value: 0 }, - waterNoiseTexture: { - value: waterNoiseTexture + resolution: { + value: new THREE.Vector2() }, - flowmapTexture: { - value: flowmapTexture + waterNormalTexture1:{ + value:waterNormalTexture1 }, + waterNormalTexture2:{ + value:waterNormalTexture2 + } }, vertexShader: `\ @@ -237,99 +194,98 @@ class WaterMesh extends BatchedMesh { } `, fragmentShader: `\ + + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} #include #include + varying vec3 vPos; + varying vec2 vUv; uniform mat4 modelMatrix; - - uniform float uTime; - uniform float uUJump; - uniform float uVJump; - uniform float uTiling; - uniform float uSpeed; - uniform float uFlowStrength; - uniform float uFlowOffset; uniform vec3 sunPosition; - uniform vec3 playerPosition; - uniform vec3 playerDirection; - uniform sampler2D waterDerivativeHeightTexture; - uniform sampler2D waterNoiseTexture; - uniform sampler2D flowmapTexture; + uniform vec3 sunDirection; - - varying vec2 vUv; - varying vec3 vPos; - - float frac(float v) - { - return v - floor(v); - } - vec3 FlowUVW (vec2 uv, vec2 flowVector, vec2 jump, float flowOffset, float tiling, float time, bool flowB) { - float phaseOffset = flowB ? 0.5 : 0.; - float progress = frac(time + phaseOffset); - vec3 uvw; - uvw.xy = uv - flowVector * (progress + flowOffset); - uvw.xy *= tiling; - uvw.xy += phaseOffset; - uvw.xy += (time - progress) * jump; - uvw.z = 1. - abs(1. - 2. * progress); - return uvw; + uniform sampler2D tDepth; + uniform sampler2D tDudv; + uniform float cameraNear; + uniform float cameraFar; + uniform vec2 resolution; + + uniform sampler2D waterNormalTexture1; + uniform sampler2D waterNormalTexture2; + + float getDepth( const in vec2 screenPosition ) { + return unpackRGBAToDepth( texture2D( tDepth, screenPosition ) ); } - vec3 UnpackDerivativeHeight (vec4 textureData) { - vec3 dh = textureData.agb; - dh.xy = dh.xy * 2. - 1.; - return dh; + + float getViewZ( const in float depth ) { + return perspectiveDepthToViewZ( depth, cameraNear, cameraFar ); + } + vec4 getNoise( vec2 uv ) { + vec2 uv0 = ( uv / 103.0 ) + vec2(uTime / 34.0, uTime / 58.0); + vec2 uv1 = uv / 107.0-vec2( uTime / -38.0, uTime / 64.0 ); + vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( uTime / 202.0, uTime / 194.0 ); + vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( uTime / 218.0, uTime / -226.0 ); + vec4 noise = texture2D( waterNormalTexture1, uv0 ) + + texture2D( waterNormalTexture1, uv1 ) + + texture2D( waterNormalTexture2, uv2 ) + + texture2D( waterNormalTexture2, uv3 ); + return noise * 0.5 - 1.0; + } + void sunLight( const vec3 surfaceNormal, const vec3 eyeDirection, float shiny, float spec, float diffuse, inout vec3 diffuseColor, inout vec3 specularColor ) { + vec3 reflection = normalize( reflect( -sunDirection, surfaceNormal ) ); + float direction = max( 0.0, dot( eyeDirection, reflection ) ); + specularColor += pow( direction, shiny ) * vec3(0.3, 0.3, 0.3) * spec; + diffuseColor += max( dot( sunDirection, surfaceNormal ), 0.0 ) * vec3(0.3, 0.3, 0.3) * diffuse; } - - float shineDamper = 10.; - float reflectivity = 0.1; void main() { - vec4 worldPosition = modelMatrix * vec4( vPos, 1.0 ); - vec3 sunToPlayer = normalize(sunPosition - playerPosition); - vec3 worldToEye = vec3(playerPosition.x + sunToPlayer.x * 100., playerPosition.y, playerPosition.z + sunToPlayer.z * 100.)-worldPosition.xyz; - - vec3 eyeDirection = normalize( worldToEye ); - // vec3 eyeDirection = normalize(worldPosition.xyz - cameraPosition); - vec2 uv = worldPosition.xz * 0.05; - vec2 flowmap = texture2D(flowmapTexture, uv / 5.).rg * 2. - 1.; - flowmap *= uFlowStrength; - float noise = texture2D(flowmapTexture, uv).a; - float time = uTime * uSpeed + noise; - vec2 jump = vec2(uUJump, uVJump); - vec3 uvwA = FlowUVW(uv, flowmap, jump, uFlowOffset, uTiling, time / 1.7, false); - vec3 uvwB = FlowUVW(uv, flowmap, jump, uFlowOffset, uTiling, time / 1.7, true); - vec3 dhA = UnpackDerivativeHeight(texture2D(waterDerivativeHeightTexture, uvwA.xy * 0.5)) * uvwA.z * 5.5; - vec3 dhB = UnpackDerivativeHeight(texture2D(waterDerivativeHeightTexture, uvwB.xy * 0.5)) * uvwB.z * 5.5; - vec3 surfaceNormal = normalize(vec3(-(dhA.xy + dhB.xy), 1.)); - vec3 fromSunVector = worldPosition.xyz - (sunPosition + playerPosition); - vec3 reflectedLight = reflect(normalize(fromSunVector), surfaceNormal); - float specular = max(dot(reflectedLight, eyeDirection), 0.0); - specular = pow(specular, shineDamper); - vec3 specularHighlight = vec3(0.0282 * 0.9, 0.431 * 0.9, 0.47 * 0.9) * specular * reflectivity; - - vec4 texA = texture2D(waterNoiseTexture, uvwA.xy) * uvwA.z; - vec4 texB = texture2D(waterNoiseTexture, uvwB.xy) * uvwB.z; - gl_FragColor = (texA + texB) * vec4(0.048 / 1.5, 0.24 / 1.5, 0.384 / 1.5, 0.97) + vec4(0.0282, 0.431, 0.47, 0.); - gl_FragColor.rgb /= 3.; - gl_FragColor += vec4( specularHighlight, 0.0 ); + vec4 worldPosition = modelMatrix * vec4( vPos, 1.0 ); + vec4 noise = getNoise( worldPosition.xz * 2.); + vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) ); + vec3 diffuseLight = vec3(1.0); + vec3 specularLight = vec3(0.1, 0.6, 0.6); + vec3 worldToEye = worldPosition.xyz; + vec3 eyeDirection = normalize( worldToEye ); + sunLight( surfaceNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight ); + float distance = length(worldToEye); + float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 ); + + vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) * 0.2 ) * vec3(0.5, 0.5, 0.5); + vec3 albedo = ( vec3(0.3, 0.3, 0.3) * diffuseLight * 0.025 + scatter ); + vec3 outgoingLight = albedo; + gl_FragColor = (vec4( outgoingLight, 0.95 )) + + vec4(0.0282, 0.470, 0.431, 0.); + + // foam + vec2 screenUV = gl_FragCoord.xy / resolution; + + float fragmentLinearEyeDepth = getViewZ( gl_FragCoord.z ); + float linearEyeDepth = getViewZ( getDepth( screenUV ) ); + + float diff = saturate( fragmentLinearEyeDepth - linearEyeDepth ); + if(diff > 0.){ + vec2 channelA = texture2D( tDudv, vec2(0.25 * worldPosition.x + uTime * 0.04, 0.5 * worldPosition.z - uTime * 0.03) ).rg; + vec2 channelB = texture2D( tDudv, vec2(0.5 * worldPosition.x - uTime * 0.05, 0.35 * worldPosition.z + uTime * 0.04) ).rg; + vec2 displacement = (channelA + channelB) * 0.5; + displacement = ( ( displacement * 2.0 ) - 1.0 ) * 1.0; + diff += displacement.x; - - - ${THREE.ShaderChunk.logdepthbuf_fragment} + + // vec2 displacement = texture2D( tDudv, ( worldPosition.xz * 1.0 ) - uTime * 0.05 ).rg; + // displacement = ( ( displacement * 2.0 ) - 1.0 ) * 1.0; + // diff += displacement.x; + + gl_FragColor = mix( vec4(1.0, 1.0, 1.0, gl_FragColor.a), gl_FragColor, step( 0.05, diff ) ); + } + + + ${THREE.ShaderChunk.logdepthbuf_fragment} } `, side: THREE.DoubleSide, transparent: true - // fog: true }); - // const {renderer} = useInternals(); - // renderer.context.depthFunc(renderer.context.LESS) - // material.extensions = renderer.getContext().getExtension("WEBGL_multi_draw"); - - - super(geometry, material, allocator); this.frustumCulled = false; @@ -338,15 +294,10 @@ class WaterMesh extends BatchedMesh { this.allocator = allocator; this.physicsObjects = []; - this.lightMapper = lightMapper; - this.localVector5 = new THREE.Vector3(); this.physicsObjectToChunkMap = new Map(); } -// async addChunk(chunk, { signal }) { -// const renderData = await this.getChunkRenderData(chunk, signal); -// this.drawChunk(chunk, renderData, signal); -// } + async getChunkRenderData(chunk, signal) { const meshData = await this.procGenInstance.dcWorkerManager.generateLiquidChunk( @@ -430,49 +381,66 @@ class WaterMesh extends BatchedMesh { geometry.index.update(indexOffset, meshData.indices.length); }; const _handleMesh = () => { + const chunkSize = chunkWorldSize * chunk.lod; localSphere.center.set( - (chunk.min.x + 0.5) * chunkWorldSize, - (chunk.min.y + 0.5) * chunkWorldSize, - (chunk.min.z + 0.5) * chunkWorldSize + (chunk.min.x + 0.5) * chunkSize, + (chunk.min.y + 0.5) * chunkSize, + (chunk.min.z + 0.5) * chunkSize ) .applyMatrix4(this.matrixWorld); localSphere.radius = chunkRadius; + + localVector3D.set(chunk.min.x, chunk.min.y, chunk.min.z).multiplyScalar(chunkSize); // min + localVector3D2.set(chunk.min.x, chunk.min.y, chunk.min.z).addScalar(chunk.lod).multiplyScalar(chunkSize); // max + const geometryBinding = this.allocator.alloc( meshData.positions.length, meshData.indices.length, - localSphere + localSphere, + localVector3D, + localVector3D2, + this.appMatrix, + meshData.peeks ); + // const geometryBinding = this.allocator.alloc( + // meshData.positions.length, + // meshData.indices.length, + // localSphere + // ); _renderMeshDataToGeometry( meshData, this.allocator.geometry, geometryBinding ); - // signal.addEventListener('abort', (e) => { - // this.allocator.free(geometryBinding); - // }); - // let called = false; + let called = false; const onchunkremove = e => { - // const {chunk: removeChunk} = e; - // if (chunk.equalsNodeLod(removeChunk)) { - /* if (!called) { - called = true; - } else { - console.warn('double destroy'); - debugger; - } */ - - this.allocator.free(geometryBinding); + this.allocator.free(geometryBinding); - tracker.offChunkRemove(chunk, onchunkremove); - // } + tracker.offChunkRemove(chunk, onchunkremove); + // const {chunk: removeChunk} = e.data; + // if (chunk.equalsNodeLod(removeChunk)) { + // if (!called) { + // called = true; + // } else { + // console.warn('double destroy'); + // debugger; + // } + + // this.allocator.free(geometryBinding); + + // tracker.removeEventListener('chunkremove', onchunkremove); + // } }; tracker.onChunkRemove(chunk, onchunkremove); + // tracker.addEventListener('chunkremove', onchunkremove); }; _handleMesh(); const _handlePhysics = async () => { + this.matrixWorld.decompose(localVector, localQuaternion, localVector2); + waterWorldPosition.copy(localVector); const physicsObject = this.physics.addCookedGeometry( geometryBuffer, localVector, @@ -484,38 +452,41 @@ class WaterMesh extends BatchedMesh { - this.physics.disableGeometryQueries(physicsObject); - physicsObject.coord = chunk; + // this.physics.disableGeometryQueries(physicsObject); physicsObject.positions = meshData.positions; - physicsObject.center = new THREE.Vector3().set( - (chunk.x + 0.5) * chunkWorldSize, - (chunk.y + 0.5) * chunkWorldSize, - (chunk.z + 0.5) * chunkWorldSize - ).applyMatrix4(this.matrixWorld); - - const onchunkremove = () => { - // const {chunk: removeChunk} = e; - // if (chunk.equalsNodeLod(removeChunk)) { - this.physics.removeGeometry(physicsObject); - this.physicsObjects.splice( - this.physicsObjects.indexOf(physicsObject), - 1 - ); - this.physicsObjectToChunkMap.delete(physicsObject); + - tracker.offChunkRemove(chunk, onchunkremove); - // } + + const onchunkremove = e => { + this.physics.removeGeometry(physicsObject); + + const index = this.physicsObjects.indexOf(physicsObject); + this.physicsObjects.splice(index, 1); + this.physicsObjectToChunkMap.delete(physicsObject); + + tracker.offChunkRemove(chunk, onchunkremove); + // const {chunk: removeChunk} = e.data; + // if (chunk.equalsNodeLod(removeChunk)) { + // if (!called) { + // called = true; + // } else { + // console.warn('double destroy'); + // debugger; + // } + + // this.physics.removeGeometry(physicsObject); + // this.physicsObjects.splice( + // this.physicsObjects.indexOf(physicsObject), + // 1 + // ); + // this.physicsObjectToChunkMap.delete(physicsObject); + + // tracker.removeEventListener('chunkremove', onchunkremove); + // } } + // tracker.addEventListener('chunkremove', onchunkremove); tracker.onChunkRemove(chunk, onchunkremove); - - // signal.addEventListener('abort', (e) => { - // this.physics.removeGeometry(physicsObject); - // this.physicsObjects.splice( - // this.physicsObjects.indexOf(physicsObject), - // 1 - // ); - // }); }; _handlePhysics(); } @@ -525,12 +496,6 @@ class WaterMesh extends BatchedMesh { // XXX needs to apply to the terrain mesh too, though the terrain mesh is driving the lighting (maybe rethink this) // XXX create a new lighting app which tracks the lighting only // XXX maybe do the same for hte heightfield? - if (this.lightMapper.updateCoord(min2xCoord)) { - this.material.uniforms.uLightBasePosition.value.copy( - this.lightMapper.lightBasePosition - ); - this.material.uniforms.uLightBasePosition.needsUpdate = true; - } } } @@ -583,97 +548,25 @@ class WaterChunkGenerator { } } } -// disposeChunk(chunk) { -// const binding = chunk.binding; -// if (binding) { -// const { abortController } = binding; -// abortController.abort(abortError); -// chunk.binding = null; -// } -// } -// async relodChunks(oldChunks, newChunk) { -// // console.log('relod chunk', oldChunk, newChunk); - -// try { -// const oldAbortControllers = oldChunks.map(oldChunk => { -// return oldChunk.binding.abortController; -// }); -// // const oldAbortController = oldChunk.binding.abortController; -// const newSignal = this.bindChunk(newChunk); - -// const abortOldChunks = e => { -// for (const oldAbortController of oldAbortControllers) { -// oldAbortController.abort(abortError); -// } -// }; -// newSignal.addEventListener('abort', abortOldChunks); - -// const renderData = await this.waterMesh.getChunkRenderData( -// newChunk, -// newSignal -// ); - -// newSignal.removeEventListener('abort', abortOldChunks); - -// for (const oldChunk of oldChunks) { -// this.disposeChunk(oldChunk); -// } -// this.waterMesh.drawChunk(newChunk, renderData, newSignal); -// } catch (err) { -// if (!err?.isAbortError) { -// console.warn(err); -// } -// } -// } async relodChunksTask(task, tracker) { // console.log('got task', task); // const {oldChunks, newChunk, signal} = task; // console.log('relod chunk', task); try { - /* const oldAbortControllers = oldChunks.map(oldChunk => { - return oldChunk.binding.abortController; - }); */ - // const oldAbortController = oldChunk.binding.abortController; - // const newSignal = this.bindChunk(newChunk); - - /* const abortOldChunks = e => { - for (const oldAbortController of oldAbortControllers) { - oldAbortController.abort(abortError); - } - }; - newSignal.addEventListener('abort', abortOldChunks); */ - let {maxLodNode, newNodes, oldNodes, signal} = task; - // newNodes = newNodes.filter(newNode => newNode.lod <= 2); - // console.log('got new nodes', newNodes, oldNodes); - const renderDatas = await Promise.all(newNodes.map(newNode => this.waterMesh.getChunkRenderData( newNode, signal ))); signal.throwIfAborted(); - // console.log('got data', renderDatas); - - // tracker.emitChunkDestroy(maxLodNode); for (const oldNode of oldNodes) { console.log('destroy old node', oldNode); tracker.emitChunkDestroy(oldNode); } - - /* for (const oldNode of oldNodes) { - const liveChunk = liveChunks.find(chunk => chunk.min.equals(oldNode.min)); - if (liveChunk) { - liveChunk.destroy(); - liveChunks.splice(liveChunks.indexOf(liveChunk), 1); - } - } */ - /* for (const oldNode of oldNodes) { - oldNode.destroy(); - } */ for (let i = 0; i < newNodes.length; i++) { const newNode = newNodes[i]; const renderData = renderDatas[i]; @@ -704,10 +597,7 @@ class WaterChunkGenerator { } update(timestamp, timeDiff) { - for (const mesh of this.getMeshes()) { - //console.log(mesh.physicsObjects) - //mesh.update(timestamp, timeDiff); - } + } destroy() { @@ -743,13 +633,12 @@ export default (e) => { const lods = app.getComponent('lods') ?? defaultNumNods; const minLodRange = app.getComponent('minLodRange') ?? defaultMinLodRange; const debug = app.getComponent('debug') ?? false; -// let water = null; -// let waterPhysicsId = null; - const waterSurfacePos = new THREE.Vector3(0, 63, 0); - const cameraWaterSurfacePos = new THREE.Vector3(0, 63, 0); + + const waterSurfacePos = new THREE.Vector3(0, 0, 0); + const particleWaterSurfacePos = new THREE.Vector3(0, 0, 0); + const cameraWaterSurfacePos = new THREE.Vector3(0, 0, 0); let contactWater = false; - //let wholeBelowwWater = false; -// let floatOnWater = false; + let cameraDir = new THREE.Vector3(); let playerDir = new THREE.Vector3(); const playerHeadPos = new THREE.Vector3(); @@ -813,11 +702,7 @@ export default (e) => { physics, textures, }); - // tracker = procGenInstance.getChunkTracker({ - // numLods, - // trackY: true, - // relod: true, - // }); + tracker = procGenInstance.getChunkTracker({ lods, minLodRange, @@ -828,11 +713,14 @@ export default (e) => { app.add(tracker.debugMesh); tracker.debugMesh.updateMatrixWorld(); } + // tracker.addEventListener('coordupdate', coordupdate); // tracker.addEventListener('chunkdatarequest', chunkdatarequest); // tracker.addEventListener('chunkadd', chunkadd); tracker.onChunkDataRequest(chunkdatarequest); tracker.onChunkAdd(chunkadd); - + // tracker.addEventListener('chunkremove', chunkremove); + // tracker.addEventListener('chunkrelod', chunkrelod); + const renderPosition = app.getComponent('renderPosition'); if (renderPosition) { tracker.update(localVector.fromArray(renderPosition)); @@ -840,13 +728,6 @@ export default (e) => { app.addEventListener('componentupdate', componentupdate); if (wait) { - // await new Promise((accept, reject) => { - // tracker.addEventListener('update', () => { - // accept(); - // }, { - // once: true, - // }); - // }); await tracker.waitForLoad(); } app.add(generator.object); @@ -857,7 +738,12 @@ export default (e) => { app.getPhysicsObjects = () => generator ? generator.getPhysicsObjects() : []; app.getChunkForPhysicsObject = (physicsObject) => generator ? generator.getChunkForPhysicsObject(physicsObject) : null; + const coordupdate = (e) => { + const {coord} = e.data; + generator.getMeshes()[0].updateCoord(coord); + }; const chunkdatarequest = (e) => { + const {chunk, waitUntil, signal} = e; // console.log('lod tracker chunkdatarequest', chunk); @@ -877,20 +763,7 @@ export default (e) => { const {renderData, chunk} = e; generator.getMeshes()[0].drawChunk(chunk, renderData, tracker); }; - // const chunkadd = (e) => { - // const {chunk, waitUntil} = e.data; - // waitUntil(generator.generateChunk(chunk)); - // }; - // const chunkremove = (e) => { - // const {chunk} = e.data; - // generator.disposeChunk(chunk); - // }; - // const chunkrelod = (e) => { - // const {oldChunks, newChunk} = e.data; - // generator.relodChunks(oldChunks, newChunk); - // }; - - + const localVector01 = new THREE.Vector3(); const localVector02 = new THREE.Vector3(); const localVector03 = new THREE.Vector3(); @@ -898,6 +771,7 @@ export default (e) => { const localVector05 = new THREE.Vector3(); const localVector06 = new THREE.Vector3(); const localVector07 = new THREE.Vector3(); + const qt01 = new THREE.Quaternion(); @@ -960,6 +834,29 @@ export default (e) => { } } + const pixelRatio = renderer.getPixelRatio(); + + const renderTarget = new THREE.WebGLRenderTarget( + window.innerWidth * pixelRatio, + window.innerHeight * pixelRatio + ); + renderTarget.texture.minFilter = THREE.NearestFilter; + renderTarget.texture.magFilter = THREE.NearestFilter; + renderTarget.texture.generateMipmaps = false; + renderTarget.stencilBuffer = false; + + const depthMaterial = new THREE.MeshDepthMaterial(); + depthMaterial.depthPacking = THREE.RGBADepthPacking; + depthMaterial.blending = THREE.NoBlending; + + + const geometry = new THREE.SphereGeometry( 0.5, 32, 16 ); + const material = new THREE.MeshBasicMaterial( { color: 0xffff00 , transparent:true, opacity:0.3} ); + const sphere = new THREE.Mesh( geometry, material ); + app.add( sphere ); + const material2 = new THREE.MeshBasicMaterial( { color: 0xff0000, transparent:true, opacity:0.3} ); + const sphere2 = new THREE.Mesh( geometry, material2 ); + app.add( sphere2 ); useFrame(({timestamp, timeDiff}) => { if (!!tracker && !app.getComponent('renderPosition')) { @@ -970,87 +867,74 @@ export default (e) => { .decompose(localVector, localQuaternion, localVector2); tracker.update(localVector); if(generator && localPlayer.avatar){ - if(!alreadySetComposer){ - if(renderSettings.findRenderSettings(scene)){ - for(const pass of renderSettings.findRenderSettings(scene).passes){ - if(pass.constructor.name === 'WebaWaterPass'){ - pass._selects.push(generator.getMeshes()[0]); - pass.opacity = 0.12; - reflectionSsrPass = pass; - } - } - alreadySetComposer = true; - console.log(renderSettings.findRenderSettings(scene)) - } - } - if(reflectionSsrPass){ - reflectionSsrPass.ssrMaterial.uniforms.uTime.value = timestamp / 1000; - reflectionSsrPass.ssrMaterial.uniforms.distortionTexture.value = dudvMap; - } - - - let playerIsOnSurface = false; - let cameraIsOnSurface = false; - let min = null; - tempPhysics = null; - localVector02.set(localPlayer.position.x, localPlayer.position.y - localPlayer.avatar.height, localPlayer.position.z); - for(const physicsId of generator.getPhysicsObjects()){ - for(let i = 0; i < physicsId.positions.length / 3; i++){ - tempPos.set(app.position.x + physicsId.positions[i * 3 + 0], app.position.y + physicsId.positions[i * 3 + 1], app.position.z + physicsId.positions[i * 3 + 2]); - if(!min || tempPos.distanceTo(localVector02) < min){ - min = tempPos.distanceTo(localVector02); - tempPhysicsPos.set(tempPos.x, tempPos.y, tempPos.z); - tempPhysics = physicsId; - } - } - } - // trace water surface + // set post processing and handle material uniforms { - if(tempPhysics){ - generator.physics.enableGeometryQueries(tempPhysics); - localVector03.set(localPlayer.position.x, localPlayer.position.y, localPlayer.position.z); - const result3 = physics.raycast(localVector03, downVector); - if(result3){ - if(result3.objectId === tempPhysics.physicsId){ - waterSurfacePos.set(result3.point[0], result3.point[1], result3.point[2]); - playerIsOnSurface = true; - if(!playerHighestWaterSurface) - playerHighestWaterSurface = result3.point[1]; - else - playerHighestWaterSurface = playerHighestWaterSurface < waterSurfacePos.y ? waterSurfacePos.y : playerHighestWaterSurface; + if(!alreadySetComposer){ + if(renderSettings.findRenderSettings(scene)){ + for(const pass of renderSettings.findRenderSettings(scene).passes){ + if(pass.constructor.name === 'WebaWaterPass'){ + pass._selects.push(generator.getMeshes()[0]); + pass.opacity = 0.12; + webaWaterPass = pass; + } + if(pass.constructor.name === 'WebaverseRenderPass'){ + pass.foamDepthMaterial = depthMaterial; + pass.foamRenderTarget = renderTarget; + pass.water = generator.getMeshes()[0]; + pass.scene = scene; + pass.camera = camera; + pass.foamInvisibleList.push(localPlayer.avatar.app); + pass.foamInvisibleList.push(generator.getMeshes()[0]); + foamPass = pass; + generator.getMeshes()[0].material.uniforms.cameraNear.value = camera.near; + generator.getMeshes()[0].material.uniforms.cameraFar.value = camera.far; + generator.getMeshes()[0].material.uniforms.resolution.value.set( + window.innerWidth * window.devicePixelRatio, + window.innerHeight * window.devicePixelRatio + ); + generator.getMeshes()[0].material.uniforms.tDudv.value = dudvMap2; + generator.getMeshes()[0].material.uniforms.tDepth.value = renderTarget.texture; + } } + alreadySetComposer = true; } - - generator.physics.disableGeometryQueries(tempPhysics); } - } - // trace water surface + if(webaWaterPass){ + webaWaterPass.ssrMaterial.uniforms.uTime.value = timestamp / 1000; + webaWaterPass.ssrMaterial.uniforms.distortionTexture.value = dudvMap; + } + generator.getMeshes()[0].material.uniforms.uTime.value = timestamp / 1000; + } + // { + // for(const physicsObject of generator.getPhysicsObjects()){ + // generator.physics.enableGeometryQueries(physicsObject); + // } + // localVector03.set(localPlayer.position.x, localPlayer.position.y, localPlayer.position.z); + // const result3 = physics.raycast(localVector03, downVector); + // for(const physicsObject of generator.getPhysicsObjects()){ + // if(result3.objectId === physicsObject.physicsId){ + // waterSurfacePos.set(result3.point[0], result3.point[1], result3.point[2]); + // particleWaterSurfacePos.set(result3.point[0], result3.point[1], result3.point[2]).sub(waterWorldPosition); + // } + // generator.physics.disableGeometryQueries(physicsObject) + // } + // } { - if(tempPhysics){ - generator.physics.enableGeometryQueries(tempPhysics); - localVector04.set(camera.position.x + cameraDir.x * 0.2, camera.position.y, camera.position.z + cameraDir.z * 0.2); - const result4 = physics.raycast(localVector04, downVector); - if(result4){ - if(result4.objectId === tempPhysics.physicsId){ - cameraWaterSurfacePos.set(result4.point[0], result4.point[1], result4.point[2]); - cameraIsOnSurface = true; - if(!cameraHighestWaterSurface) - cameraHighestWaterSurface = result4.point[1]; - else - cameraHighestWaterSurface = cameraHighestWaterSurface < cameraWaterSurfacePos.y ? cameraWaterSurfacePos.y : cameraHighestWaterSurface; - } - } - generator.physics.disableGeometryQueries(tempPhysics); - } - } - - contactWater = false; - if(generator.getPhysicsObjects().length < 1){ - contactWater = lastContactWater; - } - else if(tempPhysics){ - generator.physics.enableGeometryQueries(tempPhysics); - + let min = null; + tempPhysics = null; + localVector02.set(localPlayer.position.x, localPlayer.position.y - localPlayer.avatar.height, localPlayer.position.z); + for(const physicsObject of generator.getPhysicsObjects()){ + for(let i = 0; i < physicsObject.positions.length / 3; i++){ + tempPos.set(physicsObject.positions[i * 3 + 0], physicsObject.positions[i * 3 + 1], physicsObject.positions[i * 3 + 2]).add(waterWorldPosition); + if(!min || tempPos.distanceTo(localVector02) < min){ + min = tempPos.distanceTo(localVector02); + tempPhysicsPos.set(tempPos.x, tempPos.y, tempPos.z); + tempPhysics = physicsObject; + } + } + generator.physics.enableGeometryQueries(physicsObject); + } + if(tempPhysics){ tempDir.set(tempPhysicsPos.x - localPlayer.position.x, tempPhysicsPos.y - (localPlayer.position.y - localPlayer.avatar.height), tempPhysicsPos.z - localPlayer.position.z); tempDir.normalize(); @@ -1059,81 +943,37 @@ export default (e) => { localVector01.set(tempPhysicsPos.x + tempDir.x * detectDistance, tempPhysicsPos.y + tempDir.y * detectDistance, tempPhysicsPos.z + tempDir.z * detectDistance); localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); localVector06.copy(localVector01).sub(localVector05); - - localVector07.set(tempPhysicsPos.x - tempDir.x * detectDistance, tempPhysicsPos.y - tempDir.y * detectDistance, tempPhysicsPos.z - tempDir.z * detectDistance); - const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; - - { - let result = null; - if(count % 2 === 0){ - upVector.crossVectors(localVector01, localVector05); - mx.lookAt(localVector01, localVector05, upVector); - qt.setFromRotationMatrix(mx); - result = generator.physics.raycast(localVector01, qt); - if(result){ - if(result.objectId === tempPhysics.physicsId && result.distance <= ds){ - testContact1 = true; - } - else{ - if(result.distance > ds){ - testContact1 = false; - } - else{ - testContact1 = rayCastByEliminatingChunk(generator, result, ds, localVector01, qt, tempPhysics); - } - } - } - } - else{ - upVector2.crossVectors(localVector07, localVector05); - mx2.lookAt(localVector07, localVector05, upVector2); - qt2.setFromRotationMatrix(mx2); - result = generator.physics.raycast(localVector07, qt2); - if(result){ - if(result.objectId === tempPhysics.physicsId && result.distance <= ds){ - testContact2 = true; - } - else{ - if(result.distance > ds){ - testContact2 = false; - } - else{ - testContact2 = rayCastByEliminatingChunk(generator, result, ds, localVector07, qt2, tempPhysics) - } - } - } - - } - - if(testContact2 === testContact1){ - // console.log('detect error', testContact2, testContact1); - contactWater = lastContactWater; - } - else{ - if(testContact1){ - contactWater = true; - } - else{ - contactWater = false; - } - } + upVector.crossVectors(localVector01, localVector05); + mx.lookAt(localVector01, localVector05, upVector); + qt.setFromRotationMatrix(mx); + let result = generator.physics.raycast(localVector01, qt); + + contactWater = false; + for(const physicsObject of generator.getPhysicsObjects()){ + if(result.objectId === physicsObject.physicsId && result.distance <= ds){ + contactWater = true; + // sphere.position.set(result.point[0], result.point[1], result.point[2]).sub(waterWorldPosition); + localVector07.set(result.point[0], result.point[1], result.point[2]); + } + generator.physics.disableGeometryQueries(physicsObject) } - - - if(playerIsOnSurface){ - if(waterSurfacePos.y > localPlayer.position.y - localPlayer.avatar.height){ - contactWater = true; - } - else{ - contactWater = false; - } + if(contactWater){ + if(localVector07.y - localPlayer.position.y > 0.1 || localVector07.y - (localPlayer.position.y - localPlayer.avatar.height) > localPlayer.avatar.height * 0.5){ + waterSurfacePos.copy(localVector07); + particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); + } + else{ + waterSurfacePos.y = 1000; + particleWaterSurfacePos.y = 1000; + } } - - generator.physics.disableGeometryQueries(tempPhysics); + } } - + sphere2.position.copy(particleWaterSurfacePos); + app.updateMatrixWorld(); + if(!contactWater){ if(localPlayer.hasAction('swim')){ //console.log('remove'); @@ -1170,53 +1010,11 @@ export default (e) => { } } } + - if(!playerIsOnSurface){ - if(playerHighestWaterSurface) - waterSurfacePos.y = playerHighestWaterSurface; - if(!localPlayer.hasAction('swim')){ - contactWater = false; - } - } - if(!cameraIsOnSurface){ - if(cameraHighestWaterSurface) - cameraWaterSurfacePos.y = cameraHighestWaterSurface; - } - // if(testContact2 !== testContact1) - lastContactWater = contactWater; - - - - if(localPlayer.hasAction('swim')){ - if(localPlayer.getAction('swim').animationType === 'breaststroke'){ - if(lastSwimmingHand !== localPlayer.characterSfx.currentSwimmingHand){ - if(localPlayer.characterSfx.currentSwimmingHand !== null){ - localPlayer.getAction('swim').swimDamping = 1; - } - lastSwimmingHand = localPlayer.characterSfx.currentSwimmingHand; - } - if(localPlayer.getAction('swim').swimDamping < 4){ - localPlayer.getAction('swim').swimDamping *= 1.05; - } - else{ - localPlayer.getAction('swim').swimDamping = 4; - } - - } - else if(localPlayer.getAction('swim').animationType === 'freestyle'){ - localPlayer.getAction('swim').swimDamping = 0; - } - else{ - localPlayer.getAction('swim').swimDamping = 4; - } - - } - generator.getMeshes()[0].material.uniforms.uTime.value = timestamp / 1000; - generator.getMeshes()[0].material.uniforms.playerPosition.value.copy(localPlayer.position); - generator.getMeshes()[0].material.uniforms.playerDirection.value.copy(playerDir); + } } - count++; }); useCleanup(() => { @@ -1224,4124 +1022,10 @@ export default (e) => { if (tracker) { tracker.destroy(); } - }); - } - //#################################################################### underwater mask ################################################################### - { - - // const color = 0xFF0000; - // const density = 0.1; - // rootScene.fog = new THREE.FogExp2(color, 1); - // rootScene.updateMatrixWorld(); - - //rootScene.fog = new THREE.FogExp2(new THREE.Color(0/255, 5/255, 10/255).getHex(), 0.1); - - - - - const geometry = new THREE.PlaneGeometry( 2, 2 ); - const material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - cameraWaterSurfacePos:{ - value: new THREE.Vector3() - }, - contactWater:{ - value: false - } - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - uniform float uTime; - - varying vec2 vUv; - varying vec3 vPos; - - void main() { - vUv = uv; - - - vec3 pos = position; - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - - gl_Position = projectionPosition; - vPos = modelPosition.xyz; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform bool contactWater; - //uniform sampler2D sphereTexture; - uniform vec3 cameraWaterSurfacePos; - - varying vec2 vUv; - varying vec3 vPos; - - void main() { - gl_FragColor = vec4(0.0141, 0.235, 0.25, 0.7); - if(!contactWater || vPos.y > cameraWaterSurfacePos.y) - discard; - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - //blending: THREE.AdditiveBlending, - depthWrite: false, - }); - const mask = new THREE.Mesh( geometry, material ); - //app.add( mask ); - // camera.add(mask); - let cameraHasMask = false; - let alreadySetComposer = false; - useFrame(({timestamp}) => { - if(!alreadySetComposer && renderSettings.findRenderSettings(scene)){ - renderSettings.findRenderSettings(scene).fog.color.r = 4 / 255; - renderSettings.findRenderSettings(scene).fog.color.g = 41.5 / 255; - renderSettings.findRenderSettings(scene).fog.color.b = 44.5 / 255; - alreadySetComposer = true; - } - - - // mask.position.set(camera.position.x + cameraDir.x * 0.4, camera.position.y, camera.position.z + cameraDir.z * 0.4); - // mask.rotation.copy(camera.rotation); - mask.position.set(0, 0, -0.2); - mask.material.uniforms.uTime.value = timestamp / 1000; - mask.material.uniforms.cameraWaterSurfacePos.value.copy(cameraWaterSurfacePos); - mask.material.uniforms.contactWater.value = contactWater; - if(camera.position.y + 0.03 < cameraWaterSurfacePos.y && contactWater){ - if(renderSettings.findRenderSettings(scene)){ - renderSettings.findRenderSettings(scene).fog.density = 0.05; - } - } - else{ - if(renderSettings.findRenderSettings(scene)){ - renderSettings.findRenderSettings(scene).fog.density = 0; - } - } - if(camera.position.y - 0.03 < cameraWaterSurfacePos.y && contactWater){ - if(!cameraHasMask){ - camera.add(mask); - cameraHasMask = true; - } - } - else{ - if(cameraHasMask){ - camera.remove(mask); - cameraHasMask = false; - } - } - app.updateMatrixWorld(); - + app.removeEventListener('componentupdate', componentupdate); }); } - //################################################################ bubble ########################################################### - { - const particleCount = 40; - let info = { - velocity: [particleCount], - offset: [particleCount], - lastTime:[particleCount] - } - - const _getGeometry = geometry => { - //console.log(geometry) - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - - - const scales = new Float32Array(particleCount); - const scalesAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scalesAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const startTimeAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - startTimeAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('startTime', startTimeAttribute); - - - const offset = new Float32Array(particleCount * 2); - const offsetAttribute = new THREE.InstancedBufferAttribute(offset, 2); - geometry2.setAttribute('offset', offsetAttribute); - - - return geometry2; - }; - - const material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - cameraBillboardQuaternion: { - value: new THREE.Quaternion(), - }, - bubbleTexture1: { - value: bubbleTexture1, - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - uniform vec4 cameraBillboardQuaternion; - - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying vec2 vOffset; - - - attribute vec3 positions; - attribute vec3 color; - attribute float scales; - attribute float opacity; - attribute vec2 offset; - - - vec3 rotateVecQuat(vec3 position, vec4 q) { - vec3 v = position.xyz; - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); - } - void main() { - vUv = uv; - vPos = position; - // vOpacity = opacity; - // vColor = color; - vOffset = offset; - vec3 pos = position; - pos = rotateVecQuat(pos, cameraBillboardQuaternion); - pos*=scales; - pos+=positions; - //pos = qtransform(pos, quaternions); - //pos.y=cos(uTime/100.); - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform sampler2D bubbleTexture1; - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying vec2 vOffset; - - void main() { - vec4 bubble = texture2D( - bubbleTexture1, - vec2( - vUv.x / 6. + vOffset.x, - vUv.y / 5. + vOffset.y - ) - ); - - gl_FragColor = bubble; - if(gl_FragColor.a < 0.25){ - discard; - } - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - // blending: THREE.AdditiveBlending, - // depthWrite: false, - //blending: 1, - - }); - let mesh = null; - function addInstancedMesh() { - const geometry2 = new THREE.PlaneGeometry( .02, .02 ); - const geometry = _getGeometry(geometry2); - mesh = new THREE.InstancedMesh(geometry, material, particleCount); - const positionsAttribute = mesh.geometry.getAttribute('positions'); - for (let i = 0; i < particleCount; i++) { - positionsAttribute.setXYZ(i, localPlayer.position.x + Math.random() * 5, localPlayer.position.y + Math.random() * 5, localPlayer.position.z + Math.random() * 5); - info.velocity[i] = new THREE.Vector3(); - - } - positionsAttribute.needsUpdate = true; - app.add(mesh); - } - addInstancedMesh(); - let maxEmmit = 5; - let lastEmmitTime = 0; - useFrame(({timestamp}) => { - if (mesh && localPlayer.avatar) { - let currentEmmit = 0; - //console.log(Math.floor(currentSpeed * 10 + 1)) - const opacityAttribute = mesh.geometry.getAttribute('opacity'); - const offsetAttribute = mesh.geometry.getAttribute('offset'); - const positionsAttribute = mesh.geometry.getAttribute('positions'); - const scalesAttribute = mesh.geometry.getAttribute('scales'); - const startTimeAttribute = mesh.geometry.getAttribute('startTime'); - if(timestamp - lastEmmitTime > 100 && contactWater){ - for (let i = 0; i < (Math.floor(currentSpeed * 10 + 1) * 5) ; i++){ - if(scalesAttribute.getX(i) <= 0){ - - if(currentSpeed > 0.1){ - // playerHeadPos.x += -playerDir.x * 0.25; - // playerHeadPos.z += -playerDir.z * 0.25; - playerHeadPos.x += (Math.random() - 0.5) * 0.5; - playerHeadPos.y += (Math.random() - 0.5) * 0.2; - playerHeadPos.z += (Math.random() - 0.5) * 0.5; - info.velocity[i].x = -playerDir.x * 0.005; - info.velocity[i].y = 0.0025 + Math.random() * 0.0025; - info.velocity[i].z = -playerDir.z * 0.005; - } - else{ - playerHeadPos.x += -playerDir.x * 0.25; - playerHeadPos.z += -playerDir.z * 0.25; - playerHeadPos.x += (Math.random() - 0.5) * 0.5; - playerHeadPos.z += (Math.random() - 0.5) * 0.5; - playerHeadPos.y -= localPlayer.avatar.height * 0.6; - playerHeadPos.y += (Math.random()) * 0.2 - info.velocity[i].x = 0; - info.velocity[i].y = 0.0025 + Math.random() * 0.0025; - info.velocity[i].z = 0; - - } - if(playerHeadPos.y > waterSurfacePos.y) - playerHeadPos.y = waterSurfacePos.y - app.position.y; - positionsAttribute.setXYZ(i, playerHeadPos.x - app.position.x, playerHeadPos.y - app.position.y, playerHeadPos.z - app.position.z); - - - - - info.offset[i] = Math.floor(Math.random() * 29); - info.lastTime[i] = (50 + Math.random() * 50); - startTimeAttribute.setX(i, 0); - scalesAttribute.setX(i, Math.random()); - if(currentSpeed <= 0.1 && !localPlayer.hasAction('swim')){ - scalesAttribute.setX(i, 0); - } - currentEmmit++; - } - if(currentEmmit > maxEmmit){ - lastEmmitTime = timestamp; - break; - } - - } - } - - for (let i = 0; i < particleCount; i++){ - if(positionsAttribute.getY(i) >= waterSurfacePos.y - 0.005 - app.position.y){ - info.velocity[i].y = 0; - } - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i) + info.velocity[i].x, - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) + info.velocity[i].z - ); - - startTimeAttribute.setX(i, startTimeAttribute.getX(i) + 1); - if(startTimeAttribute.getX(i) % 2 === 0) - info.offset[i] += 1; - if(info.offset[i] >= 30){ - info.offset[i] = 0; - } - offsetAttribute.setXY(i, (5 / 6) - Math.floor(info.offset[i] / 6) * (1. / 6.), Math.floor(info.offset[i] % 5) * 0.2); - if(scalesAttribute.getX(i) > 0) - scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.01); - if(startTimeAttribute.getX(i) > info.lastTime[i] || positionsAttribute.getY(i) > waterSurfacePos.y - app.position.y){ - scalesAttribute.setX(i, 0); - } - } - - mesh.instanceMatrix.needsUpdate = true; - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - startTimeAttribute.needsUpdate = true; - offsetAttribute.needsUpdate = true; - - - - mesh.material.uniforms.uTime.value=timestamp/1000; - mesh.material.uniforms.cameraBillboardQuaternion.value.copy(camera.quaternion); - - - - } - app.updateMatrixWorld(); - - }); - } - //################################################################ half circle follow player ########################################################### - { - const particleCount = 30; - //##################################################### get circle geometry ##################################################### - const identityQuaternion = new THREE.Quaternion(); - const _getCircleGeometry = geometry => { - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - const quaternions = new Float32Array(particleCount * 4); - for (let i = 0; i < particleCount; i++) { - identityQuaternion.toArray(quaternions, i * 4); - } - const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - geometry2.setAttribute('quaternions', quaternionsAttribute); - - const textureRotation = new Float32Array(particleCount); - const textureRotAttribute = new THREE.InstancedBufferAttribute(textureRotation, 1); - geometry2.setAttribute('textureRotation', textureRotAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - const scales = new Float32Array(particleCount); - const scaleAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scaleAttribute); - - const playerRotation = new Float32Array(particleCount); - const playerRotAttribute = new THREE.InstancedBufferAttribute(playerRotation, 1); - geometry2.setAttribute('playerRotation', playerRotAttribute); - - const speed = new Float32Array(particleCount); - const speedAttribute = new THREE.InstancedBufferAttribute(speed, 1); - geometry2.setAttribute('speed', speedAttribute); - - const rand = new Float32Array(particleCount); - const randAttribute = new THREE.InstancedBufferAttribute(rand, 1); - geometry2.setAttribute('random', randAttribute); - - return geometry2; - }; - - //##################################################### material ##################################################### - const splashMaterial = new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - noiseMap:{ - value: noiseMap3 - }, - noiseMap2:{ - value: noiseMap - }, - noiseCircleTexture: { - value: noiseCircleTexture, - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - - varying vec2 vUv; - varying vec3 vPos; - varying float vBroken; - varying float vOpacity; - varying float vSpeed; - varying float vRand; - varying float vTextureRotation; - - attribute float textureRotation; - attribute vec3 positions; - attribute float scales; - attribute float random; - attribute float opacity; - attribute vec4 quaternions; - attribute float broken; - attribute float speed; - attribute float playerRotation; - vec3 qtransform(vec3 v, vec4 q) { - return v + 2.0*cross(cross(v, q.xyz ) + q.w*v, q.xyz); - } - - void main() { - mat3 rotY = - mat3(cos(playerRotation), 0.0, -sin(playerRotation), 0.0, 1.0, 0.0, sin(playerRotation), 0.0, cos(playerRotation)); - - vTextureRotation = textureRotation; - vOpacity=opacity; - vBroken=broken; - vSpeed=speed; - vRand=random; - vUv=uv; - vPos=position; - vec3 pos = position; - pos = qtransform(pos, quaternions); - pos*=rotY; - pos*=scales; - pos+=positions; - - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - varying float vBroken; - varying float vOpacity; - varying float vSpeed; - varying float vRand; - varying vec2 vUv; - varying vec3 vPos; - varying float vTextureRotation; - uniform sampler2D noiseMap; - uniform sampler2D noiseMap2; - uniform sampler2D noiseCircleTexture; - //#define PI 3.1415926 - const float rFrequency = 10.0; - const float rSpeed = .08; - const float rThickness = 50.0; - const float radiusEnd = .45; - const float radiusStart = .08; - const float PI = 3.1415926535897932384626433832795; - //Noise that moves radially outwards via polar coordinates - float radialNoise(vec2 uv){ - //Matches sampling to speed of ripples - uv.y -= rSpeed*uTime; - - - - const int octaves = 2; - //Increasing scale makes noise more fine-grained - const float scale = .15; - //Increasing power makes noise more 'solid' at outer ripple edge - float power = 2.2; - float total = 0.0; - for(int i = 0; iradiusStart) ? ripple*distScalar : 0.0; - - - float angle = atan(toCenter.x,toCenter.y); - angle = (angle + PI) / (2.0 * PI); - float noise = radialNoise(vec2(angle,dist)); - - - float total = ripple; - total -= noise; - total = total < vRand/10. ? 0.0 : 1.0; - - gl_FragColor = vec4(total); - - float mid = 0.5; - vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1. - sin(vTextureRotation*PI) * (vUv.y - mid) * 1. + mid, - cos(vTextureRotation*PI) * (vUv.y - mid) * 1. + sin(vTextureRotation*PI) * (vUv.x - mid) * 1. + mid); - if(vSpeed>0.1){ - if(vUv.y<0.45){ - // gl_FragColor.a=0.; - discard; - } - } - gl_FragColor.a*=vOpacity; - - vec3 noise2 = texture2D( - noiseMap2, - rotated - ).rgb; - - - float broken = abs( sin( 1.0 - vBroken ) ) - noise2.g; - if ( broken < 0.0001 ) discard; - if(gl_FragColor.a <= 0.){ - discard; - } - else{ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - - - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - // depthWrite: false, - // blending: THREE.AdditiveBlending, - - }); - - - - - - //##################################################### object ##################################################### - let rippleMesh=null; - let quaternion = new THREE.Quaternion(); - - const addInstancedMesh2=()=>{ - const geometry2 = new THREE.PlaneGeometry( 0.5, 0.5 ); - const geometry =_getCircleGeometry(geometry2) - rippleMesh = new THREE.InstancedMesh( - geometry, - splashMaterial, - particleCount - ); - //dropletRipplegroup.add(rippleMesh); - app.add(rippleMesh); - - const quaternionsAttribute = rippleMesh.geometry.getAttribute('quaternions'); - for (let i = 0; i < particleCount; i++) { - quaternion.setFromAxisAngle(new THREE.Vector3(1,0,0),-Math.PI/2); - quaternionsAttribute.setXYZW(i,quaternion.x,quaternion.y,quaternion.z,quaternion.w); - } - quaternionsAttribute.needsUpdate = true; - } - addInstancedMesh2(); - app.updateMatrixWorld(); - - let currentIndex=0; - let lastEmmitTime=0; - let localVector = new THREE.Vector3(); - useFrame(({timestamp}) => { - if(currentIndex>=particleCount){ - currentIndex=0; - } - - - if (rippleMesh) { - const opacityAttribute = rippleMesh.geometry.getAttribute('opacity'); - const brokenAttribute = rippleMesh.geometry.getAttribute('broken'); - const positionsAttribute = rippleMesh.geometry.getAttribute('positions'); - const scalesAttribute = rippleMesh.geometry.getAttribute('scales'); - const quaternionsAttribute = rippleMesh.geometry.getAttribute('quaternions'); - const speedAttribute = rippleMesh.geometry.getAttribute('speed'); - const playerRotationAttribute = rippleMesh.geometry.getAttribute('playerRotation'); - const randAttribute = rippleMesh.geometry.getAttribute('random'); - const textureRotationAttribute = rippleMesh.geometry.getAttribute('textureRotation'); - for (let i = 0; i < particleCount; i++) { - if(brokenAttribute.getX(i) < 0.15){ - const opacityOfCircle = currentSpeed > 0.3 ? 0.1 : 0.04; - opacityAttribute.setX(i,opacityAttribute.getX(i) + opacityOfCircle); - } - else{ - opacityAttribute.setX(i,opacityAttribute.getX(i)-0.013); - } - - scalesAttribute.setX(i,scalesAttribute.getX(i)+0.1*(currentSpeed+0.3)); - if(brokenAttribute.getX(i)<1) - brokenAttribute.setX(i, brokenAttribute.getX(i)+0.01); - - - } - if(timestamp - lastEmmitTime > 150 * Math.pow((1.1-currentSpeed),0.3) && currentSpeed>0.005 && contactWater){ - if( - (localPlayer.hasAction('swim') && localPlayer.getAction('swim').onSurface) - ||(!localPlayer.hasAction('swim') && waterSurfacePos.y >= localPlayer.position.y - localPlayer.avatar.height * 0.7) - ){ - if(localPlayer.rotation.x!==0){ - playerRotationAttribute.setX(currentIndex,Math.PI+localPlayer.rotation.y); - } - else{ - playerRotationAttribute.setX(currentIndex,-localPlayer.rotation.y); - } - speedAttribute.setX(currentIndex,currentSpeed); - brokenAttribute.setX(currentIndex,0.1); - scalesAttribute.setX(currentIndex,1.5+Math.random()*0.1); - opacityAttribute.setX(currentIndex, 0.1); - if(currentSpeed > 0.1){ - positionsAttribute.setXYZ( - currentIndex, - localPlayer.position.x + 0.25 * playerDir.x + (Math.random() - 0.5) * 0.1 - app.position.x, - waterSurfacePos.y + 0.01 - app.position.y, - localPlayer.position.z + 0.25 * playerDir.z + (Math.random() - 0.5) * 0.1 - app.position.z - ); - } - else{ - positionsAttribute.setXYZ( - currentIndex, - localPlayer.position.x - 0.05 * playerDir.x - app.position.x, - waterSurfacePos.y + 0.01 - app.position.y, - localPlayer.position.z - 0.05 * playerDir.z - app.position.z - ); - } - - randAttribute.setX(currentIndex, Math.random() * 0.5); - textureRotationAttribute.setX(currentIndex, Math.random() * 2); - currentIndex++; - lastEmmitTime=timestamp; - } - - } - - positionsAttribute.needsUpdate = true; - randAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - speedAttribute.needsUpdate = true; - brokenAttribute.needsUpdate = true; - textureRotationAttribute.needsUpdate = true; - quaternionsAttribute.needsUpdate = true; - playerRotationAttribute.needsUpdate = true; - rippleMesh.material.uniforms.uTime.value=timestamp/1000; - - } - app.updateMatrixWorld(); - - }); - } - //###################################################################### floating splash follow player ###################################################################### - { - const particleCount = 30; - //##################################################### get splash geometry ##################################################### - const identityQuaternion = new THREE.Quaternion(); - const _getSplashGeometry = geometry => { - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - const quaternions = new Float32Array(particleCount * 4); - for (let i = 0; i < particleCount; i++) { - identityQuaternion.toArray(quaternions, i * 4); - } - const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - geometry2.setAttribute('quaternions', quaternionsAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - const scales = new Float32Array(particleCount); - const scaleAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scaleAttribute); - - const textureRotation = new Float32Array(particleCount); - const textureRotAttribute = new THREE.InstancedBufferAttribute(textureRotation, 1); - geometry2.setAttribute('textureRotation', textureRotAttribute); - - return geometry2; - }; - - //##################################################### material ##################################################### - const splashMaterial = new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - noiseMap:{ - value: noiseMap - }, - perlinnoise:{ - value: splashTexture - } - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - - varying vec2 vUv; - varying vec3 vPos; - varying float vBroken; - varying float vOpacity; - varying float vTextureRotation; - - attribute float textureRotation; - attribute vec3 positions; - attribute float scales; - attribute float opacity; - attribute vec4 quaternions; - attribute float broken; - - vec3 qtransform(vec3 v, vec4 q) { - return v + 2.0*cross(cross(v, q.xyz ) + q.w*v, q.xyz); - } - - void main() { - vTextureRotation = textureRotation; - vOpacity=opacity; - vBroken=broken; - vUv=uv; - vPos=position; - vec3 pos = position; - pos = qtransform(pos, quaternions); - //pos*=rotY; - pos*=scales; - pos+=positions; - //pos*=rotX; - - - - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - varying float vBroken; - varying float vOpacity; - varying vec2 vUv; - varying vec3 vPos; - varying float vTextureRotation; - uniform sampler2D noiseMap; - uniform sampler2D perlinnoise; - #define PI 3.1415926 - void main() { - float mid = 0.5; - vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1. - sin(vTextureRotation*PI) * (vUv.y - mid) * 1. + mid, - cos(vTextureRotation*PI) * (vUv.y - mid) * 1. + sin(vTextureRotation*PI) * (vUv.x - mid) * 1. + mid); - vec4 splash = texture2D( - perlinnoise, - rotated - ); - if(splash.r > 0.1){ - gl_FragColor = vec4(1.0); - } - else{ - discard; - } - - // gl_FragColor.a *= vOpacity; - - - //float broken = abs( sin( 1.0 - vBroken ) ) - noise2.g; - float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated ).g; - if ( broken < 0.03 ) discard; - - if(gl_FragColor.a > 0.){ - gl_FragColor = vec4(0.7, 0.7, 0.7, 1.0); - } - - - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - // transparent: true, - // depthWrite: false, - // blending: THREE.AdditiveBlending, - - }); - - //##################################################### object ##################################################### - let rippleMesh=null; - let quaternion = new THREE.Quaternion(); - - const addInstancedMesh2=()=>{ - const geometry2 = new THREE.PlaneGeometry( 0.5, 0.5 ); - const geometry =_getSplashGeometry(geometry2) - rippleMesh = new THREE.InstancedMesh( - geometry, - splashMaterial, - particleCount - ); - app.add(rippleMesh); - - const quaternionsAttribute = rippleMesh.geometry.getAttribute('quaternions'); - for (let i = 0; i < particleCount; i++) { - quaternion.setFromAxisAngle(new THREE.Vector3(1,0,0),-Math.PI/2); - quaternionsAttribute.setXYZW(i,quaternion.x,quaternion.y,quaternion.z,quaternion.w); - } - quaternionsAttribute.needsUpdate = true; - } - addInstancedMesh2(); - app.updateMatrixWorld(); - - - let currentIndex=0; - let lastEmmitTime=0; - useFrame(({timestamp}) => { - - if(currentIndex>=particleCount){ - currentIndex=0; - } - - if (rippleMesh) { - const opacityAttribute = rippleMesh.geometry.getAttribute('opacity'); - const brokenAttribute = rippleMesh.geometry.getAttribute('broken'); - const positionsAttribute = rippleMesh.geometry.getAttribute('positions'); - const scalesAttribute = rippleMesh.geometry.getAttribute('scales'); - const textureRotationAttribute = rippleMesh.geometry.getAttribute('textureRotation'); - for (let i = 0; i < particleCount; i++) { - scalesAttribute.setX(i,scalesAttribute.getX(i)+0.05*(currentSpeed+0.3)); - if(brokenAttribute.getX(i)<1) - brokenAttribute.setX(i, brokenAttribute.getX(i)+0.005); - - - } - const emmitDelay = currentSpeed > 0.3 ? 100 : 200; - if(timestamp - lastEmmitTime > emmitDelay * Math.pow((1.1 - currentSpeed), 0.3) && currentSpeed > 0.1){ - if( - (localPlayer.hasAction('swim') && localPlayer.getAction('swim').onSurface) - ||(!localPlayer.hasAction('swim') && contactWater) - ){ - let brokenDegree = currentSpeed > 0.3 ? 0.23 + 0.2 * Math.random() : 0.4 + 0.3 * Math.random(); - if(currentSpeed > 0.5){ - brokenDegree *= 1.3; - } - if(!localPlayer.hasAction('swim')){ - brokenDegree *= 1.1; - } - brokenAttribute.setX(currentIndex, brokenDegree); - scalesAttribute.setX(currentIndex, 1.2 + Math.random() * 0.1); - opacityAttribute.setX(currentIndex, 0.1); - positionsAttribute.setXYZ( - currentIndex, - localPlayer.position.x + 0.2 * playerDir.x + (Math.random() - 0.5) * 0.1 - app.position.x, - waterSurfacePos.y + 0.01 - app.position.y, - localPlayer.position.z + 0.2 * playerDir.z + (Math.random() - 0.5) * 0.1 - app.position.z - ); - textureRotationAttribute.setX(currentIndex, Math.random() * 2); - currentIndex++; - lastEmmitTime=timestamp; - } - } - - - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - brokenAttribute.needsUpdate = true; - textureRotationAttribute.needsUpdate = true; - rippleMesh.material.uniforms.uTime.value=timestamp/1000; - - } - app.updateMatrixWorld(); - - }); - } - //################################################################ swimming splash ########################################################### - { - - const particleCount = 100; - let info = { - velocity: [particleCount], - acc: [particleCount] - } - const group = new THREE.Group(); - //const acc = new THREE.Vector3(0, -0.001, 0); - - const _getGeometry = geometry => { - //console.log(geometry) - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - - const color = new Float32Array(particleCount * 3); - const colorAttribute = new THREE.InstancedBufferAttribute(color, 3); - geometry2.setAttribute('color', colorAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - // const quaternions = new Float32Array(particleCount * 4); - // for (let i = 0; i < particleCount; i++) { - // identityQuaternion.toArray(quaternions, i * 4); - // } - // const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - // geometry2.setAttribute('quaternions', quaternionsAttribute); - - const scales = new Float32Array(particleCount); - const scalesAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scalesAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const startTimeAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - startTimeAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('startTime', startTimeAttribute); - - const textureRotation = new Float32Array(particleCount); - const textureRotAttribute = new THREE.InstancedBufferAttribute(textureRotation, 1); - geometry2.setAttribute('textureRotation', textureRotAttribute); - - return geometry2; - }; - - const material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - cameraBillboardQuaternion: { - value: new THREE.Quaternion(), - }, - splashTexture: { - value: splashTexture2, - }, - waterSurfacePos: { - value: new THREE.Vector3(), - }, - noiseMap:{ - value: noiseMap - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - uniform vec4 cameraBillboardQuaternion; - - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vBroken; - varying float vTextureRotation; - - attribute float textureRotation; - attribute float broken; - attribute vec3 positions; - attribute vec3 color; - attribute float scales; - attribute float opacity; - - - - vec3 rotateVecQuat(vec3 position, vec4 q) { - vec3 v = position.xyz; - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); - } - void main() { - vUv = uv; - vBroken = broken; - vTextureRotation = textureRotation; - // vOpacity = opacity; - // vColor = color; - - vec3 pos = position; - pos = rotateVecQuat(pos, cameraBillboardQuaternion); - pos *= scales; - pos += positions; - - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - vPos = modelPosition.xyz; - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform sampler2D splashTexture; - uniform sampler2D noiseMap; - uniform vec3 waterSurfacePos; - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vTextureRotation; - varying float vBroken; - #define PI 3.1415926 - - void main() { - float mid = 0.5; - vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, - cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); - vec4 splash = texture2D( - splashTexture, - rotated - ); - if(splash.r > 0.1){ - gl_FragColor = vec4(0.75, 0.75, 0.75, 1.0); - } - else{ - discard; - } - if(vPos.y < waterSurfacePos.y){ - discard; - } - //gl_FragColor.a *= 0.5; - float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated * 0.8 ).g; - if ( broken < 0.0001 ) discard; - - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - //blending: THREE.AdditiveBlending, - // depthWrite: false, - //blending: 1, - - }); - let mesh = null; - function addInstancedMesh() { - const geometry2 = new THREE.PlaneGeometry( 0.1, 0.1 ); - const geometry = _getGeometry(geometry2); - mesh = new THREE.InstancedMesh(geometry, material, particleCount); - for(let i = 0; i < particleCount; i++){ - info.velocity[i] = new THREE.Vector3(); - } - app.add(mesh); - } - addInstancedMesh(); - - - let playEffectSw = 0; - const localVector2 = new THREE.Vector3(); - let rotateY = new THREE.Quaternion(); - rotateY.setFromAxisAngle(new THREE.Vector3(0, 1, 0), -Math.PI / 2); - useFrame(({timestamp}) => { - localVector2.set(playerDir.x, playerDir.y, playerDir.z).applyQuaternion(rotateY); - - if (contactWater){ - if(playEffectSw === 0) - playEffectSw = 1; - } - else{ - if(playEffectSw === 2) - playEffectSw = 0; - } - - if (mesh) { - //console.log(Math.floor(currentSpeed * 10 + 1)) - const brokenAttribute = mesh.geometry.getAttribute('broken'); - const opacityAttribute = mesh.geometry.getAttribute('opacity'); - const positionsAttribute = mesh.geometry.getAttribute('positions'); - const scalesAttribute = mesh.geometry.getAttribute('scales'); - const startTimeAttribute = mesh.geometry.getAttribute('startTime'); - const colorAttribute = mesh.geometry.getAttribute('color'); - const textureRotationAttribute = mesh.geometry.getAttribute('textureRotation'); - - if( - localPlayer.hasAction('swim') - && localPlayer.getAction('swim').onSurface - && !localPlayer.hasAction('fly') - // && localPlayer.getAction('swim').animationType === 'breaststroke' - && currentSpeed > 0.3 - ){ - const splashposition = localPlayer.getAction('swim').animationType === 'breaststroke' ? 0.32 : 0.15; - const splashposition2 = localPlayer.getAction('swim').animationType === 'breaststroke' ? 0.1 : 0.2; - let currentEmmit = 0; - for(let i = 0; i < particleCount; i++){ - if(brokenAttribute.getX(i) >= 1){ - info.velocity[i].x = localVector2.x * (Math.random() - 0.5) * 0.2 + playerDir.x * splashposition2 * (1 + currentSpeed); - info.velocity[i].y = 0.08 + Math.random() * 0.08; - info.velocity[i].z = localVector2.z * (Math.random() - 0.5) * 0.2 + playerDir.z * splashposition2 * (1 + currentSpeed); - positionsAttribute.setXYZ( i, - localPlayer.position.x + info.velocity[i].x * 0.5 + playerDir.x * splashposition - app.position.x, - waterSurfacePos.y - 0.1 * Math.random() - app.position.y, - localPlayer.position.z + info.velocity[i].z * 0.5 + playerDir.z * splashposition - app.position.z - ); - info.velocity[i].divideScalar(5); - info.acc[i] = -0.0015 - currentSpeed * 0.0015; - scalesAttribute.setX(i, 2 + Math.random() * 2); - if(localPlayer.getAction('swim').animationType === 'breaststroke') - brokenAttribute.setX(i, 0.2 + Math.random() * 0.2); - else - brokenAttribute.setX(i, 0.25 + Math.random() * 0.2); - textureRotationAttribute.setX(i, Math.random() * 2); - currentEmmit++; - } - if(currentEmmit >= 2){ - break; - } - } - - - } - for (let i = 0; i < particleCount; i++){ - if(currentSpeed < 0.2){ - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i), - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) - ); - } - else{ - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i) + info.velocity[i].x, - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) + info.velocity[i].z - ); - } - if(brokenAttribute.getX(i) < 1){ - //if(info.velocity[i].y < 0) - // if(info.velocity[i].y > 0) - brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.016); - // else - // brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.02 * (1 + currentSpeed)); - scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.01 * (1 + currentSpeed)); - // else{ - // brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.005); - // } - } - info.velocity[i].y += info.acc[i]; - } - - - mesh.instanceMatrix.needsUpdate = true; - brokenAttribute.needsUpdate = true; - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - startTimeAttribute.needsUpdate = true; - colorAttribute.needsUpdate = true; - textureRotationAttribute.needsUpdate = true; - - mesh.material.uniforms.uTime.value=timestamp/1000; - mesh.material.uniforms.cameraBillboardQuaternion.value.copy(camera.quaternion); - mesh.material.uniforms.waterSurfacePos.value.copy(waterSurfacePos); - - if(playEffectSw === 1){ - playEffectSw = 2; - } - - } - app.updateMatrixWorld(); - - }); - } - //################################################################ freestyle swimming splash ########################################################### - { - - const particleCount = 100; - let info = { - velocity: [particleCount], - acc: [particleCount] - } - const group = new THREE.Group(); - //const acc = new THREE.Vector3(0, -0.001, 0); - - const _getGeometry = geometry => { - //console.log(geometry) - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - - const color = new Float32Array(particleCount * 3); - const colorAttribute = new THREE.InstancedBufferAttribute(color, 3); - geometry2.setAttribute('color', colorAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - // const quaternions = new Float32Array(particleCount * 4); - // for (let i = 0; i < particleCount; i++) { - // identityQuaternion.toArray(quaternions, i * 4); - // } - // const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - // geometry2.setAttribute('quaternions', quaternionsAttribute); - - const scales = new Float32Array(particleCount); - const scalesAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scalesAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const startTimeAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - startTimeAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('startTime', startTimeAttribute); - - const textureRotation = new Float32Array(particleCount); - const textureRotAttribute = new THREE.InstancedBufferAttribute(textureRotation, 1); - geometry2.setAttribute('textureRotation', textureRotAttribute); - - return geometry2; - }; - - const material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - cameraBillboardQuaternion: { - value: new THREE.Quaternion(), - }, - splashTexture: { - value: splashTexture2, - }, - waterSurfacePos: { - value: new THREE.Vector3(), - }, - noiseMap:{ - value: noiseMap - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - uniform vec4 cameraBillboardQuaternion; - - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vBroken; - varying float vTextureRotation; - - attribute float textureRotation; - attribute float broken; - attribute vec3 positions; - attribute vec3 color; - attribute float scales; - attribute float opacity; - - - - vec3 rotateVecQuat(vec3 position, vec4 q) { - vec3 v = position.xyz; - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); - } - void main() { - vUv = uv; - vBroken = broken; - vTextureRotation = textureRotation; - // vOpacity = opacity; - // vColor = color; - - vec3 pos = position; - pos = rotateVecQuat(pos, cameraBillboardQuaternion); - pos *= scales; - pos += positions; - - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - vPos = modelPosition.xyz; - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform sampler2D splashTexture; - uniform sampler2D noiseMap; - uniform vec3 waterSurfacePos; - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vTextureRotation; - varying float vBroken; - #define PI 3.1415926 - - void main() { - float mid = 0.5; - vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, - cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); - vec4 splash = texture2D( - splashTexture, - rotated - ); - if(splash.r > 0.1){ - gl_FragColor = vec4(0.75, 0.75, 0.75, 1.0); - } - else{ - discard; - } - if(vPos.y < waterSurfacePos.y){ - discard; - } - //gl_FragColor.a *= 0.5; - float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated * 0.8 ).g; - if ( broken < 0.0001 ) discard; - - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - //blending: THREE.AdditiveBlending, - // depthWrite: false, - //blending: 1, - - }); - let mesh = null; - function addInstancedMesh() { - const geometry2 = new THREE.PlaneGeometry( 0.1, 0.1 ); - const geometry = _getGeometry(geometry2); - mesh = new THREE.InstancedMesh(geometry, material, particleCount); - for(let i = 0; i < particleCount; i++){ - info.velocity[i] = new THREE.Vector3(); - } - app.add(mesh); - } - addInstancedMesh(); - - - let playEffectSw = 0; - const localVector2 = new THREE.Vector3(); - let rotateY = new THREE.Quaternion(); - rotateY.setFromAxisAngle(new THREE.Vector3(0, 1, 0), -Math.PI / 2); - let lastStroke = null; - useFrame(({timestamp}) => { - localVector2.set(playerDir.x, playerDir.y, playerDir.z).applyQuaternion(rotateY); - - - - if (contactWater){ - if(playEffectSw === 0) - playEffectSw = 1; - } - else{ - if(playEffectSw === 2) - playEffectSw = 0; - } - - if (mesh) { - - //console.log(Math.floor(currentSpeed * 10 + 1)) - const brokenAttribute = mesh.geometry.getAttribute('broken'); - const opacityAttribute = mesh.geometry.getAttribute('opacity'); - const positionsAttribute = mesh.geometry.getAttribute('positions'); - const scalesAttribute = mesh.geometry.getAttribute('scales'); - const startTimeAttribute = mesh.geometry.getAttribute('startTime'); - const colorAttribute = mesh.geometry.getAttribute('color'); - const textureRotationAttribute = mesh.geometry.getAttribute('textureRotation'); - - if( - localPlayer.hasAction('swim') - && localPlayer.getAction('swim').animationType === 'freestyle' - && localPlayer.getAction('swim').onSurface - && !localPlayer.hasAction('fly') - ){ - if(localPlayer.characterSfx.currentSwimmingHand !== lastStroke){ - if(localPlayer.characterSfx.currentSwimmingHand === 'right'){ - let currentEmmit = 0; - for(let i = 0; i < particleCount; i++){ - if(brokenAttribute.getX(i) >= 1){ - info.velocity[i].x = (Math.random() - 0.5) * 0.1 + playerDir.x * 0.45 * (1 + currentSpeed) + localVector2.x * 0.1; - info.velocity[i].y = 0.18 + Math.random() * 0.18; - info.velocity[i].z = (Math.random() - 0.5) * 0.1 + playerDir.z * 0.45 * (1 + currentSpeed) + localVector2.z * 0.1; - positionsAttribute.setXYZ( i, - localPlayer.position.x + (Math.random() - 0.5) * 0.1 + info.velocity[i].x - playerDir.x * 0.15 - app.position.x, - waterSurfacePos.y - app.position.y, - localPlayer.position.z + (Math.random() - 0.5) * 0.1 + info.velocity[i].z - playerDir.z * 0.15 - app.position.z - ); - info.velocity[i].divideScalar(10); - info.acc[i] = -0.001 - currentSpeed * 0.0015; - scalesAttribute.setX(i, 1 + Math.random()); - brokenAttribute.setX(i, 0.25 + Math.random() * 0.2); - textureRotationAttribute.setX(i, Math.random() * 2); - currentEmmit++; - } - if(currentEmmit >= 50){ - break; - } - } - - } - else if(localPlayer.characterSfx.currentSwimmingHand === 'left'){ - let currentEmmit = 0; - for(let i = 0; i < particleCount; i++){ - if(brokenAttribute.getX(i) >= 1){ - info.velocity[i].x = (Math.random() - 0.5) * 0.1 + playerDir.x * 0.45 * (1 + currentSpeed) - localVector2.x * 0.1; - info.velocity[i].y = 0.18 + Math.random() * 0.18; - info.velocity[i].z = (Math.random() - 0.5) * 0.1 + playerDir.z * 0.45 * (1 + currentSpeed) - localVector2.z * 0.1; - positionsAttribute.setXYZ( i, - localPlayer.position.x + (Math.random() - 0.5) * 0.1 + info.velocity[i].x - playerDir.x * 0.25 - app.position.x, - waterSurfacePos.y - app.position.y, - localPlayer.position.z + (Math.random() - 0.5) * 0.1 + info.velocity[i].z - playerDir.z * 0.25 - app.position.z - ); - info.velocity[i].divideScalar(10); - info.acc[i] = -0.001 - currentSpeed * 0.0015; - scalesAttribute.setX(i, 1 + Math.random()); - brokenAttribute.setX(i, 0.25 + Math.random() * 0.2); - textureRotationAttribute.setX(i, Math.random() * 2); - currentEmmit++; - } - if(currentEmmit >= 50){ - break; - } - } - - } - } - } - for (let i = 0; i < particleCount; i++){ - if(currentSpeed < 0.2){ - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i), - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) - ); - } - else{ - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i) + info.velocity[i].x, - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) + info.velocity[i].z - ); - } - - if(brokenAttribute.getX(i) < 1){ - //if(info.velocity[i].y < 0) - brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.016); - scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.01); - // else{ - // brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.005); - // } - } - info.velocity[i].y += info.acc[i]; - } - - - mesh.instanceMatrix.needsUpdate = true; - brokenAttribute.needsUpdate = true; - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - startTimeAttribute.needsUpdate = true; - colorAttribute.needsUpdate = true; - textureRotationAttribute.needsUpdate = true; - - mesh.material.uniforms.uTime.value=timestamp/1000; - mesh.material.uniforms.cameraBillboardQuaternion.value.copy(camera.quaternion); - mesh.material.uniforms.waterSurfacePos.value.copy(waterSurfacePos); - - if(playEffectSw === 1){ - playEffectSw = 2; - } - lastStroke = localPlayer.characterSfx.currentSwimmingHand; - } - app.updateMatrixWorld(); - - - }); - } - -//################################################################ falling and raising splash ########################################################### -{ - - const particleCount = 60; - let info = { - velocity: [particleCount], - acc: [particleCount] - } - //const acc = new THREE.Vector3(0, -0.001, 0); - - const _getGeometry = geometry => { - //console.log(geometry) - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - - const color = new Float32Array(particleCount * 3); - const colorAttribute = new THREE.InstancedBufferAttribute(color, 3); - geometry2.setAttribute('color', colorAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - // const quaternions = new Float32Array(particleCount * 4); - // for (let i = 0; i < particleCount; i++) { - // identityQuaternion.toArray(quaternions, i * 4); - // } - // const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - // geometry2.setAttribute('quaternions', quaternionsAttribute); - - const scales = new Float32Array(particleCount); - const scalesAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scalesAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const startTimeAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - startTimeAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('startTime', startTimeAttribute); - - const textureRotation = new Float32Array(particleCount); - const textureRotAttribute = new THREE.InstancedBufferAttribute(textureRotation, 1); - geometry2.setAttribute('textureRotation', textureRotAttribute); - - return geometry2; - }; - - const material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - cameraBillboardQuaternion: { - value: new THREE.Quaternion(), - }, - splashTexture: { - value: splashTexture2, - }, - waterSurfacePos: { - value: new THREE.Vector3(), - }, - noiseMap:{ - value: noiseMap - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - uniform vec4 cameraBillboardQuaternion; - - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vBroken; - varying float vTextureRotation; - - attribute float textureRotation; - attribute float broken; - attribute vec3 positions; - attribute vec3 color; - attribute float scales; - attribute float opacity; - - - - vec3 rotateVecQuat(vec3 position, vec4 q) { - vec3 v = position.xyz; - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); - } - void main() { - vUv = uv; - vBroken = broken; - vTextureRotation = textureRotation; - // vOpacity = opacity; - // vColor = color; - - vec3 pos = position; - pos = rotateVecQuat(pos, cameraBillboardQuaternion); - pos *= scales; - pos += positions; - - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - vPos = modelPosition.xyz; - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform sampler2D splashTexture; - uniform sampler2D noiseMap; - uniform vec3 waterSurfacePos; - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vTextureRotation; - varying float vBroken; - #define PI 3.1415926 - - void main() { - float mid = 0.5; - vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, - cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); - vec4 splash = texture2D( - splashTexture, - rotated - ); - if(splash.r > 0.1){ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - if(vPos.y < waterSurfacePos.y){ - gl_FragColor.a = 0.; - } - //gl_FragColor.a *= 0.5; - float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated * 0.8 ).g; - if ( broken < 0.0001 ) discard; - if(gl_FragColor.a > 0.){ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - else{ - discard; - } - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - //blending: THREE.AdditiveBlending, - // depthWrite: false, - //blending: 1, - - }); - let mesh = null; - function addInstancedMesh() { - const geometry2 = new THREE.PlaneGeometry( 0.2, 0.2 ); - const geometry = _getGeometry(geometry2); - mesh = new THREE.InstancedMesh(geometry, material, particleCount); - for(let i = 0; i < particleCount; i++){ - info.velocity[i] = new THREE.Vector3(); - } - app.add(mesh); - } - addInstancedMesh(); - - - let playEffectSw = 0; - let lastTimePlaySplash = 0; - let lastPlayerPositionY = 0; - useFrame(({timestamp}) => { - if(!localPlayer.avatar) - return; - // if (waterSurfacePos.y < localPlayer.position.y && waterSurfacePos.y > localPlayer.position.y - localPlayer.avatar.height * 0.95 && timestamp - lastTimePlaySplash > 150){ - // if(playEffectSw === 0 && Math.abs(localPlayer.characterPhysics.velocity.y) > 2.3 && Math.abs(localPlayer.position.y - lastPlayerPositionY) > 0.05 && currentSpeed < 0.1){ - // playEffectSw = 1; - // lastTimePlaySplash = timestamp; - // } - - // } - // else{ - // if(playEffectSw === 2) - // playEffectSw = 0; - // } - if (contactWater){ - if(playEffectSw === 0 && waterSurfacePos.y < localPlayer.position.y){ - playEffectSw = 1; - } - - } - else{ - if(playEffectSw === 2) - playEffectSw = 0; - } - - if (mesh) { - //console.log(Math.floor(currentSpeed * 10 + 1)) - const brokenAttribute = mesh.geometry.getAttribute('broken'); - const opacityAttribute = mesh.geometry.getAttribute('opacity'); - const positionsAttribute = mesh.geometry.getAttribute('positions'); - const scalesAttribute = mesh.geometry.getAttribute('scales'); - const startTimeAttribute = mesh.geometry.getAttribute('startTime'); - const colorAttribute = mesh.geometry.getAttribute('color'); - const textureRotationAttribute = mesh.geometry.getAttribute('textureRotation'); - if(contactWater){ - if(playEffectSw === 1){ - let currentEmmit = 0; - for(let i = 0; i < particleCount; i++){ - if(brokenAttribute.getX(i) >= 1){ - info.velocity[i].x = (Math.random() - 0.5) * 0.1 * 1.5; - info.velocity[i].y = 0.2 * 1.1; - info.velocity[i].z = (Math.random() - 0.5) * 0.1 * 1.5; - positionsAttribute.setXYZ( i, - localPlayer.position.x + info.velocity[i].x - app.position.x, - waterSurfacePos.y - 0.1 * Math.random() - app.position.y, - localPlayer.position.z + info.velocity[i].z - app.position.z - ); - info.velocity[i].divideScalar(7); - info.acc[i] = -0.0015; - scalesAttribute.setX(i, (1.5)); - brokenAttribute.setX(i, 0.25 + Math.random() * 0.2); - textureRotationAttribute.setX(i, Math.random() * 2); - currentEmmit++; - } - if(currentEmmit >= 10){ - break; - } - - } - } - } - - for (let i = 0; i < particleCount; i++){ - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i) + info.velocity[i].x, - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) + info.velocity[i].z - ); - if(brokenAttribute.getX(i) < 1){ - //if(info.velocity[i].y < 0) - brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.01 * (1 + currentSpeed)); - scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.01 * (1 + currentSpeed)); - // else{ - // brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.005); - // } - } - info.velocity[i].y += info.acc[i]; - } - - - mesh.instanceMatrix.needsUpdate = true; - brokenAttribute.needsUpdate = true; - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - startTimeAttribute.needsUpdate = true; - colorAttribute.needsUpdate = true; - textureRotationAttribute.needsUpdate = true; - - mesh.material.uniforms.uTime.value=timestamp/1000; - mesh.material.uniforms.cameraBillboardQuaternion.value.copy(camera.quaternion); - mesh.material.uniforms.waterSurfacePos.value.copy(waterSurfacePos); - - if(playEffectSw === 1){ - playEffectSw = 2; - } - - } - app.updateMatrixWorld(); - lastPlayerPositionY = localPlayer.position.y; - - }); - } - //################################################################ walking splash ########################################################### - { - - const particleCount = 30; - let info = { - velocity: [particleCount], - acc: [particleCount] - } - //const acc = new THREE.Vector3(0, -0.001, 0); - - const _getGeometry = geometry => { - //console.log(geometry) - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - - const color = new Float32Array(particleCount * 3); - const colorAttribute = new THREE.InstancedBufferAttribute(color, 3); - geometry2.setAttribute('color', colorAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - // const quaternions = new Float32Array(particleCount * 4); - // for (let i = 0; i < particleCount; i++) { - // identityQuaternion.toArray(quaternions, i * 4); - // } - // const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - // geometry2.setAttribute('quaternions', quaternionsAttribute); - - const scales = new Float32Array(particleCount); - const scalesAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scalesAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const startTimeAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - startTimeAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('startTime', startTimeAttribute); - - const textureRotation = new Float32Array(particleCount); - const textureRotAttribute = new THREE.InstancedBufferAttribute(textureRotation, 1); - geometry2.setAttribute('textureRotation', textureRotAttribute); - - return geometry2; - }; - - const material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - cameraBillboardQuaternion: { - value: new THREE.Quaternion(), - }, - splashTexture: { - value: splashTexture2, - }, - waterSurfacePos: { - value: new THREE.Vector3(), - }, - noiseMap:{ - value: noiseMap - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - uniform vec4 cameraBillboardQuaternion; - - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vBroken; - varying float vTextureRotation; - - attribute float textureRotation; - attribute float broken; - attribute vec3 positions; - attribute vec3 color; - attribute float scales; - attribute float opacity; - - - - vec3 rotateVecQuat(vec3 position, vec4 q) { - vec3 v = position.xyz; - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); - } - void main() { - vUv = uv; - vBroken = broken; - vTextureRotation = textureRotation; - // vOpacity = opacity; - // vColor = color; - - vec3 pos = position; - pos = rotateVecQuat(pos, cameraBillboardQuaternion); - pos *= scales; - pos += positions; - - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - vPos = modelPosition.xyz; - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform sampler2D splashTexture; - uniform sampler2D noiseMap; - uniform vec3 waterSurfacePos; - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vTextureRotation; - varying float vBroken; - #define PI 3.1415926 - - void main() { - float mid = 0.5; - vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, - cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); - vec4 splash = texture2D( - splashTexture, - rotated - ); - if(splash.r > 0.1){ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - if(vPos.y < waterSurfacePos.y){ - gl_FragColor.a = 0.; - } - //gl_FragColor.a *= 0.5; - float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated * 0.8 ).g; - if ( broken < 0.0001 ) discard; - if(gl_FragColor.a > 0.){ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - else{ - discard; - } - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - //blending: THREE.AdditiveBlending, - // depthWrite: false, - //blending: 1, - - }); - let mesh = null; - function addInstancedMesh() { - const geometry2 = new THREE.PlaneGeometry( 0.2, 0.2 ); - const geometry = _getGeometry(geometry2); - mesh = new THREE.InstancedMesh(geometry, material, particleCount); - for(let i = 0; i < particleCount; i++){ - info.velocity[i] = new THREE.Vector3(); - } - app.add(mesh); - } - addInstancedMesh(); - - - let playEffectSw = 0; - let lastStep = null; - const localVector2 = new THREE.Vector3(); - let rotateY = new THREE.Quaternion(); - rotateY.setFromAxisAngle(new THREE.Vector3(0, 1, 0), -Math.PI / 2); - useFrame(({timestamp}) => { - localVector2.set(playerDir.x, playerDir.y, playerDir.z).applyQuaternion(rotateY); - if (contactWater){ - if(playEffectSw === 0 && waterSurfacePos.y < localPlayer.position.y) - playEffectSw = 1; - } - else{ - if(playEffectSw === 2) - playEffectSw = 0; - } - - - if (mesh) { - //console.log(Math.floor(currentSpeed * 10 + 1)) - const brokenAttribute = mesh.geometry.getAttribute('broken'); - const opacityAttribute = mesh.geometry.getAttribute('opacity'); - const positionsAttribute = mesh.geometry.getAttribute('positions'); - const scalesAttribute = mesh.geometry.getAttribute('scales'); - const startTimeAttribute = mesh.geometry.getAttribute('startTime'); - const colorAttribute = mesh.geometry.getAttribute('color'); - const textureRotationAttribute = mesh.geometry.getAttribute('textureRotation'); - if(contactWater){ - if( - localPlayer.characterSfx.currentStep !== lastStep - && !localPlayer.hasAction('swim') - && contactWater - && ( - (currentSpeed <= 0.5 && waterSurfacePos.y < localPlayer.position.y - localPlayer.avatar.height + localPlayer.avatar.height * 0.3) - || (currentSpeed > 0.5 && waterSurfacePos.y < localPlayer.position.y - localPlayer.avatar.height + localPlayer.avatar.height * 0.4) - ) - ){ - //console.log(localPlayer.characterSfx.currentStep); - - if(localPlayer.characterSfx.currentStep === 'right'){ - let currentEmmit = 0; - for(let i = 0; i < particleCount; i++){ - if(brokenAttribute.getX(i) >= 1){ - info.velocity[i].x = (Math.random() - 0.5) * 0.1 * (1 + currentSpeed); - info.velocity[i].y = 0.2 * (1 + currentSpeed); - info.velocity[i].z = (Math.random() - 0.5) * 0.1 * (1 + currentSpeed); - positionsAttribute.setXYZ( i, - localPlayer.position.x + localVector2.x * 0.05 + info.velocity[i].x + playerDir.x * 0.35 - app.position.x, - waterSurfacePos.y - 0.1 * Math.random() - app.position.y, - localPlayer.position.z + localVector2.z * 0.05 + info.velocity[i].z + playerDir.z * 0.35 - app.position.z - ); - info.velocity[i].divideScalar(10); - info.acc[i] = -0.001 - currentSpeed * 0.0015; - scalesAttribute.setX(i, (1 + currentSpeed)); - brokenAttribute.setX(i, 0.25 + Math.random() * 0.2); - textureRotationAttribute.setX(i, Math.random() * 2); - currentEmmit++; - } - if(currentEmmit >= 10){ - break; - } - } - - } - else{ - let currentEmmit = 0; - for(let i = 0; i < particleCount; i++){ - if(brokenAttribute.getX(i) >= 1){ - info.velocity[i].x = (Math.random() - 0.5) * 0.1 * (1 + currentSpeed); - info.velocity[i].y = 0.2 * (1 + currentSpeed); - info.velocity[i].z = (Math.random() - 0.5) * 0.1 * (1 + currentSpeed); - positionsAttribute.setXYZ( i, - localPlayer.position.x - localVector2.x * 0.05 + info.velocity[i].x + playerDir.x * 0.35 - app.position.x, - waterSurfacePos.y - 0.1 * Math.random() - app.position.y, - localPlayer.position.z - localVector2.z * 0.05 + info.velocity[i].z + playerDir.z * 0.35 - app.position.z - ); - info.velocity[i].divideScalar(10); - info.acc[i] = -0.001 - currentSpeed * 0.0015; - scalesAttribute.setX(i, (1 + currentSpeed)); - brokenAttribute.setX(i, 0.25 + Math.random() * 0.2); - textureRotationAttribute.setX(i, Math.random() * 2); - currentEmmit++; - } - if(currentEmmit >= 10){ - break; - } - - } - - } - - lastStep = localPlayer.characterSfx.currentStep; - } - } - - for (let i = 0; i < particleCount; i++){ - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i) + info.velocity[i].x, - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) + info.velocity[i].z - ); - if(brokenAttribute.getX(i) < 1){ - //if(info.velocity[i].y < 0) - brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.01 * (1 + currentSpeed)); - scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.01 * (1 + currentSpeed)); - // else{ - // brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.005); - // } - } - info.velocity[i].y += info.acc[i]; - } - - - mesh.instanceMatrix.needsUpdate = true; - brokenAttribute.needsUpdate = true; - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - startTimeAttribute.needsUpdate = true; - colorAttribute.needsUpdate = true; - textureRotationAttribute.needsUpdate = true; - - mesh.material.uniforms.uTime.value=timestamp/1000; - mesh.material.uniforms.cameraBillboardQuaternion.value.copy(camera.quaternion); - mesh.material.uniforms.waterSurfacePos.value.copy(waterSurfacePos); - - if(playEffectSw === 1){ - playEffectSw = 2; - } - - } - app.updateMatrixWorld(); - - }); - } - //################################################################ lower splash ########################################################### - let secondSplash = 2; - const secondSplashPos = new THREE.Vector3(); - { - const particleCount = 12; - let info = { - velocity: [particleCount], - } - const acc = new THREE.Vector3(0, -0.002, 0); - - const _getGeometry = geometry => { - //console.log(geometry) - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - - const color = new Float32Array(particleCount * 3); - const colorAttribute = new THREE.InstancedBufferAttribute(color, 3); - geometry2.setAttribute('color', colorAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - // const quaternions = new Float32Array(particleCount * 4); - // for (let i = 0; i < particleCount; i++) { - // identityQuaternion.toArray(quaternions, i * 4); - // } - // const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - // geometry2.setAttribute('quaternions', quaternionsAttribute); - - const scales = new Float32Array(particleCount); - const scalesAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scalesAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const startTimeAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - startTimeAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('startTime', startTimeAttribute); - - const textureRotation = new Float32Array(particleCount); - const textureRotAttribute = new THREE.InstancedBufferAttribute(textureRotation, 1); - geometry2.setAttribute('textureRotation', textureRotAttribute); - - return geometry2; - }; - - const material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - cameraBillboardQuaternion: { - value: new THREE.Quaternion(), - }, - splashTexture: { - value: splashTexture2, - }, - waterSurfacePos: { - value: new THREE.Vector3(), - }, - noiseMap:{ - value: noiseMap - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - uniform vec4 cameraBillboardQuaternion; - - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vBroken; - varying float vTextureRotation; - - attribute float textureRotation; - attribute float broken; - attribute vec3 positions; - attribute vec3 color; - attribute float scales; - attribute float opacity; - - - - vec3 rotateVecQuat(vec3 position, vec4 q) { - vec3 v = position.xyz; - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); - } - void main() { - vUv = uv; - vBroken = broken; - vTextureRotation = textureRotation; - // vOpacity = opacity; - // vColor = color; - - vec3 pos = position; - pos = rotateVecQuat(pos, cameraBillboardQuaternion); - pos*=scales; - pos+=positions; - //pos = qtransform(pos, quaternions); - //pos.y=cos(uTime/100.); - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - vPos = modelPosition.xyz; - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform sampler2D splashTexture; - uniform sampler2D noiseMap; - uniform vec3 waterSurfacePos; - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vTextureRotation; - varying float vBroken; - #define PI 3.1415926 - - void main() { - float mid = 0.5; - vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, - cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); - vec4 splash = texture2D( - splashTexture, - rotated - ); - if(splash.r > 0.1){ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - if(vPos.y < waterSurfacePos.y){ - gl_FragColor.a = 0.; - } - //gl_FragColor.a *= 0.5; - float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated * 2.5 ).g; - if ( broken < 0.0001 ) discard; - if(gl_FragColor.a > 0.){ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - else{ - discard; - } - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - // blending: THREE.AdditiveBlending, - // depthWrite: false, - //blending: 1, - - }); - let mesh = null; - function addInstancedMesh() { - const geometry2 = new THREE.PlaneGeometry( 0.3, 0.3 ); - const geometry = _getGeometry(geometry2); - mesh = new THREE.InstancedMesh(geometry, material, particleCount); - for(let i = 0; i < particleCount; i++){ - info.velocity[i] = new THREE.Vector3(); - } - app.add(mesh); - } - addInstancedMesh(); - - - let playEffectSw=0; - useFrame(({timestamp}) => { - if (contactWater){ - if(playEffectSw === 0 && waterSurfacePos.y < localPlayer.position.y) - playEffectSw = 1; - } - else{ - if(playEffectSw === 2) - playEffectSw = 0; - } - - if (mesh) { - //console.log(Math.floor(currentSpeed * 10 + 1)) - const brokenAttribute = mesh.geometry.getAttribute('broken'); - const opacityAttribute = mesh.geometry.getAttribute('opacity'); - const positionsAttribute = mesh.geometry.getAttribute('positions'); - const scalesAttribute = mesh.geometry.getAttribute('scales'); - const startTimeAttribute = mesh.geometry.getAttribute('startTime'); - const colorAttribute = mesh.geometry.getAttribute('color'); - const textureRotationAttribute = mesh.geometry.getAttribute('textureRotation'); - - for (let i = 0; i < particleCount; i++){ - if(playEffectSw === 1 && fallindSpeed > 6){ - info.velocity[i].x = Math.sin(i) * .1 + (Math.random() - 0.5) * 0.01; - info.velocity[i].y = 0.15 * Math.random(); - info.velocity[i].z = Math.cos(i) * .1 + (Math.random() - 0.5) * 0.01; - positionsAttribute.setXYZ( i, - localPlayer.position.x + info.velocity[i].x - app.position.x, - waterSurfacePos.y + 0.1 * Math.random() - app.position.y, - localPlayer.position.z + info.velocity[i].z - app.position.z - ); - info.velocity[i].divideScalar(5); - scalesAttribute.setX(i, 0.8); - textureRotationAttribute.setX(i, Math.random() * 2); - brokenAttribute.setX(i, 0.2 + Math.random() * 0.25); - if(secondSplash === 2){ - secondSplash = 0; - secondSplashPos.set(localPlayer.position.x - app.position.x, waterSurfacePos.y - app.position.y, localPlayer.position.z - app.position.z); - } - } - if(scalesAttribute.getX(i) >= 0.8 && scalesAttribute.getX(i) < 2.5){ - scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.2); - } - if(scalesAttribute.getX(i) >= 2.5){ - if(brokenAttribute.getX(i) < 1){ - brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.03); - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i) + info.velocity[i].x, - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) + info.velocity[i].z - ); - info.velocity[i].add(acc); - if(secondSplash === 0){ - secondSplash = 1; - } - } - } - } - - mesh.instanceMatrix.needsUpdate = true; - brokenAttribute.needsUpdate = true; - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - startTimeAttribute.needsUpdate = true; - colorAttribute.needsUpdate = true; - textureRotationAttribute.needsUpdate = true; - - mesh.material.uniforms.uTime.value=timestamp/1000; - mesh.material.uniforms.cameraBillboardQuaternion.value.copy(camera.quaternion); - mesh.material.uniforms.waterSurfacePos.value.copy(waterSurfacePos); - - if(playEffectSw === 1){ - playEffectSw = 2; - } - - } - app.updateMatrixWorld(); - - }); - } - //################################################################ higher splash ########################################################### - { - const particleCount = 10; - let info = { - velocity: [particleCount], - } - const acc = new THREE.Vector3(0, -0.0024, 0); - - const _getGeometry = geometry => { - //console.log(geometry) - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - - const color = new Float32Array(particleCount * 3); - const colorAttribute = new THREE.InstancedBufferAttribute(color, 3); - geometry2.setAttribute('color', colorAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - // const quaternions = new Float32Array(particleCount * 4); - // for (let i = 0; i < particleCount; i++) { - // identityQuaternion.toArray(quaternions, i * 4); - // } - // const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - // geometry2.setAttribute('quaternions', quaternionsAttribute); - - const scales = new Float32Array(particleCount); - const scalesAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scalesAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const startTimeAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - startTimeAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('startTime', startTimeAttribute); - - const textureRotation = new Float32Array(particleCount); - const textureRotAttribute = new THREE.InstancedBufferAttribute(textureRotation, 1); - geometry2.setAttribute('textureRotation', textureRotAttribute); - - return geometry2; - }; - - const material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - cameraBillboardQuaternion: { - value: new THREE.Quaternion(), - }, - splashTexture: { - value: splashTexture2, - }, - waterSurfacePos: { - value: new THREE.Vector3(), - }, - noiseMap:{ - value: noiseMap - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - uniform vec4 cameraBillboardQuaternion; - - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vBroken; - varying float vTextureRotation; - - attribute float textureRotation; - attribute float broken; - attribute vec3 positions; - attribute vec3 color; - attribute float scales; - attribute float opacity; - - - - vec3 rotateVecQuat(vec3 position, vec4 q) { - vec3 v = position.xyz; - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); - } - void main() { - vUv = uv; - vBroken = broken; - vTextureRotation = textureRotation; - // vOpacity = opacity; - // vColor = color; - - vec3 pos = position; - pos = rotateVecQuat(pos, cameraBillboardQuaternion); - pos*=scales; - pos+=positions; - //pos = qtransform(pos, quaternions); - //pos.y=cos(uTime/100.); - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - vPos = modelPosition.xyz; - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform sampler2D splashTexture; - uniform sampler2D noiseMap; - uniform vec3 waterSurfacePos; - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying float vTextureRotation; - varying float vBroken; - #define PI 3.1415926 - - void main() { - float mid = 0.5; - vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, - cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); - vec4 splash = texture2D( - splashTexture, - rotated - ); - if(splash.r > vBroken){ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - else{ - discard; - } - if(vPos.y < waterSurfacePos.y){ - gl_FragColor.a = 0.; - } - //gl_FragColor.a *= 0.5; - // float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated * 1. ).g; - // if ( broken < 0.0001 ) discard; - if(gl_FragColor.a > 0.){ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - else{ - discard; - } - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - //blending: THREE.AdditiveBlending, - // depthWrite: false, - //blending: 1, - - }); - let mesh = null; - function addInstancedMesh() { - const geometry2 = new THREE.PlaneGeometry( 0.4, 0.4 ); - const geometry = _getGeometry(geometry2); - mesh = new THREE.InstancedMesh(geometry, material, particleCount); - for(let i = 0; i < particleCount; i++){ - info.velocity[i] = new THREE.Vector3(); - } - app.add(mesh); - } - addInstancedMesh(); - - - - useFrame(({timestamp}) => { - - if (mesh) { - //console.log(Math.floor(currentSpeed * 10 + 1)) - const brokenAttribute = mesh.geometry.getAttribute('broken'); - const opacityAttribute = mesh.geometry.getAttribute('opacity'); - const positionsAttribute = mesh.geometry.getAttribute('positions'); - const scalesAttribute = mesh.geometry.getAttribute('scales'); - const startTimeAttribute = mesh.geometry.getAttribute('startTime'); - const colorAttribute = mesh.geometry.getAttribute('color'); - const textureRotationAttribute = mesh.geometry.getAttribute('textureRotation'); - - for (let i = 0; i < particleCount; i++){ - if(secondSplash === 1){ - info.velocity[i].x = 0; - info.velocity[i].y = 0.13; - info.velocity[i].z = 0; - info.velocity[i].divideScalar(5); - - positionsAttribute.setXYZ( i, - secondSplashPos.x + (Math.random() - 0.5) * 0.1, - secondSplashPos.y + (i * 0.18) / 7, - secondSplashPos.z + (Math.random() - 0.5) * 0.1 - ); - - scalesAttribute.setX(i, (0.8 + (2 - i * 0.18)) / 7); - textureRotationAttribute.setX(i, Math.random() * 2); - brokenAttribute.setX(i, Math.random() * 0.5 ); - } - if(scalesAttribute.getX(i) < 0.8 + (2 - i * 0.18)){ - scalesAttribute.setX(i, scalesAttribute.getX(i) * 1.05); - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i), - secondSplashPos.y + (positionsAttribute.getY(i) - secondSplashPos.y) * 1.05, - positionsAttribute.getZ(i) - ); - - } - if(scalesAttribute.getX(i) > (0.8 + (2 - i * 0.18)) / 3){ - if(brokenAttribute.getX(i) < 1) - brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.03 * (2 - i * 0.1)); - - } - positionsAttribute.setXYZ( i, - positionsAttribute.getX(i) + info.velocity[i].x, - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) + info.velocity[i].z - ); - info.velocity[i].add(acc); - - - - // if(scalesAttribute.getX(i) >= 2.5){ - // if(brokenAttribute.getX(i) < 1){ - // brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.03); - // positionsAttribute.setXYZ( i, - // positionsAttribute.getX(i) + info.velocity[i].x, - // positionsAttribute.getY(i) + info.velocity[i].y, - // positionsAttribute.getZ(i) + info.velocity[i].z - // ); - // info.velocity[i].add(acc); - // } - // } - } - - mesh.instanceMatrix.needsUpdate = true; - brokenAttribute.needsUpdate = true; - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - startTimeAttribute.needsUpdate = true; - colorAttribute.needsUpdate = true; - textureRotationAttribute.needsUpdate = true; - - mesh.material.uniforms.uTime.value=timestamp/1000; - mesh.material.uniforms.cameraBillboardQuaternion.value.copy(camera.quaternion); - mesh.material.uniforms.waterSurfacePos.value.copy(waterSurfacePos); - - if(secondSplash === 1){ - secondSplash = 2; - } - - } - app.updateMatrixWorld(); - - }); - } - //#################################################################### droplet particle ######################################################################## - { - const dropletgroup = new THREE.Group(); - const dropletRipplegroup=new THREE.Group(); - const particleCount = 50; - let info = { - velocity: [particleCount], - alreadyHaveRipple: [particleCount], - offset: [particleCount], - } - const acc = new THREE.Vector3(0, -0.002, 0); - - - //##################################################### get ripple geometry ##################################################### - const identityQuaternion = new THREE.Quaternion(); - const _getRippleGeometry = geometry => { - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - const quaternions = new Float32Array(particleCount * 4); - for (let i = 0; i < particleCount; i++) { - identityQuaternion.toArray(quaternions, i * 4); - } - const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - geometry2.setAttribute('quaternions', quaternionsAttribute); - - const waveFreq = new Float32Array(particleCount); - const waveFreqAttribute = new THREE.InstancedBufferAttribute(waveFreq, 1); - geometry2.setAttribute('waveFreq', waveFreqAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - const scales = new Float32Array(particleCount); - const scaleAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scaleAttribute); - - return geometry2; - }; - //##################################################### ripple material ##################################################### - const rippleMaterial = new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - noiseMap:{ - value: noiseMap - } - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - - varying vec2 vUv; - varying vec3 vPos; - varying float vBroken; - varying float vOpacity; - varying float vWaveFreq; - attribute vec3 positions; - attribute float scales; - attribute float opacity; - attribute float waveFreq; - attribute vec4 quaternions; - attribute float broken; - vec3 qtransform(vec3 v, vec4 q) { - return v + 2.0*cross(cross(v, q.xyz ) + q.w*v, q.xyz); - } - - void main() { - vOpacity=opacity; - vBroken=broken; - vWaveFreq=waveFreq; - vUv=uv; - vPos=position; - vec3 pos = position; - pos = qtransform(pos, quaternions); - pos*=scales; - pos+=positions; - - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - varying float vWaveFreq; - varying float vBroken; - varying float vOpacity; - varying vec2 vUv; - varying vec3 vPos; - uniform sampler2D noiseMap; - - void main() { - - vec2 wavedUv = vec2( - vUv.x, - vUv.y + sin(vUv.x * (2.+vWaveFreq) * cos(uTime*2.)) * 0.05 - ); - float strength = 1.0 - step(0.01, abs(distance(wavedUv, vec2(0.5)) - 0.25)); - - gl_FragColor = vec4(vec3(strength), 1.0); - gl_FragColor.a*=vOpacity; - if(gl_FragColor.r < 0.01){ - discard; - } - - float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, vUv ).g; - if ( broken < 0.0001 ) discard; - if(gl_FragColor.a > 0.){ - gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); - } - else{ - discard; - } - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - // depthWrite: false, - // blending: THREE.AdditiveBlending, - - }); - - //##################################################### get droplet geometry ##################################################### - - const _getGeometry = geometry => { - //console.log(geometry) - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - - const color = new Float32Array(particleCount * 3); - const colorAttribute = new THREE.InstancedBufferAttribute(color, 3); - geometry2.setAttribute('color', colorAttribute); - // const quaternions = new Float32Array(particleCount * 4); - // for (let i = 0; i < particleCount; i++) { - // identityQuaternion.toArray(quaternions, i * 4); - // } - // const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - // geometry2.setAttribute('quaternions', quaternionsAttribute); - - const scales = new Float32Array(particleCount); - const scalesAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scalesAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const startTimeAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - startTimeAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('startTime', startTimeAttribute); - - - const offset = new Float32Array(particleCount * 2); - const offsetAttribute = new THREE.InstancedBufferAttribute(offset, 2); - geometry2.setAttribute('offset', offsetAttribute); - - - return geometry2; - }; - - const material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - cameraBillboardQuaternion: { - value: new THREE.Quaternion(), - }, - bubbleTexture1: { - value: bubbleTexture2, - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - uniform vec4 cameraBillboardQuaternion; - - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying vec2 vOffset; - - - attribute vec3 positions; - attribute vec3 color; - attribute float scales; - attribute float opacity; - attribute vec2 offset; - - - vec3 rotateVecQuat(vec3 position, vec4 q) { - vec3 v = position.xyz; - return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); - } - void main() { - vUv = uv; - vPos = position; - // vOpacity = opacity; - // vColor = color; - vOffset = offset; - vec3 pos = position; - pos = rotateVecQuat(pos, cameraBillboardQuaternion); - pos*=scales; - pos+=positions; - //pos = qtransform(pos, quaternions); - //pos.y=cos(uTime/100.); - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform sampler2D bubbleTexture1; - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vColor; - varying float vOpacity; - varying vec2 vOffset; - - void main() { - vec4 bubble = texture2D( - bubbleTexture1, - vec2( - vUv.x / 6. + vOffset.x, - vUv.y / 5. + vOffset.y - ) - ); - - gl_FragColor = bubble; - if(gl_FragColor.a < 0.5){ - discard; - } - gl_FragColor.rgb *= 5.; - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - // blending: THREE.AdditiveBlending, - // depthWrite: false, - //blending: 1, - - }); - let dropletMesh = null; - function addInstancedMesh() { - const geometry2 = new THREE.PlaneGeometry( .1, .1 ); - const geometry = _getGeometry(geometry2); - dropletMesh = new THREE.InstancedMesh(geometry, material, particleCount); - const positionsAttribute = dropletMesh.geometry.getAttribute('positions'); - for (let i = 0; i < particleCount; i++) { - positionsAttribute.setXYZ(i, localPlayer.position.x + Math.random() * 5, -500, localPlayer.position.z + Math.random() * 5); - info.velocity[i] = (new THREE.Vector3( - (Math.random() - 0.5)*3., - Math.random() * 1., - (Math.random() - 0.5)*3.)); - info.velocity[i].divideScalar(20); - info.alreadyHaveRipple[i] = false; - - } - positionsAttribute.needsUpdate = true; - dropletgroup.add(dropletMesh); - app.add(dropletgroup); - } - addInstancedMesh(); - - //################################################################ ripple object ######################################################### - let rippleMesh=null; - let quaternion = new THREE.Quaternion(); - - let euler = new THREE.Euler(); - const addInstancedMesh2=()=>{ - const geometry2 = new THREE.PlaneGeometry( 0.45, 0.45 ); - const geometry =_getRippleGeometry(geometry2) - rippleMesh = new THREE.InstancedMesh( - geometry, - rippleMaterial, - particleCount - ); - dropletRipplegroup.add(rippleMesh); - app.add(dropletRipplegroup); - const positionsAttribute = rippleMesh.geometry.getAttribute('positions'); - const quaternionsAttribute = rippleMesh.geometry.getAttribute('quaternions'); - - for (let i = 0; i < particleCount; i++) { - - positionsAttribute.setXYZ(i,.1* Math.random(), .1* Math.random(), 0); - - - euler.x=-Math.PI/2; - euler.y=0; - euler.z=0; - quaternion.setFromEuler(euler); - quaternionsAttribute.setXYZW(i,quaternion.x,quaternion.y,quaternion.z,quaternion.w); - } - positionsAttribute.needsUpdate = true; - quaternionsAttribute.needsUpdate = true; - } - addInstancedMesh2(); - - - - let jumpSw=0; - - useFrame(({timestamp}) => { - if (contactWater){ - if(jumpSw === 0 && waterSurfacePos.y < localPlayer.position.y) - jumpSw = 1; - } - else{ - if(jumpSw === 2) - jumpSw = 0; - } - if (dropletMesh && rippleMesh) { - const rippleOpacityAttribute = rippleMesh.geometry.getAttribute('opacity'); - const rippleBrokenAttribute = rippleMesh.geometry.getAttribute('broken'); - const rippleWaveFreqAttribute = rippleMesh.geometry.getAttribute('waveFreq'); - const ripplePositionsAttribute = rippleMesh.geometry.getAttribute('positions'); - const rippleScalesAttribute = rippleMesh.geometry.getAttribute('scales'); - - const opacityAttribute = dropletMesh.geometry.getAttribute('opacity'); - const offsetAttribute = dropletMesh.geometry.getAttribute('offset'); - const positionsAttribute = dropletMesh.geometry.getAttribute('positions'); - const scalesAttribute = dropletMesh.geometry.getAttribute('scales'); - const startTimeAttribute = dropletMesh.geometry.getAttribute('startTime'); - - - let falling = fallindSpeed > 10 ? 10 : fallindSpeed; - let dropletNum = particleCount * (falling / 10); - dropletNum /= 3; - falling = falling < 5 ? 7 : falling; - for (let i = 0; i < particleCount; i++) { - if (jumpSw==1) { - let rand = Math.random(); - scalesAttribute.setX(i, rand); - positionsAttribute.setXYZ(i, 0, 0, 0); - - info.velocity[i].x = (Math.random() - 0.5) * 1 * (falling / 10); - info.velocity[i].y = Math.random() * 1.6 * (falling / 10); - info.velocity[i].z = (Math.random() - 0.5) * 1 * (falling / 10); - - info.velocity[i].divideScalar(20); - - info.alreadyHaveRipple[i]=false; - if(i > dropletNum){ - scalesAttribute.setX(i, 0.001); - } - info.offset[i] = Math.floor(Math.random() * 29); - startTimeAttribute.setX(i, 0); - } - if(positionsAttribute.getY(i) >= -100){ - info.velocity[i].add(acc); - scalesAttribute.setX(i, scalesAttribute.getX(i) / 1.035); - positionsAttribute.setXYZ( - i, - positionsAttribute.getX(i) + info.velocity[i].x, - positionsAttribute.getY(i) + info.velocity[i].y, - positionsAttribute.getZ(i) + info.velocity[i].z - ) - startTimeAttribute.setX(i, startTimeAttribute.getX(i) + 1); - if(startTimeAttribute.getX(i) % 2 === 0) - info.offset[i] += 1; - if(info.offset[i] >= 30){ - info.offset[i] = 0; - } - offsetAttribute.setXY(i, (5 / 6) - Math.floor(info.offset[i] / 6) * (1. / 6.), Math.floor(info.offset[i] % 5) * 0.2); - - } - if(positionsAttribute.getY(i) < 0 && !info.alreadyHaveRipple[i] && scalesAttribute.getX(i) > 0.001){ - scalesAttribute.setX(i, 0.0001); - ripplePositionsAttribute.setXYZ(i, positionsAttribute.getX(i), 0, positionsAttribute.getZ(i)); - rippleScalesAttribute.setX(i,Math.random()*0.2); - rippleOpacityAttribute.setX(i,0.5+0.3*Math.random()); - rippleWaveFreqAttribute.setX(i, Math.random()*(i%10)); - rippleBrokenAttribute.setX(i, Math.random()-0.8); - info.alreadyHaveRipple[i]=true; - } - rippleOpacityAttribute.setX(i,rippleOpacityAttribute.getX(i)-0.013); - rippleScalesAttribute.setX(i,rippleScalesAttribute.getX(i)+0.02); - if(rippleBrokenAttribute.getX(i)<1) - rippleBrokenAttribute.setX(i, rippleBrokenAttribute.getX(i)+0.02); - - - } - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - startTimeAttribute.needsUpdate = true; - offsetAttribute.needsUpdate = true; - - - - dropletMesh.material.uniforms.uTime.value=timestamp/1000; - dropletMesh.material.uniforms.cameraBillboardQuaternion.value.copy(camera.quaternion); - - - ripplePositionsAttribute.needsUpdate = true; - rippleOpacityAttribute.needsUpdate = true; - rippleScalesAttribute.needsUpdate = true; - rippleBrokenAttribute.needsUpdate = true; - rippleWaveFreqAttribute.needsUpdate = true; - rippleMesh.material.uniforms.uTime.value=timestamp/1000; - if(jumpSw==1){ - dropletgroup.position.x = localPlayer.position.x - app.position.x; - dropletgroup.position.y = waterSurfacePos.y - app.position.y; - dropletgroup.position.z = localPlayer.position.z - app.position.z; - - dropletRipplegroup.position.x = localPlayer.position.x - app.position.x; - dropletRipplegroup.position.y = waterSurfacePos.y - app.position.y; - dropletRipplegroup.position.z = localPlayer.position.z - app.position.z; - jumpSw=2; - } - - - - - } - - }); - } - //###################################################################### falling splash in ripple ###################################################################### - { - const particleCount = 5; - const group=new THREE.Group(); - - //##################################################### get ripple geometry ##################################################### - const identityQuaternion = new THREE.Quaternion(); - const _getRippleGeometry = geometry => { - const geometry2 = new THREE.BufferGeometry(); - ['position', 'normal', 'uv'].forEach(k => { - geometry2.setAttribute(k, geometry.attributes[k]); - }); - geometry2.setIndex(geometry.index); - - const positions = new Float32Array(particleCount * 3); - const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); - geometry2.setAttribute('positions', positionsAttribute); - const quaternions = new Float32Array(particleCount * 4); - for (let i = 0; i < particleCount; i++) { - identityQuaternion.toArray(quaternions, i * 4); - } - const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); - geometry2.setAttribute('quaternions', quaternionsAttribute); - - const waveFreq = new Float32Array(particleCount); - const waveFreqAttribute = new THREE.InstancedBufferAttribute(waveFreq, 1); - geometry2.setAttribute('waveFreq', waveFreqAttribute); - - const opacityAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - opacityAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('opacity', opacityAttribute); - - const brokenAttribute = new THREE.InstancedBufferAttribute(new Float32Array(particleCount), 1); - brokenAttribute.setUsage(THREE.DynamicDrawUsage); - geometry2.setAttribute('broken', brokenAttribute); - - const scales = new Float32Array(particleCount); - const scaleAttribute = new THREE.InstancedBufferAttribute(scales, 1); - geometry2.setAttribute('scales', scaleAttribute); - - const playerRotation = new Float32Array(particleCount); - const playerRotAttribute = new THREE.InstancedBufferAttribute(playerRotation, 1); - geometry2.setAttribute('playerRotation', playerRotAttribute); - - const speed = new Float32Array(particleCount); - const speedAttribute = new THREE.InstancedBufferAttribute(speed, 1); - geometry2.setAttribute('speed', speedAttribute); - - return geometry2; - }; - - //##################################################### material ##################################################### - const splashMaterial = new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - noiseMap:{ - value: noiseMap - }, - perlinnoise:{ - value: splashTexture - } - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - - varying vec2 vUv; - varying vec3 vPos; - varying float vBroken; - varying float vOpacity; - varying float vWaveFreq; - varying float vSpeed; - attribute vec3 positions; - attribute float scales; - attribute float opacity; - attribute float waveFreq; - attribute vec4 quaternions; - attribute float broken; - attribute float speed; - attribute float playerRotation; - vec3 qtransform(vec3 v, vec4 q) { - return v + 2.0*cross(cross(v, q.xyz ) + q.w*v, q.xyz); - } - - void main() { - - mat3 rotY = - mat3(cos(playerRotation), 0.0, -sin(playerRotation), 0.0, 1.0, 0.0, sin(playerRotation), 0.0, cos(playerRotation)); - mat3 rotX = - mat3(1.0, 0.0, 0.0, 0.0, cos(PI/2.), sin(PI/2.), 0.0, -sin(PI/2.), cos(PI/2.)); - - mat3 rotZ = mat3( - cos(-PI/2.), sin(-PI/2.), 0.0, - -sin(-PI/2.), cos(-PI/2.), 0.0, - 0.0, 0.0 , 1.0 - ); - - vOpacity=opacity; - vBroken=broken; - vWaveFreq=waveFreq; - vSpeed=speed; - vUv=uv; - vPos=position; - vec3 pos = position; - pos = qtransform(pos, quaternions); - pos*=rotY; - pos*=scales; - pos+=positions; - //pos*=rotX; - - - - vec4 modelPosition = modelMatrix * vec4(pos, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - - gl_Position = projectionPosition; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - varying float vWaveFreq; - varying float vBroken; - varying float vOpacity; - varying float vSpeed; - varying vec2 vUv; - varying vec3 vPos; - uniform sampler2D noiseMap; - uniform sampler2D perlinnoise; - //#define PI 3.1415926 - - - void main() { - - vec4 splash = texture2D( - perlinnoise, - vUv - ); - if(splash.r > 0.1){ - gl_FragColor = vec4(0.8, 0.8, 0.8, 1.0); - } - else{ - discard; - } - - // gl_FragColor.a*=vOpacity; - - - //float broken = abs( sin( 1.0 - vBroken ) ) - noise2.g; - float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, vUv ).g; - if ( broken < 0.0001 ) discard; - - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - // depthWrite: false, - //blending: THREE.AdditiveBlending, - - }); - - - - - - //##################################################### object ##################################################### - let rippleMesh=null; - let quaternion = new THREE.Quaternion(); - - const addInstancedMesh2=()=>{ - const geometry2 = new THREE.PlaneGeometry( 0.5, 0.5 ); - const geometry =_getRippleGeometry(geometry2) - rippleMesh = new THREE.InstancedMesh( - geometry, - splashMaterial, - particleCount - ); - group.add(rippleMesh); - app.add(group); - const brokenAttribute = rippleMesh.geometry.getAttribute('broken'); - const quaternionsAttribute = rippleMesh.geometry.getAttribute('quaternions'); - for (let i = 0; i < particleCount; i++) { - quaternion.setFromAxisAngle(new THREE.Vector3(1,0,0),-Math.PI/2); - quaternionsAttribute.setXYZW(i,quaternion.x,quaternion.y,quaternion.z,quaternion.w); - brokenAttribute.setX(i, 1); - } - brokenAttribute.needsUpdate = true; - quaternionsAttribute.needsUpdate = true; - } - addInstancedMesh2(); - app.updateMatrixWorld(); - - let jumpSw=0; - useFrame(({timestamp}) => { - if (contactWater){ - if(jumpSw === 0 && waterSurfacePos.y < localPlayer.position.y) - jumpSw = 1; - } - else{ - if(jumpSw === 2) - jumpSw = 0; - } - - - - if (rippleMesh) { - const opacityAttribute = rippleMesh.geometry.getAttribute('opacity'); - const brokenAttribute = rippleMesh.geometry.getAttribute('broken'); - const waveFreqAttribute = rippleMesh.geometry.getAttribute('waveFreq'); - const positionsAttribute = rippleMesh.geometry.getAttribute('positions'); - const scalesAttribute = rippleMesh.geometry.getAttribute('scales'); - const quaternionsAttribute = rippleMesh.geometry.getAttribute('quaternions'); - const speedAttribute = rippleMesh.geometry.getAttribute('speed'); - const playerRotationAttribute = rippleMesh.geometry.getAttribute('playerRotation'); - let falling = fallindSpeed > 10 ? 10 : fallindSpeed; - for (let i = 0; i < particleCount; i++) { - if(jumpSw===1){ - playerRotationAttribute.setX(i, Math.random() * 2 * Math.PI); - waveFreqAttribute.setX(i, Math.random()); - //speedAttribute.setX(i,currentSpeed); - brokenAttribute.setX(i, 0.2 + Math.random() * (1 - falling / 10)); - scalesAttribute.setX(i, Math.random() * 0.1); - opacityAttribute.setX(i,0.15); - positionsAttribute.setXYZ(i, (Math.random() - 0.5) * 0.5 * (falling / 10), 0, (Math.random() - 0.5) * 0.5 * (falling / 10)); - } - - scalesAttribute.setX(i,scalesAttribute.getX(i) + 0.04); - if(brokenAttribute.getX(i) < 1) - brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.007); - else - scalesAttribute.setX(i,0); - - } - - if(jumpSw==1){ - group.position.x = localPlayer.position.x - app.position.x; - group.position.y = waterSurfacePos.y - app.position.y; - group.position.z = localPlayer.position.z - app.position.z; - jumpSw=2; - } - - positionsAttribute.needsUpdate = true; - opacityAttribute.needsUpdate = true; - scalesAttribute.needsUpdate = true; - speedAttribute.needsUpdate = true; - brokenAttribute.needsUpdate = true; - waveFreqAttribute.needsUpdate = true; - quaternionsAttribute.needsUpdate = true; - playerRotationAttribute.needsUpdate = true; - rippleMesh.material.uniforms.uTime.value=timestamp/1000; - - } - app.updateMatrixWorld(); - - }); - } - //###################################################################### ripple ###################################################################### - { - let splashMesh; - const group = new THREE.Group(); - (async () => { - const u = `${baseUrl}/assets/ripple.glb`; - const splashMeshApp = await new Promise((accept, reject) => { - const {gltfLoader} = useLoaders(); - gltfLoader.load(u, accept, function onprogress() {}, reject); - - }); - group.add(splashMeshApp.scene) - splashMesh = splashMeshApp.scene.children[0]; - splashMesh.scale.set(0, 0, 0); - splashMesh.material= new THREE.ShaderMaterial({ - uniforms: { - uTime: { - value: 0, - }, - vBroken: { - value: 0, - }, - vTextureRotation:{ - value:0 - }, - rippleTexture:{ - value: rippleTexture2 - }, - maskTexture:{ - value: maskTexture - }, - voronoiNoiseTexture:{ - value:voronoiNoiseTexture - }, - waterSurfacePos:{ - value: new THREE.Vector3() - }, - playerPos:{ - value: new THREE.Vector3() - }, - noiseMap:{ - value: noiseMap - }, - }, - vertexShader: `\ - - ${THREE.ShaderChunk.common} - ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - - uniform float uTime; - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vPos2; - - void main() { - vUv=uv; - vPos2=position; - vec4 modelPosition = modelMatrix * vec4(position, 1.0); - vec4 viewPosition = viewMatrix * modelPosition; - vec4 projectionPosition = projectionMatrix * viewPosition; - - gl_Position = projectionPosition; - vPos = modelPosition.xyz; - ${THREE.ShaderChunk.logdepthbuf_vertex} - } - `, - fragmentShader: `\ - ${THREE.ShaderChunk.logdepthbuf_pars_fragment} - uniform float uTime; - uniform float vTextureRotation; - uniform float vBroken; - - uniform sampler2D rippleTexture; - uniform sampler2D noiseMap; - uniform sampler2D maskTexture; - uniform sampler2D voronoiNoiseTexture; - - uniform vec3 waterSurfacePos; - uniform vec3 playerPos; - - - varying vec2 vUv; - varying vec3 vPos; - varying vec3 vPos2; - #define PI 3.1415926 - - void main() { - vec2 mainUv = vec2( - vUv.x , - vUv.y - uTime / 1. - ); - vec4 voronoiNoise = texture2D( - voronoiNoiseTexture, - mainUv - ); - - vec2 distortionUv = mix(vUv, mainUv + voronoiNoise.rg, 0.3); - - - vec4 ripple = texture2D( - rippleTexture, - (distortionUv + mainUv) / 2. - ); - vec4 noise = texture2D( - noiseMap, - (distortionUv + mainUv) / 2. - ); - if(ripple.a > 0.5){ - gl_FragColor = ripple; - } - else{ - gl_FragColor.a = 0.; - discard; - } - - // if(vPos.y < waterSurfacePos.y){ - // discard; - // } - - - float broken = abs( sin( 1.0 - vBroken ) ) - noise.g; - if ( broken < 0.0001 ) discard; - gl_FragColor.rgb *= 0.8; - - ${THREE.ShaderChunk.logdepthbuf_fragment} - } - `, - side: THREE.DoubleSide, - transparent: true, - // depthWrite: false, - blending: THREE.AdditiveBlending, - }); - })(); - - let groupInApp = false; - let playEffectSw=0; - let alreadySetComposer = false; - useFrame(({timestamp}) => { - if(!alreadySetComposer){ - if(splashMesh && reflectionSsrPass){ - reflectionSsrPass._selects.push(splashMesh); - alreadySetComposer = true; - } - } - if (contactWater){ - if(playEffectSw === 0 && waterSurfacePos.y < localPlayer.position.y){ - playEffectSw = 1; - if(fallindSpeed > 1){ - // todo: Commented temporarily for merging, to prevent reporting error, need to be restored. - let regex = new RegExp('^water/jump_water[0-9]*.wav$'); - const candidateAudios = soundFiles.water.filter(f => regex.test(f.name)); - const audioSpec = candidateAudios[Math.floor(Math.random() * candidateAudios.length)]; - sounds.playSound(audioSpec); - } - } - - } - else{ - if(playEffectSw === 2) - playEffectSw = 0; - } - - if (splashMesh) { - - // splashMesh.scale.z += 0.006; - // splashMesh.scale.y += 0.006; - // splashMesh.position.y -= 0.01; - // if(splashMesh.scale.z < 0.3) - // splashMesh.material.uniforms.vBroken.value = splashMesh.material.uniforms.vBroken.value - 0.02; - // else{ - // if(splashMesh.material.uniforms.vBroken.value < 1) - // splashMesh.material.uniforms.vBroken.value = splashMesh.material.uniforms.vBroken.value + 0.02; - // } - if(playEffectSw === 1 && fallindSpeed > 6){ - group.position.x = localPlayer.position.x - app.position.x; - group.position.y = waterSurfacePos.y - app.position.y; - group.position.z = localPlayer.position.z - app.position.z; - splashMesh.material.uniforms.vBroken.value = 0.1; - splashMesh.scale.set(0.2, 1, 0.2); - splashMesh.material.uniforms.uTime.value = 120; - if(!groupInApp){ - app.add(group); - groupInApp = true; - } - } - let falling = fallindSpeed > 10 ? 10 : fallindSpeed; - if(splashMesh.material.uniforms.vBroken.value < 1){ - if(splashMesh.scale.x > 0.15 * (1 + falling * 0.1)) - splashMesh.material.uniforms.vBroken.value = splashMesh.material.uniforms.vBroken.value * 1.025; - splashMesh.scale.x += 0.007 * (1 + falling * 0.1); - // splashMesh.scale.y += 0.01; - splashMesh.scale.z += 0.007 * (1 + falling * 0.1); - } - else{ - if(groupInApp){ - app.remove(group); - groupInApp = false; - } - } - - - if(playEffectSw === 1){ - playEffectSw = 2; - } - splashMesh.material.uniforms.uTime.value += 0.015; - group.updateMatrixWorld(); - - } - - - }); - } - - //###################################################################### 3 layers ripple ###################################################################### -// { -// const identityQuaternion = new THREE.Quaternion(); -// const count = 3; - - -// const _getRippleGeometry = geometry => { -// const geometry2 = new THREE.BufferGeometry(); -// ['position', 'normal', 'uv'].forEach(k => { -// geometry2.setAttribute(k, geometry.attributes[k]); -// }); -// geometry2.setIndex(geometry.index); - -// const positions = new Float32Array(count * 3); -// const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); -// geometry2.setAttribute('positions', positionsAttribute); -// const quaternions = new Float32Array(count * 4); -// for (let i = 0; i < count; i++) { -// identityQuaternion.toArray(quaternions, i * 4); -// } -// const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); -// geometry2.setAttribute('quaternions', quaternionsAttribute); - -// // const startTimes = new Float32Array(count); -// // const startTimesAttribute = new THREE.InstancedBufferAttribute(startTimes, 1); -// // geometry2.setAttribute('startTimes', startTimesAttribute); - -// const scales = new Float32Array(count); -// const scaleAttribute = new THREE.InstancedBufferAttribute(scales, 1); -// geometry2.setAttribute('scales', scaleAttribute); - -// return geometry2; -// }; - -// //######################################################################### material ######################################################################### -// const rippleMaterial = new THREE.ShaderMaterial({ -// uniforms: { -// uTime: { -// value: 0, -// }, -// opacity: { -// value: 0, -// }, -// uBroken: { -// value: 0, -// }, -// perlinnoise:{ -// value: rippleTexture -// }, -// noiseMap:{ -// value: noiseMap -// } -// }, -// vertexShader: `\ - -// ${THREE.ShaderChunk.common} -// ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - -// uniform float uTime; - -// varying vec2 vUv; -// varying vec3 vPos; -// attribute vec3 positions; -// attribute float scales; -// attribute vec4 quaternions; - -// vec3 qtransform(vec3 v, vec4 q) { -// return v + 2.0*cross(cross(v, q.xyz ) + q.w*v, q.xyz); -// } - -// void main() { -// vUv=uv; -// vPos=position; -// vec3 pos = position; -// pos+=positions; -// pos*=scales; -// pos = qtransform(pos, quaternions); -// //pos.y=cos(uTime/100.); -// vec4 modelPosition = modelMatrix * vec4(pos, 1.0); -// vec4 viewPosition = viewMatrix * modelPosition; -// vec4 projectionPosition = projectionMatrix * viewPosition; - -// gl_Position = projectionPosition; -// ${THREE.ShaderChunk.logdepthbuf_vertex} -// } -// `, -// fragmentShader: `\ -// ${THREE.ShaderChunk.logdepthbuf_pars_fragment} -// uniform float uTime; -// uniform float opacity; -// uniform float uBroken; -// varying vec2 vUv; -// varying vec3 vPos; -// uniform sampler2D perlinnoise; -// uniform sampler2D noiseMap; - - - - - -// void main() { -// vec3 ripple = texture2D( -// perlinnoise, -// mod(1.*vec2(5.*vUv.x,2.*vUv.y-uTime*5. ),1.) -// ).rgb; - -// vec3 noise = texture2D( -// noiseMap, -// mod(1.*vec2(2.*vUv.x,2.*vUv.y-uTime*5. ),1.) -// ).rgb; - - - -// gl_FragColor = vec4(ripple.rgb,1.0); - -// if(gl_FragColor.r >= 0.65){ -// gl_FragColor = vec4(1.,1.,1.,1.); -// }else{ -// gl_FragColor = vec4(0.,0.,1.,0.); -// } -// float broken = abs( sin( pow(1.0 - vUv.y,1.) ) ) - noise.g; -// if ( broken < 0.0001 ) discard; -// gl_FragColor.a*=opacity; -// if(uTime>0.48) -// gl_FragColor.a=0.; - -// if(gl_FragColor.a > 0.){ -// gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); -// } -// else{ -// discard; -// } - -// //gl_FragColor=vec4(1.0,1.0,0.,1.0); -// ${THREE.ShaderChunk.logdepthbuf_fragment} -// } -// `, -// side: THREE.DoubleSide, -// transparent: true, -// // depthWrite: false, -// // blending: THREE.AdditiveBlending, - -// }); - - -// let rippleApp; -// let group = new THREE.Group(); -// (async () => { -// const u = `${baseUrl}/assets/torus2.glb`; -// rippleApp = await new Promise((accept, reject) => { -// const {gltfLoader} = useLoaders(); -// gltfLoader.load(u, accept, function onprogress() {}, reject); - -// }); -// rippleApp.scene.traverse(o => { -// if (o.isMesh) { -// addInstancedMesh(o.geometry); -// } -// }); - - -// })(); - -// let quaternion = new THREE.Quaternion(); -// let euler = new THREE.Euler(); -// let mesh=null; -// const addInstancedMesh=(rippleGeometry)=>{ -// const geometry = _getRippleGeometry(rippleGeometry); -// mesh = new THREE.InstancedMesh( -// geometry, -// rippleMaterial, -// count -// ); -// group.add(mesh); -// app.add(group); -// const positionsAttribute = mesh.geometry.getAttribute('positions'); -// const scalesAttribute = mesh.geometry.getAttribute('scales'); -// const quaternionsAttribute = mesh.geometry.getAttribute('quaternions'); -// for (let i = 0; i < count; i++) { - -// let randScale = 0.5+0.4*i*(Math.random()); -// let randPos = 0.15*(Math.random()); -// positionsAttribute.setXYZ(i, randPos, (Math.random()-0.5)*0.5, randPos); -// scalesAttribute.setX(i, randScale); - -// euler.x=(Math.random()-0.5)*0.25; -// euler.y=(Math.random()-0.5); -// euler.z=(Math.random()-0.5)*0.25; - - -// quaternion.setFromEuler(euler); -// quaternionsAttribute.setXYZW(i,quaternion.x,quaternion.y,quaternion.z,quaternion.w); - - -// } -// positionsAttribute.needsUpdate = true; -// scalesAttribute.needsUpdate = true; -// quaternionsAttribute.needsUpdate = true; -// } - -// app.updateMatrixWorld(); - - -// let playEffectSw=0; -// useFrame(({timestamp}) => { -// if (contactWater ){ -// if(playEffectSw === 0 && waterSurfacePos.y < localPlayer.position.y) -// playEffectSw = 1; -// } -// else{ -// if(playEffectSw === 2) -// playEffectSw = 0; -// } -// if (mesh) { -// const positionsAttribute = mesh.geometry.getAttribute('positions'); -// const scalesAttribute = mesh.geometry.getAttribute('scales'); -// const quaternionsAttribute = mesh.geometry.getAttribute('quaternions'); -// let falling = fallindSpeed > 10 ? 10 : fallindSpeed; -// for (let i = 0; i < count; i++) { -// if(playEffectSw === 1){ - -// let randScale = (0.3 * (falling / 10) * (i + 1)) / 3; -// scalesAttribute.setX(i, randScale * 2); -// if(fallindSpeed <= 6){ -// if(i !== 2){ -// scalesAttribute.setX(i, 0); -// } -// } - -// positionsAttribute.setXYZ(i, 0, (Math.random()-0.5)*0.1, 0); - - -// euler.x=(Math.random()-0.5)*0.05; -// euler.y=(Math.random()-0.5); -// euler.z=(Math.random()-0.5)*0.05; - - -// quaternion.setFromEuler(euler); -// quaternionsAttribute.setXYZW(i,quaternion.x,quaternion.y,quaternion.z,quaternion.w); -// } -// if(scalesAttribute.getX(i) > 0) -// scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.01 * (i + 1) * 0.25); - -// } -// positionsAttribute.needsUpdate = true; -// scalesAttribute.needsUpdate = true; -// quaternionsAttribute.needsUpdate = true; -// } - - - - -// if(playEffectSw === 1){ -// group.position.copy(localPlayer.position); -// rippleMaterial.uniforms.uTime.value=0.35; -// rippleMaterial.uniforms.opacity.value = 1; -// playEffectSw = 2; -// } - - - -// if(rippleMaterial.uniforms.uTime.value>0.43) -// rippleMaterial.uniforms.opacity.value-=0.05; - - -// rippleMaterial.uniforms.uTime.value += 0.0025 - - - - -// // if (localPlayer.avatar) { -// // group.position.y -= localPlayer.avatar.height; -// // group.position.y += 0.65; -// // } -// group.position.y = waterSurfacePos.y - 0.05; -// app.updateMatrixWorld(); -// }); -// } - //###################################################################### swim sprint splash ###################################################################### -// { -// let splashMesh; -// const group = new THREE.Group(); -// (async () => { -// const u = `${baseUrl}/assets/droplet.glb`; -// const splashMeshApp = await new Promise((accept, reject) => { -// const {gltfLoader} = useLoaders(); -// gltfLoader.load(u, accept, function onprogress() {}, reject); - -// }); -// group.add(splashMeshApp.scene) -// app.add(group); -// splashMesh = splashMeshApp.scene.children[0]; -// splashMeshApp.scene.rotation.x = -Math.PI / 2; -// // splashMesh.scale.z = 0.3; -// // splashMesh.scale.x = 1.5; -// splashMesh.material= new THREE.ShaderMaterial({ -// uniforms: { -// uTime: { -// value: 0, -// }, -// vBroken: { -// value: 0, -// }, -// vTextureRotation:{ -// value:0 -// }, -// splashTexture:{ -// value: rippleTexture -// }, -// waterSurfacePos:{ -// value: new THREE.Vector3() -// }, -// playerPos:{ -// value: new THREE.Vector3() -// }, -// noiseMap:{ -// value: noiseMap -// }, -// }, -// vertexShader: `\ - -// ${THREE.ShaderChunk.common} -// ${THREE.ShaderChunk.logdepthbuf_pars_vertex} - - -// uniform float uTime; - -// varying vec2 vUv; -// varying vec3 vPos; -// varying vec3 vPos2; - -// void main() { -// vUv=uv; -// vPos2=position; -// vec4 modelPosition = modelMatrix * vec4(position, 1.0); -// vec4 viewPosition = viewMatrix * modelPosition; -// vec4 projectionPosition = projectionMatrix * viewPosition; - -// gl_Position = projectionPosition; -// vPos = modelPosition.xyz; -// ${THREE.ShaderChunk.logdepthbuf_vertex} -// } -// `, -// fragmentShader: `\ -// ${THREE.ShaderChunk.logdepthbuf_pars_fragment} -// uniform float uTime; -// uniform float vTextureRotation; -// uniform float vBroken; - -// uniform sampler2D splashTexture; -// uniform sampler2D noiseMap; -// uniform vec3 waterSurfacePos; -// uniform vec3 playerPos; - - -// varying vec2 vUv; -// varying vec3 vPos; -// varying vec3 vPos2; -// #define PI 3.1415926 - -// void main() { -// float mid = 0.5; -// vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, -// cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); -// vec4 splash = texture2D( -// splashTexture, -// vUv -// ); -// if(splash.r > 0.1){ -// gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); -// } -// else{ -// discard; -// } -// if(vPos.y < waterSurfacePos.y){ -// discard; -// } -// float tBroken = vBroken < 0.4 ? 0.4 : vBroken; -// float broken2 = abs( sin( 1.0 - tBroken * (1. - vPos2.z) ) ) - texture2D( noiseMap, vUv ).g; -// if( broken2 < 0.0001){ -// discard; -// } -// float broken3 = abs( sin( 1.0 - 0.75 * vUv.y ) ) - texture2D( noiseMap, vUv ).g; -// if ( broken3 < 0.0001) discard; - -// float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, vUv ).g; -// if ( broken < 0.0001 ) discard; - -// ${THREE.ShaderChunk.logdepthbuf_fragment} -// } -// `, -// side: THREE.DoubleSide, -// transparent: true, -// // depthWrite: false, -// // blending: THREE.AdditiveBlending, -// }); -// })(); - -// useFrame(({timestamp}) => { - -// if (splashMesh) { -// if(splashMesh.scale.z > 0.5){ -// splashMesh.scale.z = 0.1; -// splashMesh.scale.y = 0.2; -// splashMesh.position.y = 0.39765170216560364; -// // splashMesh.scale.x = 1.5; -// splashMesh.material.uniforms.vBroken.value = 0.8; -// splashMesh.material.uniforms.vTextureRotation.value = Math.random() * 2; -// } -// else{ -// splashMesh.scale.z += 0.006; -// splashMesh.scale.y += 0.006; -// splashMesh.position.y -= 0.01; -// if(splashMesh.scale.z < 0.3) -// splashMesh.material.uniforms.vBroken.value = splashMesh.material.uniforms.vBroken.value - 0.02; -// else{ -// if(splashMesh.material.uniforms.vBroken.value < 1) -// splashMesh.material.uniforms.vBroken.value = splashMesh.material.uniforms.vBroken.value + 0.02; -// } -// } - -// // splashMesh.scale.x -= 0.01; - -// group.position.copy(localPlayer.position); -// group.position.x += playerDir.x * 0.7; -// group.position.z += playerDir.z * 0.7; - -// group.position.y = waterSurfacePos.y + 0.02; -// group.rotation.copy(localPlayer.rotation); -// splashMesh.material.uniforms.waterSurfacePos.value.copy(waterSurfacePos); -// splashMesh.material.uniforms.playerPos.value.set(localPlayer.position.x + playerDir.x, localPlayer.position.y, localPlayer.position.z + playerDir.z); - - -// } - - -// }); -// } - - useFrame(() => { - /* if (!!tracker && !app.getComponent('renderPosition')) { - const localPlayer = useLocalPlayer(); - localMatrix - .copy(localPlayer.matrixWorld) - .premultiply(localMatrix2.copy(app.matrixWorld).invert()) - .decompose(localVector, localQuaternion, localVector2); - tracker.update(localVector, localQuaternion, camera.projectionMatrix); - } */ - }); - + return app; }; \ No newline at end of file From 2041b1742cf86a42eee72db7e7c157f95f32bd6d Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Sun, 24 Jul 2022 21:03:14 -0400 Subject: [PATCH 02/16] double check --- index.js | 159 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 109 insertions(+), 50 deletions(-) diff --git a/index.js b/index.js index 8ca76b2..abf5498 100644 --- a/index.js +++ b/index.js @@ -857,6 +857,7 @@ export default (e) => { const material2 = new THREE.MeshBasicMaterial( { color: 0xff0000, transparent:true, opacity:0.3} ); const sphere2 = new THREE.Mesh( geometry, material2 ); app.add( sphere2 ); + const testHDir = new THREE.Vector3(); useFrame(({timestamp, timeDiff}) => { if (!!tracker && !app.getComponent('renderPosition')) { @@ -919,61 +920,121 @@ export default (e) => { // generator.physics.disableGeometryQueries(physicsObject) // } // } - { - let min = null; - tempPhysics = null; - localVector02.set(localPlayer.position.x, localPlayer.position.y - localPlayer.avatar.height, localPlayer.position.z); - for(const physicsObject of generator.getPhysicsObjects()){ - for(let i = 0; i < physicsObject.positions.length / 3; i++){ - tempPos.set(physicsObject.positions[i * 3 + 0], physicsObject.positions[i * 3 + 1], physicsObject.positions[i * 3 + 2]).add(waterWorldPosition); - if(!min || tempPos.distanceTo(localVector02) < min){ - min = tempPos.distanceTo(localVector02); - tempPhysicsPos.set(tempPos.x, tempPos.y, tempPos.z); - tempPhysics = physicsObject; - } - } - generator.physics.enableGeometryQueries(physicsObject); - } - if(tempPhysics){ + + + // check whether in the water + let min = null; + tempPhysics = null; + localVector02.set(localPlayer.position.x, localPlayer.position.y - localPlayer.avatar.height, localPlayer.position.z); + for(const physicsObject of generator.getPhysicsObjects()){ + + for(let i = 0; i < physicsObject.positions.length / 3; i++){ + tempPos.set(physicsObject.positions[i * 3 + 0], physicsObject.positions[i * 3 + 1], physicsObject.positions[i * 3 + 2]).add(waterWorldPosition); + if(!min || tempPos.distanceTo(localVector02) < min){ + min = tempPos.distanceTo(localVector02); + tempPhysicsPos.set(tempPos.x, tempPos.y, tempPos.z); + tempPhysics = physicsObject; + } + } + generator.physics.enableGeometryQueries(physicsObject); + } + if(tempPhysics){ tempDir.set(tempPhysicsPos.x - localPlayer.position.x, tempPhysicsPos.y - (localPlayer.position.y - localPlayer.avatar.height), tempPhysicsPos.z - localPlayer.position.z); tempDir.normalize(); - const detectDistance = 0.3; - - localVector01.set(tempPhysicsPos.x + tempDir.x * detectDistance, tempPhysicsPos.y + tempDir.y * detectDistance, tempPhysicsPos.z + tempDir.z * detectDistance); - localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); - localVector06.copy(localVector01).sub(localVector05); - const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; - upVector.crossVectors(localVector01, localVector05); - mx.lookAt(localVector01, localVector05, upVector); - qt.setFromRotationMatrix(mx); - let result = generator.physics.raycast(localVector01, qt); - - contactWater = false; - for(const physicsObject of generator.getPhysicsObjects()){ - if(result.objectId === physicsObject.physicsId && result.distance <= ds){ - contactWater = true; - // sphere.position.set(result.point[0], result.point[1], result.point[2]).sub(waterWorldPosition); - localVector07.set(result.point[0], result.point[1], result.point[2]); - } - generator.physics.disableGeometryQueries(physicsObject) + if(count % 2 === 0){ + localVector01.set(tempPhysicsPos.x + tempDir.x * detectDistance, tempPhysicsPos.y + tempDir.y * detectDistance, tempPhysicsPos.z + tempDir.z * detectDistance); + localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); + localVector06.copy(localVector01).sub(localVector05); + const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; + upVector.crossVectors(localVector01, localVector05); + mx.lookAt(localVector01, localVector05, upVector); + qt.setFromRotationMatrix(mx); + let result = generator.physics.raycast(localVector01, qt); + testContact1 = false; + for(const physicsObject of generator.getPhysicsObjects()){ + if(result.objectId === physicsObject.physicsId && result.distance <= ds){ + testContact1 = true; + localVector07.set(result.point[0], result.point[1], result.point[2]); + } + generator.physics.disableGeometryQueries(physicsObject) + } + if(testContact1){ + testHDir.copy(localVector01).sub(localVector05).normalize(); + if(testHDir.y > 0.85 && localVector07.y > localPlayer.position.y){ + + console.log('h', testHDir.y); + waterSurfacePos.copy(localVector07); + particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); + if(!playerHighestWaterSurface) + playerHighestWaterSurface = result.point[1]; + else + playerHighestWaterSurface = playerHighestWaterSurface < waterSurfacePos.y ? waterSurfacePos.y : playerHighestWaterSurface; + + } + else{ + waterSurfacePos.y = playerHighestWaterSurface; + particleWaterSurfacePos.y = playerHighestWaterSurface - waterWorldPosition.y; + } + + + } + } - if(contactWater){ - if(localVector07.y - localPlayer.position.y > 0.1 || localVector07.y - (localPlayer.position.y - localPlayer.avatar.height) > localPlayer.avatar.height * 0.5){ - waterSurfacePos.copy(localVector07); - particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); - } - else{ - waterSurfacePos.y = 1000; - particleWaterSurfacePos.y = 1000; - } + else{ + localVector01.set(tempPhysicsPos.x - tempDir.x * detectDistance, tempPhysicsPos.y - tempDir.y * detectDistance, tempPhysicsPos.z - tempDir.z * detectDistance); + localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); + localVector06.copy(localVector01).sub(localVector05); + const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; + upVector.crossVectors(localVector01, localVector05); + mx.lookAt(localVector01, localVector05, upVector); + qt.setFromRotationMatrix(mx); + let result = generator.physics.raycast(localVector01, qt); + testContact2 = true; + for(const physicsObject of generator.getPhysicsObjects()){ + if(result.objectId === physicsObject.physicsId && result.distance <= ds){ + testContact2 = false; + localVector07.set(result.point[0], result.point[1], result.point[2]); + } + generator.physics.disableGeometryQueries(physicsObject) + } + if(testContact2){ + testHDir.copy(localVector01).sub(localVector05).normalize(); + if(testHDir.y < -0.85 && localVector07.y > localPlayer.position.y - localPlayer.avatar.height * 0.5){ + + console.log('h2', testHDir.y); + waterSurfacePos.copy(localVector07); + particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); + if(!playerHighestWaterSurface) + playerHighestWaterSurface = result.point[1]; + else + playerHighestWaterSurface = playerHighestWaterSurface < waterSurfacePos.y ? waterSurfacePos.y : playerHighestWaterSurface; + + } + else{ + waterSurfacePos.y = playerHighestWaterSurface; + particleWaterSurfacePos.y = playerHighestWaterSurface - waterWorldPosition.y; + } + + + } } - } } + if(testContact1 === testContact2){ + contactWater = testContact1; + lastContactWater = contactWater; + } + else{ + console.log('inconsist') + contactWater = lastContactWater; + } + + + sphere2.position.copy(particleWaterSurfacePos); app.updateMatrixWorld(); - + // handle swim action if(!contactWater){ if(localPlayer.hasAction('swim')){ //console.log('remove'); @@ -1009,12 +1070,10 @@ export default (e) => { localPlayer.removeAction('swim'); } } - } - - - + } } } + count++; }); useCleanup(() => { From 9fcc696c620690dbaf6399d6d72765d5860af348 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Sun, 24 Jul 2022 21:41:47 -0400 Subject: [PATCH 03/16] initial swim action check --- index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index abf5498..1125a6f 100644 --- a/index.js +++ b/index.js @@ -962,7 +962,6 @@ export default (e) => { if(testContact1){ testHDir.copy(localVector01).sub(localVector05).normalize(); if(testHDir.y > 0.85 && localVector07.y > localPlayer.position.y){ - console.log('h', testHDir.y); waterSurfacePos.copy(localVector07); particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); @@ -1001,7 +1000,6 @@ export default (e) => { if(testContact2){ testHDir.copy(localVector01).sub(localVector05).normalize(); if(testHDir.y < -0.85 && localVector07.y > localPlayer.position.y - localPlayer.avatar.height * 0.5){ - console.log('h2', testHDir.y); waterSurfacePos.copy(localVector07); particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); @@ -1042,6 +1040,7 @@ export default (e) => { } } else{ + if(playerHighestWaterSurface){ if(waterSurfacePos.y >= localPlayer.position.y - localPlayer.avatar.height + localPlayer.avatar.height * 0.8){ if(!localPlayer.hasAction('swim')){ //console.log('add'); @@ -1070,6 +1069,8 @@ export default (e) => { localPlayer.removeAction('swim'); } } + } + } } } From 3d9470c64f744421ea093303a663a4dc301d6722 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Sun, 24 Jul 2022 23:25:50 -0400 Subject: [PATCH 04/16] import particle --- index.js | 59 +++++++++++++++++--------------------------------------- 1 file changed, 18 insertions(+), 41 deletions(-) diff --git a/index.js b/index.js index 1125a6f..ab113cd 100644 --- a/index.js +++ b/index.js @@ -1,7 +1,7 @@ import metaversefile from 'metaversefile'; // import { useSyncExternalStore } from 'react'; import * as THREE from 'three'; -import { ConvexGeometry } from 'three/examples/jsm/geometries/ConvexGeometry.js'; +import ParticleEffect from './particle.js'; // import { terrainVertex, terrainFragment } from './shaders/terrainShader.js'; // import biomeSpecs from './biomes.js'; @@ -170,6 +170,9 @@ class WaterMesh extends BatchedMesh { }, waterNormalTexture2:{ value:waterNormalTexture2 + }, + waterWorldPosition:{ + value: new THREE.Vector3() } }, vertexShader: `\ @@ -205,6 +208,8 @@ class WaterMesh extends BatchedMesh { uniform float uTime; uniform vec3 sunPosition; uniform vec3 sunDirection; + uniform vec3 waterWorldPosition; + uniform sampler2D tDepth; uniform sampler2D tDudv; @@ -245,7 +250,7 @@ class WaterMesh extends BatchedMesh { vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) ); vec3 diffuseLight = vec3(1.0); vec3 specularLight = vec3(0.1, 0.6, 0.6); - vec3 worldToEye = worldPosition.xyz; + vec3 worldToEye = worldPosition.xyz - waterWorldPosition; vec3 eyeDirection = normalize( worldToEye ); sunLight( surfaceNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight ); float distance = length(worldToEye); @@ -634,6 +639,8 @@ export default (e) => { const minLodRange = app.getComponent('minLodRange') ?? defaultMinLodRange; const debug = app.getComponent('debug') ?? false; + const particleEffect = new ParticleEffect(app, localPlayer); + const waterSurfacePos = new THREE.Vector3(0, 0, 0); const particleWaterSurfacePos = new THREE.Vector3(0, 0, 0); const cameraWaterSurfacePos = new THREE.Vector3(0, 0, 0); @@ -663,6 +670,7 @@ export default (e) => { currentSpeed = localVector.set(localPlayer.avatar.velocity.x, 0, localPlayer.avatar.velocity.z).length(); playerHeadPos.setFromMatrixPosition(localPlayer.avatar.modelBoneOutputs.Head.matrixWorld); } + }); @@ -799,40 +807,7 @@ export default (e) => { let alreadySetComposer = false; - const rayCastByEliminatingChunk = (generator, result, ds, testVector, quaternion, targetPhysics) =>{ - let maxCheck = 5; - let physicsList = []; - for(let i = 0; i < maxCheck; i++){ - if(result.distance <= ds){ - let dummy = metaversefile.getPhysicsObjectByPhysicsId(result.objectId); - if(dummy){ - physicsList.push(dummy); - } - for(const p of physicsList){ - generator.physics.disableGeometryQueries(p); - } - result = generator.physics.raycast(testVector, quaternion); - for(const p of physicsList){ - if(metaversefile.getAppByPhysicsId(p.physicsId).name !== 'water') - generator.physics.enableGeometryQueries(p); - } - if(result){ - if(result.objectId === targetPhysics.physicsId && result.distance <= ds){ - return true; - } - } - else{ - return false; - } - } - else{ - return false; - } - if(i === maxCheck - 1){ - return false; - } - } - } + const pixelRatio = renderer.getPixelRatio(); @@ -860,6 +835,7 @@ export default (e) => { const testHDir = new THREE.Vector3(); useFrame(({timestamp, timeDiff}) => { + particleEffect.update(waterWorldPosition); if (!!tracker && !app.getComponent('renderPosition')) { const localPlayer = useLocalPlayer(); localMatrix @@ -905,6 +881,7 @@ export default (e) => { webaWaterPass.ssrMaterial.uniforms.distortionTexture.value = dudvMap; } generator.getMeshes()[0].material.uniforms.uTime.value = timestamp / 1000; + generator.getMeshes()[0].material.uniforms.waterWorldPosition.value.copy(waterWorldPosition); } // { // for(const physicsObject of generator.getPhysicsObjects()){ @@ -922,7 +899,7 @@ export default (e) => { // } - // check whether in the water + // check whether player is in the water let min = null; tempPhysics = null; localVector02.set(localPlayer.position.x, localPlayer.position.y - localPlayer.avatar.height, localPlayer.position.z); @@ -962,7 +939,7 @@ export default (e) => { if(testContact1){ testHDir.copy(localVector01).sub(localVector05).normalize(); if(testHDir.y > 0.85 && localVector07.y > localPlayer.position.y){ - console.log('h', testHDir.y); + // console.log('h', testHDir.y); waterSurfacePos.copy(localVector07); particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); if(!playerHighestWaterSurface) @@ -1000,7 +977,7 @@ export default (e) => { if(testContact2){ testHDir.copy(localVector01).sub(localVector05).normalize(); if(testHDir.y < -0.85 && localVector07.y > localPlayer.position.y - localPlayer.avatar.height * 0.5){ - console.log('h2', testHDir.y); + // console.log('h2', testHDir.y); waterSurfacePos.copy(localVector07); particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); if(!playerHighestWaterSurface) @@ -1030,8 +1007,8 @@ export default (e) => { - sphere2.position.copy(particleWaterSurfacePos); - app.updateMatrixWorld(); + // sphere2.position.copy(particleWaterSurfacePos); + // app.updateMatrixWorld(); // handle swim action if(!contactWater){ if(localPlayer.hasAction('swim')){ From a454c2beda95cc6328bae14a236ec252ed048eea Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Mon, 25 Jul 2022 01:29:52 -0400 Subject: [PATCH 05/16] import particle --- index.js | 189 +++++++++++++++++++++++++++----------- particle.js | 179 ++++++++++++++++++++++++++++++++++++ shaders/particleShader.js | 78 ++++++++++++++++ 3 files changed, 393 insertions(+), 53 deletions(-) create mode 100644 particle.js create mode 100644 shaders/particleShader.js diff --git a/index.js b/index.js index ab113cd..d208ac0 100644 --- a/index.js +++ b/index.js @@ -256,11 +256,11 @@ class WaterMesh extends BatchedMesh { float distance = length(worldToEye); float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 ); - vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) * 0.2 ) * vec3(0.5, 0.5, 0.5); + vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) * 0.25 ) * vec3(0.5, 0.5, 0.5); vec3 albedo = ( vec3(0.3, 0.3, 0.3) * diffuseLight * 0.025 + scatter ); vec3 outgoingLight = albedo; - gl_FragColor = (vec4( outgoingLight, 0.95 )) + + vec4(0.0282, 0.470, 0.431, 0.); - + gl_FragColor = (vec4( outgoingLight, 0.95 )) + vec4(0.0282, 0.470, 0.431, 0.); + gl_FragColor.rgb /= 1.2; // foam vec2 screenUV = gl_FragCoord.xy / resolution; @@ -807,8 +807,6 @@ export default (e) => { let alreadySetComposer = false; - - const pixelRatio = renderer.getPixelRatio(); const renderTarget = new THREE.WebGLRenderTarget( @@ -824,18 +822,13 @@ export default (e) => { depthMaterial.depthPacking = THREE.RGBADepthPacking; depthMaterial.blending = THREE.NoBlending; - - const geometry = new THREE.SphereGeometry( 0.5, 32, 16 ); - const material = new THREE.MeshBasicMaterial( { color: 0xffff00 , transparent:true, opacity:0.3} ); - const sphere = new THREE.Mesh( geometry, material ); - app.add( sphere ); - const material2 = new THREE.MeshBasicMaterial( { color: 0xff0000, transparent:true, opacity:0.3} ); - const sphere2 = new THREE.Mesh( geometry, material2 ); - app.add( sphere2 ); const testHDir = new THREE.Vector3(); useFrame(({timestamp, timeDiff}) => { - particleEffect.update(waterWorldPosition); + particleEffect.update(timestamp); + particleEffect.particlePosition.set(localPlayer.position.x - waterWorldPosition.x, waterSurfacePos.y - waterWorldPosition.y, localPlayer.position.z - waterWorldPosition.z); + particleEffect.contactWater = contactWater; + particleEffect.fallindSpeed = fallindSpeed; if (!!tracker && !app.getComponent('renderPosition')) { const localPlayer = useLocalPlayer(); localMatrix @@ -853,6 +846,7 @@ export default (e) => { pass._selects.push(generator.getMeshes()[0]); pass.opacity = 0.12; webaWaterPass = pass; + particleEffect.webaWaterPass = webaWaterPass; } if(pass.constructor.name === 'WebaverseRenderPass'){ pass.foamDepthMaterial = depthMaterial; @@ -871,6 +865,7 @@ export default (e) => { ); generator.getMeshes()[0].material.uniforms.tDudv.value = dudvMap2; generator.getMeshes()[0].material.uniforms.tDepth.value = renderTarget.texture; + particleEffect.foamPass = foamPass; } } alreadySetComposer = true; @@ -920,42 +915,39 @@ export default (e) => { tempDir.normalize(); const detectDistance = 0.3; if(count % 2 === 0){ - localVector01.set(tempPhysicsPos.x + tempDir.x * detectDistance, tempPhysicsPos.y + tempDir.y * detectDistance, tempPhysicsPos.z + tempDir.z * detectDistance); - localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); - localVector06.copy(localVector01).sub(localVector05); - const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; - upVector.crossVectors(localVector01, localVector05); - mx.lookAt(localVector01, localVector05, upVector); - qt.setFromRotationMatrix(mx); - let result = generator.physics.raycast(localVector01, qt); - testContact1 = false; - for(const physicsObject of generator.getPhysicsObjects()){ - if(result.objectId === physicsObject.physicsId && result.distance <= ds){ - testContact1 = true; - localVector07.set(result.point[0], result.point[1], result.point[2]); - } - generator.physics.disableGeometryQueries(physicsObject) + localVector01.set(tempPhysicsPos.x + tempDir.x * detectDistance, tempPhysicsPos.y + tempDir.y * detectDistance, tempPhysicsPos.z + tempDir.z * detectDistance); + localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); + localVector06.copy(localVector01).sub(localVector05); + const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; + upVector.crossVectors(localVector01, localVector05); + mx.lookAt(localVector01, localVector05, upVector); + qt.setFromRotationMatrix(mx); + let result = generator.physics.raycast(localVector01, qt); + testContact1 = false; + for(const physicsObject of generator.getPhysicsObjects()){ + if(result.objectId === physicsObject.physicsId && result.distance <= ds){ + testContact1 = true; + localVector07.set(result.point[0], result.point[1], result.point[2]); } - if(testContact1){ - testHDir.copy(localVector01).sub(localVector05).normalize(); - if(testHDir.y > 0.85 && localVector07.y > localPlayer.position.y){ - // console.log('h', testHDir.y); - waterSurfacePos.copy(localVector07); - particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); - if(!playerHighestWaterSurface) - playerHighestWaterSurface = result.point[1]; - else - playerHighestWaterSurface = playerHighestWaterSurface < waterSurfacePos.y ? waterSurfacePos.y : playerHighestWaterSurface; - - } - else{ - waterSurfacePos.y = playerHighestWaterSurface; - particleWaterSurfacePos.y = playerHighestWaterSurface - waterWorldPosition.y; - } - + generator.physics.disableGeometryQueries(physicsObject) + } + if(testContact1){ + testHDir.copy(localVector01).sub(localVector05).normalize(); + if(testHDir.y > 0.85 && localVector07.y > localPlayer.position.y){ + // console.log('h', testHDir.y); + waterSurfacePos.copy(localVector07); + particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); + if(!playerHighestWaterSurface) + playerHighestWaterSurface = result.point[1]; + else + playerHighestWaterSurface = playerHighestWaterSurface < waterSurfacePos.y ? waterSurfacePos.y : playerHighestWaterSurface; } - + else{ + waterSurfacePos.y = playerHighestWaterSurface; + particleWaterSurfacePos.y = playerHighestWaterSurface - waterWorldPosition.y; + } + } } else{ localVector01.set(tempPhysicsPos.x - tempDir.x * detectDistance, tempPhysicsPos.y - tempDir.y * detectDistance, tempPhysicsPos.z - tempDir.z * detectDistance); @@ -1004,12 +996,6 @@ export default (e) => { contactWater = lastContactWater; } - - - - // sphere2.position.copy(particleWaterSurfacePos); - // app.updateMatrixWorld(); - // handle swim action if(!contactWater){ if(localPlayer.hasAction('swim')){ //console.log('remove'); @@ -1063,6 +1049,103 @@ export default (e) => { app.removeEventListener('componentupdate', componentupdate); }); } + //#################################################################### underwater mask ################################################################### + { + const geometry = new THREE.PlaneGeometry( 2, 2 ); + const material= new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + cameraWaterSurfacePos:{ + value: new THREE.Vector3() + }, + contactWater:{ + value: false + } + }, + vertexShader: `\ + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + uniform float uTime; + varying vec2 vUv; + varying vec3 vPos; + + void main() { + vUv = uv; + + vec3 pos = position; + vec4 modelPosition = modelMatrix * vec4(pos, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + + gl_Position = projectionPosition; + vPos = modelPosition.xyz; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } + `, + fragmentShader: `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + uniform bool contactWater; + uniform vec3 cameraWaterSurfacePos; + + varying vec2 vUv; + varying vec3 vPos; + + void main() { + gl_FragColor = vec4(0.0141, 0.235, 0.25, 0.7); + if(!contactWater || vPos.y > cameraWaterSurfacePos.y) + discard; + ${THREE.ShaderChunk.logdepthbuf_fragment} + } + `, + side: THREE.DoubleSide, + transparent: true, + //blending: THREE.AdditiveBlending, + depthWrite: false, + }); + const mask = new THREE.Mesh( geometry, material ); + //app.add( mask ); + // camera.add(mask); + let cameraHasMask = false; + let alreadySetComposer = false; + useFrame(({timestamp}) => { + if(!alreadySetComposer && foamPass && renderSettings.findRenderSettings(scene)){ + renderSettings.findRenderSettings(scene).fog.color.r = 4 / 255; + renderSettings.findRenderSettings(scene).fog.color.g = 41.5 / 255; + renderSettings.findRenderSettings(scene).fog.color.b = 44.5 / 255; + foamPass.foamInvisibleList.push(mask); + alreadySetComposer = true; + } + mask.position.set(0, 0, -0.2); + mask.material.uniforms.uTime.value = timestamp / 1000; + mask.material.uniforms.cameraWaterSurfacePos.value.copy(waterSurfacePos); + mask.material.uniforms.contactWater.value = contactWater; + if(camera.position.y + 0.03 < waterSurfacePos.y && contactWater){ + if(renderSettings.findRenderSettings(scene)){ + renderSettings.findRenderSettings(scene).fog.density = 0.05; + } + } + else{ + if(renderSettings.findRenderSettings(scene)){ + renderSettings.findRenderSettings(scene).fog.density = 0; + } + } + if(camera.position.y - 0.03 < waterSurfacePos.y && contactWater){ + if(!cameraHasMask){ + camera.add(mask); + cameraHasMask = true; + } + } + else{ + if(cameraHasMask){ + camera.remove(mask); + cameraHasMask = false; + } + } + }); + } return app; }; \ No newline at end of file diff --git a/particle.js b/particle.js new file mode 100644 index 0000000..130e91f --- /dev/null +++ b/particle.js @@ -0,0 +1,179 @@ +import metaversefile from 'metaversefile'; +import * as THREE from 'three'; +import { rippleVertex, rippleFragment } from './shaders/particleShader.js'; + +const baseUrl = import.meta.url.replace(/(\/)[^\/\\]*$/, '$1'); +const { + useLoaders, + useSound +} = metaversefile; +const sounds = useSound(); +const soundFiles = sounds.getSoundFiles(); + +const textureLoader = new THREE.TextureLoader(); +const bubbleTexture1 = textureLoader.load(`${baseUrl}/textures/Bubble3.png`); +const bubbleTexture2 = textureLoader.load(`${baseUrl}/textures/Bubble2.png`); +const noiseCircleTexture = textureLoader.load(`${baseUrl}/textures/noiseCircle.png`); +// const noiseTexture = textureLoader.load(`${baseUrl}/textures/perlin-noise.jpg`); +// const noiseTexture2 = textureLoader.load(`${baseUrl}/textures/noise.jpg`); +const voronoiNoiseTexture = textureLoader.load(`${baseUrl}/textures/voronoiNoise.jpg`); +voronoiNoiseTexture.wrapS = voronoiNoiseTexture.wrapT = THREE.RepeatWrapping; +const noiseMap = textureLoader.load(`${baseUrl}/textures/noise.jpg`); +noiseMap.wrapS = noiseMap.wrapT = THREE.RepeatWrapping; +const dudvMap = textureLoader.load(`${baseUrl}/textures/dudvMap.png`); +dudvMap.wrapS = dudvMap.wrapT = THREE.RepeatWrapping; +const dudvMap2 = textureLoader.load(`${baseUrl}/textures/dudvMap2.png`); +dudvMap2.wrapS = dudvMap2.wrapT = THREE.RepeatWrapping; +const noiseMap3 = textureLoader.load(`${baseUrl}/textures/noise3.png`); +const maskTexture = textureLoader.load(`${baseUrl}/textures/mask.png`); +const splashTexture = textureLoader.load(`${baseUrl}/textures/splash1.png`); +const splashTexture2 = textureLoader.load(`${baseUrl}/textures/splash2.png`); +// const splashTexture4 = textureLoader.load(`${baseUrl}/textures/splash.png`); +const rippleTexture = textureLoader.load(`${baseUrl}/textures/ripple3.png`); +rippleTexture.wrapS = rippleTexture.wrapT = THREE.RepeatWrapping; +const rippleTexture2 = textureLoader.load(`${baseUrl}/textures/ripple2.png`); +rippleTexture2.wrapS = rippleTexture2.wrapT = THREE.RepeatWrapping; + +const waterNormalTexture1 = textureLoader.load(`${baseUrl}/textures/waterNormal2.png`); +waterNormalTexture1.wrapS = waterNormalTexture1.wrapT = THREE.RepeatWrapping; +const waterNormalTexture2 = textureLoader.load(`${baseUrl}/textures/waterNormal3.png`); +waterNormalTexture2.wrapS = waterNormalTexture2.wrapT = THREE.RepeatWrapping; + + +const waterDerivativeHeightTexture = textureLoader.load(`${baseUrl}/textures/water-derivative-height.png`); +waterDerivativeHeightTexture.wrapS = waterDerivativeHeightTexture.wrapT = THREE.RepeatWrapping; +const waterNormalTexture = textureLoader.load(`${baseUrl}/textures/water-normal.png`); +waterNormalTexture.wrapS = waterNormalTexture.wrapT = THREE.RepeatWrapping; +const waterNoiseTexture = textureLoader.load(`${baseUrl}/textures/perlin-noise.jpg`); +waterNoiseTexture.wrapS = waterNoiseTexture.wrapT = THREE.RepeatWrapping; +const waterNoiseTexture2 = textureLoader.load(`${baseUrl}/textures/water.png`); +waterNoiseTexture2.wrapS = waterNoiseTexture2.wrapT = THREE.RepeatWrapping; +const flowmapTexture = textureLoader.load(`${baseUrl}/textures/flowmap.png`); +flowmapTexture.wrapS = flowmapTexture.wrapT = THREE.RepeatWrapping; +class ParticleEffect{ + + constructor(app, player) { + this.app = app; + this.player = player; + + this.particlePosition = new THREE.Vector3(); + + this.contactWater = false; + this.lastContactWater = false; + + this.fallindSpeed = 0; + + this.alreadySetComposer = false; + + + + + this.rippleMesh = null; + this.initRipple(); + + + + } + update(timestamp){ + if(!this.alreadySetComposer){ + if(this.foamPass && this.webaWaterPass && this.rippleMesh){ + this.webaWaterPass._selects.push(this.rippleMesh); + this.foamPass.foamInvisibleList.push(this.rippleMesh); + this.alreadySetComposer = true; + } + } + + const _handleRipple = () =>{ + if(this.rippleMesh){ + if(this.contactWater && this.lastContactWater !== this.contactWater){ + if(this.fallindSpeed > 1){ + let regex = new RegExp('^water/jump_water[0-9]*.wav$'); + const candidateAudios = soundFiles.water.filter(f => regex.test(f.name)); + const audioSpec = candidateAudios[Math.floor(Math.random() * candidateAudios.length)]; + sounds.playSound(audioSpec); + } + if(this.fallindSpeed > 6){ + this.rippleGroup.position.copy(this.particlePosition); + this.rippleMesh.material.uniforms.vBroken.value = 0.1; + this.rippleMesh.scale.set(0.2, 1, 0.2); + this.rippleMesh.material.uniforms.uTime.value = 120; + } + + } + this.lastContactWater = this.contactWater; + let falling = this.fallindSpeed > 10 ? 10 : this.fallindSpeed; + if(this.rippleMesh.material.uniforms.vBroken.value < 1){ + if(this.rippleMesh.scale.x > 0.15 * (1 + falling * 0.1)) + this.rippleMesh.material.uniforms.vBroken.value = this.rippleMesh.material.uniforms.vBroken.value * 1.025; + this.rippleMesh.scale.x += 0.007 * (1 + falling * 0.1); + this.rippleMesh.scale.z += 0.007 * (1 + falling * 0.1); + this.rippleMesh.material.uniforms.uTime.value += 0.015; + } + } + } + _handleRipple(); + + + this.app.updateMatrixWorld(); + } + initRipple(){ + this.rippleGroup = new THREE.Group(); + (async () => { + const u = `${baseUrl}/assets/ripple.glb`; + const splashMeshApp = await new Promise((accept, reject) => { + const {gltfLoader} = useLoaders(); + gltfLoader.load(u, accept, function onprogress() {}, reject); + + }); + this.rippleGroup.add(splashMeshApp.scene) + this.rippleMesh = splashMeshApp.scene.children[0]; + this.rippleMesh.scale.set(0, 0, 0); + this.app.add(this.rippleGroup); + + this.rippleMesh.material = new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + vBroken: { + value: 0, + }, + vTextureRotation:{ + value:0 + }, + rippleTexture:{ + value: rippleTexture2 + }, + maskTexture:{ + value: maskTexture + }, + voronoiNoiseTexture:{ + value:voronoiNoiseTexture + }, + waterSurfacePos:{ + value: new THREE.Vector3() + }, + playerPos:{ + value: new THREE.Vector3() + }, + noiseMap:{ + value: noiseMap + }, + }, + vertexShader: rippleVertex, + fragmentShader: rippleFragment, + side: THREE.DoubleSide, + transparent: true, + // depthWrite: false, + blending: THREE.AdditiveBlending, + }); + })(); + } + + + +} + + + +export default ParticleEffect; \ No newline at end of file diff --git a/shaders/particleShader.js b/shaders/particleShader.js new file mode 100644 index 0000000..ec74710 --- /dev/null +++ b/shaders/particleShader.js @@ -0,0 +1,78 @@ +import * as THREE from 'three' +const rippleVertex = `\ + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + + + uniform float uTime; + + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vPos2; + + void main() { + vUv=uv; + vPos2=position; + vec4 modelPosition = modelMatrix * vec4(position, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + + gl_Position = projectionPosition; + vPos = modelPosition.xyz; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } +` +const rippleFragment = `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + uniform float vTextureRotation; + uniform float vBroken; + uniform sampler2D rippleTexture; + uniform sampler2D noiseMap; + uniform sampler2D maskTexture; + uniform sampler2D voronoiNoiseTexture; + + uniform vec3 waterSurfacePos; + uniform vec3 playerPos; + + + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vPos2; + #define PI 3.1415926 + void main() { + vec2 mainUv = vec2( + vUv.x , + vUv.y - uTime / 1. + ); + vec4 voronoiNoise = texture2D( + voronoiNoiseTexture, + mainUv + ); + vec2 distortionUv = mix(vUv, mainUv + voronoiNoise.rg, 0.3); + + + vec4 ripple = texture2D( + rippleTexture, + (distortionUv + mainUv) / 2. + ); + vec4 noise = texture2D( + noiseMap, + (distortionUv + mainUv) / 2. + ); + if(ripple.a > 0.5){ + gl_FragColor = ripple; + } + else{ + gl_FragColor.a = 0.; + discard; + } + float broken = abs( sin( 1.0 - vBroken ) ) - noise.g; + if ( broken < 0.0001 ) discard; + gl_FragColor.rgb *= 0.8; + ${THREE.ShaderChunk.logdepthbuf_fragment} + } +` + + +export {rippleVertex, rippleFragment}; \ No newline at end of file From bdb2ead3e331aab5224773d0d32f80181db5c5b6 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Mon, 25 Jul 2022 10:06:48 -0400 Subject: [PATCH 06/16] splash --- index.js | 37 +----- particle.js | 243 +++++++++++++++++++++++++++++++++++++- shaders/particleShader.js | 184 ++++++++++++++++++++++++++++- 3 files changed, 427 insertions(+), 37 deletions(-) diff --git a/index.js b/index.js index d208ac0..ca3f750 100644 --- a/index.js +++ b/index.js @@ -23,9 +23,6 @@ const { // useLodder, } = metaversefile; -const sounds = useSound(); -const soundFiles = sounds.getSoundFiles(); - const waterWorldPosition = new THREE.Vector3(); let webaWaterPass = null; @@ -33,28 +30,12 @@ let foamPass = null; const baseUrl = import.meta.url.replace(/(\/)[^\/\\]*$/, '$1'); const textureLoader = new THREE.TextureLoader(); -const bubbleTexture1 = textureLoader.load(`${baseUrl}/textures/Bubble3.png`); -const bubbleTexture2 = textureLoader.load(`${baseUrl}/textures/Bubble2.png`); -const noiseCircleTexture = textureLoader.load(`${baseUrl}/textures/noiseCircle.png`); -// const noiseTexture = textureLoader.load(`${baseUrl}/textures/perlin-noise.jpg`); -// const noiseTexture2 = textureLoader.load(`${baseUrl}/textures/noise.jpg`); -const voronoiNoiseTexture = textureLoader.load(`${baseUrl}/textures/voronoiNoise.jpg`); -voronoiNoiseTexture.wrapS = voronoiNoiseTexture.wrapT = THREE.RepeatWrapping; -const noiseMap = textureLoader.load(`${baseUrl}/textures/noise.jpg`); -noiseMap.wrapS = noiseMap.wrapT = THREE.RepeatWrapping; + const dudvMap = textureLoader.load(`${baseUrl}/textures/dudvMap.png`); dudvMap.wrapS = dudvMap.wrapT = THREE.RepeatWrapping; const dudvMap2 = textureLoader.load(`${baseUrl}/textures/dudvMap2.png`); dudvMap2.wrapS = dudvMap2.wrapT = THREE.RepeatWrapping; -const noiseMap3 = textureLoader.load(`${baseUrl}/textures/noise3.png`); -const maskTexture = textureLoader.load(`${baseUrl}/textures/mask.png`); -const splashTexture = textureLoader.load(`${baseUrl}/textures/splash1.png`); -const splashTexture2 = textureLoader.load(`${baseUrl}/textures/splash2.png`); -// const splashTexture4 = textureLoader.load(`${baseUrl}/textures/splash.png`); -const rippleTexture = textureLoader.load(`${baseUrl}/textures/ripple3.png`); -rippleTexture.wrapS = rippleTexture.wrapT = THREE.RepeatWrapping; -const rippleTexture2 = textureLoader.load(`${baseUrl}/textures/ripple2.png`); -rippleTexture2.wrapS = rippleTexture2.wrapT = THREE.RepeatWrapping; + const waterNormalTexture1 = textureLoader.load(`${baseUrl}/textures/waterNormal2.png`); waterNormalTexture1.wrapS = waterNormalTexture1.wrapT = THREE.RepeatWrapping; @@ -62,16 +43,7 @@ const waterNormalTexture2 = textureLoader.load(`${baseUrl}/textures/waterNormal3 waterNormalTexture2.wrapS = waterNormalTexture2.wrapT = THREE.RepeatWrapping; -const waterDerivativeHeightTexture = textureLoader.load(`${baseUrl}/textures/water-derivative-height.png`); -waterDerivativeHeightTexture.wrapS = waterDerivativeHeightTexture.wrapT = THREE.RepeatWrapping; -const waterNormalTexture = textureLoader.load(`${baseUrl}/textures/water-normal.png`); -waterNormalTexture.wrapS = waterNormalTexture.wrapT = THREE.RepeatWrapping; -const waterNoiseTexture = textureLoader.load(`${baseUrl}/textures/perlin-noise.jpg`); -waterNoiseTexture.wrapS = waterNoiseTexture.wrapT = THREE.RepeatWrapping; -const waterNoiseTexture2 = textureLoader.load(`${baseUrl}/textures/water.png`); -waterNoiseTexture2.wrapS = waterNoiseTexture2.wrapT = THREE.RepeatWrapping; -const flowmapTexture = textureLoader.load(`${baseUrl}/textures/flowmap.png`); -flowmapTexture.wrapS = flowmapTexture.wrapT = THREE.RepeatWrapping; + // const localVector = new THREE.Vector3(); const localVector2 = new THREE.Vector3(); @@ -639,7 +611,7 @@ export default (e) => { const minLodRange = app.getComponent('minLodRange') ?? defaultMinLodRange; const debug = app.getComponent('debug') ?? false; - const particleEffect = new ParticleEffect(app, localPlayer); + const particleEffect = new ParticleEffect(app, localPlayer, camera); const waterSurfacePos = new THREE.Vector3(0, 0, 0); const particleWaterSurfacePos = new THREE.Vector3(0, 0, 0); @@ -829,6 +801,7 @@ export default (e) => { particleEffect.particlePosition.set(localPlayer.position.x - waterWorldPosition.x, waterSurfacePos.y - waterWorldPosition.y, localPlayer.position.z - waterWorldPosition.z); particleEffect.contactWater = contactWater; particleEffect.fallindSpeed = fallindSpeed; + particleEffect.waterSurfacePos.copy(waterSurfacePos); if (!!tracker && !app.getComponent('renderPosition')) { const localPlayer = useLocalPlayer(); localMatrix diff --git a/particle.js b/particle.js index 130e91f..42daf02 100644 --- a/particle.js +++ b/particle.js @@ -1,6 +1,8 @@ import metaversefile from 'metaversefile'; import * as THREE from 'three'; import { rippleVertex, rippleFragment } from './shaders/particleShader.js'; +import { lowerSplashVertex, lowerSplashFragment } from './shaders/particleShader.js'; +import { higherSplashVertex, higherSplashFragment } from './shaders/particleShader.js'; const baseUrl = import.meta.url.replace(/(\/)[^\/\\]*$/, '$1'); const { @@ -52,20 +54,29 @@ const flowmapTexture = textureLoader.load(`${baseUrl}/textures/flowmap.png`); flowmapTexture.wrapS = flowmapTexture.wrapT = THREE.RepeatWrapping; class ParticleEffect{ - constructor(app, player) { + constructor(app, player, camera) { this.app = app; this.player = player; + this.camera = camera; this.particlePosition = new THREE.Vector3(); + this.waterSurfacePos = new THREE.Vector3(); this.contactWater = false; this.lastContactWater = false; + this.higherSplashSw = 2; + this.higherSplashPos = new THREE.Vector3(); + this.fallindSpeed = 0; this.alreadySetComposer = false; - + this.lowerSplash = null; + this.initLowerSplash(); + + this.higherSplash = null; + this.initHigherSplash(); this.rippleMesh = null; @@ -100,7 +111,6 @@ class ParticleEffect{ } } - this.lastContactWater = this.contactWater; let falling = this.fallindSpeed > 10 ? 10 : this.fallindSpeed; if(this.rippleMesh.material.uniforms.vBroken.value < 1){ if(this.rippleMesh.scale.x > 0.15 * (1 + falling * 0.1)) @@ -113,8 +123,126 @@ class ParticleEffect{ } _handleRipple(); + const _handleLowerSplash = () =>{ + if(this.lowerSplash){ + const brokenAttribute = this.lowerSplash.geometry.getAttribute('broken'); + const positionsAttribute = this.lowerSplash.geometry.getAttribute('positions'); + const scalesAttribute = this.lowerSplash.geometry.getAttribute('scales'); + const textureRotationAttribute = this.lowerSplash.geometry.getAttribute('textureRotation'); + const particleCount = this.lowerSplash.info.particleCount; + for (let i = 0; i < particleCount; i++){ + if(this.contactWater && this.lastContactWater !== this.contactWater){ + if(this.fallindSpeed > 6){ + this.lowerSplash.info.velocity[i].x = Math.sin(i) * .1 + (Math.random() - 0.5) * 0.01; + this.lowerSplash.info.velocity[i].y = 0.15 * Math.random(); + this.lowerSplash.info.velocity[i].z = Math.cos(i) * .1 + (Math.random() - 0.5) * 0.01; + positionsAttribute.setXYZ( i, + this.particlePosition.x + this.lowerSplash.info.velocity[i].x, + this.particlePosition.y + 0.1 * Math.random(), + this.particlePosition.z + this.lowerSplash.info.velocity[i].z + ); + this.lowerSplash.info.velocity[i].divideScalar(5); + scalesAttribute.setX(i, 0.8); + textureRotationAttribute.setX(i, Math.random() * 2); + brokenAttribute.setX(i, 0.2 + Math.random() * 0.25); + if(this.higherSplashSw === 2){ + this.higherSplashSw = 0; + this.higherSplashPos.copy(this.particlePosition); + } + } + + } + if(scalesAttribute.getX(i) >= 0.8 && scalesAttribute.getX(i) < 2.5){ + scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.2); + } + if(scalesAttribute.getX(i) >= 2.5){ + if(brokenAttribute.getX(i) < 1){ + brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.03); + positionsAttribute.setXYZ( i, + positionsAttribute.getX(i) + this.lowerSplash.info.velocity[i].x, + positionsAttribute.getY(i) + this.lowerSplash.info.velocity[i].y, + positionsAttribute.getZ(i) + this.lowerSplash.info.velocity[i].z + ); + this.lowerSplash.info.velocity[i].add(this.lowerSplash.info.acc); + if(this.higherSplashSw === 0){ + this.higherSplashSw = 1; + } + } + } + } + brokenAttribute.needsUpdate = true; + positionsAttribute.needsUpdate = true; + scalesAttribute.needsUpdate = true; + textureRotationAttribute.needsUpdate = true; + this.lowerSplash.material.uniforms.uTime.value = timestamp / 1000; + this.lowerSplash.material.uniforms.cameraBillboardQuaternion.value.copy(this.camera.quaternion); + this.lowerSplash.material.uniforms.waterSurfacePos.value.copy(this.waterSurfacePos); + } + } + _handleLowerSplash(); + + const _handleHigherSplash = () =>{ + if(this.higherSplash){ + const brokenAttribute = this.higherSplash.geometry.getAttribute('broken'); + const positionsAttribute = this.higherSplash.geometry.getAttribute('positions'); + const scalesAttribute = this.higherSplash.geometry.getAttribute('scales'); + const textureRotationAttribute = this.higherSplash.geometry.getAttribute('textureRotation'); + const particleCount = this.higherSplash.info.particleCount; + for (let i = 0; i < particleCount; i++){ + if(this.higherSplashSw === 1){ + this.higherSplash.info.velocity[i].x = 0; + this.higherSplash.info.velocity[i].y = 0.13; + this.higherSplash.info.velocity[i].z = 0; + this.higherSplash.info.velocity[i].divideScalar(5); + + positionsAttribute.setXYZ( i, + this.higherSplashPos.x + (Math.random() - 0.5) * 0.1, + this.higherSplashPos.y + (i * 0.18) / 7, + this.higherSplashPos.z + (Math.random() - 0.5) * 0.1 + ); + + scalesAttribute.setX(i, (0.8 + (2 - i * 0.18)) / 7); + textureRotationAttribute.setX(i, Math.random() * 2); + brokenAttribute.setX(i, Math.random() * 0.5 ); + } + if(scalesAttribute.getX(i) < 0.8 + (2 - i * 0.18)){ + scalesAttribute.setX(i, scalesAttribute.getX(i) * 1.05); + positionsAttribute.setXYZ( i, + positionsAttribute.getX(i), + this.higherSplashPos.y + (positionsAttribute.getY(i) - this.higherSplashPos.y) * 1.05, + positionsAttribute.getZ(i) + ); + + } + if(scalesAttribute.getX(i) > (0.8 + (2 - i * 0.18)) / 3){ + if(brokenAttribute.getX(i) < 1) + brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.03 * (2 - i * 0.1)); + + } + positionsAttribute.setXYZ( i, + positionsAttribute.getX(i) + this.higherSplash.info.velocity[i].x, + positionsAttribute.getY(i) + this.higherSplash.info.velocity[i].y, + positionsAttribute.getZ(i) + this.higherSplash.info.velocity[i].z + ); + this.higherSplash.info.velocity[i].add(this.higherSplash.info.acc); + } + brokenAttribute.needsUpdate = true; + positionsAttribute.needsUpdate = true; + scalesAttribute.needsUpdate = true; + textureRotationAttribute.needsUpdate = true; + this.higherSplash.material.uniforms.uTime.value = timestamp / 1000; + this.higherSplash.material.uniforms.cameraBillboardQuaternion.value.copy(this.camera.quaternion); + this.higherSplash.material.uniforms.waterSurfacePos.value.copy(this.waterSurfacePos); + if(this.higherSplashSw === 1){ + this.higherSplashSw = 2; + } + } + } + _handleHigherSplash(); + this.app.updateMatrixWorld(); + this.lastContactWater = this.contactWater; } initRipple(){ this.rippleGroup = new THREE.Group(); @@ -169,7 +297,114 @@ class ParticleEffect{ }); })(); } - + initLowerSplash(){ + const particleCount = 12; + const attributeSpecs = []; + attributeSpecs.push({name: 'broken', itemSize: 1}); + attributeSpecs.push({name: 'scales', itemSize: 1}); + attributeSpecs.push({name: 'textureRotation', itemSize: 1}); + const geometry2 = new THREE.PlaneGeometry(0.3, 0.3); + const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); + const material= new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + cameraBillboardQuaternion: { + value: new THREE.Quaternion(), + }, + splashTexture: { + value: splashTexture2, + }, + waterSurfacePos: { + value: new THREE.Vector3(), + }, + noiseMap:{ + value: noiseMap + }, + }, + vertexShader: lowerSplashVertex, + fragmentShader: lowerSplashFragment, + side: THREE.DoubleSide, + transparent: true, + }); + this.lowerSplash = new THREE.InstancedMesh(geometry, material, particleCount); + this.lowerSplash.info = { + particleCount: particleCount, + velocity: [particleCount], + acc: new THREE.Vector3(0, -0.002, 0) + } + for(let i = 0; i < particleCount; i++){ + this.lowerSplash.info.velocity[i] = new THREE.Vector3(); + } + this.app.add(this.lowerSplash); + + } + initHigherSplash(){ + const particleCount = 10; + const attributeSpecs = []; + attributeSpecs.push({name: 'broken', itemSize: 1}); + attributeSpecs.push({name: 'scales', itemSize: 1}); + attributeSpecs.push({name: 'textureRotation', itemSize: 1}); + const geometry2 = new THREE.PlaneGeometry(0.4, 0.4); + const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); + const material= new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + cameraBillboardQuaternion: { + value: new THREE.Quaternion(), + }, + splashTexture: { + value: splashTexture2, + }, + waterSurfacePos: { + value: new THREE.Vector3(), + }, + noiseMap:{ + value: noiseMap + }, + }, + vertexShader: higherSplashVertex, + fragmentShader: higherSplashFragment, + side: THREE.DoubleSide, + transparent: true, + }); + this.higherSplash = new THREE.InstancedMesh(geometry, material, particleCount); + this.higherSplash.info = { + particleCount: particleCount, + velocity: [particleCount], + acc: new THREE.Vector3(0, -0.0024, 0) + } + for(let i = 0; i < particleCount; i++){ + this.higherSplash.info.velocity[i] = new THREE.Vector3(); + } + this.app.add(this.higherSplash); + + } + _getGeometry = (geometry, attributeSpecs, particleCount) => { + const geometry2 = new THREE.BufferGeometry(); + ['position', 'normal', 'uv'].forEach(k => { + geometry2.setAttribute(k, geometry.attributes[k]); + }); + geometry2.setIndex(geometry.index); + + const positions = new Float32Array(particleCount * 3); + const positionsAttribute = new THREE.InstancedBufferAttribute(positions, 3); + geometry2.setAttribute('positions', positionsAttribute); + + for(const attributeSpec of attributeSpecs){ + const { + name, + itemSize, + } = attributeSpec; + const array = new Float32Array(particleCount * itemSize); + geometry2.setAttribute(name, new THREE.InstancedBufferAttribute(array, itemSize)); + } + + return geometry2; + }; } diff --git a/shaders/particleShader.js b/shaders/particleShader.js index ec74710..b713b23 100644 --- a/shaders/particleShader.js +++ b/shaders/particleShader.js @@ -74,5 +74,187 @@ const rippleFragment = `\ } ` +const lowerSplashVertex = `\ + + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + + + uniform float uTime; + uniform vec4 cameraBillboardQuaternion; + + + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vColor; + varying float vOpacity; + varying float vBroken; + varying float vTextureRotation; + + attribute float textureRotation; + attribute float broken; + attribute vec3 positions; + attribute vec3 color; + attribute float scales; + attribute float opacity; + + + vec3 rotateVecQuat(vec3 position, vec4 q) { + vec3 v = position.xyz; + return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); + } + void main() { + vUv = uv; + vBroken = broken; + vTextureRotation = textureRotation; + // vOpacity = opacity; + // vColor = color; + + vec3 pos = position; + pos = rotateVecQuat(pos, cameraBillboardQuaternion); + pos*=scales; + pos+=positions; + //pos = qtransform(pos, quaternions); + //pos.y=cos(uTime/100.); + vec4 modelPosition = modelMatrix * vec4(pos, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + vPos = modelPosition.xyz; + gl_Position = projectionPosition; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } +` +const lowerSplashFragment = `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + uniform sampler2D splashTexture; + uniform sampler2D noiseMap; + uniform vec3 waterSurfacePos; + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vColor; + varying float vOpacity; + varying float vTextureRotation; + varying float vBroken; + #define PI 3.1415926 + void main() { + float mid = 0.5; + vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, + cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); + vec4 splash = texture2D( + splashTexture, + rotated + ); + if(splash.r > 0.1){ + gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); + } + if(vPos.y < waterSurfacePos.y){ + gl_FragColor.a = 0.; + } + //gl_FragColor.a *= 0.5; + float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated * 2.5 ).g; + if ( broken < 0.0001 ) discard; + if(gl_FragColor.a > 0.){ + gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); + } + else{ + discard; + } + ${THREE.ShaderChunk.logdepthbuf_fragment} + } +` +const higherSplashVertex = `\ + + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + + + uniform float uTime; + uniform vec4 cameraBillboardQuaternion; + + + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vColor; + varying float vOpacity; + varying float vBroken; + varying float vTextureRotation; + + attribute float textureRotation; + attribute float broken; + attribute vec3 positions; + attribute vec3 color; + attribute float scales; + attribute float opacity; + + + vec3 rotateVecQuat(vec3 position, vec4 q) { + vec3 v = position.xyz; + return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); + } + void main() { + vUv = uv; + vBroken = broken; + vTextureRotation = textureRotation; + // vOpacity = opacity; + // vColor = color; + + vec3 pos = position; + pos = rotateVecQuat(pos, cameraBillboardQuaternion); + pos*=scales; + pos+=positions; + //pos = qtransform(pos, quaternions); + //pos.y=cos(uTime/100.); + vec4 modelPosition = modelMatrix * vec4(pos, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + vPos = modelPosition.xyz; + gl_Position = projectionPosition; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } +` +const higherSplashFragment = `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + uniform sampler2D splashTexture; + uniform sampler2D noiseMap; + uniform vec3 waterSurfacePos; + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vColor; + varying float vOpacity; + varying float vTextureRotation; + varying float vBroken; + #define PI 3.1415926 + void main() { + float mid = 0.5; + vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, + cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); + vec4 splash = texture2D( + splashTexture, + rotated + ); + if(splash.r > vBroken){ + gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); + } + else{ + discard; + } + if(vPos.y < waterSurfacePos.y){ + gl_FragColor.a = 0.; + } + //gl_FragColor.a *= 0.5; + // float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated * 1. ).g; + // if ( broken < 0.0001 ) discard; + if(gl_FragColor.a > 0.){ + gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); + } + else{ + discard; + } + ${THREE.ShaderChunk.logdepthbuf_fragment} + } +` + -export {rippleVertex, rippleFragment}; \ No newline at end of file +export {rippleVertex, rippleFragment, lowerSplashVertex, lowerSplashFragment, higherSplashVertex, higherSplashFragment}; \ No newline at end of file From e7ad0d10799dacda3f88ea51f86d1016acd26110 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Mon, 25 Jul 2022 11:01:17 -0400 Subject: [PATCH 07/16] objectId bug --- index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index ca3f750..d641bd5 100644 --- a/index.js +++ b/index.js @@ -898,7 +898,7 @@ export default (e) => { let result = generator.physics.raycast(localVector01, qt); testContact1 = false; for(const physicsObject of generator.getPhysicsObjects()){ - if(result.objectId === physicsObject.physicsId && result.distance <= ds){ + if(result && result.objectId === physicsObject.physicsId && result.distance <= ds){ testContact1 = true; localVector07.set(result.point[0], result.point[1], result.point[2]); } @@ -933,7 +933,7 @@ export default (e) => { let result = generator.physics.raycast(localVector01, qt); testContact2 = true; for(const physicsObject of generator.getPhysicsObjects()){ - if(result.objectId === physicsObject.physicsId && result.distance <= ds){ + if(result && result.objectId === physicsObject.physicsId && result.distance <= ds){ testContact2 = false; localVector07.set(result.point[0], result.point[1], result.point[2]); } From 5f850cfdaefd8f8b89f869262f02b648244c0667 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Mon, 25 Jul 2022 18:47:05 -0400 Subject: [PATCH 08/16] floatins splash --- particle.js | 302 +++++++++++++++++++++++++++++++++++++- shaders/particleShader.js | 235 ++++++++++++++++++++++++++++- 2 files changed, 534 insertions(+), 3 deletions(-) diff --git a/particle.js b/particle.js index 42daf02..59513b7 100644 --- a/particle.js +++ b/particle.js @@ -3,6 +3,9 @@ import * as THREE from 'three'; import { rippleVertex, rippleFragment } from './shaders/particleShader.js'; import { lowerSplashVertex, lowerSplashFragment } from './shaders/particleShader.js'; import { higherSplashVertex, higherSplashFragment } from './shaders/particleShader.js'; +import { dropletVertex, dropletFragment } from './shaders/particleShader.js'; +import { dropletRippleVertex, dropletRippleFragment } from './shaders/particleShader.js'; +import { floatingSplashVertex, floatingSplashFragment } from './shaders/particleShader.js'; const baseUrl = import.meta.url.replace(/(\/)[^\/\\]*$/, '$1'); const { @@ -10,7 +13,7 @@ const { useSound } = metaversefile; const sounds = useSound(); -const soundFiles = sounds.getSoundFiles(); +const soundFiles = sounds.getSoundFiles(); const textureLoader = new THREE.TextureLoader(); const bubbleTexture1 = textureLoader.load(`${baseUrl}/textures/Bubble3.png`); @@ -78,10 +81,17 @@ class ParticleEffect{ this.higherSplash = null; this.initHigherSplash(); + this.droplet = null; + this.dropletRipple = null; + this.initDroplet(); + this.rippleMesh = null; this.initRipple(); + this.floatingSplash = null; + this.initFloatingSplash(); + } @@ -203,7 +213,7 @@ class ParticleEffect{ scalesAttribute.setX(i, (0.8 + (2 - i * 0.18)) / 7); textureRotationAttribute.setX(i, Math.random() * 2); - brokenAttribute.setX(i, Math.random() * 0.5 ); + brokenAttribute.setX(i, scalesAttribute.getX(i) * 1.2); } if(scalesAttribute.getX(i) < 0.8 + (2 - i * 0.18)){ scalesAttribute.setX(i, scalesAttribute.getX(i) * 1.05); @@ -240,6 +250,151 @@ class ParticleEffect{ } _handleHigherSplash(); + const _handleDroplet = () =>{ + if(this.droplet && this.dropletRipple){ + + + const rippleBrokenAttribute = this.dropletRipple.geometry.getAttribute('broken'); + const rippleWaveFreqAttribute = this.dropletRipple.geometry.getAttribute('waveFreq'); + const ripplePositionsAttribute = this.dropletRipple.geometry.getAttribute('positions'); + const rippleScalesAttribute = this.dropletRipple.geometry.getAttribute('scales'); + + const offsetAttribute = this.droplet.geometry.getAttribute('offset'); + const positionsAttribute = this.droplet.geometry.getAttribute('positions'); + const scalesAttribute = this.droplet.geometry.getAttribute('scales'); + const particleCount = this.droplet.info.particleCount; + let falling = this.fallindSpeed > 10 ? 10 : this.fallindSpeed; + let dropletNum = particleCount * (falling / 10); + dropletNum /= 3; + falling = falling < 5 ? 7 : falling; + for (let i = 0; i < particleCount; i++){ + if(this.contactWater && this.lastContactWater !== this.contactWater){ + this.dropletgroup.position.copy(this.particlePosition); + this.dropletRipplegroup.position.copy(this.particlePosition); + if(this.fallindSpeed > 0.5){ + let rand = Math.random(); + scalesAttribute.setX(i, rand); + positionsAttribute.setXYZ(i, 0, 0, 0); + + this.droplet.info.velocity[i].x = (Math.random() - 0.5) * 1 * (falling / 10); + this.droplet.info.velocity[i].y = Math.random() * 1.6 * (falling / 10); + this.droplet.info.velocity[i].z = (Math.random() - 0.5) * 1 * (falling / 10); + + this.droplet.info.velocity[i].divideScalar(20); + + this.droplet.info.alreadyHaveRipple[i] = false; + if(i > dropletNum){ + scalesAttribute.setX(i, 0.001); + } + this.droplet.info.offset[i] = Math.floor(Math.random() * 29); + this.droplet.info.startTime[i] = 0; + } + } + if(positionsAttribute.getY(i) >= -100){ + this.droplet.info.velocity[i].add(this.droplet.info.acc); + scalesAttribute.setX(i, scalesAttribute.getX(i) / 1.035); + positionsAttribute.setXYZ( + i, + positionsAttribute.getX(i) + this.droplet.info.velocity[i].x, + positionsAttribute.getY(i) + this.droplet.info.velocity[i].y, + positionsAttribute.getZ(i) + this.droplet.info.velocity[i].z + ) + this.droplet.info.startTime[i] = this.droplet.info.startTime[i] + 1; + if(this.droplet.info.startTime[i] % 2 === 0) + this.droplet.info.offset[i] += 1; + if(this.droplet.info.offset[i] >= 30){ + this.droplet.info.offset[i] = 0; + } + offsetAttribute.setXY(i, (5 / 6) - Math.floor(this.droplet.info.offset[i] / 6) * (1. / 6.), Math.floor(this.droplet.info.offset[i] % 5) * 0.2); + } + if(positionsAttribute.getY(i) < 0 && !this.droplet.info.alreadyHaveRipple[i] && scalesAttribute.getX(i) > 0.001){ + scalesAttribute.setX(i, 0.0001); + ripplePositionsAttribute.setXYZ(i, positionsAttribute.getX(i), 0.01, positionsAttribute.getZ(i)); + rippleScalesAttribute.setX(i, Math.random() * 0.2); + rippleWaveFreqAttribute.setX(i, Math.random() * (i % 10)); + rippleBrokenAttribute.setX(i, Math.random() - 0.8); + this.droplet.info.alreadyHaveRipple[i] = true; + } + rippleScalesAttribute.setX(i, rippleScalesAttribute.getX(i) + 0.02); + if(rippleBrokenAttribute.getX(i) < 1){ + rippleBrokenAttribute.setX(i, rippleBrokenAttribute.getX(i) + 0.02); + } + } + offsetAttribute.needsUpdate = true; + positionsAttribute.needsUpdate = true; + scalesAttribute.needsUpdate = true; + + ripplePositionsAttribute.needsUpdate = true; + rippleScalesAttribute.needsUpdate = true; + rippleBrokenAttribute.needsUpdate = true; + rippleWaveFreqAttribute.needsUpdate = true; + + this.dropletRipple.material.uniforms.uTime.value=timestamp/1000; + + this.droplet.material.uniforms.uTime.value = timestamp / 1000; + this.droplet.material.uniforms.cameraBillboardQuaternion.value.copy(this.camera.quaternion); + } + } + _handleDroplet(); + + const _handleFloatingSplash = () =>{ + if(this.floatingSplash){ + if(this.floatingSplash.info.currentIndex >= this.floatingSplash.info.particleCount){ + this.floatingSplash.info.currentIndex = 0; + } + const brokenAttribute = this.floatingSplash.geometry.getAttribute('broken'); + const positionsAttribute = this.floatingSplash.geometry.getAttribute('positions'); + const scalesAttribute = this.floatingSplash.geometry.getAttribute('scales'); + const textureRotationAttribute = this.floatingSplash.geometry.getAttribute('textureRotation'); + const particleCount = this.floatingSplash.info.particleCount; + for (let i = 0; i < particleCount; i++) { + scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.05 * (this.currentSpeed + 0.3)); + if(brokenAttribute.getX(i) < 1) + brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.005); + } + const emmitDelay = this.currentSpeed > 0.3 ? 100 : 200; + if( + timestamp - this.floatingSplash.info.lastEmmitTime > emmitDelay * Math.pow((1.1 - this.currentSpeed), 0.3) + && (this.currentSpeed > 0.1 || this.fallindSpeed > 6) + ){ + if( + (this.player.hasAction('swim') && this.player.getAction('swim').onSurface) + ||(!this.player.hasAction('swim') && this.contactWater) + || this.contactWater && this.lastContactWater !== this.contactWater + ){ + let brokenDegree = this.currentSpeed > 0.3 ? 0.23 + 0.2 * Math.random() : 0.4 + 0.3 * Math.random(); + if(this.currentSpeed > 0.5){ + brokenDegree *= 1.3; + } + if(this.fallindSpeed > 6){ + brokenDegree = 0.15 + 0.2 * Math.random(); + } + if(!this.player.hasAction('swim')){ + brokenDegree *= 1.1; + } + brokenAttribute.setX(this.floatingSplash.info.currentIndex, brokenDegree); + scalesAttribute.setX(this.floatingSplash.info.currentIndex, 1.2 + Math.random() * 0.1); + positionsAttribute.setXYZ( + this.floatingSplash.info.currentIndex, + this.particlePosition.x + 0.2 * this.playerDir.x + (Math.random() - 0.5) * 0.1, + this.particlePosition.y + 0.01, + this.particlePosition.z + 0.2 * this.playerDir.z + (Math.random() - 0.5) * 0.1 + ); + textureRotationAttribute.setX(this.floatingSplash.info.currentIndex, Math.random() * 2); + this.floatingSplash.info.currentIndex++; + this.floatingSplash.info.lastEmmitTime = timestamp; + } + + } + brokenAttribute.needsUpdate = true; + positionsAttribute.needsUpdate = true; + scalesAttribute.needsUpdate = true; + textureRotationAttribute.needsUpdate = true; + this.floatingSplash.material.uniforms.uTime.value = timestamp / 1000; + } + } + _handleFloatingSplash(); + this.app.updateMatrixWorld(); this.lastContactWater = this.contactWater; @@ -383,6 +538,149 @@ class ParticleEffect{ this.app.add(this.higherSplash); } + initDroplet(){ + this.dropletgroup = new THREE.Group(); + const particleCount = 50; + const attributeSpecs = []; + attributeSpecs.push({name: 'scales', itemSize: 1}); + attributeSpecs.push({name: 'offset', itemSize: 1}); + const geometry2 = new THREE.PlaneGeometry(0.1, 0.1); + const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); + const material= new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + cameraBillboardQuaternion: { + value: new THREE.Quaternion(), + }, + bubbleTexture1: { + value: bubbleTexture2, + }, + }, + vertexShader: dropletVertex, + fragmentShader: dropletFragment, + side: THREE.DoubleSide, + transparent: true, + }); + this.droplet = new THREE.InstancedMesh(geometry, material, particleCount); + + this.droplet.info = { + velocity: [particleCount], + alreadyHaveRipple: [particleCount], + offset: [particleCount], + acc: new THREE.Vector3(0, -0.002, 0), + startTime: [particleCount], + particleCount: particleCount + } + for(let i = 0; i < particleCount; i++){ + this.droplet.info.velocity[i] = new THREE.Vector3(); + this.droplet.info.alreadyHaveRipple[i] = false; + } + this.dropletgroup.add(this.droplet); + this.app.add(this.dropletgroup); + + + this.dropletRipplegroup = new THREE.Group(); + const rippleAttributeSpecs = []; + rippleAttributeSpecs.push({name: 'scales', itemSize: 1}); + rippleAttributeSpecs.push({name: 'broken', itemSize: 1}); + rippleAttributeSpecs.push({name: 'waveFreq', itemSize: 1}); + + const geometry4 = new THREE.PlaneGeometry(0.45, 0.45); + const geometry3 = this._getGeometry(geometry4, rippleAttributeSpecs, particleCount); + + const quaternions = new Float32Array(particleCount * 4); + const identityQuaternion = new THREE.Quaternion(); + for (let i = 0; i < particleCount; i++) { + identityQuaternion.toArray(quaternions, i * 4); + } + const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); + geometry3.setAttribute('quaternions', quaternionsAttribute); + + + const material2 = new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + noiseMap:{ + value: noiseMap + } + }, + vertexShader: dropletRippleVertex, + fragmentShader: dropletRippleFragment, + side: THREE.DoubleSide, + transparent: true, + }); + this.dropletRipple = new THREE.InstancedMesh(geometry3, material2, particleCount); + const euler = new THREE.Euler(-Math.PI / 2, 0, 0); + const quaternion = new THREE.Quaternion(); + const quaternionAttribute = this.dropletRipple.geometry.getAttribute('quaternions'); + for (let i = 0; i < particleCount; i++) { + quaternion.setFromEuler(euler); + quaternionAttribute.setXYZW(i, quaternion.x, quaternion.y, quaternion.z, quaternion.w); + } + quaternionAttribute.needsUpdate = true; + + this.dropletRipplegroup.add(this.dropletRipple); + this.app.add(this.dropletRipplegroup); + + + + } + initFloatingSplash(){ + const particleCount = 30; + const attributeSpecs = []; + attributeSpecs.push({name: 'scales', itemSize: 1}); + attributeSpecs.push({name: 'broken', itemSize: 1}); + attributeSpecs.push({name: 'textureRotation', itemSize: 1}); + const geometry2 = new THREE.PlaneGeometry(0.5, 0.5); + const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); + + const quaternions = new Float32Array(particleCount * 4); + const identityQuaternion = new THREE.Quaternion(); + for (let i = 0; i < particleCount; i++) { + identityQuaternion.toArray(quaternions, i * 4); + } + const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); + geometry.setAttribute('quaternions', quaternionsAttribute); + + const material = new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + noiseMap:{ + value: noiseMap + }, + perlinnoise:{ + value: splashTexture + } + }, + vertexShader: floatingSplashVertex, + fragmentShader: floatingSplashFragment, + side: THREE.DoubleSide, + transparent: true, + }); + this.floatingSplash = new THREE.InstancedMesh(geometry, material, particleCount); + + this.floatingSplash.info = { + particleCount: particleCount, + currentIndex: 0, + lastEmmitTime: 0 + } + const euler = new THREE.Euler(-Math.PI / 2, 0, 0); + const quaternion = new THREE.Quaternion(); + const quaternionAttribute = this.floatingSplash.geometry.getAttribute('quaternions'); + for (let i = 0; i < particleCount; i++) { + quaternion.setFromEuler(euler); + quaternionAttribute.setXYZW(i, quaternion.x, quaternion.y, quaternion.z, quaternion.w); + } + quaternionAttribute.needsUpdate = true; + this.app.add(this.floatingSplash); + } + _getGeometry = (geometry, attributeSpecs, particleCount) => { const geometry2 = new THREE.BufferGeometry(); ['position', 'normal', 'uv'].forEach(k => { diff --git a/shaders/particleShader.js b/shaders/particleShader.js index b713b23..0cee94d 100644 --- a/shaders/particleShader.js +++ b/shaders/particleShader.js @@ -67,6 +67,7 @@ const rippleFragment = `\ gl_FragColor.a = 0.; discard; } + gl_FragColor.a *= 1.5; float broken = abs( sin( 1.0 - vBroken ) ) - noise.g; if ( broken < 0.0001 ) discard; gl_FragColor.rgb *= 0.8; @@ -255,6 +256,238 @@ const higherSplashFragment = `\ ${THREE.ShaderChunk.logdepthbuf_fragment} } ` +const dropletVertex = `\ + + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + + + uniform float uTime; + uniform vec4 cameraBillboardQuaternion; + + + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vColor; + varying float vOpacity; + varying vec2 vOffset; + + attribute vec3 positions; + attribute vec3 color; + attribute float scales; + attribute float opacity; + attribute vec2 offset; + + vec3 rotateVecQuat(vec3 position, vec4 q) { + vec3 v = position.xyz; + return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); + } + void main() { + vUv = uv; + vPos = position; + // vOpacity = opacity; + // vColor = color; + vOffset = offset; + vec3 pos = position; + pos = rotateVecQuat(pos, cameraBillboardQuaternion); + pos*=scales; + pos+=positions; + //pos = qtransform(pos, quaternions); + //pos.y=cos(uTime/100.); + vec4 modelPosition = modelMatrix * vec4(pos, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + + gl_Position = projectionPosition; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } +` +const dropletFragment = `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + uniform sampler2D bubbleTexture1; + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vColor; + varying float vOpacity; + varying vec2 vOffset; + void main() { + vec4 bubble = texture2D( + bubbleTexture1, + vec2( + vUv.x / 6. + vOffset.x, + vUv.y / 5. + vOffset.y + ) + ); + + gl_FragColor = bubble; + if(gl_FragColor.a < 0.5){ + discard; + } + gl_FragColor.rgb *= 5.; + ${THREE.ShaderChunk.logdepthbuf_fragment} + } +` +const dropletRippleVertex = `\ + + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + + + uniform float uTime; + + varying vec2 vUv; + varying vec3 vPos; + varying float vBroken; + varying float vWaveFreq; + + attribute vec3 positions; + attribute float scales; + attribute float waveFreq; + attribute vec4 quaternions; + attribute float broken; + + vec3 qtransform(vec3 v, vec4 q) { + return v + 2.0*cross(cross(v, q.xyz ) + q.w*v, q.xyz); + } + + void main() { + + vBroken=broken; + vWaveFreq=waveFreq; + vUv=uv; + vPos=position; + vec3 pos = position; + pos = qtransform(pos, quaternions); + pos*=scales; + pos+=positions; + + vec4 modelPosition = modelMatrix * vec4(pos, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + + gl_Position = projectionPosition; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } +` +const dropletRippleFragment = `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + varying float vWaveFreq; + varying float vBroken; + varying vec2 vUv; + varying vec3 vPos; + uniform sampler2D noiseMap; + + void main() { + + vec2 wavedUv = vec2( + vUv.x, + vUv.y + sin(vUv.x * (2. + vWaveFreq) * cos(uTime * 2.)) * 0.05 + ); + float strength = 1.0 - step(0.01, abs(distance(wavedUv, vec2(0.5)) - 0.25)); + gl_FragColor = vec4(vec3(strength), 1.0); + + if(gl_FragColor.r < 0.01){ + discard; + } + float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, vUv ).g; + if ( broken < 0.0001 ) discard; + if(gl_FragColor.a > 0.){ + gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); + } + else{ + discard; + } + ${THREE.ShaderChunk.logdepthbuf_fragment} + } +` +const floatingSplashVertex = `\ + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + + + uniform float uTime; + + varying vec2 vUv; + varying vec3 vPos; + varying float vBroken; + varying float vTextureRotation; + + attribute float textureRotation; + attribute vec3 positions; + attribute float scales; + attribute vec4 quaternions; + attribute float broken; + vec3 qtransform(vec3 v, vec4 q) { + return v + 2.0*cross(cross(v, q.xyz ) + q.w*v, q.xyz); + } + + void main() { + vTextureRotation = textureRotation; + vBroken=broken; + vUv=uv; + vPos=position; + vec3 pos = position; + pos = qtransform(pos, quaternions); + pos*=scales; + pos+=positions; + + + + vec4 modelPosition = modelMatrix * vec4(pos, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + + gl_Position = projectionPosition; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } +` +const floatingSplashFragment = `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + + varying float vBroken; + varying vec2 vUv; + varying vec3 vPos; + varying float vTextureRotation; + + uniform sampler2D noiseMap; + uniform sampler2D perlinnoise; + #define PI 3.1415926 + void main() { + float mid = 0.5; + vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1. - sin(vTextureRotation*PI) * (vUv.y - mid) * 1. + mid, + cos(vTextureRotation*PI) * (vUv.y - mid) * 1. + sin(vTextureRotation*PI) * (vUv.x - mid) * 1. + mid); + vec4 splash = texture2D( + perlinnoise, + rotated + ); + if(splash.r > 0.1){ + gl_FragColor = vec4(1.0); + } + else{ + discard; + } + + float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated ).g; + if ( broken < 0.03 ) discard; + + if(gl_FragColor.a > 0.){ + gl_FragColor = vec4(0.7, 0.7, 0.7, 1.0); + } + + + ${THREE.ShaderChunk.logdepthbuf_fragment} + } +` -export {rippleVertex, rippleFragment, lowerSplashVertex, lowerSplashFragment, higherSplashVertex, higherSplashFragment}; \ No newline at end of file +export { + rippleVertex, rippleFragment, + lowerSplashVertex, lowerSplashFragment, + higherSplashVertex, higherSplashFragment, + dropletVertex, dropletFragment, + dropletRippleVertex, dropletRippleFragment, + floatingSplashVertex, floatingSplashFragment +}; \ No newline at end of file From 7fb208e3d1055d2809108bbcd878342634601f66 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Mon, 25 Jul 2022 21:12:33 -0400 Subject: [PATCH 09/16] swimming splash --- particle.js | 305 +++++++++++++++++++++++++++++++++++++- shaders/particleShader.js | 87 ++++++++++- 2 files changed, 390 insertions(+), 2 deletions(-) diff --git a/particle.js b/particle.js index 59513b7..5bdefa2 100644 --- a/particle.js +++ b/particle.js @@ -6,6 +6,7 @@ import { higherSplashVertex, higherSplashFragment } from './shaders/particleShad import { dropletVertex, dropletFragment } from './shaders/particleShader.js'; import { dropletRippleVertex, dropletRippleFragment } from './shaders/particleShader.js'; import { floatingSplashVertex, floatingSplashFragment } from './shaders/particleShader.js'; +import { swimmingSplashVertex, swimmingSplashFragment } from './shaders/particleShader.js'; const baseUrl = import.meta.url.replace(/(\/)[^\/\\]*$/, '$1'); const { @@ -92,10 +93,49 @@ class ParticleEffect{ this.floatingSplash = null; this.initFloatingSplash(); - + this.swimmingSplash = null; + this.initSwimmingSplash(); + this.localVector2 = new THREE.Vector3(); + this.rotateY = new THREE.Quaternion(); + this.rotateY.setFromAxisAngle(new THREE.Vector3(0, 1, 0), -Math.PI / 2); + this.lastStroke = null; + this.lastStep = null; + + this.swimmingRipple = null; + this.initSwimmingRipple(); + + + this.cameraDir = new THREE.Vector3(); + this.playerDir = new THREE.Vector3(); + this.playerHeadPos = new THREE.Vector3(); + this.currentSpeed = 0; + this.fallindSpeed = 0; + + this.localVector3 = new THREE.Vector3(); + this.localVector4 = new THREE.Vector3(); + this.localVector5 = new THREE.Vector3(); } + tracePlayerInfo(){ + //############################################################# trace camera player direction and speed ######################################################################## + this.localVector3.set(0, 0, -1); + this.cameraDir = this.localVector3.applyQuaternion( this.camera.quaternion ); + this.cameraDir.normalize(); + + this.localVector4.set(0, 0, -1); + this.playerDir = this.localVector4.applyQuaternion( this.player.quaternion ); + this.playerDir.normalize(); + + this.fallindSpeed = 0 - this.player.characterPhysics.velocity.y; + if(this.player.avatar){ + this.currentSpeed = this.localVector5.set(this.player.avatar.velocity.x, 0, this.player.avatar.velocity.z).length(); + this.playerHeadPos.setFromMatrixPosition(this.player.avatar.modelBoneOutputs.Head.matrixWorld); + } + } update(timestamp){ + this.tracePlayerInfo(); + + if(!this.alreadySetComposer){ if(this.foamPass && this.webaWaterPass && this.rippleMesh){ this.webaWaterPass._selects.push(this.rippleMesh); @@ -395,6 +435,177 @@ class ParticleEffect{ } _handleFloatingSplash(); + + const _handleSwimmingSplash = () =>{ + this.localVector2.set(this.playerDir.x, this.playerDir.y, this.playerDir.z).applyQuaternion(this.rotateY); + if(this.swimmingSplash){ + + const brokenAttribute = this.swimmingSplash.geometry.getAttribute('broken'); + const positionsAttribute = this.swimmingSplash.geometry.getAttribute('positions'); + const scalesAttribute = this.swimmingSplash.geometry.getAttribute('scales'); + const textureRotationAttribute = this.swimmingSplash.geometry.getAttribute('textureRotation'); + const particleCount = this.swimmingSplash.info.particleCount; + if(this.player.hasAction('swim')){ + if( + this.player.getAction('swim').onSurface + && !this.player.hasAction('fly') + ){ + if( + this.player.getAction('swim').animationType === 'freestyle' + ){ + if(this.player.characterSfx.currentSwimmingHand !== this.lastStroke){ + let currentEmmit = 0; + for(let i = 0; i < particleCount; i++){ + if(brokenAttribute.getX(i) >= 1){ + if(this.player.characterSfx.currentSwimmingHand === 'right'){ + this.swimmingSplash.info.velocity[i].x = (Math.random() - 0.5) * 0.1 + this.playerDir.x * 0.45 * (1 + this.currentSpeed) + this.localVector2.x * 0.1; + this.swimmingSplash.info.velocity[i].y = 0.18 + Math.random() * 0.18; + this.swimmingSplash.info.velocity[i].z = (Math.random() - 0.5) * 0.1 + this.playerDir.z * 0.45 * (1 + this.currentSpeed) + this.localVector2.z * 0.1; + } + else{ + this.swimmingSplash.info.velocity[i].x = (Math.random() - 0.5) * 0.1 + this.playerDir.x * 0.45 * (1 + this.currentSpeed) - this.localVector2.x * 0.1; + this.swimmingSplash.info.velocity[i].y = 0.18 + Math.random() * 0.18; + this.swimmingSplash.info.velocity[i].z = (Math.random() - 0.5) * 0.1 + this.playerDir.z * 0.45 * (1 + this.currentSpeed) - this.localVector2.z * 0.1; + } + + positionsAttribute.setXYZ( i, + this.particlePosition.x + (Math.random() - 0.5) * 0.1 + this.swimmingSplash.info.velocity[i].x - this.playerDir.x * 0.25, + this.particlePosition.y, + this.particlePosition.z + (Math.random() - 0.5) * 0.1 + this.swimmingSplash.info.velocity[i].z - this.playerDir.z * 0.25 + ); + this.swimmingSplash.info.velocity[i].divideScalar(10); + this.swimmingSplash.info.acc[i] = -0.001 - this.currentSpeed * 0.0015; + scalesAttribute.setX(i, 1 + Math.random()); + brokenAttribute.setX(i, 0.25 + Math.random() * 0.2); + textureRotationAttribute.setX(i, Math.random() * 2); + currentEmmit++; + } + if(currentEmmit >= 50){ + break; + } + } + } + } + if(this.currentSpeed > 0.3){ + const splashposition = this.player.getAction('swim').animationType === 'breaststroke' ? 0.32 : 0.15; + const splashposition2 = this.player.getAction('swim').animationType === 'breaststroke' ? 0.1 : 0.2; + let currentEmmit = 0; + for(let i = 0; i < particleCount; i++){ + if(brokenAttribute.getX(i) >= 1){ + this.swimmingSplash.info.velocity[i].x = this.localVector2.x * (Math.random() - 0.5) * 0.2 + this.playerDir.x * splashposition2 * (1 + this.currentSpeed); + this.swimmingSplash.info.velocity[i].y = 0.08 + Math.random() * 0.08; + this.swimmingSplash.info.velocity[i].z = this.localVector2.z * (Math.random() - 0.5) * 0.2 + this.playerDir.z * splashposition2 * (1 + this.currentSpeed); + positionsAttribute.setXYZ( i, + this.particlePosition.x + this.swimmingSplash.info.velocity[i].x * 0.5 + this.playerDir.x * splashposition, + this.particlePosition.y - 0.1 * Math.random(), + this.particlePosition.z + this.swimmingSplash.info.velocity[i].z * 0.5 + this.playerDir.z * splashposition + ); + this.swimmingSplash.info.velocity[i].divideScalar(5); + this.swimmingSplash.info.acc[i] = -0.0015 - this.currentSpeed * 0.0015; + scalesAttribute.setX(i, 2 + Math.random() * 2); + if(this.player.getAction('swim').animationType === 'breaststroke') + brokenAttribute.setX(i, 0.2 + Math.random() * 0.2); + else + brokenAttribute.setX(i, 0.25 + Math.random() * 0.2); + textureRotationAttribute.setX(i, Math.random() * 2); + currentEmmit++; + } + if(currentEmmit >= 2){ + break; + } + } + } + } + } + else{ + if(this.contactWater){ + if( + this.player.characterSfx.currentStep !== this.lastStep + && ( + (this.currentSpeed <= 0.5 && this.waterSurfacePos.y < this.player.position.y - this.player.avatar.height * 0.7) + || (this.currentSpeed > 0.5 && this.waterSurfacePos.y < this.player.position.y - this.player.avatar.height * 0.6) + ) + ){ + + let currentEmmit = 0; + for(let i = 0; i < particleCount; i++){ + if(brokenAttribute.getX(i) >= 1){ + this.swimmingSplash.info.velocity[i].x = (Math.random() - 0.5) * 0.1 * (1 + this.currentSpeed); + this.swimmingSplash.info.velocity[i].y = 0.2 * (1 + this.currentSpeed); + this.swimmingSplash.info.velocity[i].z = (Math.random() - 0.5) * 0.1 * (1 + this.currentSpeed); + if(this.player.characterSfx.currentStep === 'left'){ + positionsAttribute.setXYZ( i, + this.particlePosition.x + this.localVector2.x * 0.05 + this.swimmingSplash.info.velocity[i].x + this.playerDir.x * 0.35, + this.particlePosition.y + 0.1 * Math.random(), + this.particlePosition.z + this.localVector2.z * 0.05 + this.swimmingSplash.info.velocity[i].z + this.playerDir.z * 0.35 + ); + } + else{ + positionsAttribute.setXYZ( i, + this.particlePosition.x - this.localVector2.x * 0.05 + this.swimmingSplash.info.velocity[i].x + this.playerDir.x * 0.35, + this.particlePosition.y + 0.1 * Math.random(), + this.particlePosition.z - this.localVector2.z * 0.05 + this.swimmingSplash.info.velocity[i].z + this.playerDir.z * 0.35 + ); + } + + this.swimmingSplash.info.velocity[i].divideScalar(10); + this.swimmingSplash.info.acc[i] = -0.001 - this.currentSpeed * 0.0015; + scalesAttribute.setX(i, (1 + this.currentSpeed)); + brokenAttribute.setX(i, 0.25 + Math.random() * 0.2); + textureRotationAttribute.setX(i, Math.random() * 2); + currentEmmit++; + } + if(currentEmmit >= 50){ + break; + } + } + this.lastStep = this.player.characterSfx.currentStep; + } + } + } + + for (let i = 0; i < particleCount; i++){ + if(this.currentSpeed < 0.2){ + positionsAttribute.setXYZ( i, + positionsAttribute.getX(i), + positionsAttribute.getY(i) + this.swimmingSplash.info.velocity[i].y, + positionsAttribute.getZ(i) + ); + } + else{ + positionsAttribute.setXYZ( i, + positionsAttribute.getX(i) + this.swimmingSplash.info.velocity[i].x, + positionsAttribute.getY(i) + this.swimmingSplash.info.velocity[i].y, + positionsAttribute.getZ(i) + this.swimmingSplash.info.velocity[i].z + ); + } + + if(brokenAttribute.getX(i) < 1){ + if(this.player.hasAction('swim')){ + brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.016); + scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.01); + } + else{ + brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.01 * (1 + this.currentSpeed)); + scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.01 * (1 + this.currentSpeed)); + } + } + this.swimmingSplash.info.velocity[i].y += this.swimmingSplash.info.acc[i]; + } + + + brokenAttribute.needsUpdate = true; + positionsAttribute.needsUpdate = true; + scalesAttribute.needsUpdate = true; + textureRotationAttribute.needsUpdate = true; + this.swimmingSplash.material.uniforms.uTime.value = timestamp / 1000; + this.swimmingSplash.material.uniforms.cameraBillboardQuaternion.value.copy(this.camera.quaternion); + this.swimmingSplash.material.uniforms.waterSurfacePos.value.copy(this.waterSurfacePos); + this.lastStroke = this.player.characterSfx.currentSwimmingHand; + } + } + _handleSwimmingSplash(); + this.app.updateMatrixWorld(); this.lastContactWater = this.contactWater; @@ -680,6 +891,98 @@ class ParticleEffect{ quaternionAttribute.needsUpdate = true; this.app.add(this.floatingSplash); } + initSwimmingSplash(){ + const particleCount = 200; + const attributeSpecs = []; + attributeSpecs.push({name: 'scales', itemSize: 1}); + attributeSpecs.push({name: 'broken', itemSize: 1}); + attributeSpecs.push({name: 'textureRotation', itemSize: 1}); + const geometry2 = new THREE.PlaneGeometry(0.1, 0.1); + const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); + + const material = new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + cameraBillboardQuaternion: { + value: new THREE.Quaternion(), + }, + splashTexture: { + value: splashTexture2, + }, + waterSurfacePos: { + value: new THREE.Vector3(), + }, + noiseMap:{ + value: noiseMap + }, + }, + vertexShader: swimmingSplashVertex, + fragmentShader: swimmingSplashFragment, + side: THREE.DoubleSide, + transparent: true, + }); + this.swimmingSplash = new THREE.InstancedMesh(geometry, material, particleCount); + + this.swimmingSplash.info = { + particleCount: particleCount, + velocity: [particleCount], + acc: [particleCount] + } + + for (let i = 0; i < particleCount; i++) { + this.swimmingSplash.info.velocity[i] = new THREE.Vector3(); + } + + this.app.add(this.swimmingSplash); + } + initSwimmingRipple(){ + // const particleCount = 30; + // const attributeSpecs = []; + // attributeSpecs.push({name: 'scales', itemSize: 1}); + // attributeSpecs.push({name: 'broken', itemSize: 1}); + // attributeSpecs.push({name: 'textureRotation', itemSize: 1}); + // const geometry2 = new THREE.PlaneGeometry(0.1, 0.1); + // const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); + + // const material = new THREE.ShaderMaterial({ + // uniforms: { + // uTime: { + // value: 0, + // }, + // cameraBillboardQuaternion: { + // value: new THREE.Quaternion(), + // }, + // splashTexture: { + // value: splashTexture2, + // }, + // waterSurfacePos: { + // value: new THREE.Vector3(), + // }, + // noiseMap:{ + // value: noiseMap + // }, + // }, + // vertexShader: swimmingSplashVertex, + // fragmentShader: swimmingSplashFragment, + // side: THREE.DoubleSide, + // transparent: true, + // }); + // this.swimmingSplash = new THREE.InstancedMesh(geometry, material, particleCount); + + // this.swimmingSplash.info = { + // particleCount: particleCount, + // velocity: [particleCount], + // acc: [particleCount] + // } + + // for (let i = 0; i < particleCount; i++) { + // this.swimmingSplash.info.velocity[i] = new THREE.Vector3(); + // } + + // this.app.add(this.swimmingSplash); + } _getGeometry = (geometry, attributeSpecs, particleCount) => { const geometry2 = new THREE.BufferGeometry(); diff --git a/shaders/particleShader.js b/shaders/particleShader.js index 0cee94d..e29315d 100644 --- a/shaders/particleShader.js +++ b/shaders/particleShader.js @@ -481,6 +481,90 @@ const floatingSplashFragment = `\ ${THREE.ShaderChunk.logdepthbuf_fragment} } ` +const swimmingSplashVertex = `\ + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + + + uniform float uTime; + uniform vec4 cameraBillboardQuaternion; + + + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vColor; + varying float vOpacity; + varying float vBroken; + varying float vTextureRotation; + attribute float textureRotation; + attribute float broken; + attribute vec3 positions; + attribute vec3 color; + attribute float scales; + attribute float opacity; + + + vec3 rotateVecQuat(vec3 position, vec4 q) { + vec3 v = position.xyz; + return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); + } + void main() { + vUv = uv; + vBroken = broken; + vTextureRotation = textureRotation; + // vOpacity = opacity; + // vColor = color; + + vec3 pos = position; + pos = rotateVecQuat(pos, cameraBillboardQuaternion); + pos *= scales; + pos += positions; + + vec4 modelPosition = modelMatrix * vec4(pos, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + vPos = modelPosition.xyz; + gl_Position = projectionPosition; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } +` +const swimmingSplashFragment = `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + uniform sampler2D splashTexture; + uniform sampler2D noiseMap; + uniform vec3 waterSurfacePos; + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vColor; + varying float vOpacity; + varying float vTextureRotation; + varying float vBroken; + #define PI 3.1415926 + void main() { + float mid = 0.5; + vec2 rotated = vec2(cos(vTextureRotation*PI) * (vUv.x - mid) * 1.1 - sin(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + mid, + cos(vTextureRotation*PI) * (vUv.y - mid) * 1.1 + sin(vTextureRotation*PI) * (vUv.x - mid) * 1.1 + mid); + vec4 splash = texture2D( + splashTexture, + rotated + ); + if(splash.r > 0.1){ + gl_FragColor = vec4(0.75, 0.75, 0.75, 1.0); + } + else{ + discard; + } + if(vPos.y < waterSurfacePos.y){ + discard; + } + //gl_FragColor.a *= 0.5; + float broken = abs( sin( 1.0 - vBroken ) ) - texture2D( noiseMap, rotated * 0.8 ).g; + if ( broken < 0.0001 ) discard; + + ${THREE.ShaderChunk.logdepthbuf_fragment} + } +` export { @@ -489,5 +573,6 @@ export { higherSplashVertex, higherSplashFragment, dropletVertex, dropletFragment, dropletRippleVertex, dropletRippleFragment, - floatingSplashVertex, floatingSplashFragment + floatingSplashVertex, floatingSplashFragment, + swimmingSplashVertex, swimmingSplashFragment }; \ No newline at end of file From d4ef918e6822af45ee8fa83d00b6b19350f7a176 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Mon, 25 Jul 2022 22:49:08 -0400 Subject: [PATCH 10/16] bubble --- particle.js | 301 ++++++++++++++++++++++++++++++++------ shaders/particleShader.js | 187 ++++++++++++++++++++++- 2 files changed, 446 insertions(+), 42 deletions(-) diff --git a/particle.js b/particle.js index 5bdefa2..6648cce 100644 --- a/particle.js +++ b/particle.js @@ -7,6 +7,9 @@ import { dropletVertex, dropletFragment } from './shaders/particleShader.js'; import { dropletRippleVertex, dropletRippleFragment } from './shaders/particleShader.js'; import { floatingSplashVertex, floatingSplashFragment } from './shaders/particleShader.js'; import { swimmingSplashVertex, swimmingSplashFragment } from './shaders/particleShader.js'; +import { swimmingRippleVertex, swimmingRippleFragment } from './shaders/particleShader.js'; +import { bubbleVertex, bubbleFragment } from './shaders/particleShader.js'; + const baseUrl = import.meta.url.replace(/(\/)[^\/\\]*$/, '$1'); const { @@ -104,10 +107,14 @@ class ParticleEffect{ this.swimmingRipple = null; this.initSwimmingRipple(); + this.bubble = null; + this.initBubble(); + this.cameraDir = new THREE.Vector3(); this.playerDir = new THREE.Vector3(); this.playerHeadPos = new THREE.Vector3(); + this.waterWorldPosition = new THREE.Vector3(); this.currentSpeed = 0; this.fallindSpeed = 0; @@ -606,6 +613,164 @@ class ParticleEffect{ } _handleSwimmingSplash(); + const _handleSwimmingRipple = () =>{ + const particleCount = this.swimmingRipple.info.particleCount; + if(this.swimmingRipple.info.currentIndex >= particleCount){ + this.swimmingRipple.info.currentIndex = 0; + } + if (this.swimmingRipple) { + const brokenAttribute = this.swimmingRipple.geometry.getAttribute('broken'); + const positionsAttribute = this.swimmingRipple.geometry.getAttribute('positions'); + const scalesAttribute = this.swimmingRipple.geometry.getAttribute('scales'); + const speedAttribute = this.swimmingRipple.geometry.getAttribute('speed'); + const playerRotationAttribute = this.swimmingRipple.geometry.getAttribute('playerRotation'); + const randAttribute = this.swimmingRipple.geometry.getAttribute('random'); + for (let i = 0; i < particleCount; i++) { + scalesAttribute.setX(i,scalesAttribute.getX(i) + 0.1 * (this.currentSpeed + 0.3)); + if(brokenAttribute.getX(i) < 1) + brokenAttribute.setX(i, brokenAttribute.getX(i) + 0.01); + } + if(timestamp - this.swimmingRipple.info.lastEmmitTime > 150 * Math.pow((1.1 - this.currentSpeed), 0.3) && this.currentSpeed > 0.005 && this.contactWater){ + if( + (this.player.hasAction('swim') && this.player.getAction('swim').onSurface) + ||(!this.player.hasAction('swim') && this.waterSurfacePos.y >= this.player.position.y - this.player.avatar.height * 0.7) + ){ + if(this.player.rotation.x !== 0){ + playerRotationAttribute.setX(this.swimmingRipple.info.currentIndex, Math.PI + this.player.rotation.y); + } + else{ + playerRotationAttribute.setX(this.swimmingRipple.info.currentIndex, -this.player.rotation.y); + } + speedAttribute.setX(this.swimmingRipple.info.currentIndex, this.currentSpeed); + brokenAttribute.setX(this.swimmingRipple.info.currentIndex, 0.1); + scalesAttribute.setX(this.swimmingRipple.info.currentIndex, 1.5 + Math.random() * 0.1); + if(this.currentSpeed > 0.1){ + positionsAttribute.setXYZ( + this.swimmingRipple.info.currentIndex, + this.particlePosition.x + 0.25 * this.playerDir.x + (Math.random() - 0.5) * 0.1, + this.particlePosition.y + 0.01, + this.particlePosition.z + 0.25 * this.playerDir.z + (Math.random() - 0.5) * 0.1 + ); + } + else{ + positionsAttribute.setXYZ( + this.swimmingRipple.info.currentIndex, + this.particlePosition.x - 0.05 * this.playerDir.x, + this.particlePosition.y + 0.01, + this.particlePosition.z - 0.05 * this.playerDir.z + ); + } + + randAttribute.setX(this.swimmingRipple.info.currentIndex, Math.random()); + this.swimmingRipple.info.currentIndex++; + this.swimmingRipple.info.lastEmmitTime=timestamp; + } + + } + + positionsAttribute.needsUpdate = true; + randAttribute.needsUpdate = true; + scalesAttribute.needsUpdate = true; + speedAttribute.needsUpdate = true; + brokenAttribute.needsUpdate = true; + playerRotationAttribute.needsUpdate = true; + this.swimmingRipple.material.uniforms.uTime.value = timestamp / 1000; + + } + + + + + } + _handleSwimmingRipple(); + + const _handleBubble = () =>{ + const particleCount = this.bubble.info.particleCount; + if(this.bubble && this.player.avatar){ + let currentEmmit = 0; + const offsetAttribute = this.bubble.geometry.getAttribute('offset'); + const positionsAttribute = this.bubble.geometry.getAttribute('positions'); + const scalesAttribute = this.bubble.geometry.getAttribute('scales'); + if(timestamp - this.bubble.info.lastEmmitTime > 100 && this.contactWater){ + for (let i = 0; i < (Math.floor(this.currentSpeed * 10 + 1) * 5); i++){ + if(scalesAttribute.getX(i) <= 0){ + if(this.currentSpeed > 0.1){ + this.playerHeadPos.x += (Math.random() - 0.5) * 0.5; + this.playerHeadPos.y += (Math.random() - 0.5) * 0.2; + this.playerHeadPos.z += (Math.random() - 0.5) * 0.5; + this.bubble.info.velocity[i].x = -this.playerDir.x * 0.005; + this.bubble.info.velocity[i].y = 0.0025 + Math.random() * 0.0025; + this.bubble.info.velocity[i].z = -this.playerDir.z * 0.005; + } + else{ + this.playerHeadPos.x += -this.playerDir.x * 0.25; + this.playerHeadPos.z += -this.playerDir.z * 0.25; + this.playerHeadPos.x += (Math.random() - 0.5) * 0.5; + this.playerHeadPos.z += (Math.random() - 0.5) * 0.5; + this.playerHeadPos.y -= this.player.avatar.height * 0.6; + this.playerHeadPos.y += (Math.random()) * 0.2 + this.bubble.info.velocity[i].x = 0; + this.bubble.info.velocity[i].y = 0.0025 + Math.random() * 0.0025; + this.bubble.info.velocity[i].z = 0; + + } + if(this.playerHeadPos.y > this.waterSurfacePos.y) + this.playerHeadPos.y = this.particlePosition.y; + positionsAttribute.setXYZ(i, this.playerHeadPos.x - this.waterWorldPosition.x, this.playerHeadPos.y - this.waterWorldPosition.y, this.playerHeadPos.z - this.waterWorldPosition.z); + + this.bubble.info.offset[i] = Math.floor(Math.random() * 29); + this.bubble.info.lastTime[i] = (50 + Math.random() * 50); + this.bubble.info.startTime[i] = 0; + scalesAttribute.setX(i, Math.random()); + if(this.currentSpeed <= 0.1 && !this.player.hasAction('swim')){ + scalesAttribute.setX(i, 0); + } + currentEmmit++; + } + if(currentEmmit > this.bubble.info.maxEmmit){ + this.bubble.info.lastEmmitTime = timestamp; + break; + } + + } + } + for (let i = 0; i < particleCount; i++){ + if(positionsAttribute.getY(i) >= this.particlePosition.y - 0.005){ + this.bubble.info.velocity[i].y = 0; + } + positionsAttribute.setXYZ( i, + positionsAttribute.getX(i) + this.bubble.info.velocity[i].x, + positionsAttribute.getY(i) + this.bubble.info.velocity[i].y, + positionsAttribute.getZ(i) + this.bubble.info.velocity[i].z + ); + this.bubble.info.startTime[i] = this.bubble.info.startTime[i] + 1; + if(this.bubble.info.startTime[i] % 2 === 0) + this.bubble.info.offset[i] += 1; + if(this.bubble.info.offset[i] >= 30){ + this.bubble.info.offset[i] = 0; + } + offsetAttribute.setXY(i, (5 / 6) - Math.floor(this.bubble.info.offset[i] / 6) * (1. / 6.), Math.floor(this.bubble.info.offset[i] % 5) * 0.2); + if(scalesAttribute.getX(i) > 0) + scalesAttribute.setX(i, scalesAttribute.getX(i) + 0.01); + if(this.bubble.info.startTime[i] > this.bubble.info.lastTime[i] || positionsAttribute.getY(i) > this.particlePosition.y){ + scalesAttribute.setX(i, 0); + } + } + + + positionsAttribute.needsUpdate = true; + scalesAttribute.needsUpdate = true; + offsetAttribute.needsUpdate = true; + + this.bubble.material.uniforms.uTime.value = timestamp / 1000; + this.bubble.material.uniforms.cameraBillboardQuaternion.value.copy(this.camera.quaternion); + } + + + + } + _handleBubble(); + this.app.updateMatrixWorld(); this.lastContactWater = this.contactWater; @@ -938,50 +1103,104 @@ class ParticleEffect{ this.app.add(this.swimmingSplash); } initSwimmingRipple(){ - // const particleCount = 30; - // const attributeSpecs = []; - // attributeSpecs.push({name: 'scales', itemSize: 1}); - // attributeSpecs.push({name: 'broken', itemSize: 1}); - // attributeSpecs.push({name: 'textureRotation', itemSize: 1}); - // const geometry2 = new THREE.PlaneGeometry(0.1, 0.1); - // const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); - - // const material = new THREE.ShaderMaterial({ - // uniforms: { - // uTime: { - // value: 0, - // }, - // cameraBillboardQuaternion: { - // value: new THREE.Quaternion(), - // }, - // splashTexture: { - // value: splashTexture2, - // }, - // waterSurfacePos: { - // value: new THREE.Vector3(), - // }, - // noiseMap:{ - // value: noiseMap - // }, - // }, - // vertexShader: swimmingSplashVertex, - // fragmentShader: swimmingSplashFragment, - // side: THREE.DoubleSide, - // transparent: true, - // }); - // this.swimmingSplash = new THREE.InstancedMesh(geometry, material, particleCount); + const particleCount = 30; + const attributeSpecs = []; + attributeSpecs.push({name: 'scales', itemSize: 1}); + attributeSpecs.push({name: 'broken', itemSize: 1}); + attributeSpecs.push({name: 'random', itemSize: 1}); + attributeSpecs.push({name: 'playerRotation', itemSize: 1}); + attributeSpecs.push({name: 'speed', itemSize: 1}); + const geometry2 = new THREE.PlaneGeometry(0.5, 0.5); + const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); + + const quaternions = new Float32Array(particleCount * 4); + const identityQuaternion = new THREE.Quaternion(); + for (let i = 0; i < particleCount; i++) { + identityQuaternion.toArray(quaternions, i * 4); + } + const quaternionsAttribute = new THREE.InstancedBufferAttribute(quaternions, 4); + geometry.setAttribute('quaternions', quaternionsAttribute); + + const material = new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + noiseMap:{ + value: noiseMap3 + }, + noiseMap2:{ + value: noiseMap + } + }, + vertexShader: swimmingRippleVertex, + fragmentShader: swimmingRippleFragment, + side: THREE.DoubleSide, + transparent: true, + }); + this.swimmingRipple = new THREE.InstancedMesh(geometry, material, particleCount); + + this.swimmingRipple.info = { + particleCount: particleCount, + currentIndex: 0, + lastEmmitTime: 0, + } + const euler = new THREE.Euler(-Math.PI / 2, 0, 0); + const quaternion = new THREE.Quaternion(); + const quaternionAttribute = this.swimmingRipple.geometry.getAttribute('quaternions'); + for (let i = 0; i < particleCount; i++) { + quaternion.setFromEuler(euler); + quaternionAttribute.setXYZW(i, quaternion.x, quaternion.y, quaternion.z, quaternion.w); + } + quaternionAttribute.needsUpdate = true; + + + this.app.add(this.swimmingRipple); + } + initBubble(){ + const particleCount = 40; + const attributeSpecs = []; + attributeSpecs.push({name: 'scales', itemSize: 1}); + attributeSpecs.push({name: 'offset', itemSize: 1}); + const geometry2 = new THREE.PlaneGeometry(0.02, 0.02); + const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); + + const material = new THREE.ShaderMaterial({ + uniforms: { + uTime: { + value: 0, + }, + cameraBillboardQuaternion: { + value: new THREE.Quaternion(), + }, + bubbleTexture1: { + value: bubbleTexture1, + }, + }, + vertexShader: bubbleVertex, + fragmentShader: bubbleFragment, + side: THREE.DoubleSide, + transparent: true, + }); + this.bubble = new THREE.InstancedMesh(geometry, material, particleCount); + + this.bubble.info = { + particleCount: particleCount, + maxEmmit: 5, + lastEmmitTime: 0, + velocity: [particleCount], + offset: [particleCount], + startTime:[particleCount], + lastTime:[particleCount] + } + + for (let i = 0; i < particleCount; i++) { + this.bubble.info.velocity[i] = new THREE.Vector3(); + } - // this.swimmingSplash.info = { - // particleCount: particleCount, - // velocity: [particleCount], - // acc: [particleCount] - // } - // for (let i = 0; i < particleCount; i++) { - // this.swimmingSplash.info.velocity[i] = new THREE.Vector3(); - // } - // this.app.add(this.swimmingSplash); + this.app.add(this.bubble); } _getGeometry = (geometry, attributeSpecs, particleCount) => { diff --git a/shaders/particleShader.js b/shaders/particleShader.js index e29315d..3316b8d 100644 --- a/shaders/particleShader.js +++ b/shaders/particleShader.js @@ -566,6 +566,189 @@ const swimmingSplashFragment = `\ } ` +const swimmingRippleVertex = `\ + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + + + uniform float uTime; + + varying vec2 vUv; + varying vec3 vPos; + varying float vBroken; + varying float vSpeed; + varying float vRand; + + + attribute float textureRotation; + attribute vec3 positions; + attribute float scales; + attribute float random; + attribute vec4 quaternions; + attribute float broken; + attribute float speed; + attribute float playerRotation; + vec3 qtransform(vec3 v, vec4 q) { + return v + 2.0*cross(cross(v, q.xyz ) + q.w*v, q.xyz); + } + + void main() { + mat3 rotY = + mat3(cos(playerRotation), 0.0, -sin(playerRotation), 0.0, 1.0, 0.0, sin(playerRotation), 0.0, cos(playerRotation)); + vBroken=broken; + vSpeed=speed; + vRand=random; + vUv=uv; + vPos=position; + vec3 pos = position; + pos = qtransform(pos, quaternions); + pos*=rotY; + pos*=scales; + pos+=positions; + + vec4 modelPosition = modelMatrix * vec4(pos, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + + gl_Position = projectionPosition; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } +` +const swimmingRippleFragment = `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + varying float vBroken; + varying float vSpeed; + varying float vRand; + varying vec2 vUv; + varying vec3 vPos; + uniform sampler2D noiseMap; + uniform sampler2D noiseMap2; + + const float rFrequency = 10.0; + const float rSpeed = .08; + const float rThickness = 50.0; + const float radiusEnd = .45; + const float radiusStart = .08; + const float PI = 3.1415926535897932384626433832795; + + float radialNoise(vec2 uv){ + uv.y -= rSpeed*uTime; + const int octaves = 2; + const float scale = .15; + float power = 2.2; + float total = 0.0; + for(int i = 0; iradiusStart) ? ripple*distScalar : 0.0; + float angle = atan(toCenter.x,toCenter.y); + angle = (angle + PI) / (2.0 * PI); + float noise = radialNoise(vec2(angle,dist)); + float total = ripple; + total -= noise; + total = total < (vRand * 0.5) / 10. ? 0.0 : 1.0; + gl_FragColor = vec4(total); + float mid = 0.5; + vec2 rotated = vec2(cos(vRand * 2. * PI) * (vUv.x - mid) * 1. - sin(vRand * 2. * PI) * (vUv.y - mid) * 1. + mid, + cos(vRand * 2. * PI) * (vUv.y - mid) * 1. + sin(vRand * 2. * PI) * (vUv.x - mid) * 1. + mid); + if(vSpeed > 0.1){ + if(vUv.y < 0.45){ + discard; + } + } + vec3 noise2 = texture2D( + noiseMap2, + rotated + ).rgb; + float broken = abs( sin( 1.0 - vBroken ) ) - noise2.g; + if ( broken < 0.0001 ) discard; + if(gl_FragColor.a <= 0.){ + discard; + } + else{ + gl_FragColor = vec4(0.9, 0.9, 0.9, 1.0); + } + ${THREE.ShaderChunk.logdepthbuf_fragment} + } +` + +const bubbleVertex = `\ + ${THREE.ShaderChunk.common} + ${THREE.ShaderChunk.logdepthbuf_pars_vertex} + + + uniform float uTime; + uniform vec4 cameraBillboardQuaternion; + + + varying vec2 vUv; + varying vec3 vPos; + varying vec3 vColor; + varying vec2 vOffset; + + attribute vec3 positions; + attribute vec3 color; + attribute float scales; + attribute vec2 offset; + + vec3 rotateVecQuat(vec3 position, vec4 q) { + vec3 v = position.xyz; + return v + 2.0 * cross(q.xyz, cross(q.xyz, v) + q.w * v); + } + void main() { + vUv = uv; + vPos = position; + vOffset = offset; + vec3 pos = position; + pos = rotateVecQuat(pos, cameraBillboardQuaternion); + pos*=scales; + pos+=positions; + vec4 modelPosition = modelMatrix * vec4(pos, 1.0); + vec4 viewPosition = viewMatrix * modelPosition; + vec4 projectionPosition = projectionMatrix * viewPosition; + + gl_Position = projectionPosition; + ${THREE.ShaderChunk.logdepthbuf_vertex} + } +` +const bubbleFragment = `\ + ${THREE.ShaderChunk.logdepthbuf_pars_fragment} + uniform float uTime; + uniform sampler2D bubbleTexture1; + varying vec2 vUv; + varying vec3 vPos; + varying vec2 vOffset; + void main() { + vec4 bubble = texture2D( + bubbleTexture1, + vec2( + vUv.x / 6. + vOffset.x, + vUv.y / 5. + vOffset.y + ) + ); + + gl_FragColor = bubble; + if(gl_FragColor.a < 0.25){ + discard; + } + ${THREE.ShaderChunk.logdepthbuf_fragment} +} +` + export { rippleVertex, rippleFragment, @@ -574,5 +757,7 @@ export { dropletVertex, dropletFragment, dropletRippleVertex, dropletRippleFragment, floatingSplashVertex, floatingSplashFragment, - swimmingSplashVertex, swimmingSplashFragment + swimmingSplashVertex, swimmingSplashFragment, + swimmingRippleVertex, swimmingRippleFragment, + bubbleVertex, bubbleFragment }; \ No newline at end of file From de9318c8c7e0bce897d41657061a0891bbee0f0a Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Mon, 25 Jul 2022 23:09:20 -0400 Subject: [PATCH 11/16] clean code --- index.js | 291 +++++++++++++++++++++++++++---------------------------- 1 file changed, 142 insertions(+), 149 deletions(-) diff --git a/index.js b/index.js index d641bd5..a2fd880 100644 --- a/index.js +++ b/index.js @@ -35,14 +35,19 @@ const dudvMap = textureLoader.load(`${baseUrl}/textures/dudvMap.png`); dudvMap.wrapS = dudvMap.wrapT = THREE.RepeatWrapping; const dudvMap2 = textureLoader.load(`${baseUrl}/textures/dudvMap2.png`); dudvMap2.wrapS = dudvMap2.wrapT = THREE.RepeatWrapping; - +const bubbleTexture1 = textureLoader.load(`${baseUrl}/textures/Bubble3.png`); +const bubbleTexture2 = textureLoader.load(`${baseUrl}/textures/Bubble2.png`); const waterNormalTexture1 = textureLoader.load(`${baseUrl}/textures/waterNormal2.png`); waterNormalTexture1.wrapS = waterNormalTexture1.wrapT = THREE.RepeatWrapping; const waterNormalTexture2 = textureLoader.load(`${baseUrl}/textures/waterNormal3.png`); waterNormalTexture2.wrapS = waterNormalTexture2.wrapT = THREE.RepeatWrapping; - +const noiseMap = textureLoader.load(`${baseUrl}/textures/noise.jpg`); +noiseMap.wrapS = noiseMap.wrapT = THREE.RepeatWrapping; +const splashTexture = textureLoader.load(`${baseUrl}/textures/splash1.png`); +const splashTexture2 = textureLoader.load(`${baseUrl}/textures/splash2.png`); +const noiseMap3 = textureLoader.load(`${baseUrl}/textures/noise3.png`); // const localVector = new THREE.Vector3(); @@ -111,10 +116,6 @@ class WaterMesh extends BatchedMesh { const {geometry} = allocator; const material = new THREE.ShaderMaterial({ - defines: { - DEPTH_PACKING: 1, - ORTHOGRAPHIC_CAMERA: 0 - }, uniforms: { uTime: { value: 0 @@ -617,36 +618,6 @@ export default (e) => { const particleWaterSurfacePos = new THREE.Vector3(0, 0, 0); const cameraWaterSurfacePos = new THREE.Vector3(0, 0, 0); let contactWater = false; - - let cameraDir = new THREE.Vector3(); - let playerDir = new THREE.Vector3(); - const playerHeadPos = new THREE.Vector3(); - let currentSpeed = 0; - let fallindSpeed = 0; - - //############################################################# trace camera player direction and speed ######################################################################## - { - const localVector = new THREE.Vector3(); - const localVector2 = new THREE.Vector3(); - useFrame(() => { - localVector.set(0, 0, -1); - cameraDir = localVector.applyQuaternion( camera.quaternion ); - cameraDir.normalize(); - - localVector2.set(0, 0, -1); - playerDir = localVector2.applyQuaternion( localPlayer.quaternion ); - playerDir.normalize(); - - fallindSpeed = 0 - localPlayer.characterPhysics.velocity.y; - if(localPlayer.avatar){ - currentSpeed = localVector.set(localPlayer.avatar.velocity.x, 0, localPlayer.avatar.velocity.z).length(); - playerHeadPos.setFromMatrixPosition(localPlayer.avatar.modelBoneOutputs.Head.matrixWorld); - } - - - - }); - } { let live = true; @@ -752,15 +723,34 @@ export default (e) => { const localVector06 = new THREE.Vector3(); const localVector07 = new THREE.Vector3(); const qt01 = new THREE.Quaternion(); + + + const pixelRatio = renderer.getPixelRatio(); + const renderTarget = new THREE.WebGLRenderTarget( + window.innerWidth * pixelRatio, + window.innerHeight * pixelRatio + ); + renderTarget.texture.minFilter = THREE.NearestFilter; + renderTarget.texture.magFilter = THREE.NearestFilter; + renderTarget.texture.generateMipmaps = false; + renderTarget.stencilBuffer = false; + + const depthMaterial = new THREE.MeshDepthMaterial(); + depthMaterial.depthPacking = THREE.RGBADepthPacking; + depthMaterial.blending = THREE.NoBlending; + const updateParticle = (timestamp) =>{ + particleEffect.update(timestamp); + particleEffect.particlePosition.set(localPlayer.position.x - waterWorldPosition.x, waterSurfacePos.y - waterWorldPosition.y, localPlayer.position.z - waterWorldPosition.z); + particleEffect.contactWater = contactWater; + particleEffect.waterSurfacePos.copy(waterSurfacePos); + particleEffect.waterWorldPosition.copy(waterWorldPosition); + } let qt = new THREE.Quaternion(); let mx = new THREE.Matrix4(); - let qt2 = new THREE.Quaternion(); - let mx2 = new THREE.Matrix4(); let upVector = new THREE.Vector3(0, 1, 0); - let upVector2 = new THREE.Vector3(0, 1, 0); let tempPos = new THREE.Vector3(); let tempPhysicsPos = new THREE.Vector3(); let tempPhysics = null; @@ -779,29 +769,10 @@ export default (e) => { let alreadySetComposer = false; - const pixelRatio = renderer.getPixelRatio(); - - const renderTarget = new THREE.WebGLRenderTarget( - window.innerWidth * pixelRatio, - window.innerHeight * pixelRatio - ); - renderTarget.texture.minFilter = THREE.NearestFilter; - renderTarget.texture.magFilter = THREE.NearestFilter; - renderTarget.texture.generateMipmaps = false; - renderTarget.stencilBuffer = false; - - const depthMaterial = new THREE.MeshDepthMaterial(); - depthMaterial.depthPacking = THREE.RGBADepthPacking; - depthMaterial.blending = THREE.NoBlending; - const testHDir = new THREE.Vector3(); useFrame(({timestamp, timeDiff}) => { - particleEffect.update(timestamp); - particleEffect.particlePosition.set(localPlayer.position.x - waterWorldPosition.x, waterSurfacePos.y - waterWorldPosition.y, localPlayer.position.z - waterWorldPosition.z); - particleEffect.contactWater = contactWater; - particleEffect.fallindSpeed = fallindSpeed; - particleEffect.waterSurfacePos.copy(waterSurfacePos); + updateParticle(timestamp); if (!!tracker && !app.getComponent('renderPosition')) { const localPlayer = useLocalPlayer(); localMatrix @@ -851,79 +822,31 @@ export default (e) => { generator.getMeshes()[0].material.uniforms.uTime.value = timestamp / 1000; generator.getMeshes()[0].material.uniforms.waterWorldPosition.value.copy(waterWorldPosition); } - // { - // for(const physicsObject of generator.getPhysicsObjects()){ - // generator.physics.enableGeometryQueries(physicsObject); - // } - // localVector03.set(localPlayer.position.x, localPlayer.position.y, localPlayer.position.z); - // const result3 = physics.raycast(localVector03, downVector); - // for(const physicsObject of generator.getPhysicsObjects()){ - // if(result3.objectId === physicsObject.physicsId){ - // waterSurfacePos.set(result3.point[0], result3.point[1], result3.point[2]); - // particleWaterSurfacePos.set(result3.point[0], result3.point[1], result3.point[2]).sub(waterWorldPosition); - // } - // generator.physics.disableGeometryQueries(physicsObject) - // } - // } - - - // check whether player is in the water - let min = null; - tempPhysics = null; - localVector02.set(localPlayer.position.x, localPlayer.position.y - localPlayer.avatar.height, localPlayer.position.z); - for(const physicsObject of generator.getPhysicsObjects()){ - - for(let i = 0; i < physicsObject.positions.length / 3; i++){ - tempPos.set(physicsObject.positions[i * 3 + 0], physicsObject.positions[i * 3 + 1], physicsObject.positions[i * 3 + 2]).add(waterWorldPosition); - if(!min || tempPos.distanceTo(localVector02) < min){ - min = tempPos.distanceTo(localVector02); - tempPhysicsPos.set(tempPos.x, tempPos.y, tempPos.z); - tempPhysics = physicsObject; - } - } - generator.physics.enableGeometryQueries(physicsObject); - } - if(tempPhysics){ - tempDir.set(tempPhysicsPos.x - localPlayer.position.x, tempPhysicsPos.y - (localPlayer.position.y - localPlayer.avatar.height), tempPhysicsPos.z - localPlayer.position.z); - tempDir.normalize(); - const detectDistance = 0.3; - if(count % 2 === 0){ - localVector01.set(tempPhysicsPos.x + tempDir.x * detectDistance, tempPhysicsPos.y + tempDir.y * detectDistance, tempPhysicsPos.z + tempDir.z * detectDistance); - localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); - localVector06.copy(localVector01).sub(localVector05); - const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; - upVector.crossVectors(localVector01, localVector05); - mx.lookAt(localVector01, localVector05, upVector); - qt.setFromRotationMatrix(mx); - let result = generator.physics.raycast(localVector01, qt); - testContact1 = false; - for(const physicsObject of generator.getPhysicsObjects()){ - if(result && result.objectId === physicsObject.physicsId && result.distance <= ds){ - testContact1 = true; - localVector07.set(result.point[0], result.point[1], result.point[2]); - } - generator.physics.disableGeometryQueries(physicsObject) - } - if(testContact1){ - testHDir.copy(localVector01).sub(localVector05).normalize(); - if(testHDir.y > 0.85 && localVector07.y > localPlayer.position.y){ - // console.log('h', testHDir.y); - waterSurfacePos.copy(localVector07); - particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); - if(!playerHighestWaterSurface) - playerHighestWaterSurface = result.point[1]; - else - playerHighestWaterSurface = playerHighestWaterSurface < waterSurfacePos.y ? waterSurfacePos.y : playerHighestWaterSurface; - - } - else{ - waterSurfacePos.y = playerHighestWaterSurface; - particleWaterSurfacePos.y = playerHighestWaterSurface - waterWorldPosition.y; - } + + + { + // check whether player is in the water for temporary. + // This hack need to be replaced by convex trigger. + let min = null; + tempPhysics = null; + localVector02.set(localPlayer.position.x, localPlayer.position.y - localPlayer.avatar.height, localPlayer.position.z); + for(const physicsObject of generator.getPhysicsObjects()){ + for(let i = 0; i < physicsObject.positions.length / 3; i++){ + tempPos.set(physicsObject.positions[i * 3 + 0], physicsObject.positions[i * 3 + 1], physicsObject.positions[i * 3 + 2]).add(waterWorldPosition); + if(!min || tempPos.distanceTo(localVector02) < min){ + min = tempPos.distanceTo(localVector02); + tempPhysicsPos.set(tempPos.x, tempPos.y, tempPos.z); + tempPhysics = physicsObject; + } } - } - else{ - localVector01.set(tempPhysicsPos.x - tempDir.x * detectDistance, tempPhysicsPos.y - tempDir.y * detectDistance, tempPhysicsPos.z - tempDir.z * detectDistance); + generator.physics.enableGeometryQueries(physicsObject); + } + if(tempPhysics){ + tempDir.set(tempPhysicsPos.x - localPlayer.position.x, tempPhysicsPos.y - (localPlayer.position.y - localPlayer.avatar.height), tempPhysicsPos.z - localPlayer.position.z); + tempDir.normalize(); + const detectDistance = 0.1; + if(count % 2 === 0){ + localVector01.set(tempPhysicsPos.x + tempDir.x * detectDistance, tempPhysicsPos.y + tempDir.y * detectDistance, tempPhysicsPos.z + tempDir.z * detectDistance); localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); localVector06.copy(localVector01).sub(localVector05); const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; @@ -931,18 +854,21 @@ export default (e) => { mx.lookAt(localVector01, localVector05, upVector); qt.setFromRotationMatrix(mx); let result = generator.physics.raycast(localVector01, qt); - testContact2 = true; + testContact1 = false; for(const physicsObject of generator.getPhysicsObjects()){ if(result && result.objectId === physicsObject.physicsId && result.distance <= ds){ - testContact2 = false; + testContact1 = true; localVector07.set(result.point[0], result.point[1], result.point[2]); } generator.physics.disableGeometryQueries(physicsObject) } - if(testContact2){ + if(!result){ + testContact1 = lastContactWater; + } + if(testContact1){ testHDir.copy(localVector01).sub(localVector05).normalize(); - if(testHDir.y < -0.85 && localVector07.y > localPlayer.position.y - localPlayer.avatar.height * 0.5){ - // console.log('h2', testHDir.y); + if(testHDir.y > 0.85 && localVector07.y > localPlayer.position.y){ + // console.log('h', testHDir.y); waterSurfacePos.copy(localVector07); particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); if(!playerHighestWaterSurface) @@ -955,19 +881,61 @@ export default (e) => { waterSurfacePos.y = playerHighestWaterSurface; particleWaterSurfacePos.y = playerHighestWaterSurface - waterWorldPosition.y; } - - } - } - } - if(testContact1 === testContact2){ - contactWater = testContact1; - lastContactWater = contactWater; - } - else{ - console.log('inconsist') - contactWater = lastContactWater; + } + else{ + localVector01.set(tempPhysicsPos.x - tempDir.x * detectDistance, tempPhysicsPos.y - tempDir.y * detectDistance, tempPhysicsPos.z - tempDir.z * detectDistance); + localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); + localVector06.copy(localVector01).sub(localVector05); + const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; + upVector.crossVectors(localVector01, localVector05); + mx.lookAt(localVector01, localVector05, upVector); + qt.setFromRotationMatrix(mx); + let result = generator.physics.raycast(localVector01, qt); + testContact2 = true; + for(const physicsObject of generator.getPhysicsObjects()){ + if(result && result.objectId === physicsObject.physicsId && result.distance <= ds){ + testContact2 = false; + localVector07.set(result.point[0], result.point[1], result.point[2]); + } + generator.physics.disableGeometryQueries(physicsObject) + } + if(!result){ + testContact2 = lastContactWater; + } + if(testContact2){ + testHDir.copy(localVector01).sub(localVector05).normalize(); + if(testHDir.y < -0.85 && localVector07.y > localPlayer.position.y - localPlayer.avatar.height * 0.5){ + // console.log('h2', testHDir.y); + waterSurfacePos.copy(localVector07); + particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); + if(!playerHighestWaterSurface) + playerHighestWaterSurface = result.point[1]; + else + playerHighestWaterSurface = playerHighestWaterSurface < waterSurfacePos.y ? waterSurfacePos.y : playerHighestWaterSurface; + + } + else{ + waterSurfacePos.y = playerHighestWaterSurface; + particleWaterSurfacePos.y = playerHighestWaterSurface - waterWorldPosition.y; + } + + + } + } + } + if(testContact1 === testContact2){ + contactWater = testContact1; + lastContactWater = contactWater; + } + else{ + // console.log('inconsist', testContact1, testContact2 ) + contactWater = lastContactWater; + } } + + + if(!contactWater){ if(localPlayer.hasAction('swim')){ @@ -1007,7 +975,32 @@ export default (e) => { } } - } + } + // handel swimming damping. Should not be here. Maybe should place in io-manager + if(localPlayer.hasAction('swim')){ + if(localPlayer.getAction('swim').animationType === 'breaststroke'){ + if(lastSwimmingHand !== localPlayer.characterSfx.currentSwimmingHand){ + if(localPlayer.characterSfx.currentSwimmingHand !== null){ + localPlayer.getAction('swim').swimDamping = 1; + } + lastSwimmingHand = localPlayer.characterSfx.currentSwimmingHand; + } + if(localPlayer.getAction('swim').swimDamping < 4){ + localPlayer.getAction('swim').swimDamping *= 1.05; + } + else{ + localPlayer.getAction('swim').swimDamping = 4; + } + + } + else if(localPlayer.getAction('swim').animationType === 'freestyle'){ + localPlayer.getAction('swim').swimDamping = 0; + } + else{ + localPlayer.getAction('swim').swimDamping = 4; + } + + } } } count++; @@ -1119,6 +1112,6 @@ export default (e) => { } }); } - + return app; }; \ No newline at end of file From b32171640254b89abed6288c3580841937c37dbb Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Mon, 25 Jul 2022 23:10:19 -0400 Subject: [PATCH 12/16] clean code --- index.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/index.js b/index.js index a2fd880..7f1f7aa 100644 --- a/index.js +++ b/index.js @@ -35,8 +35,6 @@ const dudvMap = textureLoader.load(`${baseUrl}/textures/dudvMap.png`); dudvMap.wrapS = dudvMap.wrapT = THREE.RepeatWrapping; const dudvMap2 = textureLoader.load(`${baseUrl}/textures/dudvMap2.png`); dudvMap2.wrapS = dudvMap2.wrapT = THREE.RepeatWrapping; -const bubbleTexture1 = textureLoader.load(`${baseUrl}/textures/Bubble3.png`); -const bubbleTexture2 = textureLoader.load(`${baseUrl}/textures/Bubble2.png`); const waterNormalTexture1 = textureLoader.load(`${baseUrl}/textures/waterNormal2.png`); waterNormalTexture1.wrapS = waterNormalTexture1.wrapT = THREE.RepeatWrapping; @@ -45,9 +43,7 @@ waterNormalTexture2.wrapS = waterNormalTexture2.wrapT = THREE.RepeatWrapping; const noiseMap = textureLoader.load(`${baseUrl}/textures/noise.jpg`); noiseMap.wrapS = noiseMap.wrapT = THREE.RepeatWrapping; -const splashTexture = textureLoader.load(`${baseUrl}/textures/splash1.png`); -const splashTexture2 = textureLoader.load(`${baseUrl}/textures/splash2.png`); -const noiseMap3 = textureLoader.load(`${baseUrl}/textures/noise3.png`); + // const localVector = new THREE.Vector3(); From 13ad294ef05c8a561137a838e7b29b088deb4e32 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Tue, 26 Jul 2022 00:19:10 -0400 Subject: [PATCH 13/16] clean code --- index.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.js b/index.js index 7f1f7aa..d0281ec 100644 --- a/index.js +++ b/index.js @@ -197,10 +197,10 @@ class WaterMesh extends BatchedMesh { return perspectiveDepthToViewZ( depth, cameraNear, cameraFar ); } vec4 getNoise( vec2 uv ) { - vec2 uv0 = ( uv / 103.0 ) + vec2(uTime / 34.0, uTime / 58.0); - vec2 uv1 = uv / 107.0-vec2( uTime / -38.0, uTime / 64.0 ); - vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( uTime / 202.0, uTime / 194.0 ); - vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( uTime / 218.0, uTime / -226.0 ); + vec2 uv0 = ( uv / 103.0 ) + vec2(uTime / 25.5, uTime / 43.5); + vec2 uv1 = uv / 107.0-vec2( uTime / -28.5, uTime / 48.0 ); + vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( uTime / 151.5, uTime / 145.5 ); + vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( uTime / 163.5, uTime / -469.5 ); vec4 noise = texture2D( waterNormalTexture1, uv0 ) + texture2D( waterNormalTexture1, uv1 ) + texture2D( waterNormalTexture2, uv2 ) + @@ -214,7 +214,7 @@ class WaterMesh extends BatchedMesh { diffuseColor += max( dot( sunDirection, surfaceNormal ), 0.0 ) * vec3(0.3, 0.3, 0.3) * diffuse; } void main() { - vec4 worldPosition = modelMatrix * vec4( vPos, 1.0 ); + vec4 worldPosition = modelMatrix * vec4( vPos, 1.0 ) * 2.; vec4 noise = getNoise( worldPosition.xz * 2.); vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) ); vec3 diffuseLight = vec3(1.0); @@ -225,7 +225,7 @@ class WaterMesh extends BatchedMesh { float distance = length(worldToEye); float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 ); - vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) * 0.25 ) * vec3(0.5, 0.5, 0.5); + vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) * 0.5 ) * vec3(0.5, 0.5, 0.5); vec3 albedo = ( vec3(0.3, 0.3, 0.3) * diffuseLight * 0.025 + scatter ); vec3 outgoingLight = albedo; gl_FragColor = (vec4( outgoingLight, 0.95 )) + vec4(0.0282, 0.470, 0.431, 0.); From 869b0e9fd91836d5c6caaeadb56fef2f19f12c1e Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Tue, 26 Jul 2022 10:32:19 -0400 Subject: [PATCH 14/16] ripple bug --- particle.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/particle.js b/particle.js index 6648cce..ab7eb49 100644 --- a/particle.js +++ b/particle.js @@ -91,6 +91,7 @@ class ParticleEffect{ this.rippleMesh = null; + this.rippleGroupInApp = false; this.initRipple(); this.floatingSplash = null; @@ -165,6 +166,10 @@ class ParticleEffect{ this.rippleMesh.material.uniforms.vBroken.value = 0.1; this.rippleMesh.scale.set(0.2, 1, 0.2); this.rippleMesh.material.uniforms.uTime.value = 120; + if(!this.rippleGroupInApp){ + this.app.add(this.rippleGroup); + this.rippleGroupInApp = true; + } } } @@ -744,8 +749,8 @@ class ParticleEffect{ positionsAttribute.getZ(i) + this.bubble.info.velocity[i].z ); this.bubble.info.startTime[i] = this.bubble.info.startTime[i] + 1; - if(this.bubble.info.startTime[i] % 2 === 0) - this.bubble.info.offset[i] += 1; + // if(this.bubble.info.startTime[i] % 2 === 0) + this.bubble.info.offset[i] += 3; if(this.bubble.info.offset[i] >= 30){ this.bubble.info.offset[i] = 0; } @@ -787,7 +792,7 @@ class ParticleEffect{ this.rippleGroup.add(splashMeshApp.scene) this.rippleMesh = splashMeshApp.scene.children[0]; this.rippleMesh.scale.set(0, 0, 0); - this.app.add(this.rippleGroup); + // this.app.add(this.rippleGroup); this.rippleMesh.material = new THREE.ShaderMaterial({ uniforms: { From c30f0706d13fd6fa99aacf8eecc8cf51d905848d Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Tue, 26 Jul 2022 15:33:31 -0400 Subject: [PATCH 15/16] bubble bug --- particle.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/particle.js b/particle.js index ab7eb49..a96398a 100644 --- a/particle.js +++ b/particle.js @@ -14,7 +14,7 @@ import { bubbleVertex, bubbleFragment } from './shaders/particleShader.js'; const baseUrl = import.meta.url.replace(/(\/)[^\/\\]*$/, '$1'); const { useLoaders, - useSound + useSound, } = metaversefile; const sounds = useSound(); const soundFiles = sounds.getSoundFiles(); @@ -122,6 +122,7 @@ class ParticleEffect{ this.localVector3 = new THREE.Vector3(); this.localVector4 = new THREE.Vector3(); this.localVector5 = new THREE.Vector3(); + } tracePlayerInfo(){ @@ -748,9 +749,9 @@ class ParticleEffect{ positionsAttribute.getY(i) + this.bubble.info.velocity[i].y, positionsAttribute.getZ(i) + this.bubble.info.velocity[i].z ); - this.bubble.info.startTime[i] = this.bubble.info.startTime[i] + 1; - // if(this.bubble.info.startTime[i] % 2 === 0) - this.bubble.info.offset[i] += 3; + this.bubble.info.startTime[i]++; + if(this.bubble.info.startTime[i] % 2 === 0) + this.bubble.info.offset[i] += 1; if(this.bubble.info.offset[i] >= 30){ this.bubble.info.offset[i] = 0; } @@ -767,7 +768,7 @@ class ParticleEffect{ scalesAttribute.needsUpdate = true; offsetAttribute.needsUpdate = true; - this.bubble.material.uniforms.uTime.value = timestamp / 1000; + // this.bubble.material.uniforms.uTime.value = timestamp / 1000; this.bubble.material.uniforms.cameraBillboardQuaternion.value.copy(this.camera.quaternion); } @@ -924,7 +925,7 @@ class ParticleEffect{ const particleCount = 50; const attributeSpecs = []; attributeSpecs.push({name: 'scales', itemSize: 1}); - attributeSpecs.push({name: 'offset', itemSize: 1}); + attributeSpecs.push({name: 'offset', itemSize: 2}); const geometry2 = new THREE.PlaneGeometry(0.1, 0.1); const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); const material= new THREE.ShaderMaterial({ @@ -1166,7 +1167,7 @@ class ParticleEffect{ const particleCount = 40; const attributeSpecs = []; attributeSpecs.push({name: 'scales', itemSize: 1}); - attributeSpecs.push({name: 'offset', itemSize: 1}); + attributeSpecs.push({name: 'offset', itemSize: 2}); const geometry2 = new THREE.PlaneGeometry(0.02, 0.02); const geometry = this._getGeometry(geometry2, attributeSpecs, particleCount); @@ -1203,8 +1204,6 @@ class ParticleEffect{ this.bubble.info.velocity[i] = new THREE.Vector3(); } - - this.app.add(this.bubble); } From b55f70406f7a29e6d40fc11409bee25fc27ec7a7 Mon Sep 17 00:00:00 2001 From: tcm390 <60634884+tcm390@users.noreply.github.com> Date: Wed, 27 Jul 2022 09:54:03 -0400 Subject: [PATCH 16/16] rmove raycast --- index.js | 135 +++---------------------------------------------------- 1 file changed, 6 insertions(+), 129 deletions(-) diff --git a/index.js b/index.js index d0281ec..ca21a61 100644 --- a/index.js +++ b/index.js @@ -711,16 +711,6 @@ export default (e) => { generator.getMeshes()[0].drawChunk(chunk, renderData, tracker); }; - const localVector01 = new THREE.Vector3(); - const localVector02 = new THREE.Vector3(); - const localVector03 = new THREE.Vector3(); - const localVector04 = new THREE.Vector3(); - const localVector05 = new THREE.Vector3(); - const localVector06 = new THREE.Vector3(); - const localVector07 = new THREE.Vector3(); - const qt01 = new THREE.Quaternion(); - - const pixelRatio = renderer.getPixelRatio(); const renderTarget = new THREE.WebGLRenderTarget( window.innerWidth * pixelRatio, @@ -744,28 +734,20 @@ export default (e) => { } - let qt = new THREE.Quaternion(); - let mx = new THREE.Matrix4(); - let upVector = new THREE.Vector3(0, 1, 0); - let tempPos = new THREE.Vector3(); - let tempPhysicsPos = new THREE.Vector3(); - let tempPhysics = null; + let playerHighestWaterSurface = null; let cameraHighestWaterSurface = null; - let tempDir = new THREE.Vector3(); + const downVector = new THREE.Quaternion(); downVector.setFromAxisAngle( new THREE.Vector3( 1, 0, 0 ), -Math.PI / 2 ); - let lastContactWater; - let count = 0; - let testContact1; - let testContact2; + + let lastSwimmingHand = null; - let alreadySetComposer = false; - const testHDir = new THREE.Vector3(); + useFrame(({timestamp, timeDiff}) => { updateParticle(timestamp); @@ -823,111 +805,7 @@ export default (e) => { { // check whether player is in the water for temporary. // This hack need to be replaced by convex trigger. - let min = null; - tempPhysics = null; - localVector02.set(localPlayer.position.x, localPlayer.position.y - localPlayer.avatar.height, localPlayer.position.z); - for(const physicsObject of generator.getPhysicsObjects()){ - for(let i = 0; i < physicsObject.positions.length / 3; i++){ - tempPos.set(physicsObject.positions[i * 3 + 0], physicsObject.positions[i * 3 + 1], physicsObject.positions[i * 3 + 2]).add(waterWorldPosition); - if(!min || tempPos.distanceTo(localVector02) < min){ - min = tempPos.distanceTo(localVector02); - tempPhysicsPos.set(tempPos.x, tempPos.y, tempPos.z); - tempPhysics = physicsObject; - } - } - generator.physics.enableGeometryQueries(physicsObject); - } - if(tempPhysics){ - tempDir.set(tempPhysicsPos.x - localPlayer.position.x, tempPhysicsPos.y - (localPlayer.position.y - localPlayer.avatar.height), tempPhysicsPos.z - localPlayer.position.z); - tempDir.normalize(); - const detectDistance = 0.1; - if(count % 2 === 0){ - localVector01.set(tempPhysicsPos.x + tempDir.x * detectDistance, tempPhysicsPos.y + tempDir.y * detectDistance, tempPhysicsPos.z + tempDir.z * detectDistance); - localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); - localVector06.copy(localVector01).sub(localVector05); - const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; - upVector.crossVectors(localVector01, localVector05); - mx.lookAt(localVector01, localVector05, upVector); - qt.setFromRotationMatrix(mx); - let result = generator.physics.raycast(localVector01, qt); - testContact1 = false; - for(const physicsObject of generator.getPhysicsObjects()){ - if(result && result.objectId === physicsObject.physicsId && result.distance <= ds){ - testContact1 = true; - localVector07.set(result.point[0], result.point[1], result.point[2]); - } - generator.physics.disableGeometryQueries(physicsObject) - } - if(!result){ - testContact1 = lastContactWater; - } - if(testContact1){ - testHDir.copy(localVector01).sub(localVector05).normalize(); - if(testHDir.y > 0.85 && localVector07.y > localPlayer.position.y){ - // console.log('h', testHDir.y); - waterSurfacePos.copy(localVector07); - particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); - if(!playerHighestWaterSurface) - playerHighestWaterSurface = result.point[1]; - else - playerHighestWaterSurface = playerHighestWaterSurface < waterSurfacePos.y ? waterSurfacePos.y : playerHighestWaterSurface; - - } - else{ - waterSurfacePos.y = playerHighestWaterSurface; - particleWaterSurfacePos.y = playerHighestWaterSurface - waterWorldPosition.y; - } - } - } - else{ - localVector01.set(tempPhysicsPos.x - tempDir.x * detectDistance, tempPhysicsPos.y - tempDir.y * detectDistance, tempPhysicsPos.z - tempDir.z * detectDistance); - localVector05.set(tempPhysicsPos.x, tempPhysicsPos.y, tempPhysicsPos.z); - localVector06.copy(localVector01).sub(localVector05); - const ds = Math.sqrt(localVector06.x * localVector06.x + localVector06.y * localVector06.y + localVector06.z * localVector06.z) * 2.5; - upVector.crossVectors(localVector01, localVector05); - mx.lookAt(localVector01, localVector05, upVector); - qt.setFromRotationMatrix(mx); - let result = generator.physics.raycast(localVector01, qt); - testContact2 = true; - for(const physicsObject of generator.getPhysicsObjects()){ - if(result && result.objectId === physicsObject.physicsId && result.distance <= ds){ - testContact2 = false; - localVector07.set(result.point[0], result.point[1], result.point[2]); - } - generator.physics.disableGeometryQueries(physicsObject) - } - if(!result){ - testContact2 = lastContactWater; - } - if(testContact2){ - testHDir.copy(localVector01).sub(localVector05).normalize(); - if(testHDir.y < -0.85 && localVector07.y > localPlayer.position.y - localPlayer.avatar.height * 0.5){ - // console.log('h2', testHDir.y); - waterSurfacePos.copy(localVector07); - particleWaterSurfacePos.copy(localVector07).sub(waterWorldPosition); - if(!playerHighestWaterSurface) - playerHighestWaterSurface = result.point[1]; - else - playerHighestWaterSurface = playerHighestWaterSurface < waterSurfacePos.y ? waterSurfacePos.y : playerHighestWaterSurface; - - } - else{ - waterSurfacePos.y = playerHighestWaterSurface; - particleWaterSurfacePos.y = playerHighestWaterSurface - waterWorldPosition.y; - } - - - } - } - } - if(testContact1 === testContact2){ - contactWater = testContact1; - lastContactWater = contactWater; - } - else{ - // console.log('inconsist', testContact1, testContact2 ) - contactWater = lastContactWater; - } + } @@ -999,7 +877,6 @@ export default (e) => { } } } - count++; }); useCleanup(() => {