Hello, thank you very much for your tip. I have already seen and tried this solution. But unfortunately it doesn’t work, regardless if the scene is in the viewport or not, it is rendered all the time, although with the IntersectionObserver the different divs are recognized…
I investigated further and here are the results based on the resolution that is displayed. The performance problems occur at HD or higher because the scene has to render much more. Is there a culprit here in my code?
import * as THREE from "three"
import { useRef } from "react"
import { Canvas, useFrame } from "@react-three/fiber"
import { EffectComposer, SSAO } from "@react-three/postprocessing"
import { BallCollider, Physics, RigidBody, CylinderCollider } from "@react-three/rapier"
THREE.ColorManagement.legacyMode = false
const baubleMaterial = new THREE.MeshPhysicalMaterial({
roughness: 0.65,
// color: "#000000",
// emissive: "#ffffff",
// transmission: 0.5, // Add transparency
// thickness: 1.0, // Add refraction!
});
const sphereGeometry = new THREE.IcosahedronGeometry(1, 0)
const baubles = [...Array(40)].map(() => ({ scale: [0.75, 0.75, 1, 1, 1.25][Math.floor(Math.random() * 5)] }))
function Bauble({ vec = new THREE.Vector3(), scale, r = THREE.MathUtils.randFloatSpread }) {
const api = useRef()
useFrame((state, delta) => {
delta = Math.min(0.1, delta)
api.current.applyImpulse(
vec
.copy(api.current.translation())
.normalize()
.multiply({ x: -20 * delta * scale, y: -100 * delta * scale, z: -50 * delta * scale }),
)
})
return (
<RigidBody linearDamping={0.75} angularDamping={0.9} friction={0.2} position={[r(20), r(20) - 25, r(20) - 10]} ref={api} colliders={false} dispose={null}>
<BallCollider args={[scale]} />
<CylinderCollider rotation={[Math.PI / 2, 0, 0]} position={[0, 0, 1.2 * scale]} args={[0.15 * scale, 0.275 * scale]} />
<mesh castShadow receiveShadow scale={scale} geometry={sphereGeometry} material={baubleMaterial} />
</RigidBody>
)
}
function Pointer({ vec = new THREE.Vector3() }) {
const ref = useRef()
useFrame(({ mouse, viewport }) => {
vec.lerp({ x: (mouse.x * viewport.width) / 2, y: (mouse.y * viewport.height) / 2, z: 0 }, 0.2)
ref.current.setNextKinematicTranslation(vec)
})
return (
<RigidBody position={[100, 100, 100]} type="kinematicPosition" colliders={false} ref={ref}>
<BallCollider args={[2]} />
</RigidBody>
)
}
const animate = () =>{
if(isInView){
render()
}
window.requestAnimationFrame(animate)
}
const render = () =>{
renderer.render(scene,camera)
}
export const App = () => (
<Canvas
shadows
gl={{ alpha: true, stencil: false, depth: false, antialias: false }}
camera={{ position: [0, 0, 20], fov: 32.5, near: 1, far: 100 }}
onCreated={(state) => (state.gl.toneMappingExposure = 1.5)}>
<ambientLight intensity={0.5} />
<spotLight position={[20, 20, 25]} penumbra={1} angle={0.2} color="white" castShadow shadow-mapSize={[512, 512]} />
<directionalLight position={[0, 5, -4]} intensity={4} />
<directionalLight position={[0, -15, -0]} intensity={4} color="#000000" />
<Physics gravity={[0, 0, 0]}>
<Pointer />
{baubles.map((props, i) => <Bauble key={i} {...props} />) /* prettier-ignore */}
</Physics>
<EffectComposer multisampling={0}>
<SSAO samples={11} radius={0.15} intensity={20} luminanceInfluence={0.6} color="#000000" />
<SSAO samples={21} radius={0.03} intensity={15} luminanceInfluence={0.6} color="#000000" />
</EffectComposer>
</Canvas>
)