Add edge line to 3D object with Three.js - three.js

I am trying to add the edge lines to the 3D object with Three.js. Here is the object loaded:
Here is the code I used to draw the edges:
// geometry is the object loaded from remote server
const edgeGeometry = new EdgesGeometry( geometry );
const edgeMaterial = new LineBasicMaterial( { color: 0x333333, linewidth: 0.5 } );
const edgeWireframe = new LineSegments( edgeGeometry, edgeMaterial );
scene.add(edgeWireframe );
The result is like this:
This the goal I am trying to achieve:
Only the edges have the lines. The question is: How can I draw the edge lines without these lines on the curve surfaces? Thank you for your time.

Related

Move Threejs mesh to the center of another mesh

I have the following structure in my scene (imported from glb):
I try to move the mesh svgGroupsvg_test to the center of mesh named M_Top (red cross is the expected location).
Here is my code:
function engraveSVG(object, value) {
//object is the name of the target mesh
var svgMeshName = 'svgGroup' + value
loadSVGandFit(svgMeshName, object, value).then(res => {
var svgMesh = scene.getObjectByName(svgMeshName);
svgMesh.scale.set(0.1, 0.1, 1)
const axesHelper = new THREE.AxesHelper( 20 );
svgMesh.parent.add(axesHelper)
moveCenterMeshToOtherMeshCenter(svgMesh, scene.getObjectByName(object))
})
}
I tried the following functions:
function moveCenterMeshToOtherMeshCenter(centerMesh, otherMesh) {
// get the center positions of both meshes in the local world
const centerMeshPosition = new THREE.Vector3();
const otherMeshPosition = new THREE.Vector3();
centerMesh.getWorldPosition(centerMeshPosition);
otherMesh.getWorldPosition(otherMeshPosition);
// calculate the difference between the center positions of both meshes
const difference = otherMeshPosition.sub(centerMeshPosition);
// translate the center mesh by the difference
centerMesh.translateX(difference.x);
centerMesh.translateY(difference.y);
centerMesh.translateZ(difference.z);
}
function moveCenterToOther(centerMesh, otherMesh) {
const centerBox = new THREE.Box3().setFromObject(centerMesh);
const otherBox = new THREE.Box3().setFromObject(otherMesh);
const centerPosition = centerBox.getCenter(new THREE.Vector3());
const otherPosition = otherBox.getCenter(new THREE.Vector3());
const offset = new THREE.Vector3().subVectors(otherPosition, centerPosition);
centerMesh.position.add(offset);
}
Is there something wrong ? Get center return a value around 0.
I chose to add the svg mesh in the same group of my target mesh. But it changes nothing.
The axes is also in the local coordinate.
Any help would be very appreciate.
I found a solution. I add my SVG in the root of the scene. I am now able to get the correct bounding box size and center in the world coordinates.

ThreeJs add Texture to a GLTF object surface

I am trying to apply an image dynamically on a gltf loaded mesh.
The code to load the model looks like:
const gltfLoader = new GLTFLoader();
const url = 'resources/models/mesh.gltf';
gltfLoader.load(url, (gltf) => {
const root = gltf.scene;
scene.add(root);
})
When looking from top the element looks like a rounded rect:
When inspecting the imported mesh I can see that the BufferGeometry has a count of 18.000 points:
Everything works fine however if I apply the texture like this:
const texture = new THREE.TextureLoader().load( 'textures/land_ocean_ice_cloud_2048.jpg' );
const material = new THREE.MeshBasicMaterial( { map: texture } );
root.children[0].material = material;
The image is not visible but the mesh is now colored in 1 color.
Is it possible to apply the image just on the top face of the rect?
Hard to tell what the problem is without seeing the resulting image. However, I would just assign a new texture like this: root.children[0].material.map = texture instead of creating a whole new material, since you don't want to lose all the material attributes that came in the GLTF.
Additionally, MeshBasicMaterial always looks flat because it is not affected by lights.

Three.js: Add a texture to an object just on the outside

