1

I have created a line graph in 3D using THREE.js and the CatmullRomCurve3 class, which takes care of the curves and smoothing I wanted.

Unfortunately, now that I want to take that curve and turn it into a mesh, and perhaps extrude that mesh, it appears I can't. When I attempt something like:

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

I get errors that prove a curve isn't quite what a geometry constructor wants:

 three.js:27731 Uncaught TypeError: shape.extractPoints is not a function
    at ExtrudeBufferGeometry.addShape (three.js:27731)
    at ExtrudeBufferGeometry.addShapeList (three.js:27656)
    at new ExtrudeBufferGeometry (three.js:27612)
    at new ChartTest (ChartTest.js:33)
    at createSceneSubjects (SceneManager.js:89)
    at new SceneManager (SceneManager.js:27)
    at main.js:16

I have seen examples where a curve is passed as an extrudePath parameter, such as:

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

but that requires a shape to be passed to ExtrudeGeometry along with extrudeSettings, but there has to be a more straightforward way than trying to create a separate shape, when the curve already defines the shape I want to extrude. (This also seems to extrude the path and not the shape it describes.)

Any help would be greatly appreciated!

sands
  • 342
  • 3
  • 9
  • 1
    It's a little unclear what your problem is. Are you trying to create a ribbon, or an actual solid? It sounds like you have the solution but you don't like how it's handled? – manthrax Mar 25 '18 at 04:42
  • Also, you can add pictures of what you have and what you want to achieve. – prisoner849 Mar 25 '18 at 05:18

2 Answers2

2

ShapeGeometry expects an instance of type THREE.Shape as a parameter, not an object of type THREE.Curve. Besides, THREE.CatmullRomCurve3 is a 3D curve whereas THREE.Shape is a 2D entity. This means that your shapes will always be flat. You can do the following to get things working:

Sample you curve first and then create an instance of THREE.Shape. Bear in mind that z-coordinates of the given points will be ignored.

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

https://jsfiddle.net/f2Lommf5/3775/

three.js R91

Mugen87
  • 28,829
  • 4
  • 27
  • 50
  • Hi, it seems that this does not work with newer versions (0.106.2). Do you know what how it is done with the newer version please? – wassx Jul 19 '19 at 19:07
  • 1
    What do you mean with "not work"? The fiddle still runs with the latest version `R106`. – Mugen87 Jul 20 '19 at 10:32
  • I'm sorry, I mixed things up in my code with the THREE.Geometry. – wassx Jul 21 '19 at 19:22
2

In the case, if you want kind of a ribbon, here is a rough concept of how you can do it:

enter image description here

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++) { // the idea taken from 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>
prisoner849
  • 16,894
  • 4
  • 34
  • 68