Interpolated surface in Three.js - javascript

Hi folks,
I've got a question belongig surfaces in Three.js:
I got a bunch of Vec3 Points and want want to interpolate a surface through them. While searching, I stumbeled across beziers (three.js bezier - only as lines) and what looked more like I was searching : three.js Nurbs. I've tried to reconstruct the code, but the documentation was terrible (pages like this) and I didn't get how everything worked by reconstructing the code...
So here's the question:
Is there any easy way to get a shape out of my calculated points? (I would still be happy, if it's not interpolated).
Thank you guys!
Mat
Edit: What I want to acchieve is a surface plot. I stumbeled across http://acko.net/blog/making-mathbox/ but it's way too big for my needs...

After some try and error I found a solution: add a plane and than transform the single vertices.
// need to setup 'step', 'xStart', 'xEnd', 'yStart', 'yEnd'
// calc the variables
var width = Math.abs(-xStart+xEnd),
height = Math.abs(-yStart+yEnd);
var stepsX = width*step, stepsY = height*step;
var posX = (xStart+xEnd)/2;
var posZ = (yStart+yEnd)/2;
// add a plane and morph it to a function
var geometry = new THREE.PlaneGeometry( width, height, stepsX - 1, stepsY - 1 );
geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) );
var size = stepsX * (stepsY),
data = new Float32Array( size );
var count = 0, scope = {};
mesh = new THREE.Mesh( geometry, new THREE.MeshNormalMaterial( {
side : THREE.DoubleSide,
transparent: true,
shading: THREE.SmoothShading,
opacity : _opacity }));
mesh.updateMatrixWorld();
// calc y value for every vertice
for ( var i = 0; i < size; i ++ ) {
// calculate the current values
// http://stackoverflow.com/questions/11495089/how-to-get-the-absolute-position-of-a-vertex-in-three-js
var vector = mesh.geometry.vertices[i].clone();
vector.applyMatrix4(
mesh.matrixWorld
);
// set them into the scope
scope.x = vector.x + posX;
scope.y = vector.z + posZ;
// calculate point and write it in a temp array
data[i] = math.eval(term, scope);
}
// push the new vertice data
for ( var i = 0, l = geometry.vertices.length; i < l; i ++ ) {
geometry.vertices[ i ].y = data[ i ];
}
// update the new normals
geometry.computeFaceNormals();
geometry.computeVertexNormals();
// add to scene
scene.add( mesh );
Only issue is that it is not working for non static functions like tan(x). This snippet is using math.js to calc the term.
Greetings Mat

Related

Create a curved grid for threejs

I want to create a grid of, let's say 500x500, and I want it to be able to be curved in certain places (think of it as space-time plane that's curved due to gravity). I'm stuck at the start.
This is what I found on the documentation:
// Create a sine-like wave
const curve = new THREE.SplineCurve( [
new THREE.Vector2( -10, 0 ),
new THREE.Vector2( -5, 5 ),
new THREE.Vector2( 0, 0 ),
new THREE.Vector2( 5, -5 ),
new THREE.Vector2( 10, 0 )
] );
const points = curve.getPoints( 50 );
const geometry = new THREE.BufferGeometry().setFromPoints( points );
const material = new THREE.LineBasicMaterial( { color : 0xff0000 } );
// Create the final object to add to the scene
const splineObject = new THREE.Line( geometry, material );
I think this should be working but it doesn't. I don't know how to create a multiple lines from here. I tried to handle some array but I didn't know where or how. I have done my research but I can't make any headway.
I have another question: Is that this is a Vector2 I need to make it 3d for that work? There a lot of other classes like CatmullRomCurve3, CubicBezierCurve3, etc, but the problem still is that i need to make an array to create all the vectors and lines.
--
EDIT i created a code for the grid lines but the curve probleme still the same
let size = 12, step = 1;
const geometry = new THREE.BufferGeometry();
// create a simple square shape. We duplicate the top left and bottom right
// vertices because each vertex needs to appear once per triangle.
const vertices = [];
for(var i = - size; i <= size; i += step) {
vertices.push( - size, - 0.4, i);
vertices.push( size, - 0.4, i);
vertices.push( i, - 0.4, - size);
vertices.push( i, - 0.4, size);
}
let positionAttribute = new THREE.Float32BufferAttribute(vertices, 3);
geometry.setAttribute("position", positionAttribute);
let lines = new THREE.LineSegments(geometry, new THREE.LineBasicMaterial());

convert bezier into a plane road in three.js

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);
}
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;
}
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);
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.
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.

How would I create a terrain like this in Three.js

