Is it Possible to Transform a THREE.CatmullRomCurve3 into a 3D Mesh?

In my latest project, I managed to create a stunning 3D line graph using THREE.js and the CatmullRomCurve3 class for smooth curves. Everything was going smoothly until I attempted to turn that curve into a mesh and possibly extrude it.

My initial approach resulted in errors because it seems that a curve is not compatible with the geometry constructor:

    var geometry = new THREE.ShapeGeometry( curve );
    var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
    var mesh = new THREE.Mesh( geometry, material ) ;

The error messages led me to explore using the curve as an extrudePath parameter in examples like this:

var extrudeSettings = {
    steps           : 100,
    bevelEnabled    : false,
    extrudePath     : curve
};

However, this method still requires a shape to be passed to ExtrudeGeometry, which feels redundant since the curve already defines the desired shape. Is there a more straightforward way to achieve this without creating a separate shape?

If anyone has any insights or solutions to this challenge, I would greatly appreciate your help!

Answer №1

When using ShapeGeometry in three.js, make sure to pass an instance of type THREE.Shape instead of a Three.Curve object. Keep in mind that THREE.CatmullRomCurve3 is a 3D curve while THREE.Shape represents a 2D entity, resulting in flat shapes. To resolve this issue, follow these steps:</p>

<p>First, sample your curve and then create a new instance of THREE.Shape. Note that the z-coordinates of the points will be disregarded.</p>

<pre><code>const points = curve.getPoints(64);
const shape = new THREE.Shape(points);
const geometry = new THREE.ShapeGeometry(shape);

View Example Here

three.js version R91

Answer №2

If you're looking to create a ribbon-like effect, here's a basic concept of how you can achieve it:

https://i.sstatic.net/78bwG.png

var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
camera.position.set(-0.5, 4, 5);
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

var controls = new THREE.OrbitControls(camera, renderer.domElement);

var curve = new THREE.CatmullRomCurve3(
  [
    new THREE.Vector3(-2, 2, 0),
    new THREE.Vector3(-1, 0.5, 0),
    new THREE.Vector3(0, 1, 0),
    new THREE.Vector3(1, 3, 0),
    new THREE.Vector3(2, 1, 0)
  ]
);

var pointsCount = 50;
var pointsCount1 = pointsCount + 1;
var points = curve.getPoints(pointsCount);

var pts = curve.getPoints(pointsCount);
var width = 2;
var widthSteps = 1;
let pts2 = curve.getPoints(pointsCount);
pts2.forEach(p => {
  p.z += width;
});
pts = pts.concat(pts2);

var ribbonGeom = new THREE.BufferGeometry().setFromPoints(pts);

var indices = [];
for (iy = 0; iy < widthSteps; iy++) { // inspired by PlaneBufferGeometry
  for (ix = 0; ix < pointsCount; ix++) {
    var a = ix + pointsCount1 * iy;
    var b = ix + pointsCount1 * (iy + 1);
    var c = (ix + 1) + pointsCount1 * (iy + 1);
    var d = (ix + 1) + pointsCount1 * iy;
    // faces
    indices.push(a, b, d);
    indices.push(b, c, d);
  }
}
ribbonGeom.setIndex(indices);
ribbonGeom.computeVertexNormals();

var ribbon = new THREE.Mesh(ribbonGeom, new THREE.MeshNormalMaterial({
  side: THREE.DoubleSide
}));
scene.add(ribbon);

var line = new THREE.Line(new THREE.BufferGeometry().setFromPoints(points), new THREE.LineBasicMaterial({
  color: "red",
  depthTest: false
}));
scene.add(line);

render();

