Extruded spline (THREE.SceneUtils.createMultiMaterialObject) not responding to Three.Ray - three.js

I have a page using elements from the extruded spline example and the mouse tooltip example. Trying to debug the starting elements of this projects before moving on. The mouse tooltip is working on a variety of objects except for the extruded spline.
Using webGL renderer, if that matters.
Code for spline creation (not including Vector3 lines or circular extrude):
function addGeometry( geometry, color, x, y, z, rx, ry, rz, s, name ) {
var mesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [
new THREE.MeshLambertMaterial( { color: color } )
] );
mesh.position.set( x, y, z );
mesh.scale.set( s, s, s );
mesh.name = name;
scene.add( mesh );
}
The intersect/Three.Ray code in update() is the same as the example linked above. I also tried adding the spline to a parent but still no changes onMouseOver. Later this week I might transition over to ThreeX DOM events and Tween :D
Mini issue which could be separate questions:
Witnessing some inaccuracy in Ray-linked OnMouseOver events on planes. It could also be the fact I'm using large distances? Planes are 1000x1000 and camera is 2000px away. I know that's ridiculous and I'm in the process of fixing that as well.
Thanks for listening!

Since you have only provided code snippets, here is a guess: Because a Multi-material object is hierarchical, you need to set the recursive flag in ray.intersectObjects() to true like so:
var intersects = ray.intersectObjects( scene.children, true );

Related

Three.js - How to Rotate Shader Material?

My problem is trying to get the sky to rotate on its z-axis. For example if I rotate the sky by 180 degrees the shadow from the sun light should display in the opposite direction.
The code sandbox: https://codesandbox.io/s/friendly-cloud-c00zr?file=/src/main.js:
This is where I create the sky in the main.js file:
const createSky = () => {
const sky = new Sky();
sky.scale.setScalar(1000);
sky.castShadow = true;
return sky;
};
I’ve tried rotateZ and sky.rotation to no avail.
The code in the sky.js file:
https://codesandbox.io/s/little-microservice-7nh53?file=/src/sky.js
is a modified iteration of the original three.js sky-sun-shader:
https://threejs.org/examples/webgl_shaders_sky.html
All that I have changed is the up position of the sky and its geometry from boxBuffer to sphereBuffer.
I would post the code here but it but it's over 200 lines of code.
I am wondering if there is a special way to rotate this ShaderMaterial in sky.js?
sky.material.uniforms.sunPosition.value.copy( light.position ); It looks like you can use this line to have the sun move from east to west.
Here the east-west is on the x axis and north-south is on z;
let sunPivot = new THREE.Object3D();
//add the light to the pivot at an offset off 100 units( can be changed );
light.positions.set( -100, 0, 0);
sunPivot.add( light );
in the render loop:
sunPivot.rotateZ( 0.005 ); //arbitrary rotation speed
light.getWorldPosition( sky.material.uniforms.sunPosition.value ); //the uniform value as target (puts the world position of the light into the sunPosition.value

Why do Camera and Object3D look opposite directions?

