THREE.js Where does Line intersect mesh - three.js

I've got a Mesh myMesh:
const vertices = new Float32Array( [
0, 1, 0, 0, 1, 2, 2, 1, 2,
0, 1, 0, 2, 1, 2, 2, 1, 0
]);
const myGeometry = new THREE.BufferGeometry();
myGeometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
const myMesh = new THREE.Mesh(myGeometry, new THREE.MeshBasicMaterial({color: 0x00ff00, side: THREE.DoubleSide}));
scene.add(myMesh);
and a line myLine:
var material = new THREE.LineBasicMaterial( { color: "#0000ff"});
var geometry = new THREE.BufferGeometry();
const lineVerts = new Float32Array([ 1, 0, 1, 1, 2, 1]);
geometry.setAttribute('position', new THREE.BufferAttribute(lineVerts, 3));
var myLine = new THREE.Line( geometry, material );
scene.add(myLine);
jsfiddle
I'd like to get the point where the line and the mesh intersect with each other. Is this possible?
function getIntersection(mesh, line) {
// get point where they intersect (if they do so)
return point
}

Thank you for the provided link #WestLangley
Maybe the solution can help others with the same problem:
Create a normalized Vector between the Points of the line
Iterate each face (triangle) of the mesh
Check with .intersectTriangle of THREE.Ray if the line intersects the face
var v1 = new THREE.Vector3(0.5,0,1);
var v2 = new THREE.Vector3(0.5, 2, 1);
var dir = new THREE.Vector3();
dir.subVectors( v2, v1 ).normalize();
dir.normalize();
var ray = new THREE.Ray(v1, dir);
for (var i = 0; i < vertices.length; i+=9) {
var a = new THREE.Vector3(vertices[i], vertices[i+1], vertices[i+2]);
var b = new THREE.Vector3(vertices[i+3], vertices[i+4], vertices[i+5]);
var c = new THREE.Vector3(vertices[i+6], vertices[i+7], vertices[i+8]);
var target = new THREE.Vector3();
ray.intersectTriangle(a, b, c, false, target);
console.log(target);
}
jsfiddle

Related

How to work with colors / textures with buffergeometry three.js

I have a Model that has a texture and a solid color using MeshFaceMaterials, But i read that BufferGeometry faces materials its not supported.
What options are there for keeping some parts of the model differnt colors or texture for each instance.
I have been following this example, wiht instancing selected.
https://threejs.org/examples/#webgl_interactive_instances_gpu
I would be more then happy if my Track model could have 2 parts of it be solid black and 4 parts of it solid brown. But at the moment the only way i see to do that is to create two sets of instance and rip my model apart into two models.
Edited After reading reply
I think i mispoke I current have in array of MeshLambertMaterial called materials
function makeInstanced(geo, materials) {
// var vert = document.getElementById( 'vertInstanced' ).textContent;
// var frag = document.getElementById( 'fragInstanced' ).textContent;
//var material = new THREE.RawShaderMaterial({
// vertexShader: vert,
// fragmentShader: frag,
//});
var material = new THREE.MultiMaterial(materials);
var bgeo = new THREE.BufferGeometry().fromGeometry(geo);
geometryList.push(bgeo);
var mcol0 = new THREE.InstancedBufferAttribute(
new Float32Array(instanceCount * 3), 3, 1
);
var mcol1 = new THREE.InstancedBufferAttribute(
new Float32Array(instanceCount * 3), 3, 1
);
var mcol2 = new THREE.InstancedBufferAttribute(
new Float32Array(instanceCount * 3), 3, 1
);
var mcol3 = new THREE.InstancedBufferAttribute(
new Float32Array(instanceCount * 3), 3, 1
);
var igeo = new THREE.InstancedBufferGeometry();
geometryList.push(igeo);
igeo.addAttribute('mcol0', mcol0);
igeo.addAttribute('mcol1', mcol1);
igeo.addAttribute('mcol2', mcol2);
igeo.addAttribute('mcol3', mcol3)
var vertices = bgeo.attributes.position.clone();
igeo.addAttribute('position', vertices);
// var matrices = new THREE.InstancedBufferAttribute(
// new Float32Array( instanceCount * 16 ), 16, 1
// );
var matrix = new THREE.Matrix4();
var me = matrix.elements;
for (var i = 0, ul = mcol0.count; i < ul; i++) {
//Height Width X, Y, Z, ALPHA
randomizeMatrix(matrix);
//Create Object
var object = new THREE.Object3D();
objectCount++;
object.applyMatrix(matrix);
//Add Object To Matrix
mcol0.setXYZ(i, me[0], me[1], me[2]);
mcol1.setXYZ(i, me[4], me[5], me[6]);
mcol2.setXYZ(i, me[8], me[9], me[10]);
mcol3.setXYZ(i, me[12], me[13], me[14]);
}
var mesh = new THREE.Mesh(igeo, materials);
scene.add(mesh);
}