I'm very new with Three.js and I'm trying to make a ring:
http://www.websuvius.it/atma/myring/preview.html
I have a background texture ( the silver one ) and another one with a text.
I want the text only on the ring external face.
This is part of my code:
var loader = new THREE.OBJLoader( manager );
var textureLoader = new THREE.TextureLoader( manager );
loader.load( 'assets/3d/ring.obj', function ( event ) {
var object = event;
var geometry = object.children[ 0 ].geometry;
var materials = [];
var backgroundTexture = textureLoader.load('img/texture/silver.jpg');
backgroundTexture.flipY = false;
var background = new THREE.MeshBasicMaterial({
map: backgroundTexture,
color: 0xffffff
});
materials.push(background);
var customTexture = textureLoader.load('img/text.png');
customTexture.flipY = false;
var custom = new THREE.MeshBasicMaterial({
map: customTexture,
transparent: true,
opacity: 1,
color: 0xffffff
});
materials.push(custom);
mesh = THREE.SceneUtils.createMultiMaterialObject(geometry, materials);
mesh.position.y=-50;
scene.add(mesh);
}, onProgress, onError );
It is possible?
Thanks
The reason behind your issue appears to be in your .obj file. Judging from a quick glance at the texture coordinates stored in the file, the inside of the ring uses the same part of the texture image as the outside of the ring.
Increasing the transparent parts of the image won't help. Neither will the attempts to stop the texture from repeating. Those would help if the texture coordinates were larger than 1 but this is not your case unfortunately.
However, there are several solutions:
Split the object in a 3D modeling software to two objects - outside and inside of the ring - and apply the texture only to the first one.
Adjust the UV coordinates of the object in a 3D modeling software.
Adjust the UV coordinates of the vertices programmatically after loading the object to Three.JS

Threejs Raycasting a Sprite-Canvas Object is inaccurate [duplicate]

I am trying to use THREE.Raycaster to show an html label when the user hover an object. It works fine if I use THREE.Mesh but with THREE.Sprite it looks like that there is a space that increases with the scale of the object.
The creation process is the same for both scenario, I only change the type based on USE_SPRITE variable.
if ( USE_SPRITE ) {
// using SpriteMaterial / Sprite
m = new THREE.SpriteMaterial( { color: 0xff0000 } );
o = new THREE.Sprite( m );
} else {
// using MeshBasicMaterial / Material
m = new THREE.MeshBasicMaterial( { color: 0xff0000 } );
o = new THREE.Mesh(new THREE.PlaneGeometry( 1, 1, 1 ), m );
}
https://plnkr.co/edit/J0HHFMpDB5INYLSCTWHG?p=preview
I am not sure if it is a bug with THREE.Sprite or if I am doing something wrong.
Thanks in advance.
three.js r73
I would consider this a bug in three.js r.75.
Raycasting with meshes in three.js is exact. However, with sprites, it is an approximation.
Sprites always face the camera, can have different x-scale and y-scale applied (be non-square), and can be rotated (sprite.material.rotation = Math.random()).
In THREE.Sprite.prototype.raycast(), make this change:
var guessSizeSq = this.scale.x * this.scale.y / 4;
That should work much better for square sprites. The corners of the sprite will be missed, as the sprite is treated as a disk.
three.js r.75

3d object that looks the same from every direction

have a 3d maze with walls and floor.
have an image with a key ( or other object its not important, but all of em are images and not 3d models ).
I want to display it on the floor and if the camera moves around the object needs to look the same without rotating the object. How can i achieve this?
Update1:
I created a plane geometry added the image ( its a transparent png ) and rotating at render. Its working good, but if i turn the camera sometimes the plane lose transparency for about a few milisec and the get a solid black background ( blinking ).
Any idea why?
here is the code:
var texture = new THREE.ImageUtils.loadTexture('assets/images/sign.png');
var material = new THREE.MeshBasicMaterial( {map: texture, transparent: true} );
plane = new THREE.Mesh(new THREE.PlaneGeometry(115, 115,1,1), material );
plane.position.set(500, 0, 1500);
scene.add(plane);
// at render:
plane.rotation.copy( camera.rotation );
This will be achieved by using:
function animate() {
not3dObject.rotation.z = camera.rotation.z;
not3dObject.rotation.x = camera.rotation.x;
not3dObject.rotation.y = camera.rotation.y;
...
render();
}

Resources