"Three.js rendering issue: Particle sphere appearing as a straight line instead of a sphere

Exploring the world of THREE.js library has led me to attempt creating a particle sphere within my React App. Drawing inspiration from this project, I've made some progress but seem to have hit a roadblock.

Strangely, despite similarities in code - except for updating deprecated methods - whenever I try to render with THREE, an odd straight line appears every time.

Even after spending hours poring over the documentation and trying to understand each method of this component, confusion still reigns supreme.

This is what I currently have (for a live experience click here):

let camera;
let renderer;
let scene;
const vector3D = new THREE.Vector3();

// Fetch canvas constraints.
const getConstraints = () => {
  const canvas = document.getElementById("canvas");
  const { width, height } = canvas.getBoundingClientRect();
  // Determine canvas width and height - defaulting to computed constraints.
  return [canvas.width ?? width, canvas.height ?? height];
};
// Retrieve random point within sphere for particle placement.
const getRandomPointInSphere = radius => {
  const x = THREE.MathUtils.randFloat(-1, 1);
  const y = THREE.MathUtils.randFloat(-1, 1);
  const z = THREE.MathUtils.randFloat(-1, 1);

  const normaliseRatio = 1 / Math.sqrt(x * x + y * y + z * z);

  vector3D.x = x * normaliseRatio * radius;
  vector3D.y = y * normaliseRatio * radius;
  vector3D.z = z * normaliseRatio * radius;

  return vector3D;
};

// Initialize methods.
const initScene = () => {
  const [canvasWidth, canvasHeight] = getConstraints();
  // Renderer setup.
  renderer = new THREE.WebGLRenderer({
    canvas: document.getElementById("canvas"),
    antialias: true, alpha: true,
  });
  renderer.setSize(canvasWidth, canvasHeight);
  renderer.setPixelRatio(window.devicePixelRatio);

  // Scene setup.
  scene = new THREE.Scene();

  // Camera setup.
  camera = new THREE.PerspectiveCamera(45, canvasWidth, canvasHeight, 1, 1000);
  camera.position.set(100, 0, 100);
};
const initPoints = () => {
  const geometry = new THREE.BufferGeometry();
  const positions = [];

  const particleSize = 0.2;
  const particleColor = 0x1826e0; // Dark blue 
  const particleCount = 50000 / (particleSize * 10);

  for(let i = 0; i < particleCount; i++){
    let vertex = getRandomPointInSphere(50);
    positions.push(vertex.x, vertex.y, vertex.z);
  }

  geometry.setAttribute("position", new THREE.Float32BufferAttribute(positions, 3));

  const material = new THREE.PointsMaterial({ size: particleSize, color: particleColor });
  const particles = new THREE.Points(geometry, material);
  scene.add(particles);
};

initScene();
initPoints();
renderer.render(scene, camera);

Being fairly new to THREE (and canvases overall), any assistance is greatly welcomed.

Answer №1

To start off, the camera instantiation line should be corrected to:

camera = new THREE.PerspectiveCamera(45, canvasWidth / canvasHeight, 1, 1000);
, using a slash instead of a comma.

Next, ensure that the camera is looking at the center of the scene by adding camera.lookAt(scene.position);

Below is the snippet with the fixed code:

https://i.sstatic.net/b3Z5a.png

body{
  overflow: hidden;
  margin: 0;
}

canvas{
  border: 1px solid red;
}
<canvas id="canvas" width="400" height="400" />
<script type="module">
import * as THREE from "https://cdn.skypack.dev/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="dbafb3a9bebe9bebf5eae8edf5eb">[email protected]</a>";
// THREE variables
let camera;
let renderer;
let scene;
let v3 = new THREE.Vector3();
// Get constraints of the canvas.
const getConstraints = () => {
  const canvas = document.getElementById("canvas");
  const { width, height } = canvas.getBoundingClientRect();
  // Get attribute-set width and height - defaulting to computed constraints.
  return [canvas.width ?? width, canvas.height ?? height];
};
// Retrieve a random point in the sphere for a particle to be set at.

const getRandomPointInSphere = radius => {
  v3.randomDirection();

  const normaliseRatio = 1 / Math.hypot(v3.x, v3.y, v3.z);

  v3.setLength(radius * normaliseRatio);

  return v3;
};

// Initialisation methods.
const initScene = () => {
  const [canvasWidth, canvasHeight] = getConstraints();
  // Renderer initialisation.
  renderer = new THREE.WebGLRenderer({
    canvas: document.getElementById("canvas"),
    antialias: true,
    alpha: true,
  });
  renderer.setSize(canvasWidth, canvasHeight);
  renderer.setPixelRatio(window.devicePixelRatio);

  // Scene initialisation.
  scene = new THREE.Scene();

  // Camera initialisation.
  camera = new THREE.PerspectiveCamera(45, canvasWidth / canvasHeight, 1, 1000);
  camera.position.set(100, 0, 100);
  camera.lookAt(scene.position);
};
const initPoints = () => {
  const geometry = new THREE.BufferGeometry();
  const positions = [];

  const particleSize = 0.2;
  const particleColor = 0x1826e0; // Dark blue 
  const particleCount = 50000 / (particleSize * 10);

  for(let i = 0; i < particleCount; i++){
    let vertex = getRandomPointInSphere(50);
    positions.push(vertex.x, vertex.y, vertex.z);
  }

  geometry.setAttribute("position", new THREE.Float32BufferAttribute(positions, 3));

  const material = new THREE.PointsMaterial({ size: particleSize, color: particleColor });
  const particles = new THREE.Points(geometry, material);
  scene.add(particles);
};