Vertically repeat texture on side faces only

I have a geometry of a cube that I need to texture,
In the top of the cube - need to be one image
And in each side of the cube - need to be a second image that vertically repeat based on the cube height
This is the texture:
This is what I need:
And this is what I have so far: three.js/texture1
Any ideas how to achieve what I need, but stay with one material and a few faces as possible?
Thanks.
My code:
function create_geometry() {
var geometry = new THREE.Geometry();
var w = 0.5;
var h = 1;
geometry.vertices.push(
new THREE.Vector3(w, h, w),
new THREE.Vector3(w, h, -w),
new THREE.Vector3(w, 0, w),
new THREE.Vector3(w, 0, -w),
new THREE.Vector3(-w, h, -w),
new THREE.Vector3(-w, h, w),
new THREE.Vector3(-w, 0, -w),
new THREE.Vector3(-w, 0, w)
);
geometry.faces.push(
// wall
new THREE.Face3(0, 2, 1),
new THREE.Face3(2, 3, 1),
// wall
new THREE.Face3(4, 6, 5),
new THREE.Face3(6, 7, 5),
// wall
new THREE.Face3(5, 7, 0),
new THREE.Face3(7, 2, 0),
// wall
new THREE.Face3(1, 3, 4),
new THREE.Face3(3, 6, 4),
//roof
new THREE.Face3(4, 5, 1),
new THREE.Face3(5, 0, 1),
);
geometry.computeFaceNormals();
geometry.faceVertexUvs[0] = [];
geometry.faces[0].materialIndex = 0;
geometry.faces[1].materialIndex = 0;
geometry.faces[2].materialIndex = 0;
geometry.faces[3].materialIndex = 0;
geometry.faces[4].materialIndex = 0;
geometry.faces[5].materialIndex = 0;
geometry.faces[6].materialIndex = 0;
geometry.faces[7].materialIndex = 0;
geometry.faces[8].materialIndex = 0;
geometry.faces[9].materialIndex = 0;
var roof = [
new THREE.Vector2(0.0,1.0),
new THREE.Vector2(0.0,0.5),
new THREE.Vector2(1.0,0.5),
new THREE.Vector2(1.0,1.0),
];
var wall = [
new THREE.Vector2(0.0,0.5),
new THREE.Vector2(0.0,0.0),
new THREE.Vector2(1.0,0.0),
new THREE.Vector2(1.0,0.5),
];
// wall
geometry.faceVertexUvs[0][0] = [ wall[0], wall[1], wall[3] ];
geometry.faceVertexUvs[0][1] = [ wall[1], wall[2], wall[3] ];
// wall
geometry.faceVertexUvs[0][2] = [ wall[0], wall[1], wall[3] ];
geometry.faceVertexUvs[0][3] = [ wall[1], wall[2], wall[3] ];
// wall
geometry.faceVertexUvs[0][4] = [ wall[0], wall[1], wall[3] ];
geometry.faceVertexUvs[0][5] = [ wall[1], wall[2], wall[3] ];
// wall
geometry.faceVertexUvs[0][6] = [ wall[0], wall[1], wall[3] ];
geometry.faceVertexUvs[0][7] = [ wall[1], wall[2], wall[3] ];
// roof
geometry.faceVertexUvs[0][8] = [ roof[0], roof[1], roof[3] ];
geometry.faceVertexUvs[0][9] = [ roof[1], roof[2], roof[3] ];
var matrix = new THREE.Matrix4();
//matrix.makeRotationX ( (270 * Math.PI)/180 );
geometry.applyMatrix( matrix );
geometry.uvsNeedUpdate = true;
return geometry;
}
var renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(800,800);
var container = document.getElementById("container");
container.appendChild(renderer.domElement);
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(45,800/800,1,1000);
camera.position.set(0,10,20);
scene.add(camera);
var controls = new THREE.TrackballControls( camera, renderer.domElement );
controls.minDistance = 15;
controls.maxDistance = 100;
var stats = new Stats();
container.appendChild( stats.dom );
var rendererStats = new THREEx.RendererStats();
rendererStats.domElement.style.position = 'absolute';
rendererStats.domElement.style.right = '0px';
rendererStats.domElement.style.top = '0px';
document.body.appendChild( rendererStats.domElement );
// plane
var plane = new THREE.Mesh(
new THREE.PlaneGeometry( 80, 80, 1 ),
new THREE.MeshBasicMaterial( {color: 0x333333, side: THREE.DoubleSide} )
);
plane.rotation.x = (90 * Math.PI)/180;
scene.add(plane);
//
var geometry = create_geometry();
var texture = new THREE.TextureLoader().load( "texture1.png" );
var material = new THREE.MeshBasicMaterial({ map:texture });
for(var i=0; i<10; i++) {
var cube = new THREE.Mesh( geometry, material );
cube.position.x = i*1.5 - 5*1.5;
//cube.position.y = Math.random()*80 - 40;
cube.scale.y = i + 1;
scene.add( cube );
}
function render() {
controls.update();
stats.update();
rendererStats.update(renderer);
renderer.render( scene, camera );
requestAnimationFrame( render );
}
render();

