website/components/galaxy.tsx

163 lines
10 KiB
TypeScript
Raw Normal View History

2024-05-25 15:20:10 +08:00
import { lerp, BufferGeometry, Camera, EffectComposer, Points, Renderer, RenderPass, Scene, ShaderMaterial, Texture, UnrealBloomPass, ZoomBlurPass } from 'troisjs'
import { Clock, Color, MathUtils, Vector3 } from 'three'
import { useMouse } from '@vueuse/core'
const niceColors = [['#69d2e7', '#a7dbd8', '#e0e4cc', '#f38630', '#fa6900'], ['#fe4365', '#fc9d9a', '#f9cdad', '#c8c8a9', '#83af9b'], ['#ecd078', '#d95b43', '#c02942', '#542437', '#53777a'], ['#556270', '#4ecdc4', '#c7f464', '#ff6b6b', '#c44d58'], ['#774f38', '#e08e79', '#f1d4af', '#ece5ce', '#c5e0dc'], ['#e8ddcb', '#cdb380', '#036564', '#033649', '#031634'], ['#490a3d', '#bd1550', '#e97f02', '#f8ca00', '#8a9b0f'], ['#594f4f', '#547980', '#45ada8', '#9de0ad', '#e5fcc2'], ['#00a0b0', '#6a4a3c', '#cc333f', '#eb6841', '#edc951'], ['#e94e77', '#d68189', '#c6a49a', '#c6e5d9', '#f4ead5'], ['#3fb8af', '#7fc7af', '#dad8a7', '#ff9e9d', '#ff3d7f'], ['#d9ceb2', '#948c75', '#d5ded9', '#7a6a53', '#99b2b7'], ['#ffffff', '#cbe86b', '#f2e9e1', '#1c140d', '#cbe86b'], ['#efffcd', '#dce9be', '#555152', '#2e2633', '#99173c'], ['#343838', '#005f6b', '#008c9e', '#00b4cc', '#00dffc'], ['#413e4a', '#73626e', '#b38184', '#f0b49e', '#f7e4be'], ['#ff4e50', '#fc913a', '#f9d423', '#ede574', '#e1f5c4'], ['#99b898', '#fecea8', '#ff847c', '#e84a5f', '#2a363b'], ['#655643', '#80bca3', '#f6f7bd', '#e6ac27', '#bf4d28'], ['#00a8c6', '#40c0cb', '#f9f2e7', '#aee239', '#8fbe00'], ['#351330', '#424254', '#64908a', '#e8caa4', '#cc2a41'], ['#554236', '#f77825', '#d3ce3d', '#f1efa5', '#60b99a'], ['#5d4157', '#838689', '#a8caba', '#cad7b2', '#ebe3aa'], ['#8c2318', '#5e8c6a', '#88a65e', '#bfb35a', '#f2c45a'], ['#fad089', '#ff9c5b', '#f5634a', '#ed303c', '#3b8183'], ['#ff4242', '#f4fad2', '#d4ee5e', '#e1edb9', '#f0f2eb'], ['#f8b195', '#f67280', '#c06c84', '#6c5b7b', '#355c7d'], ['#d1e751', '#ffffff', '#000000', '#4dbce9', '#26ade4'], ['#1b676b', '#519548', '#88c425', '#bef202', '#eafde6'], ['#5e412f', '#fcebb6', '#78c0a8', '#f07818', '#f0a830'], ['#bcbdac', '#cfbe27', '#f27435', '#f02475', '#3b2d38'], ['#452632', '#91204d', '#e4844a', '#e8bf56', '#e2f7ce'], ['#eee6ab', '#c5bc8e', '#696758', '#45484b', '#36393b'], ['#f0d8a8', '#3d1c00', '#86b8b1', '#f2d694', '#fa2a00'], ['#2a044a', '#0b2e59', '#0d6759', '#7ab317', '#a0c55f'], ['#f04155', '#ff823a', '#f2f26f', '#fff7bd', '#95cfb7'], ['#b9d7d9', '#668284', '#2a2829', '#493736', '#7b3b3b'], ['#bbbb88', '#ccc68d', '#eedd99', '#eec290', '#eeaa88'], ['#b3cc57', '#ecf081', '#ffbe40', '#ef746f', '#ab3e5b'], ['#a3a948', '#edb92e', '#f85931', '#ce1836', '#009989'], ['#300030', '#480048', '#601848', '#c04848', '#f07241'], ['#67917a', '#170409', '#b8af03', '#ccbf82', '#e33258'], ['#aab3ab', '#c4cbb7', '#ebefc9', '#eee0b7', '#e8caaf'], ['#e8d5b7', '#0e2430', '#fc3a51', '#f5b349', '#e8d5b9'], ['#ab526b', '#bca297', '#c5ceae', '#f0e2a4', '#f4ebc3'], ['#607848', '#789048', '#c0d860', '#f0f0d8', '#604848'], ['#b6d8c0', '#c8d9bf', '#dadabd', '#ecdbbc', '#fedcba'], ['#a8e6ce', '#dcedc2', '#ffd3b5', '#ffaaa6', '#ff8c94'], ['#3e4147', '#fffedf', '#dfba69', '#5a2e2e', '#2a2c31'], ['#fc354c', '#29221f', '#13747d', '#0abfbc', '#fcf7c5'], ['#cc0c39', '#e6781e', '#c8cf02', '#f8fcc1', '#1693a7'], ['#1c2130', '#028f76', '#b3e099', '#ffeaad', '#d14334'], ['#a7c5bd', '#e5ddcb', '#eb7b59', '#cf4647', '#524656'], ['#dad6ca', '#1bb0ce', '#4f8699', '#6a5e72', '#563444'], ['#5c323e', '#a82743', '#e15e32', '#c0d23e', '#e5f04c'], ['#edebe6', '#d6e1c7', '#94c7b6', '#403b33', '#d3643b'], ['#fdf1cc', '#c6d6b8', '#987f69', '#e3ad40', '#fcd036'], ['#230f2b', '#f21d41', '#ebebbc', '#bce3c5', '#82b3ae'], ['#b9d3b0', '#81bda4', '#b28774', '#f88f79', '#f6aa93'], ['#3a111c', '#574951', '#83988e', '#bcdea5', '#e6f9bc'], ['#5e3929', '#cd8c52', '#b7d1a3', '#dee8be', '#fcf7d3'], ['#1c0113', '#6b0103', '#a30006', '#c21a01', '#f03c02'], ['#000000', '#9f111b', '#b11623', '#292c37', '#cccccc'], ['#382f32', '#ffeaf2', '#fcd9e5', '#fbc5d8', '#f1396d'], ['#e3dfba', '#c8d6bf', '#93ccc6', '#6cbdb5', '#1a1f1e'], ['#f6f6f6', '#e8e8e8', '#333333', '#990100', '#b90504'], ['#1b325f', '#9cc4e4', '#e9f2f9', '#3a89c9', '#f26c4f'], ['#a1dbb2', '#fee5ad', '#faca66', '#f7a541', '#f45d4c'], ['#c1b398', '#605951', '#fbeec2', '#61a6ab', '#accec0'], ['#5e9fa3', '#dcd1b4', '#fab87f', '#f87e7b', '#b05574'], ['#951f2b', '#f5f4d7', '#e0dfb1', '#a5a36c', '#535233'], ['#8dccad', '#988864', '#fea
const vertexShader = `
uniform float uTime;
attribute vec3 color;
attribute float size;
attribute float velocity;
varying vec4 vColor;
void main(){
vColor = vec4(color, 1.0);
vec3 p = vec3(position);
p.z = -150. + mod(position.z + uTime, 300.);
vec4 mvPosition = modelViewMatrix * vec4( p, 1.0 );
gl_PointSize = size * (-50.0 / mvPosition.z);
gl_Position = projectionMatrix * mvPosition;
}
`
const fragmentShader = `
uniform sampler2D uTexture;
varying vec4 vColor;
void main() {
gl_FragColor = vColor * texture2D(uTexture, gl_PointCoord);
}
`
const { randFloat: rnd, randInt, randFloatSpread: rndFS } = MathUtils
export default defineComponent({
components: { BufferGeometry, Camera, EffectComposer, Points, Renderer, RenderPass, Scene, ShaderMaterial, Texture, UnrealBloomPass, ZoomBlurPass },
props: {
targetTimeCoef: {
type: Number,
default: 1
}
},
setup() {
const POINTS_COUNT = 1000
const palette = niceColors[37] // niceColors[2] 27 92 45 99
const positions = new Float32Array(POINTS_COUNT * 3)
const colors = new Float32Array(POINTS_COUNT * 3)
const sizes = new Float32Array(POINTS_COUNT)
const v3 = new Vector3(), color = new Color()
for (let i = 0; i < POINTS_COUNT; i++) {
v3.set(rndFS(200), rndFS(200), rndFS(300))
v3.toArray(positions, i * 3)
color.set(palette[Math.floor(rnd(0, palette.length))])
color.toArray(colors, i * 3)
sizes[i] = rnd(5, 20)
}
const attributes = [
{ name: 'position', array: positions, itemSize: 3 },
{ name: 'color', array: colors, itemSize: 3 },
{ name: 'size', array: sizes, itemSize: 1 },
]
const uniforms = { uTime: { value: 0 } }
const clock = new Clock()
const timeCoef = 1
return {
POINTS_COUNT,
attributes, uniforms, vertexShader, fragmentShader,
clock, timeCoef,
}
},
data() {
return {
zoomStrength: 0,
}
},
mounted() {
const renderer = this.$refs.renderer as any
const points = (this.$refs.points as any).points
window.addEventListener('mousemove', (e) => {
const { x, y } = e
const midX = window.innerWidth / 2
const siteX = Math.abs(x - midX)
const midY = window.innerHeight / 2
const siteY = Math.abs(y - midY)
const da = 0.05
const tiltX = lerp(points.rotation.x, (Math.abs((siteY / midY) - 1)) * da, 0.02)
const tiltY = lerp(points.rotation.y, -(Math.abs((siteX / midX) - 1)) * da, 0.02)
points.rotation.set(tiltX, tiltY, 0)
})
window.addEventListener('click',()=>{
this.updateColors()
})
renderer.onBeforeRender(() => {
this.timeCoef = lerp(this.timeCoef, this.targetTimeCoef, 0.02)
this.uniforms.uTime.value += this.clock.getDelta() * this.timeCoef * 4
this.zoomStrength = this.timeCoef * 0.004
// console.log(positionN)
// const da = 0.05
// const tiltX = lerp(points.rotation.x, positionN.y * da, 0.02)
// const tiltY = lerp(points.rotation.y, -positionN.x * da, 0.02)
// points.rotation.set(tiltX, tiltY, 0)
})
},
methods: {
updateColors() {
const colorAttribute = (this.$refs.points as any).geometry.attributes.color
const ip = randInt(0, 99)
console.log(ip)
const palette = niceColors[ip]
const color = new Color()
for (let i = 0; i < this.POINTS_COUNT; i++) {
color.set(palette[randInt(0, palette.length)])
color.toArray(colorAttribute.array, i * 3)
}
colorAttribute.needsUpdate = true
},
},
render() {
return (
<>
<Renderer ref="renderer" resize="window" alpha={true}>
<div class="absolute top-0 left-0">
{(this.$slots.default?.())}
</div>
<Camera position={{ z: 0 }} fov={50} />
<Scene >
<Points ref="points" position={{ z: -150 }}>
<BufferGeometry attributes={this.attributes} />
<ShaderMaterial
blending={2} depth-test={false} uniforms={this.uniforms} vertex-shader={vertexShader}
fragment-shader={fragmentShader}
>
<Texture src="https://assets.codepen.io/33787/sprite.png" uniform="uTexture" />
</ShaderMaterial>
</Points>
</Scene>
<EffectComposer>
<RenderPass />
<UnrealBloomPass strength={2} radius={0} threshold={0} />
<ZoomBlurPass strength={this.zoomStrength} />
</EffectComposer>
</Renderer>
{/* <a ref="test" href="#" onClick={this.updateColors} onMouseenter={() => this.targetTimeCoef = 100} onMouseleave={() => this.targetTimeCoef = 1}>Random
Colors</a > */}
</>
)
},
})