initScene();
initPoints();
renderer.render(scene, camera);
</script>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

In Visual Studio, the .js.map files and .js files seem to be mysteriously hidden, leaving only the TypeScript .ts files visible

In the past, I utilized Visual Studio Code for Angular 2 development and had the ability to hide .js and .js.map files from the IDE. Now, I am working on a project using VS 2017 Professional with Typescript, Jasmine, Karma, and Angular 4. Task Runner, etc. ...

Angular unable to register service worker

Looking to implement push notifications in my Angular app using vanilla JavaScript instead of the Angular service worker or @angular/pwa. In angular.json, I've specified the path to the js file under the script option. However, when the service worke ...

How would the input value change if the clock time changed?

I am working with dynamic inputs that allow me to add and delete rows with inputs. These inputs include material-ui timepickers, which have an icon of a clock next to the input field. When I click on the clock icon, a clock widget appears. However, the val ...

Can JSON.parse be used on only a portion of an object in JavaScript?

Currently, I am facing an issue with a lengthy JSON file that I am fetching from a URL using https.request. Upon attempting to parse the string with JSON.parse, I encounter an "Unexpected end of JSON input" error. It appears that there is a limit to the ...

Tips for reducing the amount of repetitive code in your reducers when working with redux and a plain old JavaScript object (

When it comes to writing reducers for Redux, I often encounter challenges. My struggle usually lies in wrapping a lot of my state manipulation in functions like .map and .slice. As the structure of my state object becomes more complex, the reducers become ...

Why is it displaying undefined even though there is data stored in Firebase?

I am experiencing an issue where the datatable row is displaying "undefined" instead of the data from my Firebase database. Even when I tried inserting random data into the HTML file for the datatable, it still shows undefined. Here is a link to My Datata ...

Steps to include all dependencies in an angular application

Managing a large Angular application can be challenging. I currently use npm install to install all packages and manually load them in my index.html file, like this: <script src="node_modules/angular/angular.js"></script> Similarly, I load ot ...

What is the method to determine if a date is larger or smaller than another using Javascript?

Using the inputText function retrieves the value entered in the textbox, while the hidden field value returns the current value. This is my current code snippet: if (inputText.value.length != 0) { if (inputText.value < document.getElementById(&apo ...

How come the pop-up isn't displaying in the middle of the screen?

I have encountered a positioning issue while using a semantic modal with Angular. The problem arises when I try to display the modal as it does not appear in the correct position. https://i.sstatic.net/o033E.png Below is the code snippet from my HTML fil ...

Retrieving information from a nested array transferred to Javascipt / Jquery through JSON from PHP / Cakephp

Apologies for the basic question, but after hours of research, the examples I've found don't seem to fit the context of my array. I've successfully passed data from my CakePHP server to my jQuery JavaScript, but I'm struggling to make s ...

What is the reason for the lack of an applied CSS selector?

.colored p{ color: red; } article > .colored{ color:powderblue; } .blue{ color: white; } <!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8> <meta name="viewport" content="width=device-width, initi ...

jQuery is implemented prior to the completion of HTML loading

Is there a way to ensure that HTML content loads before executing a JavaScript function? $(document).ready(function() { var x = 10; if(x == 10) { $('h1').text("Its changed !"); alert("Test"); } }) <h1>Hello< ...

What is the best way to organize large amounts of data into an array?

I am currently working on developing a unique version of wordle using javascript and html. In order to do this, I require a comprehensive list of all possible wordle words stored in an array format. Although I have the words listed within a document contai ...

Is there a constraint on JSON data?

Is there a limit to the amount of data that JSON with AJAX can handle in outgoing and returning parameters? I am trying to send and receive a file with 10,000 lines as a string from the server. How can I accomplish this task? Can a single parameter manage ...

Modify the appearance of a card upon radio button selection

Can someone help me figure out how to change the background color of my card element when a radio button is selected? <div class="col-6 col-md-3 mt-4 text-center my-auto"> <label for="'.$abreviation.'"> ...

Tips for preventing HTML ID clashes while integrating with the Document Object Model of external websites

When incorporating additional HTML elements into a webpage using Javascript or jQuery, along with external CSS declarations, it is important to avoid conflicts with existing IDs and class names already present on the page. This could lead to issues if ther ...

Creating a dynamic dropdown menu to display nested arrays in Vuejs

I have some important data https://i.sstatic.net/Cq2t6.png Challenge I'm facing difficulty in accessing the tubes array within my data Solution script data() { return { types: [] } }, m ...

What could be causing the lack of updates for a watched object in vue?

Although there are many similar questions on this topic, mine has a unique twist. After delving into reactivity in depth, I feel like I have a solid grasp of the concept. However, one thing continues to baffle me: Summary: Why does a watched property det ...

What steps should I follow to incorporate channel logic into my WebSocket application, including setting up event bindings?

I'm currently tackling a major obstacle: my very own WebSocket server. The authentication and basic functionality are up and running smoothly, but I'm facing some challenges with the actual logic implementation. To address this, I've create ...

What is the best way to determine which watchers are triggered in Vue.js?

Within my parent component, there are numerous nested child components. Whenever a click occurs on one of the child components, it triggers an update to the route. The parent component watches the route property and performs certain actions when it change ...