Triangle Strip artifacts

I'm playing with draw groups in THREE.TriangleStripDrawMode draw mode, and I'm seeing some odd artifacts. I think it might be a bug, but I'd like someone else to confirm that I'm not doing something wrong before submitting a report.
In the snippet below, I create 4 squares composed of 4 triangles each. They're all indexed for right-hand rendering. (I realize that triangle strips don't technically need indexing, but I could potentially have complex shapes with re-used vertices.) Their other properties and results are as follows:
Red Square
Two groups: 0-9 and 9-12
Standard front-side rendering
Black artifact on the back-face of triangle index 1
Green Square
One group: 0-12
Standard front-side rendering
Black artifacts on the back-face of triangles index 1 & 3
The same thing happens when I don't use grouping at all
Blue Square
Two groups: 0-9 and 9-12
Double-side rendering
Renders as expected
Yellow Square
One group: 0-12
Double-side rendering
Triangle index 3 renders black on both sides
So did I miss something, or should I submit this as a bug in three.js?
var renderer, scene, camera, controls, stats;
var WIDTH = window.innerWidth,
HEIGHT = window.innerHeight,
FOV = 35,
NEAR = 1,
FAR = 1000;
function createShapes(){
var bg = new THREE.BufferGeometry();
bg.addAttribute("position", new THREE.BufferAttribute(new Float32Array([
-1, 1, 0,
-1, -1, 0,
0, 1, 0,
0, -1, 0,
1, 1, 0,
1, -1, 0
]), 3));
bg.addAttribute("normal", new THREE.BufferAttribute(new Float32Array([
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1,
0, 0, 1
]), 3));
bg.setIndex(new THREE.BufferAttribute(new Uint32Array([
0, 1, 2,
3, 2, 1,
2, 3, 4,
5, 4, 3
]), 1));
var group1 = bg.clone(),
group2 = bg.clone(),
group3 = bg.clone(),
group4 = bg.clone();
/**/
group1.clearGroups();
group1.addGroup(0, 9, 0);
group1.addGroup(9, 3, 0);
group2.clearGroups();
group2.addGroup(0, 12, 0);
group3.clearGroups();
group3.addGroup(0, 9, 0);
group3.addGroup(9, 3, 0);
group4.clearGroups();
group4.addGroup(0, 12, 0);
/**/
var mat1 = new THREE.MeshPhongMaterial({color: "red"}),
mat2 = new THREE.MeshPhongMaterial({color: "green"}),
mat3 = new THREE.MeshPhongMaterial({color: "blue", side: THREE.DoubleSide}),
mat4 = new THREE.MeshPhongMaterial({color: "yellow", side: THREE.DoubleSide});
var m1 = new THREE.Mesh(group1, [mat1]),
m2 = new THREE.Mesh(group2, [mat2]),
m3 = new THREE.Mesh(group3, [mat3]),
m4 = new THREE.Mesh(group4, [mat4]);
m1.drawMode = THREE.TriangleStripDrawMode;
m2.drawMode = THREE.TriangleStripDrawMode;
m3.drawMode = THREE.TriangleStripDrawMode;
m4.drawMode = THREE.TriangleStripDrawMode;
m1.position.set(-2, 2, 0);
m2.position.set(2, 2, 0);
m3.position.set(-2, -2, 0);
m4.position.set(2, -2, 0);
scene.add(m1, m2, m3, m4);
}
function init() {
document.body.style.backgroundColor = "slateGray";
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
document.body.appendChild(renderer.domElement);
document.body.style.overflow = "hidden";
document.body.style.margin = "0";
document.body.style.padding = "0";
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(FOV, WIDTH / HEIGHT, NEAR, FAR);
camera.position.z = 20;
scene.add(camera);
controls = new THREE.TrackballControls(camera, renderer.domElement);
controls.dynamicDampingFactor = 0.5;
controls.rotateSpeed = 3;
var light = new THREE.PointLight(0xffffff, 1, Infinity);
camera.add(light);
stats = new Stats();
stats.domElement.style.position = 'absolute';
stats.domElement.style.top = '0';
document.body.appendChild(stats.domElement);
resize();
window.onresize = resize;
// POPULATE EXAMPLE
createShapes();
animate();
}
function resize() {
WIDTH = window.innerWidth;
HEIGHT = window.innerHeight;
if (renderer && camera && controls) {
renderer.setSize(WIDTH, HEIGHT);
camera.aspect = WIDTH / HEIGHT;
camera.updateProjectionMatrix();
controls.handleResize();
}
}
function render() {
renderer.render(scene, camera);
}
function animate() {
requestAnimationFrame(animate);
render();
controls.update();
stats.update();
}
function threeReady() {
init();
}
(function () {
function addScript(url, callback) {
callback = callback || function () { };
var script = document.createElement("script");
script.addEventListener("load", callback);
script.setAttribute("src", url);
document.head.appendChild(script);
}
addScript("https://threejs.org/build/three.js", function () {
addScript("https://threejs.org/examples/js/controls/TrackballControls.js", function () {
addScript("https://threejs.org/examples/js/libs/stats.min.js", function () {
threeReady();
})
})
})
})();
r86 (the problem has actually been around for a while)
I had an "AHA!" moment while looking at some other examples. My indexing was off, which is also throwing off my grouping.
The indexing should be:
bg.setIndex(new THREE.BufferAttribute(new Uint32Array([
0, 1, 2, 3, 4, 5
]), 1));
Which makes sense, because that's how the triangle strip defines the steps of its vertices.
Then to draw a full square, I needed a single group:
group1.addGroup(0, 6, 0);
Which means start at the group index of 0, for 6 group indices (which covers all of them).
There's still a problem when trying to render an (odd index) individual triangle. Because the winding order for odd triangles is backwards, creating a group that starts with an odd triangle will not be lit correctly (renders black). But that's for another question...