I am trying to create a terrain from a heightmap with a "closed" bottom see the example here:
http://demos.playfuljs.com/terrain/
My terrain generation function is as so:
var img = document.getElementById("landscape-image");
var numSegments = img.width - 1; // We have one less vertex than pixel
var geometry = new THREE.PlaneGeometry(2400, 2400, numSegments, numSegments);
var material = new THREE.MeshLambertMaterial({
color: 0xccccff,
wireframe: false
});
plane = new THREE.Mesh(geometry, material);
plane.name = 'Terrain';
// set height of vertices
for (var i = 0; i < plane.geometry.vertices.length; i++) {
plane.geometry.vertices[i].z = (terrain[i]/255) * height;
}
geometry.computeFaceNormals();
geometry.computeVertexNormals();
plane.position.x = 0;
plane.rotation.x = 0;
plane.position.y = -10;
The problem I am having is how do I create that connected bottom part of the terrain with a THREE.PlaneGeometry. I can't extrude as:
The bottom must be flat if I extrude it will be bumpy like the
terrain.
Extrude takes a Shape object, not a Geometry object.
Really scratching my head here anyone done this before.
Edit: Maybe I could use two planes and merge them but how would I merge the side faces into a single piece of Geometery ?
P.S. The example draws straight to the canvas
create a plane for each side which has your amount of Segments in width and 1 in height. them set the top Vertices according to your heightmap
something like this
var geometry_l = new THREE.PlaneGeometry(2400, 0, numSegments, 1);
plane_l = new THREE.Mesh(geometry_l, material);
for (var i = 0; i < numSegments; i++) {
plane_l.geometry_l.vertices[i].z = (Terrain[0][i]/255) * height;
}
//Offset to the edge of your main plane
you might want to Change your Terrain Array to be two-dimensional for this. so you can always read the row you want.

THREE.ExplodeModifier hacking

I'm using the ExplodeModifier to duplicate the vertices so I can have individual control over Face3 objects.
For my specific example, this alone looks visually poor, so I decided to add 3 extra faces (per existing face) so I can have a pyramid shape pointing inwards the geometry.
I managed to modify the ExplodeModifier and create the extra faces, however I get several errors:
THREE.DirectGeometry.fromGeometry(): Undefined vertexUv and THREE.BufferAttribute.copyVector3sArray(): vector is undefined
I understand that now I have 9 extra vertices per face, so I need according uv's, and since I don't need a texture but a solid color I don't mind having the wrong uvs... So, I also duplicated the uvs and avoid the first warning but I can't get rid of the copyVector2sArray...
pseudo code:
var geometry = new THREE.IcosahedronGeometry( 200, 1 );
var material = new THREE.MeshPhongMaterial( { shading: THREE.FlatShading } );
var explodeModifier = new THREE.ExplodeModifier();
explodeModifier.modify( geometry );
var mesh = new THREE.Mesh( geometry, material );
scene.addChild( mesh );
The Explode Modifier has this pseudo code:
var vertices = [];
var faces = [];
for ( var i = 0, il = geometry.faces.length; i < il; i ++ ) {
(...)
var extraFace1 = new THREE.Face3().copy(face)
extraFace1.c = geometry.vertices[0]
var extraFace2 = new THREE.Face3().copy(face)
extraFace2.b = geometry.vertices[0]
var extraFace3 = new THREE.Face3().copy(face)
extraFace3.a = geometry.vertices[0]
faces.push( extraFace1 );
faces.push( extraFace2 );
faces.push( extraFace3 );
}
geometry.vertices = vertices;
geometry.faces = faces;
```
I added an example HERE. It works, but I want to avoid the console warnings...
As pointed out by #mrdoob I was assigning a THREE.Vector3 and not an index to the added THREE.Face3.
var extraFace1 = new THREE.Face3().copy(face)
extraFace1.a = geometry.faces.length * 3 - 1
var extraFace2 = new THREE.Face3().copy(face)
extraFace2.b = geometry.faces.length * 3 - 1
var extraFace3 = new THREE.Face3().copy(face)
extraFace3.c = geometry.faces.length * 3 - 1
jsfiddle updated

Can I use THREE js ExtrudeGeometry to extrude a shape over a sharp path?

I have used CatmullRomCurve3 to extrude over a curved line. Is it possible to extrude over a sharp line like below:
What I want to have is:
With possibly as few polygons as possible.
There are a number of ways you could create a geometry of steps, but to do so using ExtrudeGeometry, you could do something like:
var shape = new THREE.Shape();
shape.moveTo( 0, 0 );
var numSteps = 10, stepSize = 10;
for ( var i = 0; i < numSteps; i ++ ) {
shape.lineTo( i * stepSize, ( i + 1 ) * stepSize );
shape.lineTo( ( i + 1 ) * stepSize, ( i + 1 ) * stepSize );
}
var extrudeSettings = { amount: 100, bevelEnabled: false };
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var material = new THREE.MeshBasicMaterial( {color: 0xffffff } );
var steps = new THREE.Mesh( geometry, material );
For a full example based on webgl_geometry_extrude_shapes2, see below:
http://jsfiddle.net/cc146hcx/
I ended up creating vertices, faces and calculating UVs myself. For anyone wanting to do something similar this helped me a lot. I still do not know if ExtrudeGeometry could have been used here.

Categories