Create an unshaded circle using Three.js

I need assistance in creating a circular design that resembles the orbital patterns displayed on this website. My preference is to implement this using Three.js rather than pure WebGL.

Answer №1

CircleGeometry was introduced in Three.js r50. You can see it (although with a face) in the WebGL Geometries example.

The first vertex of the circle geometry is placed at the center of the circle. In r84, refer to CircleGeometry.js line 71, and in r65, check out CircleGeometry.js line 18. This feature is useful for achieving a "full Pac-Man" or "uninformative pie chart" appearance and is required if you plan to use materials other than LineBasicMaterial / LineDashedMaterial.

I have tested the provided code on both r60 & r65:

var radius   = 100,
    segments = 64,
    material = new THREE.LineBasicMaterial( { color: 0x0000ff } ),
    geometry = new THREE.CircleGeometry( radius, segments );

// Removing the center vertex
geometry.vertices.shift();

// Creating a non-closed circle with an open segment:
scene.add( new THREE.Line( geometry, material ) );

// For a closed circle, use LineLoop instead (refer to @jackrugile's comment as well):
scene.add( new THREE.LineLoop( geometry, material ) );

PS: The documentation now features an interactive example of CircleGeometry:

Answer №2

In the latest versions of threejs, there have been some changes to the API.

var segmentCount = 32,
    radius = 100,
    geometry = new THREE.Geometry(),
    material = new THREE.LineBasicMaterial({ color: 0xFFFFFF });

for (var i = 0; i <= segmentCount; i++) {
    var theta = (i / segmentCount) * Math.PI * 2;
    geometry.vertices.push(
        new THREE.Vector3(
            Math.cos(theta) * radius,
            Math.sin(theta) * radius,
            0));            
}

scene.add(new THREE.Line(geometry, material));

To adjust the smoothness or jaggedness of the circle in your scene, you can modify the segmentCount. A higher count will result in a smoother circle. For larger orbits like the ones on the site you provided, consider using a few hundred segments.

You can also change the order of the components within the Vector3 constructor to alter the orientation of the circle. In this code snippet, the circle is aligned with the x/y plane by default.

Answer №3

I found a funny solution to this problem:

function createCircle() {
    let circleGeometry = new THREE.CircleGeometry(1.0, 30.0);
    circleGeometry.vertices.splice(0, 1); //<= This.
    return new THREE.LineLoop(circleGeometry,
        new THREE.LineBasicMaterial({ color: 'blue' }));
}
let circle = createCircle();

Motivation: In order to achieve a perfectly round circle without any lines coming from the center, you need to remove the first vertex from the array. It's a bit of a hack, but it gets the job done. :)

