Hey im using Three meshline an add-on for three js you can find here.
https://github.com/spite/THREE.MeshLine/tree/master/src.
it works great in my code the only thing is, fog does not apply on its special own material new MeshLineMaterial. Is there any way to implement the fog value to the meshline.js file?
Thanks for your help
var geometry = new THREE.Geometry();
for( var k = 0; k < splinePoints.length; k++) {
var v = new THREE.Vector3( splinePoints[k].x + 3* Math.sin(k/4), splinePoints[k].y + 3 *Math.cos(k/4), splinePoints[k].z);
geometry.vertices.push( v );
}
makeLine(geometry, Colors.red);
function makeLine( geo, c ) {
var g = new MeshLine();
g.setGeometry( geo );
var material = new MeshLineMaterial( {
color: new THREE.Color( c ),
opacity: 1,
lineWidth: 1
});
var mesh = new THREE.Mesh( g.geometry, material );
graph.add( mesh );
}
Related
I'm trying to build a 3D model (ModelVisual3D) out of a List<Vector3D> generated from the GCode-Parser. I did use this JavaScript code as base for my C# version of it.
JavaScript Code:
https://github.com/hudbrog/gCodeViewer/blob/master/js/renderer3d.js
var buildModelIteration = function(layerNum){
var j;
var cmds = model[layerNum];
if(!cmds)return;
for(j=0;j<cmds.length;j++){
if(!cmds[j])continue;
if(isNaN(cmds[j].x))cmds[j].x=prevX;
if(isNaN(cmds[j].y))cmds[j].y=prevY;
if(isNaN(cmds[j].z))cmds[j].z=prevZ;
if(!cmds[j].extrude){
}
else {
geometry.vertices.push( new THREE.Vector3(prevX, prevY, prevZ));
geometry.vertices.push( new THREE.Vector3(cmds[j].x, cmds[j].y, cmds[j].z));
}
prevX = cmds[j].x;
prevY = cmds[j].y;
prevZ = cmds[j].z;
}
};
var buildModelIteratively = function(){
var i;
for(i=0;i<model.length;i+=1){
buildModelIteration(i);
//TODO: need to remove UI stuff from here
}
var lineMaterial = new THREE.LineBasicMaterial({color: renderOptions["colorLine"], lineWidth: 2, opacity: 0.6, fog: false});
geometry.computeBoundingBox();
object.add(new THREE.Line(geometry, lineMaterial, THREE.LinePieces));
var center = new THREE.Vector3().add(geometry.boundingBox.min, geometry.boundingBox.max).divideScalar(2);
object.position = center.multiplyScalar(-1);
}
Out of the function above, I get a list of Vector3D objects. From this, I'm trying to greate a ModelVisual3D object.
ModelVisual3D mod = new ModelVisual3D();
GeometryModel3D geometry = new GeometryModel3D();
MeshGeometry3D meshGeometry = new MeshGeometry3D();
foreach (Vector3D vect in listOfVectors)
{
meshGeometry.Positions.Add(new Point3D(vect.X, vect.Y, vect.Z));
//meshGeometry.TriangleIndices.Add(cnt)
}
meshGeometry.CalculateNormals();
meshGeometry.Validate();
geometry.Geometry = meshGeometry;
geometry.Transform = new TranslateTransform3D(2,0,-1);
geometry.Material = new DiffuseMaterial(Brushes.White);
mod.Content = geometry;
I guess I need to add some Triangles as well, however I'm not familiar with 3D Models.
Edit1:
What I want to achive is, to get the bounding box of my points cloud and add a surface to it.
Like THREE.computeBoundingBox(), see example below:
var geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3( -10, 10, 0 ),
new THREE.Vector3( -10, -10, 0 ),
new THREE.Vector3( 10, -10, 0 )
);
geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );
geometry.computeBoundingSphere();
https://threejs.org/docs/#api/en/core/Geometry.computeBoundingBox
Any help is appreciated.
If further information are needed, just let me know.
I'm working on adapting the object loading example on the THREE.js example page to allow for the loaded objects to have their faces selected and colored. My general strategy has been to follow the steps outlined here.
However, since I am not using THREE.geometry objects, I am having trouble piecing together this strategy with the obj loader code.
I currently have ray intersection working so I know when I am clicking on the object, I am just having trouble coloring the faces. I know I need to apply: vertexColors: THREE.FaceColors to the obj material and thats where I'm stuck.
My current obj loading code is as follows:
var loader = new THREE.OBJLoader( manager );
loader.load( path, function ( object ) {
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh ) {
var faceColorMaterial = new THREE.MeshBasicMaterial({ color: 0xff00ff, vertexColors: THREE.VertexColors } );
child.material = faceColorMaterial;
child.geometry.addAttribute( "color", new THREE.BufferAttribute( new Float32Array( 3 * 3 ), 3 ) );
child.geometry.dynamic = true;
}
} );
scene.add( object );
targetList.push(object);
}, onProgress, onError );
And my detection and coloring code:
var vector = new THREE.Vector3( mouse.x, mouse.y, 1 );
vector.unproject( camera );
var ray = new THREE.Raycaster( camera.position, vector.sub( camera.position ).normalize() );
var intersects = ray.intersectObjects( targetList, true );
if ( intersects.length > 0 ) {
var colorArray = intersects[0].object.geometry.attributes.color.array;
var face = intersects[0].face;
colorArray[face.a] = 1;
colorArray[face.a + 1] = 0;
colorArray[face.a + 2] = 0;
colorArray[face.b] = 1;
colorArray[face.b + 1] = 0;
colorArray[face.b + 2] = 0;
colorArray[face.c] = 1;
colorArray[face.c + 1] = 0;
colorArray[face.c + 2] = 0;
intersects[0].object.geometry.attributes.color.needsUpdate = true;
}
When I run this, my object is black and when I click the faces, they do not change color.
How can I alter my code to allow for the changes to be colored when selected?
OBJLoader should be returning BufferGeometry objects, which don't use FaceColors. BufferGeometry can use VertexColors to assign colors to a face, but you need to ensure the colors attribute is applied to the BufferGeometry. If you do have a colors attribute, then you're in luck, because OBJLoader gives you unique vertices for each triangle.
When intersectObjects returns, the Face3 should have a, b, and c, which I believe should be indicies into the mesh.geometry.attributes.position.array, but they'll also be indices into the mesh.geometry.attributes.color.array array.
var colorArray = intersects[0].object.geometry.attributes.color.array,
face = intersects[0].face;
colorArray[face.a] = 1;
colorArray[face.a + 1] = 0;
colorArray[face.a + 2] = 0;
colorArray[face.b] = 1;
colorArray[face.b + 1] = 0;
colorArray[face.b + 2] = 0;
colorArray[face.c] = 1;
colorArray[face.c + 1] = 0;
colorArray[face.c + 2] = 0;
intersects[0].object.geometry.attributes.color.needsUpdate = true;
This should turn a particular face red. But I can't stress enough that this will only work if your geometry has a colors attribute, and your material is using THREE.VertexColors.
I have an large array (50,000 to 100,000 elements) with each element containing another array of 3 points that define the vertices of a polygon. Some vertices have a parameter addition built in to the array, e.g;
var array = [
[[967.6719, 657.401, -1008.1],[967.6719, 657.401, -1001.1],[967.1551, 657.4806, -1008.1]],
[[967.1551, 657.4806, -1008.1 + LENGTH],[967.6719, 657.401, -1001.1],[967.1551, 657.4806, -1001.1]],
...etc
];
The length parameter is controlled by a slider bar. Currently the initial load time is way too long and any changes to the parameter also takes ages to update. Is there a way to optimise this?
I am currently rendering the polygons with this code;
function drawShapes(array) {
scene.remove( all_shapes );
all_shapes = new THREE.Object3D();
var LENGTH = inpLength.valueAsNumber;
var material = new THREE.LineBasicMaterial( { color: 0x02B700, linewidth: 2 } );
var triangleGeometry = new THREE.Geometry();
for (var i=0; i < array.length; i++){
for (var n=0; n<3; n++){
triangleGeometry.vertices.push(new THREE.Vector3( array[i][n][0], array[i][n][1], array[i][n][2]));
}
triangleGeometry.faces.push(new THREE.Face3(0, 1, 2));
triangleMesh = new THREE.Mesh(triangleGeometry, material);
all_shapes.add(triangleMesh)
var triangleGeometry = new THREE.Geometry();
}
scene.add( all_shapes );
}
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
I don't know what I'm doing wrong. I have multiple meshes that I am trying to merge into one mesh so that I can save on draw calls.
Each of my meshes has a unique materials. In this example it just has a different color, but really they will have unique textures mapped.
This is my code:
materials = [];
blocks = [];
var tempMat;
var tempCube;
var tempGeo;
var tempvec;
// block 1
tempMat = new THREE.MeshLambertMaterial({ color: '0x0000ff' });
materials.push( tempMat );
tempGeo = new THREE.CubeGeometry(1, 1, 1);
for (var ix=0; ix<tempGeo.faces.length; ix++) {
tempGeo.faces[ix].materialIndex = 0;
}
tempCube = new THREE.Mesh( tempGeo, tempMat );
tempCube.position.set(0, 3, -6);
blocks.push( tempCube );
// block 2
tempMat = new THREE.MeshLambertMaterial({ color: '0x00ff00' });
materials.push( tempMat );
tempGeo = new THREE.CubeGeometry(1, 1, 1);
for (var ix=0; ix<tempGeo.faces.length; ix++) {
tempGeo.faces[ix].materialIndex = 1;
}
tempCube = new THREE.Mesh( tempGeo, tempMat );
tempCube.position.set(1, 3, -6);
blocks.push( tempCube );
// Merging them all into one
var geo = new THREE.Geometry();
for (var i=0; i<blocks.length; i++) {
blocks[i].updateMatrix();
geo.merge(blocks[i].geometry, blocks[i].matrix, i);
}
var newmesh = new THREE.Mesh( geo, new THREE.MeshFaceMaterial( materials ) );
scene.add(newmesh);
Basically, that gives me an error that says:
Uncaught TypeError: Cannot read property 'visible' of undefined
every time my render function is called.
Where did I go wrong?
You are merging geometries into one, and using MeshFaceMaterial (renamed MultiMaterial in r.72).
It does not make any sense to merge geometries having different material indices.
WebGLRenderer needs to segment the geometry by material to render it.
As a rule-of-thumb, only merge geometries if they will be rendered with a single material.
three.js r.72