5

I am trying to draw a curved road in three.js from some beziers I get with previous calculations, the problem is that I can't find the way to convert the sequence of curved lines (one starting at the end of the previous one) to a curved plane.

I have a 3D scene where there are some cars, a road created with a plane and the path of the coming road is painted. I use that Bezier curves I said to represent the path as a Line with

function createAdasisBezier(initx, inity, cp1x, cp1y, cp2x, cp2y, finalx, finaly) {
  bezier = new THREE.CubicBezierCurve3(
    new THREE.Vector3(initx, inity, 0),
    new THREE.Vector3(cp1x, cp1y, 0),
    new THREE.Vector3( cp2x, cp2y, 0),
    new THREE.Vector3(finalx, finaly, 0)
  );
  curvePath = new THREE.CurvePath();
  curvePath.add(bezier);

  var geoPath = curvePath.createPointsGeometry( 5 );
  var lineMat = new THREE.LineBasicMaterial({color: 0xff0000});

  curveLine = new THREE.Line(geoPath, lineMat);

  curveLine.rotation.set(-Math.PI/2,0,0);
  curveLine.position.y = 0.1;

  scene.add(curveLine);
}

The result is this one

First, I tried extruding the line, but then I realized that it might not be the solution because I wanted to do a road, and although I could move top vertices on X and Y to place them near the bezier in order to be the external part of the curve, the result was not only unfavourable, it also made impossible to preserve a relation between a left and a right curve.

To move vertices (once identified) I did a loop and move them manually:

for (var i = 0; i < geoPath.vertices.length; ++i) {
  geoPath.vertices[i].y += 10;
}

Moving vertices right Bevel is not enabled in the extude.

Then I tried to draw a plane over each bezier (as a child of them) and rotate it to face the path, but the result was not as I expected, and it if it were, it would spoil the arcs of the curves.

To do it, I created a copy of every bezier, and place it aside the original ones, then I created the plane.

 var plane = new THREE.PlaneBufferGeometry(10,25,1,1);
 var planemesh = new THREE.Mesh(plane, material);
 planemesh.position.set(copy.geometry.vertices[0].x, copy.geometry.vertices[0].y, 0);

enter image description here

Last thing I was trying to do is creating a clone of the line, separate it some meters and "connect" the first vertex from one, to the first of the other, so I get a closed geometry, and I can create a Face, but I don't find how to "connect" vertices from 2 different geometries. I tried adding the vertex from one to the other, but it did not work.

Does anybody have an idea how could I convert the line into a curved road? Thanks in adcance.

P.S.
  • 15,970
  • 14
  • 62
  • 86
soiber
  • 172
  • 3
  • 14
  • 1
    This page may help: https://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/Bezier/bezier-der.html. It shows you how to calculate the tangent of a bezier curve at any parameter, and from that you can calculate the *normal*, and thus the road geometry coordinates. – meowgoesthedog Aug 04 '17 at 15:01

1 Answers1

4

You should try looking at the Geometry > Extrude > Shapes example. As you can see, all extruded shapes maintain their width and direction, despite turning left/right or looping completely.

Instead of using bezier curves, they're using a CatmullRomCurve3 to define the extrusion. If you look at the source code, the essential code to make the red extruded shape begins in line 69:

// Define the curve
var closedSpline = new THREE.CatmullRomCurve3( [
    new THREE.Vector3( -60, -100,  60 ),
    new THREE.Vector3( -60,   20,  60 ),
    new THREE.Vector3( -60,  120,  60 ),
    new THREE.Vector3(  60,   20, -60 ),
    new THREE.Vector3(  60, -100, -60 )
] );
closedSpline.type = 'catmullrom';
closedSpline.closed = true;

// Set up settings for later extrusion
var extrudeSettings = {
    steps           : 100,
    bevelEnabled    : false,
    extrudePath     : closedSpline
};

// Define a triangle
var pts = [], count = 3;
for ( var i = 0; i < count; i ++ ) {
    var l = 20;
    var a = 2 * i / count * Math.PI;
    pts.push( new THREE.Vector2 ( Math.cos( a ) * l, Math.sin( a ) * l ) );
}
var shape = new THREE.Shape( pts );

// Extrude the triangle along the CatmullRom curve
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var material = new THREE.MeshLambertMaterial( { color: 0xb00000, wireframe: false } );

// Create mesh with the resulting geometry
var mesh = new THREE.Mesh( geometry, material );

From here, it should only be a matter of small tweaks to these parameters to get the specific road shape you want.

M -
  • 26,908
  • 11
  • 49
  • 81
  • 3
    It works, I am really grateful to you. I did not try this before because it forced me to update my Qt version (it used revision 71 of Three.js and it was not compatible with CatmullRomCurve, now it is r74 and I can use that type of curves) It seems sometimes there is no other way than losing a bit of time updating things. You have my most sincere thanks Marco Del Valle, Thank you very much, for your quick response, and for your kindness. – soiber Aug 07 '17 at 08:36