(According to mrienstra's answer, this step is necessary when using materials other than LineBasicMaterial / LineDashedMaterial.)


If you want to control the thickness of the line, unfortunately, there are limitations with OpenGL Core Profile on most platforms. The linewidth will always be 1 regardless of the set value. However, there is a workaround using: https://github.com/spite/THREE.MeshLine

You can find a code example for this solution here:

Answer №4

I implemented code that was inspired by Mr.doob's technique mentioned in this specific GitHub post.

const numPoints = 120;
const magnitude = 50;
const angleIncrement = 360 / numPoints;

const geometry = new THREE.Geometry();
const material = new THREE.LineBasicMaterial({ color: 0xFFFFFF, opacity: 1.0 });

for (let i = 0; i <= numPoints; i++) {
    const angle = (i * angleIncrement) * Math.PI / 180;
    geometry.vertices.push(new THREE.Vector3(Math.cos(angle) * magnitude, 0, Math.sin(angle) * magnitude));
}

const line = new THREE.Line(geometry, material);
scene.add(line);

Answer №5

This particular code snippet can be found in the official documentation for Three.js:

let material = new THREE.MeshBasicMaterial({
    color: 0x0000ff
});

let radius = 8;
let segments = 64; // Adjust this value to alter the level of detail

let circleGeometry = new THREE.CircleGeometry(radius, segments);              
let circle = new THREE.Mesh(circleGeometry, material);
scene.add(circle);

Answer №6

I encountered some difficulties with the existing solutions in this scenario - particularly, there was an extra vertex at the center of the circle when using CircleGeometry, and I wasn't fond of the workaround to remove that point.

EllipseCurve proved to be more suitable for my needs (confirmed in r135):

const curve = new THREE.EllipseCurve(
  0.0, 0.0,            // Center x, y
  10.0, 10.0,          // x radius, y radius
  0.0, 2.0 * Math.PI,  // Start angle, stop angle
);

const pts = curve.getSpacedPoints(256);
const geo = new THREE.BufferGeometry().setFromPoints(pts);

const mat = new THREE.LineBasicMaterial({ color: 0xFF00FF });
const circle = new THREE.LineLoop(geo, mat);
scene.add(circle);

Answer №7

I'm not sure exactly when it was introduced, but TorusGeometry seems to be a suitable option for the job... https://i.sstatic.net/0eEb9.png Check out THREE TorusGeometry

const geometry = new THREE.TorusGeometry( 10, 3, 16, 100 );
const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
const torus = new THREE.Mesh( geometry, material );
scene.add( torus );

It appears that using TorusGeometry shouldn't be significantly more costly compared to the line approach, and it offers flexibility in adjusting size and material options.

Answer №8

After reviewing Andrew's response, I discovered that the code he provided is no longer supported in THREE.REVISION = "150". This resulted in an error message:

An issue occurred when attempting to read properties of undefined (specifically 'splice')

in relation to the following line of code:

circleGeometry.vertices.splice(0, 1);

To address this issue, please refer to the modified code I have included below for a viable solution:

function createCircle() {
    const circleGeometry = new THREE.CircleGeometry(1.0, 30);

    // Remove central vertex
    const itemSize = 3;
    circleGeometry.setAttribute('position',
        new THREE.BufferAttribute(
            circleGeometry.attributes.position.array.slice(itemSize,
                circleGeometry.attributes.position.array.length - itemSize
            ), itemSize
        )
    );
    circleGeometry.index = null;

    return new THREE.LineLoop(circleGeometry,
        new THREE.LineBasicMaterial({ color: 'blue' }));
}
const circle = createCircle();

Answer №9

If you're curious about drawing colored lines using three.js, check out the example at .

The circle shapes mentioned are actually made up of numerous small straight segments. It's possible that the shapes you referenced might even be ellipses.

Answer №10

function createCircleGeometry() {

var segments = 100, radius = 100;

var lineGeometry = new THREE.Geometry();
var verticesArray = lineGeometry.vertices;
var angle = 2 * Math.PI / segments;
for (var i = 0; i < segments; i++) {
    var xCoord = radius * Math.cos(angle * i);
    var yCoord = radius * Math.sin(angle * i);
    verticesArray.push(new THREE.Vector3(xCoord, yCoord, 0));
}
lineGeometry.computeLineDistances();
var lineMaterial = new THREE.LineDashedMaterial({ color: 0x00cc00, dashSize: 4, gapSize: 2 });
var circleShape = new THREE.Line(lineGeometry, lineMaterial);

circleShape.rotation.x = Math.PI / 2;
circleShape.position.y = cylinderParams.trackHeight + 20;
return circleShape;
}

Answer №11

Instead of creating a 3D shape with a fixed thickness (which can look distorted when zoomed in), you have the option to generate a thin circle that maintains its line quality. This method works well for UI overlays, similar to the example provided by OP.

absarc() and setFromPoints() are particularly handy in this scenario.

//Drawing an orbit at the point 0,0 with designated distance

let points = new THREE.Path().absarc(0, 0, orbitDistance, 0, Math.PI * 2).getPoints(90);
let geometry = new THREE.BufferGeometry().setFromPoints(points);
let material = new THREE.LineBasicMaterial( { color: 0x00ffff, transparent: true, opacity: 0.5 } );
geometry.rotateX( - Math.PI / 2);
let line = new THREE.Line(geometry, material);
    
scene.add(line);

Since it creates a 2D arc, you have the flexibility to move it in 3D space using .position.set(x,y,z), or place it at the 3D origin (0,0,0) like I did here. I adjusted the rotation based on my perspective from the 3D camera angle.

Answer №12

The code provided by mrienstra is no longer supported for THREE.REVISION = "150". An error message is displayed:

An issue with 'shift' function being undefined

occurs at the following line:

geometry.vertices.shift();

Please refer to the corrected code below for a solution:

const radius   = 100,
    segments = 64,
    material = new THREE.LineBasicMaterial( { color: 0x0000ff } ),
    geometry = new THREE.CircleGeometry( radius, segments );
                                            
// Exclude the central vertex
const itemSize = 3;
geometry.setAttribute( 'position',
    new THREE.BufferAttribute(
            geometry.attributes.position.array.slice( itemSize,
                geometry.attributes.position.array.length - itemSize
            ), itemSize
        )
);
geometry.index = null;
                                            
// Rendering an open circle with one segment:
scene.add( new THREE.Line( geometry, material ) );
                                            
// If you want a closed circle, use LineLoop instead (refer to @jackrugile's comment):
scene.add( new THREE.LineLoop( geometry, material ) );

Answer №13

Utilizing the "brute force" methods (such as for, cos, sin) now requires incorporating BufferGeometry instead of Geometry at version R149:
However, I am quite fond of Jammo's "absarc" technique (without g.rotateX()).

function docircle(r, segs, color) {
  let x,y,angle,avertices=[],geometry,material,lines;
  for (let i=0; i<segs; i+=1 ) {
    angle = i/segs*Math.PI*2;
    x = r*Math.cos(angle); y = r*Math.sin(angle);
    avertices.push(x,y,0);
  }
  geometry = new THREE.BufferGeometry();
  geometry.setAttribute('position', new THREE.Float32BufferAttribute(avertices, 3));
  material = new THREE.LineBasicMaterial( { color:color } );
  lines = new THREE.LineLoop(geometry, material);
  scene.add(lines);
}

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

"Enhance your website design with a full-width element using Boostrap that align

Whenever my div is scrolled to, it becomes fixed. At that point, I want the div to expand to full width. I achieved this by adding width: 100% to the div. However, the issue is that I want the content of the div to align with the rest of the page content, ...

Problem with Angular2, NodeJS, and Passport Integration

At the moment, my Angular2 front-end is running on localhost:3000 while the NodeJS back-end (using KrakenJS) is running on localhost:8000. When I input the credentials and make a call to the this.http.post('http://localhost:8000/login', body, { h ...

Managing server JSON objects in Adobe AIR

I am facing an issue with a script that fetches objects from a remote server using an Ajax call. The server sends back objects in JSON format. However, while working on Adobe AIR, I encountered a restriction on utilizing eval() due to security concerns. As ...

The duplication of the Javascript code is creating a conflict within the slider functionality

Attempting to create both an image slider and text slider on the same page using the same JavaScript is proving to be a challenge. Despite researching and trying to implement a no-conflict solution, the sliders still do not function properly together. Wh ...

Vue.js view fails to refresh upon receiving an event through eventbus

Just diving into Vue.js 2 and working on my very first (vue) web application. The setup includes two components - a header component and a login component. Once the login process is successful, a "loggedIn" flag gets toggled within an authentication servic ...

formik does not support using the "new Date" function as an initial value

I have been trying to set the initial value of a date in my component like this, but when it renders I am encountering an error. const formik = useFormik ({ initialValues: { dob: new Date () } }) During this process, I'm facing the follow ...

Substitute "Basic Authentication" with "Form Authentication"

Is there a way in W20 to switch from using "Basic Authentication" to "Form Authentication"? The current documentation mentions only the use of "basicAuth" and does not provide information on implementing form authentication. Our app is built with Angular ...

html.input javascript/jquery

This is an example of an AJAX form with 2 textboxes and a radio button to choose between unlocking and resetting the password. The goal is to make the password label and textbox disappear when the "Unlock" option is selected. However, this cannot be achi ...

Integrate a Facebook Like-box within a customized jQuery modal window

I've been working on inserting the Facebook like-box code into my page and trying to display it within a jQuery modal dialog. Here's the code I'm using: <script src="http://connect.facebook.net/en_US/all.js#xfbml=1"></script>< ...

Challenge involving CSS and Javascript for solving puzzles

In my attempt to create a puzzle with 2 rows and 3 columns using CSS and JavaScript, I envision the pieces of the puzzle being black and cut into various shapes. The objective is for users to drag these pieces onto the board in order to complete it. I have ...

Tooltipster fails to function with elements that are dynamically created

I've been struggling with this issue for several days now, but I can't seem to find a solution. In my JavaScript code, I have a function that generates HTML after an Ajax call is completed. I call this function in the following manner: $(documen ...

Stopping the PanResponder in React Native temporarily: A guide

Here is the snippet to create an instance of the panResponder: constructor( props ) { super( props ); this.position = new Animated.ValueXY(); this.panResponder = PanResponder.create( { onStartShouldSetPanResponder: ( ) => true, ...

Mastering Dropdown Navigation and Value Setting in Angular

I am facing a challenge with two components named ComponentA and ComponentB. In ComponentB, there is a link that, when clicked, should navigate to ComponentA and send specific data to it. This data needs to be displayed in the dropdown options of Component ...

Enhancing jquery datatable functionality with data-* attributes

I successfully added an id to each row of my data table using the rowId property, as outlined in the documentation. $('#myTable').DataTable( { ajax: '/api/staff', rowId: 'staffId' } ); Now I am wondering how I can ad ...

Retrieve the properties from within a closure function in a functional component

I have developed a simple React application using create-react-app. The app consists of a single component that takes in a value and an onClick callback. When the callback is triggered, the value increments. import React, { useState } from 'react&apos ...

Utilizing LoopBack Storage Service: Leveraging upload/download functions within JavaScript code

Is there a straightforward way to upload and download files using the storageService.upload and storageService.download functions in my JavaScript/Loopback code? I'm trying to achieve something like this: app.post("/sendFile", (req, res) => client ...

Instruction failed to produce HTML output

Currently facing a challenge with my code - I have a dynamically created span (via ng-repeat). <span my-size id="abc"></span> <span my-size id="def"></span> <span my-size id="ghi"></span> The goal is to extract the id ...

Switching Unicode icon when element is clicked

My form has two inputs - one for text input and the other for submitting, like a button. I have added an icon to the submit button and want it to change when clicked. <input class="searchBtn" id="submit" name="submit" type="submit" value="&#xf002"& ...

The image slider is blocking the dropdown functionality of the navbar on mobile devices

My code is experiencing a conflict of events. I have created a menu bar using nav bar, as well as an image slider called the caroussel. The issue arises when the window is minimized - the menu bar fails to drop down properly with the presence of the caro ...

Error Message: Stencil Launch Issue - InvalidTypeException("The parameter 'url' should be in string format, not " + the data type of url)

I have been working with stencil for quite some time now and am in the process of developing a custom theme for it. I have installed nvm, node 5.0, and npm 2. Despite deleting stencil and doing a fresh install of everything, including node modules and st ...