I have a basic question, but I could not find the answer.
I noticed that the following code:
const p = new THREE.Vector3();
const q = new THREE.Quaternion();
const s = new THREE.Vector3();
function setPositionAndRotation(o) {
o.position.set(1, 1, -1);
o.lookAt(0, 0, 0);
o.updateMatrix();
o.matrix.decompose(p, q, s);
console.log(JSON.stringify(q));
}
const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, .01, 1000);
var mesh = new THREE.Mesh(new THREE.Geometry(), new THREE.MeshBasicMaterial());
setPositionAndRotation(camera);
setPositionAndRotation(mesh);
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script>
produces different quaternions for Camera and Object3D:
{"_x":-0.11591689595929515,"_y":0.8804762392171493,"_z":0.27984814233312133,"_w":0.36470519963100095}
{"_x":0.27984814233312133,"_y":-0.3647051996310009,"_z":0.11591689595929516,"_w":
(These are two quaternions pointing into opposite directions on Z axis.)
The problems lies in the bahavior of the lookAt function. I dug into source code of Object3d and I found this if
https://github.com/mrdoob/three.js/blob/master/src/core/Object3D.js#L331
if ( this.isCamera ) {
m1.lookAt( position, target, this.up );
} else {
m1.lookAt( target, position, this.up );
}
As you can see Object3D is handled differently than Camera. target and position are swapped.
Object3D's documentation says:
lookAt ( x : Float, y : Float, z : Float ) : null
Rotates the object to face a point in world space.
but the code does the opposite. It uses Matrix4's lookAt function
lookAt ( eye : Vector3, center : Vector3, up : Vector3, ) : this
Constructs a rotation matrix, looking from eye towards center oriented by the up vector.
putting target into eye, and position into center.
I can deal with that, but it is weird. Is there anybody able to explain why it is so?
r.97
In three.js, an unrotated object is considered to face its local positive-z axis.
The exception is a camera, which faces its local negative-z axis.
This design decision followed OpenGL convention.

How to setup a camera that follows a circle path?

I'm trying to create a camera that follows an object that rotates on a orbit around a sphere. But everytime the camera reaches the polar coordinates of the orbit, the direction changes. I just set the position of the camera according to the object that is has to follow and calling lookAt afterwards:
function render() {
rotation += 0.002;
// set the marker position
pt = path.getPoint( t );
// set the marker position
marker.position.set( pt.x, pt.y, pt.z );
marker.lookAt( new THREE.Vector3(0,0,0) );
// rotate the mesh that illustrates the orbit
mesh.rotation.y = rotation
// set the camera position
var cameraPt = cameraPath.getPoint( t );
camera.position.set( cameraPt.x, cameraPt.y, cameraPt.z );
camera.lookAt( marker.position );
t = (t >= 1) ? 0 : t += 0.002;
renderer.render( scene, camera );
}
Here's a complete fiddle: http://jsfiddle.net/krw8nwLn/69/
I've created another fiddle with a second cube which represents the desired camera behaviour: http://jsfiddle.net/krw8nwLn/70/
What happens is that the camera's lookAt function will always try to align the camera with the horizontal plane (so that the "up" direction is always (0, 1, 0). And when you reach the top and bottom of the ellipse path, the camera will instantaneously rotate 180° so that up is still up. You can also see this in your "desired behaviour" example, as the camera cube rotates so that the colors on the other side are shown.
A solution is to not use lookAt for this case, because it does not support cameras doing flips like this. Instead set the camera's rotation vector directly. (Which requires some math, but you look like a math guy.)

Unexpected mesh results from ThreeCSG boolean operation

I am creating a scene & have used a boolean function to cut out holes in my wall. However the lighting reveals that the resultant shapes have messed up faces. I want the surface to look like one solid piece, rather than fragmented and displaying lighting backwards. Does anyone know what could be going wrong with my geometry?
The code that booleans objects is as follows:
//boolean subtract two shapes, convert meshes to bsps, subtract, then convert back to mesh
var booleanSubtract = function (Mesh1, Mesh2, material) {
//Mesh1 conversion
var mesh1BSP = new ThreeBSP( Mesh1 );
//Mesh2 conversion
var mesh2BSP = new ThreeBSP( Mesh2 );
var subtract_bsp = mesh1BSP.subtract( mesh2BSP );
var result = subtract_bsp.toMesh( material );
result.geometry.computeVertexNormals();
return result;
};
I have two lights in the scene:
var light = new THREE.DirectionalLight( 0xffffff, 0.75 );
light.position.set( 0, 0, 1 );
scene.add( light );
//create a point light
var pointLight = new THREE.PointLight(0xFFFFFF);
// set its position
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
// add to the scene
scene.add(pointLight);
EDIT: Using WestLangley's suggestion, I was able to partially fix the wall rendering. And by using material.wireframe=true; I can see that after the boolean operation my wall faces are not merged. Is there a way to merge them?
Your problems are due to two issues.
First, you should be using FlatShading.
Second, as explained in this stackoverflow post, MeshLambert material only calculates the lighting at each vertex, and interpolates the color across each face. MeshPhongMaterial calculates the color at each texel.
You need to use MeshPhongMaterial to avoid the lighting artifacts you are seeing.
three.js r.68

Inconsistent alpha channel in three.js

I'm building an educational tool using planes, extruded splines, and cylinder geometries. Planes have a texture map and the rest are either basic or Lambert materials.
Texture map on planes in the only map and it does have an alpha
channel.
Texture map has been tested as .GIF and .PNG
All objects have "transparent: true"
renderer = new THREE.WebGLRenderer( {antialias:true} );
NOTE: this is the exact same problem listed at the following link. It has not been solved and my Rep isn't high enough to comment.
in three.js, alpha channel works inconsistently
As mmaclaurin noted, it could be a change based in draw order and camera location. I am using THREE.TrackballControls and limiting camera movement to two axes.
Adding or removing the BasicMaterial for wireframe does not change the issue.
Thank you for your time reading this and any help you can offer!
Example of plane object:
var T4map = new THREE.ImageUtils.loadTexture( 'medium_T4.png' );
var T4Material = new THREE.MeshBasicMaterial( { opacity: .96, transparent:true, map: T4map } );
var T4Geometry = new THREE.PlaneGeometry(810, 699, 10, 10);
var T4 = new THREE.Mesh(T4Geometry, T4Material);
T4.position.y = -CNspacing;
T4.doubleSided = true;
scene.add(T4);
Example of extruded spline geometry where problem is most noticeable:
var mesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [
new THREE.MeshLambertMaterial( { color: 0xaaff00, opacity: 0.5, transparent: true } ),
mesh.position.set( x, y, z );
mesh.scale.set( s, s, s );
parent.add( mesh );
Try to play around with depthTest. Usually this would help:
new THREE.MeshBasicMaterial( { side:THREE.BackSide,map:texture,transparency:true, opacity:0.9, depthWrite: false, depthTest: false });
There are many other questions related to your subject, for ex.: transparent bug
Was just going to comment but its too long:
Objects that are marked with transparent = true, are painters sorted based on their centroid, and drawn back to front so that the transparency layers mostly correctly. Make sure your mesh.geometries have proper computeBoundingBox() and computeBoundingSphere() applied to them before adding them... if that doesn't fix your problem, then try using material.alphaTest = 0.5 on your materials.. this works well for things that are mostly on/off alpha.. like masks... but if you have smooth gradations of transparency from 0 to 1 in your textures, you may see fringes where the alpha test threshholding happens.

Resources