I'm trying to render a plane a set of 3 vertices (as shown). However every method I tried (mostly from SO or the official three.js forum) doesn't work for me.
// example vertices
const vert1 = new THREE.Vector3(768, -512, 40)
const vert2 = new THREE.Vector3(768, -496, 40)
const vert3 = new THREE.Vector3(616, -496, 40)
I already tried the following code for calculating the width and height of the plane, but I think it's way over-complicated (as I only calculate the X and Y coords and I think my code would grow exponentially if I'd also add the Z-coordinate and the plane's position to this logic).
const width = vert1.x !== vert2.x ? Math.abs(vert1.x - vert2.x) : Math.abs(vert1.x - vert3.x)
const height = vert1.y !== vert2.y ? Math.abs(vert1.y - vert2.y) : Math.abs(vert1.y - vert3.y)
Example:
I want to create a plane with 3 corners of points A, B and C and a plane with 3 corners of points D, E and F.
Example Video
You can use THREE.Plane.setFromCoplanarPoints() to create a plane from three coplanar points. However, an instance of THREE.Plane is just a mathematical representation of an infinite plane dividing the 3D space in two half spaces. If you want to visualize it, consider to use THREE.PlaneHelper. Or you use the approach from the following thread to derive a plane mesh from your instance of THREE.Plane.
Three.js - PlaneGeometry from Math.Plane
I create algorithm which compute mid point of longest edge of triangle. After this compute vector from point which isn't on longest edge to midpoint. On end just add computed vector to midpoint and you have coordinates of fourth point.
On end just create PlaneGeometry from this points and create mesh. Code is in typescript.
Code here:
type Line = {
startPoint: Vector3;
startPointIdx: number;
endPoint: Vector3;
endPointIdx: number;
vector: Vector3;
length: Vector3;
}
function createTestPlaneWithTexture(): void {
const pointsIn = [new Vector3(28, 3, 3), new Vector3(20, 15, 20), new Vector3(1, 13, 3)]
const lines = Array<Line>();
for (let i = 0; i < pointsIn.length; i++) {
let length, distVect;
if (i <= pointsIn.length - 2) {
distVect = new Vector3().subVectors(pointsIn[i], pointsIn[i + 1]);
length = distVect.length()
lines.push({ vector: distVect, startPoint: pointsIn[i], startPointIdx: i, endPoint: pointsIn[i + 1], endPointIdx: i + 1, length: length })
} else {
const distVect = new Vector3().subVectors(pointsIn[i], pointsIn[0]);
length = distVect.length()
lines.push({ vector: distVect, startPoint: pointsIn[i], startPointIdx: i, endPoint: pointsIn[0], endPointIdx: 0, length: length })
}
}
// find longest edge of triangle
let maxLine: LineType;
lines.forEach(line => {
if (maxLine) {
if (line.length > maxLine.length)
maxLine = line;
} else {
maxLine = line;
}
})
//get midpoint of longest edge
const midPoint = maxLine.endPoint.clone().add(maxLine.vector.clone().multiplyScalar(0.5));
//get idx unused point
const idx = [0, 1, 2].filter(value => value !== maxLine.endPointIdx && value !== maxLine.startPointIdx)[0];
//diagonal point one
const thirdPoint = pointsIn[idx];
const vec = new Vector3().subVectors(midPoint, thirdPoint);
//diagonal point two diagonal === longer diagonal of reactangle
const fourthPoint = midPoint.clone().add(vec);
const edge1 = thirdPoint.clone().sub(maxLine.endPoint).length();
const edge2 = fourthPoint.clone().sub(maxLine.endPoint).length();
//const topLeft = new Vector3(bottomLeft.x, topRight.y, bottomLeft.y);
const points = [thirdPoint, maxLine.startPoint, maxLine.endPoint, fourthPoint];
// console.log(points)
const geo = new PlaneGeometry().setFromPoints(points)
const texture = new TextureLoader().load(textureImage);
texture.wrapS = RepeatWrapping;
texture.wrapT = RepeatWrapping;
texture.repeat.set(edge2, edge1);
const mat = new MeshBasicMaterial({ color: 0xFFFFFFF, side: DoubleSide, map: texture });
const plane = new Mesh(geo, mat);
}
Related
I have made a simple plugin for the game Rust that dumps out the color information for the ingame map and NPC coordinates to datafile on a interval.
The map size ranges from -2000 to 2000 in the X and Z axis so the NPC coordinates X and Z also ranges from -2000 to 2000.
In three.js i have a PlaneBufferGeometry representing the map that is setup like this:
const mapGeometry = new THREE.PlaneBufferGeometry( 2, 2, 2000, 2000 ); // width,height,width segments,height segments
mapGeometry.rotateX( - Math.PI / 2 ); // rotate the geometry to match the scene
const customUniforms = {
bumpTexture: { value: heightTexture },
bumpScale: { type: "f", value: 0.02 },
colorTexture: { value: colorTexture }
};
const mapMaterial = new THREE.ShaderMaterial({
uniforms: customUniforms,
vertexShader: document.getElementById( 'vertexShader' ).textContent,
fragmentShader: document.getElementById( 'fragmentShader' ).textContent,
wireframe:true
});
const mapMesh = new THREE.Mesh( mapGeometry, mapMaterial );
scene.add( mapMesh );
The webpage is served with express server with socket.io integration.
The server emits updated coordinates to the connected clients on an interval.
socket.on('PositionData', function(data) {
storeNPCPositions(data);
});
I'm iterating over the NPC data and try to remap the coordinates to correspond with the setup in Three.js like this:
function storeNPCPositions(data) {
let npcs = [];
for (const npc in data.npcPositions) {
npcs.push({
name: npc,
position: {
x: remapPosition(data.npcPositions[npc].x, -2000, 2000, -1, 1), // i am uncertain about the -1 to 1 range, maybe 0 to 2?
y: remapPosition(data.npcPositions[npc].y, heightData.min, heightData.max, 0, .02),
z: remapPosition(data.npcPositions[npc].z, -2000, 2000, -1, 1), // i am uncertain about the -1 to 1 range, maybe 0 to 2?
}
});
}
window.murkymap.positionData.npcs = npcs;
}
function remapPosition(value, from1, to1, from2, to2)
{
return (value - from1) / (to1 - from1) * (to2 - from2) + from2;
}
As you can see in the code above in the storeNPCPositions function I have commented some uncertainty regarding the remapping, but either way it is wrong placement in the end result.
The image below is what I got right now, the npc's are not in the correct positions.
I hope that anyone can see the error in my code, i've been at it for many hours now.
The problem was that the NPC positions were flipped on the X axis. I made a THREE.Object3D() and added all the NPC's to that and then flipped it like this:
let npcContainer = new THREE.Object3D();
npcContainer.position.set(0,0,0);
npcContainer.rotateX(Math.PI);
let npcs = [];
const npcLineMaterial = new THREE.LineBasicMaterial({color: 0xff0000});
for (let i = 0; i < window.murkymap.positionData.npcs.length; i++) {
const npc = window.murkymap.positionData.npcs[i];
const npcPoints = [];
npcPoints.push(new THREE.Vector3(npc.position.x, 1000, npc.position.z));
npcPoints.push(new THREE.Vector3(npc.position.x,200,npc.position.z));
npcPoints.push(new THREE.Vector3(npc.position.x,-50,npc.position.z));
const npcLineGeometry = new THREE.BufferGeometry().setFromPoints( npcPoints );
const npcLine = new THREE.Line(npcLineGeometry, npcLineMaterial);
npcLine.position.y = -750;
npcLine.name = "npc";
npcLine.userData.prefab = npc.name;
npcs.push(npcLine);
}
npcContainer.remove(...npcContainer.children);
npcContainer.add(...npcs);
scene.add(npcContainer);
I try to build a house generator based on a floorplan. Generating the mesh works fine, but now I need to flip the normals on some faces.
buildRoomMeshFromPoints(planeScalar, heightScalar){
var pointsAsVector2 = []
this.points.map(e => {
pointsAsVector2.push(new THREE.Vector2(e.x * planeScalar, e.y * planeScalar))
})
var shape = new THREE.Shape();
shape.moveTo(pointsAsVector2[0].x, pointsAsVector2[0].y)
pointsAsVector2.shift()
pointsAsVector2.forEach(e => shape.lineTo(e.x, e.y))
const extrusionSettings = {
steps: 2,
depth: heightScalar,
bevelEnabled: false
};
var roomGeometry = new THREE.ExtrudeGeometry( shape, extrusionSettings );
var materialFront = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var materialSide = new THREE.MeshBasicMaterial( { color: 0xff8800 } );
var materialArray = [ materialFront, materialSide ];
var roomMaterial = new THREE.MeshFaceMaterial(materialArray);
var room = new THREE.Mesh(roomGeometry, roomMaterial);
room.position.set(0,0,0);
room.rotation.set(THREE.MathUtils.degToRad(-90),0,0)
return room;
}
This is the code that generates the house based on a collection of 2D points. To make the walls see through, I wanna change the normals of all walls and the roof.
My approach would be to compare each face normals angle to an up vector (THREE.Vector3(0,1,0)) and if the angle is greater then 0.0xx then flip it. I simply have no idea how to flip them :)
Thanks for any help!
Greetings pascal
In simplest terms, "flipping" or finding the negative of the normal (or any) vector is a matter of negating each of its components. So if your normal vector n is a THREE.Vector3 instance, then its negative is n.multiplyScalar(-1), or if it's in an array of the form [ x, y, z ], then its negative is [ -1 * x, -1 * y, -1 * z ].
Flipping the normal vectors won't do all of what you're looking to accomplish, though. Normals in Three.js (and many other engines and renderers) are separate and distinct from the notion of the side of a triangle that's being rendered. So if you only flip the vectors, Three.js will continue to render the front side of the triangles, which form the exterior of the mesh; those faces will appear darker, though, because they're reflecting light in exactly the wrong direction.
For each triangle, you need to both (a) flip the normals of its vertices; and (b) either render the back side of that triangle or reverse the facing of the triangle.
To render the back side of the triangle, you can set the .side property of your material to THREE.BackSide. (I have not tested this, and it may have other implications; among other things, you may come across other parts of your codebase that have to be specifically written with an eye to the fact that you're rendering backfaces.)
A more robust solution would be to make the triangles themselves face the other way.
ExtrudeGeometry is a factory for BufferGeometry, and the vertex positions are stored in a flat array in the .attributes.position.array property of the generated geometry. You can swap every 3rd-5th element in the array with every 6th-9th element to reverse the winding order of the triangle, which changes the side that Three.js considers to be the front. Thus, a triangle defined as (0, 0, 0), (1, 0, 1), (1, 1, 1) and represented in the array as [ 0, 0, 0, 1, 0, 1, 1, 1, 1 ] becomes (0, 0, 0), (1, 1, 1), (1, 0, 1) and [ 0, 0, 0, 1, 1, 1, 1, 0, 1 ]. (Put differently, ABC becomes ACB.)
To accomplish this in code requires something like the following.
/**
* #param { import("THREE").BufferGeometry } geom
* #return { undefined }
*/
flipSides = (geom) => {
const positions = geom.getAttribute("position");
const normals = geom.getAttribute("normal");
const newNormals = Array.from(normals.array);
for (let attrName of ["position", "normal", "uv"]) {
// for (let i = 0; i < positions.count; i += 3) {
// ExtrudeGeometry generates a non-indexed BufferGeometry. To flip
// the faces, we must reverse the winding order, i.e., for each triangle
// ABC, we must change it to ACB. We must do this for the position,
// normal, and uv buffers.
const attr = geom.getAttribute(attrName);
let newArr = Array.from(attr.array)
const sz = attr.itemSize;
for (let i = 0; i < attr.count; i++) {
const offset = sz * 3 * i;
// i is the index of the first of three vertices of a triangle.
// Sample the buffer for the second and third vertices, which
// we'll swap.
const tempB = newArr.slice(
offset + sz,
offset + 2 * sz
);
const tempC = newArr.slice(
offset + 2 * sz,
offset + 3 * sz
);
newArr.splice(offset + sz, sz, ...tempC);
newArr.splice(offset + 2 * sz, sz, ...tempB);
}
// If we're working on the normals buffer, we also need to reverse
// the normals. Since reversing a vector simply entails a
// scalar-vector multiplication by -1, and since the array is
// flat, we can do this with one map() operation.
if (attrName == "normal") {
newArr = newArr.map((e) => e * -1);
}
// Replace the position buffer with our new array
geom.setAttribute(
attrName,
new THREE.BufferAttribute(
Float32Array.from(newArr),
sz
));
attr.needsUpdate = true;
}
I've posted a demonstration of this approach on CodePen.
I am new to Three.js so perhaps I am not going abut this optimally,
I have geometry which I create as follows,
const geo = new THREE.PlaneBufferGeometry(10,0);
I then apply a rotation to it
geo.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI * 0.5 ) );
then I create a Mesh from it
const open = new THREE.Mesh( geo, materialNormal);
I then apply a bunch of operations to the mesh to position it correctly, as follows:
open.position.copy(v2(10,20);
open.position.z = 0.5*10
open.position.x -= 20
open.position.y -= 10
open.rotation.z = angle;
Now what is the best way to get the vertices of the mesh both before and after it's position is changed? I was surpised to discover that the vertices of a mesh are not in-built into three.js.
Any hints and code samples would be greatly appreciated.
I think you're getting tripped-up by some semantics regarding three.js objects.
1) A Mesh does not have vertices. A Mesh contains references to Geometry/BufferGeometry, and Material(s). The vertices are contained in the Mesh's geometry property/object.
2) You're using PlaneBufferGeometry, which means an implementation of a BufferGeometry object. BufferGeometry keeps its vertices in the position attribute (mesh.geometry.attributes.position). Keep in mind that the vertex order may be affected by the index property (mesh.geometry.index).
Now to your question, the geometric origin is also its parent Mesh's origin, so your "before mesh transformation" vertex positions are exactly the same as when you created the mesh. Just read them out as-is.
To get the "after mesh transformation" vertex positions, you'll need to take each vertex, and convert it from the Mesh's local space, into world space. Luckily, three.js has a convenient function to do this:
var tempVertex = new THREE.Vector3();
// set tempVertex based on information from mesh.geometry.attributes.position
mesh.localToWorld(tempVertex);
// tempVertex is converted from local coordinates into world coordinates,
// which is its "after mesh transformation" position
Here's an example written by typescript.
It gets the grid's position in the world coordinate system.
GetObjectVertices(obj: THREE.Object3D): { pts: Array<THREE.Vector3>, faces: Array<THREE.Face3> }
{
let pts: Array<THREE.Vector3> = [];
let rs = { pts: pts, faces: null };
if (obj.hasOwnProperty("geometry"))
{
let geo = obj["geometry"];
if (geo instanceof THREE.Geometry)
{
for (let pt of geo.vertices)
{
pts.push(pt.clone().applyMatrix4(obj.matrix));
}
rs.faces = geo.faces;
}
else if (geo instanceof THREE.BufferGeometry)
{
let tempGeo = new THREE.Geometry().fromBufferGeometry(geo);
for (let pt of tempGeo.vertices)
{
pts.push(pt.applyMatrix4(obj.matrix));
}
rs.faces = tempGeo.faces;
tempGeo.dispose();
}
}
return rs;
}
or
if (geo instanceof THREE.BufferGeometry)
{
let positions: Float32Array = geo.attributes["position"].array;
let ptCout = positions.length / 3;
for (let i = 0; i < ptCout; i++)
{
let p = new THREE.Vector3(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
}
}
I have created a three.js scene that includes a plane that intersects a mesh. What I would like to do is get an array of points for all locations where an edge of the mesh crosses the plane. I have had a good look for solutions and can't seem to find anything.
Here is an image of what I currently have:
And here I have highlighted the coordinates I am trying to gather:
If anybody can point me in the right direction, that would be most appreciated.
Thanks,
S
This is not the ultimate solution. This is just a point where you can start from.
UPD: Here is an extension of this answer, how to form contours from given points.
Also, it's referred to this SO question with awesome anwers from WestLangley and Lee Stemkoski about the .localToWorld() method of THREE.Object3D().
Let's imagine that you want to find points of intersection of a usual geometry (for example, THREE.DodecahedronGeometry()).
The idea:
THREE.Plane() has the .intersectLine ( line, optionalTarget ) method
A mesh contains faces (THREE.Face3())
Each face has a, b, c properties, where indices of vertices are stored.
When we know indices of vertices, we can get them from the array of vertices
When we know coordinates of vertices of a face, we can build three THREE.Line3() objects
When we have three lines, we can check if our plane intersects them.
If we have a point of intersection, we can store it in an array.
Repeat steps 3 - 7 for each face of the mesh
Some explanation with code:
We have plane which is THREE.PlaneGeometry() and obj which is THREE.DodecahedronGeometry()
So, let's create a THREE.Plane():
var planePointA = new THREE.Vector3(),
planePointB = new THREE.Vector3(),
planePointC = new THREE.Vector3();
var mathPlane = new THREE.Plane();
plane.localToWorld(planePointA.copy(plane.geometry.vertices[plane.geometry.faces[0].a]));
plane.localToWorld(planePointB.copy(plane.geometry.vertices[plane.geometry.faces[0].b]));
plane.localToWorld(planePointC.copy(plane.geometry.vertices[plane.geometry.faces[0].c]));
mathPlane.setFromCoplanarPoints(planePointA, planePointB, planePointC);
Here, three vertices of any face of plane are co-planar, thus we can create mathPlane from them, using the .setFromCoplanarPoints() method.
Then we'll loop through faces of our obj:
var a = new THREE.Vector3(),
b = new THREE.Vector3(),
c = new THREE.Vector3();
obj.geometry.faces.forEach(function(face) {
obj.localToWorld(a.copy(obj.geometry.vertices[face.a]));
obj.localToWorld(b.copy(obj.geometry.vertices[face.b]));
obj.localToWorld(c.copy(obj.geometry.vertices[face.c]));
lineAB = new THREE.Line3(a, b);
lineBC = new THREE.Line3(b, c);
lineCA = new THREE.Line3(c, a);
setPointOfIntersection(lineAB, mathPlane);
setPointOfIntersection(lineBC, mathPlane);
setPointOfIntersection(lineCA, mathPlane);
});
where
var pointsOfIntersection = new THREE.Geometry();
...
var pointOfIntersection = new THREE.Vector3();
and
function setPointOfIntersection(line, plane) {
pointOfIntersection = plane.intersectLine(line);
if (pointOfIntersection) {
pointsOfIntersection.vertices.push(pointOfIntersection.clone());
};
}
In the end we'll make our points visible:
var pointsMaterial = new THREE.PointsMaterial({
size: .5,
color: "yellow"
});
var points = new THREE.Points(pointsOfIntersection, pointsMaterial);
scene.add(points);
jsfiddle example. Press the button there to get the points of intersection between the plane and the dodecahedron.
Update THREE.js r.146
Sharing complete example using BufferGeometry since Geometry is deprecated since r.125, while following the wonderful example of #prisoner849 and discourse thread Plane intersects mesh with three.js r125
Example includes clipping the geometry based on the intersection points which are used to generate the LineSegments.
Can also instead create a Plane from the PlanarGeometry Quanternion and Normal
let localPlane = new THREE.Plane();
let normal = new THREE.Vector3();
let point = new THREE.Vector3();
normal.set(0, -1, 0).applyQuaternion(planarGeometry.quaternion);
point.copy(planarGeometry.position);
localPlane.setFromNormalAndCoplanarPoint(normal, point).normalize();**
Function updates Lines with current intersection based on the current position of the PlanarGeometry
let lines = new THREE.LineSegments(
new THREE.BufferGeometry(),
new THREE.LineBasicMaterial({
color: 0x000000,
linewidth: 5
})
);
function drawIntersectionLine() {
let a = new THREE.Vector3();
let b = new THREE.Vector3();
let c = new THREE.Vector3();
const isIndexed = obj.geometry.index != null;
const pos = obj.geometry.attributes.position;
const idx = obj.geometry.index;
const faceCount = (isIndexed ? idx.count : pos.count) / 3;
const clippingPlane = createPlaneFromPlanarGeometry(plane);
obj.material.clippingPlanes = [clippingPlane];
let positions = [];
for (let i = 0; i < faceCount; i++) {
let baseIdx = i * 3;
let idxA = baseIdx + 0;
a.fromBufferAttribute(pos, isIndexed ? idx.getX(idxA) : idxA);
let idxB = baseIdx + 1;
b.fromBufferAttribute(pos, isIndexed ? idx.getX(idxB) : idxB);
let idxC = baseIdx + 2;
c.fromBufferAttribute(pos, isIndexed ? idx.getX(idxC) : idxC);
obj.localToWorld(a);
obj.localToWorld(b);
obj.localToWorld(c);
lineAB = new THREE.Line3(a, b);
lineBC = new THREE.Line3(b, c);
lineCA = new THREE.Line3(c, a);
setPointOfIntersection(lineAB, clippingPlane, positions);
setPointOfIntersection(lineBC, clippingPlane, positions);
setPointOfIntersection(lineCA, clippingPlane, positions);
}
lines.geometry.setAttribute(
"position",
new THREE.BufferAttribute(new Float32Array(positions), 3)
);
}
function setPointOfIntersection(line, planarSrf, pos) {
const intersect = planarSrf.intersectLine(line, new THREE.Vector3());
if (intersect !== null) {
let vec = intersect.clone();
pos.push(vec.x);
pos.push(vec.y);
pos.push(vec.z);
}
}
Example CodePen
I am trying to Extrude the Rectangle drawn in the canvas to Three.js canvas.
Here Blue one is 2d canvas drawing and Green is 3d
var Shape = new THREE.Shape();
Shape.moveTo(0,0,0);
for(var i=0;i<=point.length/2;i++)
{
Shape.lineTo(point[i],point[i+1]);
}
var ExtrusionSettings = {
curveSegments: 3,
bevelThickness:0, bevelSize: 0, bevelEnabled: false,
material: 0, extrudeMaterial: 1,amount: 10
};
var Geometry = new THREE.ExtrudeGeometry( Shape, ExtrusionSettings );
var Material = new THREE.MeshLambertMaterial({color: 0xff8800});
Material.side = THREE.DoubleSide;
Mesh = new THREE.Mesh(Geometry,Material);
Mesh.position.set(0,0,0);
Scene.add(Mesh);
The points is passed as an array which contain the x,y coordinates of the lines in the canvas
the points are passed by
function mouseDown(event)
{
Line[0] = event.pageX - this.offsetLeft;
Line[1] = event.pageY - this.offsetTop;
console.log("down");
}
function mouseUp(event)
{
Line[2] = event.pageX - this.offsetLeft;
Line[3] = event.pageY - this.offsetTop;
console.log("up");
var Width = Math.abs(Line[2] - Line[0]);
var Height = Math.abs(Line[3] - Line[1]);
Context.beginPath();
//Context.moveTo(Line[0], Line[1]);
//Context.lineTo(Line[2], Line[3]);
//Context.rect(Line[0],Line[1],Width,Height);
Context.lineWidth="5";
Context.strokeStyle="red";
var L1P1x = Line[0];
var L1P1y = Line[1];
var L1P2x = Line[0]+Width;
var L1p2Y = Line[1];
var L2P1x = Line[0]+Width;
var L2P1y = Line[1];
var L2P2x = Line[2];
var L2P2y = Line[3];
var L3P1x = Line[2];
var L3P1y = Line[3];
var L3P2x = Line[0];
var L3P2y = Line[1]+Height;
var L4P1x = Line[0];
var L4P1y = Line[1]+Height;
var L4P2x = Line[0];
var L4P2y = Line[1];
Context.moveTo(L1P1x,L1P1y);
Context.lineTo(L1P2x,L1p2Y);
Context.moveTo(L2P1x,L2P1y);
Context.lineTo(L2P2x,L2P2y);
Context.moveTo(L3P1x,L3P1y);
Context.lineTo(L3P2x,L3P2y);
Context.moveTo(L4P1x,L4P1y);
Context.lineTo(L4P2x,L4P2y);
Context.stroke();
Points.push(L1P1x,L1P1y,L1P2x,L1p2Y,L2P1x,L2P1y,L2P2x,L2P2y,L3P1x,L3P1y,L3P2x,L3P2y,L4P1x,L4P1y,L4P2x,L4P2y);
addMesh(Points);//points are passes to draw in 3d
//console.log(Points);
}
Not a fan of three.js but looking at your code you have some basic logic errors.
The short answer
Logic errors in the for loop! Change your first snippet to the following. You have Points in the second snippet and Point in the first. I have used point in the fix as I assume that is the correct name for the array of coordinates.
var i, len, mesh; // define all the vars you will use
len = point.length; // get the number of coordinates.
if(len > 1) { // make sure there are points.
shape.moveTo(point[0], point[1]); // move to the first point
for(i = 2; i < len; i += 2) { // iterate other points and lineTo them
shape.lineTo(point[i], point[i + 1]); // add the line.
}
mesh = new THREE.Mesh(
new THREE.ExtrudeGeometry( // Create geom
shape,
{ // extrusion settings.
curveSegments : 3,
bevelThickness : 0,
bevelSize : 0,
bevelEnabled : false,
material : 0,
extrudeMaterial : 1,
amount : 10
}
),
new THREE.MeshLambertMaterial({color: 0xff8800}) // material
);
mesh.position.set(0, 0 0); // position the mesh
scene.add(mesh); // add it to the scene
}
That will fix the bug. It was the for loop that was bad.
The long answer.
You seem to be a beginner so the long answer is to give you some longer term advice. (advice only as there are no rules).
Creating the shape. You had...
var Shape = new THREE.Shape();
Shape.moveTo(0,0,0);
for(var i=0;i<=point.length/2;i++)
{
Shape.lineTo(point[i],point[i+1]);
}
Now with my pedantic eye
Never name vars with a capital. Capitaitals are reserved for named objects. Though in this case you are safe, using the name Shape in a differing scopy could well overwrite the object constructor.
var Shape = new THREE.Shape(); // you had
should be
var shape = new THREE.shape();
Capitals are only for objects that you can use the new token with, Acronyms, or constants. This is not a trivial convention as all of Javascript's inbuilt naming uses it and I have yet to find a popular framework that does not use it. DON'T CAPITALIZE, it is a bad habit in javascript and will cause endless hours looking for simple syntax bugs.
The THREE.Shape object only deals with 2D paths. You had
// 3 coordinates for for a 2D path???
Shape.moveTo(0,0,0); // remove this line it is not needed
The last 0 is ignored, ( I checked the THREE.js source code) and that is not the error.
You error is here in the following.
for(var i=0;i<=point.length/2;i++) // Only half the points ??
{ // you then line to x,y
Shape.lineTo(point[i],point[i+1]);
// Next lineTo will be y,x then x,y messing everything up.
}
point refers the the array of numbers representing the x and y coordinates of the path. It is organised with the x coord, then y then x then y.
The number of items in the array is the number of 2D points * 2. The * 2 is because there is a X and a ``Y for each point.
So need to iterate the point array correctly.
Step by step.
var i, len; // always put your vars declarations at the top
len = point.length; // I like to get the length before the loop.
The for loop needs to step by 2 as the are two entries for each point.
for(i = 0; i < len; i += 2) { //Put the { at the end. Saves space and is easier to read.
Check for the first point as you need to moveTo (note answer is slightly different)
if(i === 0) {
Add the point to the path (shape).
shape.moveTo(point[i], point[i + 1]);
Then the other points
} else {
shape.lineTo(point[i], point[i + 1]);
}
This will create the correct shape that you can then use to extrude.
Put all together as I would do it.
// where do you define scene. It should be lowercase
var i, len, mesh;
len = point.length;
if(len > 1) { // check if there are points (2 or more.
shape.moveTo(point[0], point[1]); // do the first point outside the for loop
// this saves having to do the if statement
// for each point
for(i = 2; i < len; i += 2) { // iterate points starting at the second
shape.moveTo(point[i], point[i + 1]); // add the line.
}
You had
// Such a long name for a one of abd just a mess
// Your code
//var ExtrusionSettings = {
// curveSegments: 3,
// bevelThickness:0, bevelSize: 0, bevelEnabled: false,
// material: 0, extrudeMaterial: 1,amount: 10
//};
// unless it will be used again put it inline
// Bad naming for the rest
// Your code
//var Geometry = new THREE.ExtrudeGeometry( Shape, ExtrusionSettings );
//var Material = new THREE.MeshLambertMaterial({color: 0xff8800});
//Material.side = THREE.DoubleSide;
//Mesh = new THREE.Mesh(Geometry,Material);
//Mesh.position.set(0,0,0);
//Scene.add(Mesh);
Replace it all with
// Material is used once so no need to create var for it
// Removed Material.side = THREE.DoubleSide; // assuming this is debug code only
// you had Mesh without var. That made it global scope. Never use a var without defining it first with the var token
var mesh = new THREE.Mesh( // define and assign mesh
new THREE.ExtrudeGeometry( // Create geom// indent arguments for readability
shape,
{ // extrusion settings.
curveSegments : 3, // line it all up so you can read it quickly
bevelThickness : 0,
bevelSize : 0,
bevelEnabled : false,
material : 0,
extrudeMaterial : 1,
amount : 10
}
),
new THREE.MeshLambertMaterial({color: 0xff8800})
);
mesh.position.set(0,0,0); // position the mesh
scene.add(mesh); // add it to the scene
// note the lowercase scene for the object instance scene. Need to chage that where you create it.
} // end of if(len > 1){
There is a lot of pedantic stuff there but you are clearly new to programming and bad habits are hard to break so start with good ones. Bugs and debugging are the worst part of programming. Debugging is the single most time consuming part of all programming (even for experienced professionals). The single biggest cause of bugs in all programing languages is bad style and or messy code. Writing clean consistent code makes your code easier to read and hence easier to debug. Try finding a missing { in 5000 lines of `{''s or a capital where a lowercase character should be (Hours debugging code while the simple error is right in front of you hidden in a mess can make or break being a coder)
Hope this helped..