0

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:

enter image description here

2 Answers 2

2

The stuff in your animate function can go in the useFrame hook, its a r3f hook that is called every frame

Sign up to request clarification or add additional context in comments.

Comments

1

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;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.