-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
369 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
varying vec3 vColor; | ||
|
||
void main() | ||
{ | ||
vec2 uv = gl_PointCoord; | ||
float distanceToCenter = length(uv - 0.5); | ||
float alpha = 0.05 / distanceToCenter - 0.1; | ||
|
||
gl_FragColor = vec4(vColor, alpha); | ||
#include <tonemapping_fragment> | ||
#include <colorspace_fragment> | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Simplex 3D Noise | ||
// by Ian McEwan, Ashima Arts | ||
// | ||
vec4 permute(vec4 x){ return mod(((x*34.0)+1.0)*x, 289.0); } | ||
vec4 taylorInvSqrt(vec4 r){ return 1.79284291400159 - 0.85373472095314 * r; } | ||
|
||
float simplexNoise3d(vec3 v) | ||
{ | ||
const vec2 C = vec2(1.0/6.0, 1.0/3.0) ; | ||
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); | ||
|
||
// First corner | ||
vec3 i = floor(v + dot(v, C.yyy) ); | ||
vec3 x0 = v - i + dot(i, C.xxx) ; | ||
|
||
// Other corners | ||
vec3 g = step(x0.yzx, x0.xyz); | ||
vec3 l = 1.0 - g; | ||
vec3 i1 = min( g.xyz, l.zxy ); | ||
vec3 i2 = max( g.xyz, l.zxy ); | ||
|
||
// x0 = x0 - 0. + 0.0 * C | ||
vec3 x1 = x0 - i1 + 1.0 * C.xxx; | ||
vec3 x2 = x0 - i2 + 2.0 * C.xxx; | ||
vec3 x3 = x0 - 1. + 3.0 * C.xxx; | ||
|
||
// Permutations | ||
i = mod(i, 289.0 ); | ||
vec4 p = permute( permute( permute( i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); | ||
|
||
// Gradients | ||
// ( N*N points uniformly over a square, mapped onto an octahedron.) | ||
float n_ = 1.0/7.0; // N=7 | ||
vec3 ns = n_ * D.wyz - D.xzx; | ||
|
||
vec4 j = p - 49.0 * floor(p * ns.z *ns.z); // mod(p,N*N) | ||
|
||
vec4 x_ = floor(j * ns.z); | ||
vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) | ||
|
||
vec4 x = x_ *ns.x + ns.yyyy; | ||
vec4 y = y_ *ns.x + ns.yyyy; | ||
vec4 h = 1.0 - abs(x) - abs(y); | ||
|
||
vec4 b0 = vec4( x.xy, y.xy ); | ||
vec4 b1 = vec4( x.zw, y.zw ); | ||
|
||
vec4 s0 = floor(b0)*2.0 + 1.0; | ||
vec4 s1 = floor(b1)*2.0 + 1.0; | ||
vec4 sh = -step(h, vec4(0.0)); | ||
|
||
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy ; | ||
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww ; | ||
|
||
vec3 p0 = vec3(a0.xy,h.x); | ||
vec3 p1 = vec3(a0.zw,h.y); | ||
vec3 p2 = vec3(a1.xy,h.z); | ||
vec3 p3 = vec3(a1.zw,h.w); | ||
|
||
// Normalise gradients | ||
vec4 norm = taylorInvSqrt(vec4(dot(p0,p0), dot(p1,p1), dot(p2, p2), dot(p3,p3))); | ||
p0 *= norm.x; | ||
p1 *= norm.y; | ||
p2 *= norm.z; | ||
p3 *= norm.w; | ||
|
||
// Mix final noise value | ||
vec4 m = max(0.6 - vec4(dot(x0,x0), dot(x1,x1), dot(x2,x2), dot(x3,x3)), 0.0); | ||
m = m * m; | ||
return 42.0 * dot( m*m, vec4( dot(p0,x0), dot(p1,x1), dot(p2,x2), dot(p3,x3) ) ); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
#include ./simplex.glsl // simplexNoise3d | ||
|
||
attribute vec3 aPositionTarget; | ||
attribute float aSize; | ||
|
||
uniform vec2 uResolution; | ||
uniform float uSize; | ||
uniform float uProgress; | ||
uniform vec3 uColorA; | ||
uniform vec3 uColorB; | ||
|
||
varying vec3 vColor; | ||
|
||
void main() | ||
{ | ||
// Mixed position | ||
float noiseOrigin = simplexNoise3d(position * 0.2); | ||
float noiseTarget = simplexNoise3d(aPositionTarget * 0.2); | ||
float noise = mix(noiseOrigin, noiseTarget, uProgress); | ||
noise = smoothstep(-1.0, 1.0, noise); | ||
|
||
float duration = 0.4; | ||
float delay = (1.0 - duration) * noise; | ||
float end = delay + duration; | ||
|
||
float progress = smoothstep(delay, end, uProgress); | ||
vec3 MixedPosition = mix(position, aPositionTarget, progress); | ||
|
||
// Final position | ||
vec4 modelPosition = modelMatrix * vec4(MixedPosition, 1.0); | ||
vec4 viewPosition = viewMatrix * modelPosition; | ||
vec4 projectedPosition = projectionMatrix * viewPosition; | ||
gl_Position = projectedPosition; | ||
|
||
// Point size | ||
gl_PointSize = aSize * uSize * uResolution.y; | ||
gl_PointSize *= (1.0 / - viewPosition.z); | ||
|
||
// Varying | ||
vColor = mix(uColorA, uColorB, noise); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
<!-- ================================================= SCRIPT --> | ||
<script lang="ts"> | ||
import { browser } from "$app/environment"; | ||
import { onMount } from "svelte"; | ||
import * as THREE from "three"; | ||
import { OrbitControls } from "three/addons/controls/OrbitControls.js"; | ||
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js"; | ||
import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js"; | ||
import GUI from "lil-gui"; | ||
import gsap from "gsap"; | ||
import particlesVertexShader from "$lib/shaders/morphing/vertex.glsl"; | ||
import particlesFragmentShader from "$lib/shaders/morphing/fragment.glsl"; | ||
import { base } from "$app/paths"; | ||
let canvas: any = null; | ||
const WIDTH = 800; | ||
const HEIGHT = 600; | ||
const RATIO = WIDTH / HEIGHT; | ||
const debugObject = { | ||
clearColor: "#160920", | ||
}; | ||
let gui: GUI | null = null; | ||
function start() { | ||
gui = new GUI(); | ||
const pixelRatio = Math.min(window.devicePixelRatio, 2); | ||
// Loaders | ||
const dracoLoader = new DRACOLoader(); | ||
dracoLoader.setDecoderPath(base + "/draco/"); | ||
const gltfLoader = new GLTFLoader(); | ||
gltfLoader.setDRACOLoader(dracoLoader); | ||
// Scene | ||
const scene = new THREE.Scene(); | ||
// Camera | ||
const camera = new THREE.PerspectiveCamera(35, RATIO, 0.1, 100); | ||
camera.position.set(0, 0, 8 * 2); | ||
scene.add(camera); | ||
// Camera controls | ||
const controls = new OrbitControls(camera, canvas); | ||
controls.enableDamping = true; | ||
// Renderer | ||
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true }); | ||
renderer.setPixelRatio(pixelRatio); | ||
renderer.setSize(WIDTH, HEIGHT); | ||
gui!.addColor(debugObject, "clearColor").onChange(() => { | ||
renderer.setClearColor(debugObject.clearColor); | ||
}); | ||
renderer.setClearColor(debugObject.clearColor); | ||
renderer.render(scene, camera); | ||
// Load models | ||
gltfLoader.load(base + "/morphing/models.glb", (gltf) => { | ||
/** | ||
* Particles | ||
*/ | ||
const particles = { | ||
geometry: null as THREE.BufferGeometry | null, | ||
material: null as THREE.ShaderMaterial | null, | ||
points: null as THREE.Points | null, | ||
positions: [] as Array<THREE.BufferAttribute>, | ||
index: 0, | ||
morph: (index: number) => { | ||
if (particles.geometry !== null && particles.material !== null) { | ||
// Update attributes | ||
particles.geometry.attributes.position = | ||
particles.positions[particles.index]; | ||
particles.geometry.attributes.aPositionTarget = | ||
particles.positions[index]; | ||
// Animate uProgress | ||
gsap.fromTo( | ||
particles.material.uniforms.uProgress, | ||
{ value: 0 }, | ||
{ value: 1 } | ||
); | ||
particles.index = index; | ||
} | ||
}, | ||
colorA: "#ff7300", | ||
colorB: "#0091ff", | ||
}; | ||
// Morph functions animations | ||
const morphFunctions = { | ||
"Morph 1": () => particles.morph(0), | ||
"Morph 2": () => particles.morph(1), | ||
"Morph 3": () => particles.morph(2), | ||
"Morph 4": () => particles.morph(3), | ||
}; | ||
gui!.add(morphFunctions, "Morph 1"); | ||
gui!.add(morphFunctions, "Morph 2"); | ||
gui!.add(morphFunctions, "Morph 3"); | ||
gui!.add(morphFunctions, "Morph 4"); | ||
const positions = (gltf.scene.children as Array<THREE.Mesh>).map( | ||
(child) => child.geometry.attributes.position | ||
) as Array<THREE.BufferAttribute>; | ||
const maxPositionCount = Math.max( | ||
...positions.map((position) => position.count) | ||
); | ||
for (const position of positions) { | ||
const originalArray = position.array; | ||
const newArray = new Float32Array(maxPositionCount * 3); | ||
for (let i = 0; i < maxPositionCount; i++) { | ||
const i3 = i * 3; | ||
if (i3 < originalArray.length) { | ||
newArray[i3] = originalArray[i3]; | ||
newArray[i3 + 1] = originalArray[i3 + 1]; | ||
newArray[i3 + 2] = originalArray[i3 + 2]; | ||
} else { | ||
const randomIndex = Math.floor(position.count * Math.random()) * 3; | ||
newArray[i3] = originalArray[randomIndex]; | ||
newArray[i3 + 1] = originalArray[randomIndex + 1]; | ||
newArray[i3 + 2] = originalArray[randomIndex + 2]; | ||
} | ||
} | ||
particles.positions.push(new THREE.Float32BufferAttribute(newArray, 3)); | ||
} | ||
// Geometry | ||
const sizesArray = new Float32Array(maxPositionCount) | ||
.fill(0) | ||
.map(() => Math.random()); | ||
particles.geometry = new THREE.BufferGeometry(); | ||
particles.geometry.setAttribute( | ||
"position", | ||
particles.positions[particles.index] | ||
); | ||
particles.geometry.setAttribute( | ||
"aPositionTarget", | ||
particles.positions[3] | ||
); | ||
particles.geometry.setAttribute( | ||
"aSize", | ||
new THREE.BufferAttribute(sizesArray, 1) | ||
); | ||
particles.geometry.setIndex(null); | ||
// Material | ||
particles.material = new THREE.ShaderMaterial({ | ||
vertexShader: particlesVertexShader, | ||
fragmentShader: particlesFragmentShader, | ||
uniforms: { | ||
uSize: new THREE.Uniform(0.4), | ||
uResolution: new THREE.Uniform( | ||
new THREE.Vector2(WIDTH * pixelRatio, HEIGHT * pixelRatio) | ||
), | ||
uProgress: new THREE.Uniform(0), | ||
uColorA: new THREE.Uniform(new THREE.Color(particles.colorA)), | ||
uColorB: new THREE.Uniform(new THREE.Color(particles.colorB)), | ||
}, | ||
// transparent: true, | ||
blending: THREE.AdditiveBlending, | ||
depthWrite: false, | ||
}); | ||
// Points | ||
particles.points = new THREE.Points( | ||
particles.geometry, | ||
particles.material | ||
); | ||
// NEW frustumCulled property is set to the first geometry | ||
// to update the boundingSphere and/or fix the bug if we change the geometry (3 solutions): | ||
// 1) we can deactivate the frustumCulled property | ||
particles.points.frustumCulled = false; | ||
// 2) we can update the boundingSphere property directly in the geometry property | ||
// setTimeout(() => { | ||
// console.log(particles.points!.geometry.boundingSphere); | ||
// particles.points!.geometry.boundingSphere!.radius = 15; | ||
// }, 1000); | ||
// 3) we can ask to three.js to update the boundingSphere property but it's not performant | ||
scene.add(particles.points); | ||
// Tweak | ||
gui! | ||
.add(particles.material.uniforms.uSize, "value") | ||
.min(0) | ||
.max(0.8) | ||
.step(0.01) | ||
.name("Size"); | ||
gui! | ||
.add(particles.material.uniforms.uProgress, "value") | ||
.min(0) | ||
.max(1) | ||
.step(0.01) | ||
.name("Progress") | ||
.listen(); | ||
gui! | ||
.addColor(particles, "colorA") | ||
.name("Color A") | ||
.onChange(() => { | ||
particles.material!.uniforms.uColorA.value.set(particles.colorA); | ||
}); | ||
gui! | ||
.addColor(particles, "colorB") | ||
.name("Color B") | ||
.onChange(() => { | ||
particles.material!.uniforms.uColorB.value.set(particles.colorB); | ||
}); | ||
}); | ||
// Clock | ||
const clock = new THREE.Clock(); | ||
// Animation | ||
const tick = () => { | ||
const elapsedTime = clock.getElapsedTime(); | ||
controls.update(); | ||
renderer.render(scene, camera); | ||
window.requestAnimationFrame(tick); | ||
}; | ||
tick(); | ||
} | ||
onMount(() => { | ||
if (browser) { | ||
start(); | ||
return () => { | ||
gui?.destroy(); | ||
}; | ||
} | ||
}); | ||
</script> | ||
|
||
<!-- ================================================= CONTENT --> | ||
<canvas bind:this={canvas} width={WIDTH} height={HEIGHT}></canvas> | ||
|
||
<!-- ================================================= CSS --> | ||
<style lang="postcss"> | ||
</style> |
Binary file not shown.