Reputation: 39
I've been trying to convert three.js written in vanilla JS to React Three fiber.
import * as THREE from 'three';
let scene, camera, renderer;
//Canvas
const canvas = document.querySelector('canvas')
//Number of line particles
let lineCount = 6000;
//adding buffer Geometry
let geom = new THREE.BufferGeometry();
//Giving the Buffer Geometry attributes
geom.setAttribute('position', new THREE.BufferAttribute(new Float32Array(6 * lineCount), 3));
geom.setAttribute('velocity', new THREE.BufferAttribute(new Float32Array(2 * lineCount), 1));
//creating array variable for the position
let pos = geom.getAttribute('position');
let posArray = pos.array;
//creating array variable for the velocity
let vel = geom.getAttribute('velocity');
let velArray = vel.array;
//function to initiate
const init = () => {
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, window.innerWidth/window.innerHeight, 1, 500);
camera.position.z = 200;
renderer = new THREE.WebGLRenderer({antialias: true, canvas: canvas});
renderer.setSize(window.innerWidth, window.innerHeight);
for (let lineIndex = 0; lineIndex < lineCount; lineIndex++){
let x = Math.random() * 400 - 200;
let y = Math.random() * 200 - 100;
let z = Math.random() * 500 - 100;
let xx = x;
let yy = y;
let zz = z;
//line starting position
posArray[6 * lineIndex] = x;
posArray[6 * lineIndex + 1] = y;
posArray[6 * lineIndex + 2] = z;
//line ending position
posArray[6 * lineIndex + 3] = xx;
posArray[6 * lineIndex + 4] = yy;
posArray[6 * lineIndex + 5] = zz;
velArray[2 * lineIndex] = velArray[2 * lineIndex + 1] = 0;
}
let lineMat = new THREE.LineBasicMaterial({color: '#ffffff'});
let lines = new THREE.LineSegments(geom, lineMat);
scene.add(lines);
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth/ window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}, false);
animate();
}
const animate = () => {
for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) {
velArray[2 * lineIndex] += 0.03;
velArray[2 * lineIndex + 1] += 0.025;
posArray[6 * lineIndex + 2] += velArray[2 * lineIndex];
posArray[6 * lineIndex + 5] += velArray[2 * lineIndex + 1];
if (posArray[6 * lineIndex + 5] > 200) {
let z = Math.random() * 200 - 100;
posArray[6 * lineIndex + 2] = z;
posArray[6 * lineIndex + 5] = z;
velArray[2 * lineIndex] = 0;
velArray[2 * lineIndex + 1] = 0;
}
}
pos.needsUpdate = true;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
init();
I'm having difficulty in converting the init
and animate
functions.
This is what I have so far, I've added the positions and velocity as bufferAttributes and specified the starting and ending coordinates in the for loop:
const StarLine = () => {
const warpFieldMesh = useRef();
const bufAtPos = useRef();
const bufAtVel = useRef();
const count = 100;
const [positions, velocity] = useMemo(() => {
let positions = []
let velocity = []
for (let lineIndex = 0; lineIndex < count; lineIndex++){
let x = Math.random() * 400 - 200;
let y = Math.random() * 200 - 100;
let z = Math.random() * 500 - 100;
let xx = x;
let yy = y;
let zz = z;
//line starting position
positions[6 * lineIndex] = x;
positions[6 * lineIndex + 1] = y;
positions[6 * lineIndex + 2] = z;
//line ending position
positions[6 * lineIndex + 3] = xx;
positions[6 * lineIndex + 4] = yy;
positions[6 * lineIndex + 5] = zz;
velocity[2 * lineIndex] = velocity[2 * lineIndex + 1] = 0;
}
return [new Float32Array(positions), new Float32Array(velocity)]
}, [])
useFrame(() => {
})
return (
<line ref={warpFieldMesh}>
<bufferGeometry attach="geometry">
<bufferAttribute
ref={bufAtPos}
attachObject={["attributes", "position"]}
count={positions.length / 3}
array={positions}
itemSize={3}
/>
<bufferAttribute
ref={bufAtVel}
attachObject={["attributes", "velocity"]}
count={velocity.length / 2}
array={velocity}
itemSize={1}
/>
</bufferGeometry>
<lineBasicMaterial
attach="material"
color={'#ffffff'}
/>
</line>
)
}
The vanilla JavaScript produces:
Upvotes: 0
Views: 1032
Reputation: 186
I fixed this 😊, and it's working perfectly now -
import React, { useRef, useEffect } from 'react';
import * as THREE from 'three';
const ThreeSTAR = () => {
const warpFieldMesh = useRef();
const lineCount = 1000;
useEffect(() => {
let scene, camera, renderer;
const canvas = warpFieldMesh.current;
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.z = 200;
renderer = new THREE.WebGLRenderer({ antialias: true, canvas });
renderer.setSize(window.innerWidth, window.innerHeight);
const geom = new THREE.BufferGeometry();
geom.setAttribute('position', new THREE.BufferAttribute(new Float32Array(6 * lineCount), 3));
geom.setAttribute('velocity', new THREE.BufferAttribute(new Float32Array(2 * lineCount), 1));
const pos = geom.getAttribute('position');
const posArray = pos.array;
const vel = geom.getAttribute('velocity');
const velArray = vel.array;
for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) {
let x = Math.random() * 400 - 200;
let y = Math.random() * 200 - 100;
let z = Math.random() * 500 - 100;
let xx = x;
let yy = y;
let zz = z;
posArray[6 * lineIndex] = x;
posArray[6 * lineIndex + 1] = y;
posArray[6 * lineIndex + 2] = z;
posArray[6 * lineIndex + 3] = xx;
posArray[6 * lineIndex + 4] = yy;
posArray[6 * lineIndex + 5] = zz;
velArray[2 * lineIndex] = velArray[2 * lineIndex + 1] = 0;
}
const lineMat = new THREE.LineBasicMaterial({ color: '#ffffff' });
const lines = new THREE.LineSegments(geom, lineMat);
scene.add(lines);
const resizeHandler = () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
window.addEventListener('resize', resizeHandler, false);
const animate = () => {
for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) {
velArray[2 * lineIndex] += 0.03;
velArray[2 * lineIndex + 1] += 0.025;
posArray[6 * lineIndex + 2] += velArray[2 * lineIndex];
posArray[6 * lineIndex + 5] += velArray[2 * lineIndex + 1];
if (posArray[6 * lineIndex + 5] > 200) {
let z = Math.random() * 200 - 100;
posArray[6 * lineIndex + 2] = z;
posArray[6 * lineIndex + 5] = z;
velArray[2 * lineIndex] = 0;
velArray[2 * lineIndex + 1] = 0;
}
}
pos.needsUpdate = true;
renderer.render(scene, camera);
requestAnimationFrame(animate);
};
animate();
return () => {
window.removeEventListener('resize', resizeHandler);
};
}, []);
useEffect(() => {
document.body.style.overflow = 'hidden';
return () => {
document.body.style.overflow = 'visible';
};
}, []);
return <canvas ref={warpFieldMesh} />;
};
export default ThreeSTAR;
make sure you warp this using div not canvas in app.jsx
import React from 'react';
import './App.css';
import ThreeSTAR from './components/threeSTAR';
function App() {
return (
<div>
<ThreeSTAR />
</div>
);
}
export default App;
Upvotes: 1
Reputation: 427
The stuff in your animate function can go in the useFrame hook, its a r3f hook that is called every frame
Upvotes: 2