function render() {
  requestAnimationFrame(render);
  renderer.render(scene, camera);
}
body {
  overflow: hidden;
  margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/91/three.min.js"></script>
<script src="https://threejs.org/examples/js/controls/OrbitControls.js"></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

Blending conditional and non-conditional styles in VueJS

Is it possible to set a class in Vue based on the value of a parameter and conditionally add another class if that parameter meets a certain condition? Can these two functionalities be combined into one class assignment? <button :class="'btn btn-p ...

Node, Express, and Angular redirection problem encountered

I have a web application built with node, express, and angular. The app consists of two main pages - a user profile page and a login page. My goal is to redirect any user who is not logged in to the login page when they try to access the profile page. Howe ...

The input field does not accept any values even after setting it to be editable

Hey there! I have a specific requirement where I need to edit certain fields by clicking on an edit link. Initially, these fields will be disabled and in a readonly state. Once I click on the edit link, the field should become blank and editable. The issu ...

Dividing an Image into segments using Javascript

I'm currently working on a basic Jigsaw puzzle project. To achieve this, I am required to divide the image I've selected into 20 separate pieces. I was wondering if there is a method in Javascript that can automatically cut an image into 20 equal ...

Regular expression in JavaScript that specifically matches numbers formatted in the style of JavaScript

My goal is to develop a javascript regular expression that specifically identifies valid Javascript-style numbers. The requirements entail accommodating an optional minus or plus sign before the number, recognizing the decimal dot, and supporting exponent ...

Tips for transferring the name field to a different page upon clicking

There are two pages in my project - the first one is called ItemMenuPage and the second one is called CartPage. The functionality I am trying to achieve is that when a user clicks on any item name on the ItemMenuPage, it should navigate to the CartPage, wi ...

Introducing the latest issue: "Annotation Not Found" bug detected in flowjs version 0.54.0!

Following the update to flow 0.54.0, the code snippet below is encountering an issue: function runKarmaTest() { const KARMA_CONFIG = {}; return new Promise(function (resolve, reject) { new karma.Server(KARMA_CONFIG, function (exitCode) { ...

An illustration of webpack 4 and Vue.js compatibility tailored specifically for Internet Explorer 11, featuring multiple entry points

This feels like déjà vu - yet another issue with Internet Explorer and webpack. I'm on the brink of deploying my project when IE 11 decides to mess everything up. I thought I had covered all bases with babel-polyfill and the latest versions, but of ...

Trigger a click based on the CSS path starting from a specific element in the DOM

I am currently developing a feature for mouse activities, such as moving the mouse, clicking, and scrolling. I want to be able to record these activities and then playback them later on. So far, I have successfully recorded mouse movement, and now I need t ...

Prevent selection duplication in adjacent select by disabling the option in AngularJS ng-options

In my table, I have 2 select options that change dynamically. <tr> <th>Start time</th> <th>End time</th> </tr> <tr ng-repeat="s in config.time"> <td> <select ng-model="s.start_time" ...

Struggling to destructure props when using getStaticProps in NextJS?

I have been working on an app using Next JS and typescript. My goal is to fetch data from an api using getStaticProps, and then destructure the returned props. Unfortunately, I am facing some issues with de-structuring the props. Below is my getStaticProp ...

Utilizing Grunt-express and static routes: The server must include a method named 'listen' that functions in the same way as http.Server.listen

I've been working on setting up Grunt to launch my express server using grunt-express. Even after reviewing the documentation and a related Stack Overflow post, I'm still having trouble figuring it out. I've tested various configurations in ...

Utilizing children as a prop within a Vue component

In React, I can create a FancyList component like this: const FancyList : React.SFC<{},{}> ({children}) => ( <ul> {...children} </ul> ); const FancyListItem : React.SFC<{text: string}, {}> ({children}) => < ...

What are the steps to executing commands with child processes in Node.js?

I have successfully established communication between the client and server using socket.io. I am now utilizing WebSockets to send commands from the client to the server, and I would like to execute these received commands on the server. Here is my approa ...

Replacing menu styling with JavaScript using C#

I'm currently working on a C# project to develop a smartphone-friendly website for motorists to easily pay their parking fees. However, I'm facing some challenges with the menu design. My goal is to have a white menu with black text, where the cu ...

stuck with an outdated dependency causing issues with create-react-app

Encountering a problem with create-react-app failing due to react-scripts expecting an older version of a dependency, making it difficult to select the new version as suggested. This appears to be an interface issue. Interestingly, I can successfully inst ...

Registering the service worker resulted in an error stating "Undefined is not a function"

When attempting to register a service worker using default React code, I discovered that some users were encountering a `TypeError: undefined is not a function` on the line `.then(registration => {` inside the registerValidSW function. Although it works ...

Tips for managing both DOM manipulation and state changes at the same time in AngularJS

<div my-custom-directive> <button id="myButton" ng-click="handleClick(mymodel.id)"><button> </div> app.controller('myCtrl', function($scope) { $scope.handleClick = function(id) { //Perform state change here without ...

Passing a JSON payload back and forth from JavaScript to PHP within a shared directory

I am currently working on a task where I need to transfer data from a JavaScript file to a PHP file for database insertion into MySQL. The JavaScript file's main role is to collect the data and pass it on to the PHP script for insertion. The data for ...

Dynamic and operational icons accompany the AngularJS search input field

Currently, I am delving into the world of AngularJS and experimenting with a search box. Within this search box, I want to incorporate three icons: a magnifying glass, a cross, and a spinner. For the first scenario, I envision the magnifying glass appearin ...