It is an experiment.. this geometry has this strange behavior where if i update only one attribute it looks correct: the shape 'bubbles' or the surface changes color with noise .. but when both color and position are updated it doesn't appear as it should: one of them seems to fail...
import { useFrame } from '@react-three/fiber'
import React, { useRef, useEffect } from 'react'
import { createNoise3D, createNoise4D } from 'simplex-noise'
import alea from 'alea';
import * as THREE from 'three'
function Background(props) {
const refPlane = useRef()
const refSphere = useRef()
const prng = alea('seed')
const noise3D = createNoise3D(prng)
const noise4D = createNoise4D(prng)
let posPlane, posSphere;
let newColorPlane = new Float32Array(12)
let newColorSphere = new Float32Array(12675)
let newPosSphere = new Float32Array(12675)
let attrColorSphere = new THREE.BufferAttribute(newColorSphere, 3)
let attrColorPlane = new THREE.BufferAttribute(newColorPlane, 3)
let attrPosSphere = new THREE.BufferAttribute(newColorSphere, 3)
function mapRange(value, a, b, c, d) {
value = (value - a) / (b - a);
return c + value * (d - c);
}
useEffect(() => {
posPlane = refPlane.current.geometry.getAttribute('position')
posSphere = refSphere.current.geometry.getAttribute('position')
}, []);
function updatePosPlane(positionPlane, time) {
for (let i = 0; i < (positionPlane.count * 3); i += 3) {
const x = positionPlane.array[i];
const y = positionPlane.array[i + 1];
const noise = (noise3D(x, y, time / 2));
const hue = mapRange(noise, -1, 1, 0, 1);
const color = new THREE.Color();
color.setHSL(hue, 0.9, 0.25);
newColorPlane[i] = color.r;
newColorPlane[i + 1] = color.g;
newColorPlane[i + 2] = color.b;
}
return newColorPlane
}
function updateColorSphere(positionSphere, time) {
for (let i = 0; i < (positionSphere.count * 3); i += 3) {
const x = positionSphere.array[i];
const y = positionSphere.array[i + 1];
const z = positionSphere.array[i + 2];
const noise = (noise4D(x / 5, y / 5, z / 5, time / 10));
const hue = mapRange(noise, -1, 1, 0, 1);
const color = new THREE.Color();
color.setHSL(hue, 0.9, 0.25);
newColorSphere[i] = color.r;
newColorSphere[i + 1] = color.g;
newColorSphere[i + 2] = color.b;
}
return newColorSphere
}
function updatePosSphere(positionCurve, time) {
for (let i = 0; i < (positionCurve.count * 3); i += 3) {
const x = positionCurve.array[i];
const y = positionCurve.array[i + 1];
const z = positionCurve.array[i + 2];
const noise = (noise4D(x / 5, y / 5, z / 5, time));
const vec = new THREE.Vector3(x, y, z);
const newVec = vec.addScaledVector(vec, noise / 2);
newPosSphere[i] = newVec.getComponent(0);
newPosSphere[i + 1] = newVec.getComponent(1);
newPosSphere[i + 2] = newVec.getComponent(2);
}
return newPosSphere;
}
useFrame(({ clock }) => {
const a = clock.getElapsedTime()
refPlane.current.geometry.setAttribute('color', attrColorPlane.set(updatePosPlane(posPlane, a)))
refPlane.current.geometry.attributes.color.needsUpdate = true
refSphere.current.geometry.setAttribute('position', attrPosSphere.set(updatePosSphere(posSphere, a)))
refSphere.current.geometry.setAttribute('color', attrColorSphere.set(updateColorSphere(posSphere, a)))
refSphere.current.geometry.attributes.position.needsUpdate = true
refSphere.current.geometry.attributes.color.needsUpdate = true
refSphere.current.rotation.y = a
})
return (
<>
<mesh
{...props}
ref={refPlane}
position={[0, 0, 0]}
scale={[20, 20, 0]}>
<planeGeometry />
<meshBasicMaterial color='white' vertexColors needsUpdate />
</mesh>
<mesh
{...props}
ref={refSphere}
position={[0, 0, 0]}>
<sphereGeometry args={[2, 64, 64]} />
<meshBasicMaterial vertexColors needsUpdate />
</mesh>
</>
)
}
export default Background
I have tried various things and searched here for various possible solutions but I'm new to React and Three.js and I'm probably doing something wrong. Any suggestion is welcome!