Three.js How to control position of Vector3 value z using DAT.Gui

I am new with three.js and I trying to modify the position value of Z in Vector3 using Dat.Gui. This is my code, but I am not getting any luck.
var zhighpnts = gui.add(parameters, 'x').min(0).max(400).step(.01).name('High Nodes');
zhighpnts.onChange(function(jar){
var a = new THREE.Vector3( 400, jar, 400 );
var b = new THREE.Vector3( 0, 0, 0 );
var c = new THREE.Vector3( -400, jar, -400 );
});
Thanks!
Seems like you're trying to change vertices of a triangle.
Let's create one:
var geom = new THREE.Geometry();
geom.vertices.push(new THREE.Vector3(-10, 0, 0));
geom.vertices.push(new THREE.Vector3(0, 0, 0));
geom.vertices.push(new THREE.Vector3(10, 0, 0));
geom.faces.push(new THREE.Face3(0, 1, 2)); // CCW - it's important
var tri = new THREE.Mesh(geom, new THREE.MeshBasicMaterial({color: "yellow"}));
scene.add(tri);
then we'll set an object of parameters
var parameters = {y:0};
and get vertices of our triangle:
var a = geom.vertices[geom.faces[0].a]; // face's properties a, b, c
var b = geom.vertices[geom.faces[0].b]; // contain just indices of related vertices
var c = geom.vertices[geom.faces[0].c]; // thus we'll find them in array of vertices
the rest is not so difficult, so let's create our controller:
var gui = new dat.GUI(); // create instance of dat.GUI();
gui.add(parameters, "y", 0, 20) // add a controller for 'y' property of 'parameters'
.name("High nodes") // set controller's name
.onChange( // set controller's listener
function(value) {
a.y = value; // we want to change y-value of 'a'
c.y = value; // we want to change y-value of 'c'
}
);
and one more important thing, you have to set
geom.verticesNeedUpdate = true;
in your animation/render loop.
jsfiddle example. I hope it's helpful.

Drawing custom shapes in Babylon.js

I have been searching all over the web for a way to draw custom 3d shapes in babylon.js. I would be grateful if somebody could provide a working example. For instance, a 3d irregular pentagon, triangle fan, or a wedge.
you can find a lot of info about parametric shapes in Babylon.js here:
http://doc.babylonjs.com/page.php?p=24847
And mainly for the ribbon here:
http://doc.babylonjs.com/page.php?p=25088
Here is a wedge using the ribbon object:
var createScene = function() {
var scene = new BABYLON.Scene(engine);
scene.clearColor = new BABYLON.Color3(0.8, 0.8, 0.8);
var camera = new BABYLON.ArcRotateCamera("Camera", 3 *Math.PI / 2, Math.PI / 2, 20, BABYLON.Vector3.Zero(), scene);
camera.attachControl(canvas, false);
// lights
var light = new BABYLON.HemisphericLight("hemi", new BABYLON.Vector3(0, 1, 0), scene);
light.groundColor = new BABYLON.Color3(0.2, 0.2, 0.5);
light.intensity = 0.6;
var light2 = new BABYLON.PointLight("light2", new BABYLON.Vector3(-20, 0, -20), scene);
light2.diffuse = BABYLON.Color3.White();
light2.specular = BABYLON.Color3.Green();
light2.intensity = 0.6;
// material
var mat = new BABYLON.StandardMaterial("mat1", scene);
mat.alpha = 1.0;
mat.diffuseColor = new BABYLON.Color3(0.5, 0.5, 1.0);
//mat.backFaceCulling = false;
mat.wireframe = true;
// tubular ribbon
path1 = [];
path2 = [];
path1.push( new BABYLON.Vector3(0, 0, 0) );
path2.push( new BABYLON.Vector3(0, 2, 0) );
path1.push( new BABYLON.Vector3(1, 0, 0) );
path2.push( new BABYLON.Vector3(1, 2, 0) );
path1.push( new BABYLON.Vector3(0, 0, 1) );
path2.push( new BABYLON.Vector3(0, 2, 1) );
var ribbon = BABYLON.Mesh.CreateRibbon("ribbon", [path1, path2], false, true, 0, scene);
ribbon.material = mat;
scene.registerBeforeRender(function(){
light2.position = camera.position;
});
return scene;};

Resources