Is it possible to load multiple textures on a sphere?
I mean to say is there any way in Three.js to split a sphere into n pieces , texture them separately and render those pieces once again as a whole sphere?
I do not want to load the entire texture on the sphere, instead, only those parts are to be rendered which the user will first see on the screen and as the user rotates the sphere the rest part of the texture must be loaded.
Moreover, when I use a single image on a sphere it seems to converge at poles making it worse.
This should help: https://open.bekk.no/procedural-planet-in-webgl-and-three-js
Instead of using a sphere try using a cube and expanding it into a sphere. Cube logic on the cube sphere will save you a good amount of time.
var geometry = new THREE.BoxGeometry( 1, 1, 1, 8, 8, 8 );
for ( var i in geometry.vertices ) {
var vertex = geometry.vertices[ i ];
vertex.normalize().multiplyScalar(radius);
}
var materialArray = [];
var faceMaterial = new THREE.MeshLambertMaterial({
color: sphereColor,
transparent: true,
opacity: 0.4
});
for (var i = 0; i < 6; i++) {
materialArray.push(faceMaterial);
}
var material = new THREE.MeshFaceMaterial(materialArray);
var sphere = new THREE.Mesh( geometry, material );
scene.add( sphere );
Related
I am working on a project that want to move small objects and show them in a 360 image using ThreeJS library. So I am using Spherical coordinate system in a sphere with some radius to move the objects. User starts seeing the app in the center of the sphere. I want to show some grid helper lines on the sphere ( very similar to longitude and latitude lines). I found the following code from here in the library:
var radius = 10;
var radials = 16;
var circles = 8;
var divisions = 64;
var helper = new THREE.PolarGridHelper( radius, radials, circles, divisions );
scene.add( helper );
But it only adds a polar plate with some circles not a sphere shape grid helper to the scene.
PolarGridHelper is a flat circle. If you want a spherical geometry just use SphereBufferGeometry and give it a wireframe look:
var radius = 10;
var latSegments = 18; // 10° increments
var longSegments = 36; // 10° increments
var geometry = new THREE.SphereBufferGeometry( radius, longSegments, latSegments);
var material = new THREE.MeshBasicMaterial({
color: 0xffffff,
wireframe: true
});
var sphere = new THREE.Mesh( geometry, material );
scene.add( sphere );
I'm currently loading an STL onject into my three.js scene.
For some reason, it takes a lot of GPU resources to render/animate, slowing the entire scene down so I've been considering alternatives.
As it's quite a simple shape, I thought I could use create the 2D shape and extrude it.
The 3D shape is a square frame (it's a photo frame), no curves or any other clever geometry.
Initially, I thought about creating 4x 3D oblongs, rotating each one by 90 degrees and placing them just right in the scene to make it look like a frame - but that's not ideal.
So as an alternative to loading the STL model into the scene, how can I create this shape in three.js (with empty space in the centre) and then extrude it to give it some depth?
Basic extrusion example: Shape -> ExtrudeGeometry -> Mesh
const { renderer, scene, camera } = initThree();
//Create a frame shape..
var frame = new THREE.Shape();
frame.moveTo(-4, -3);
frame.lineTo( 4, -3);
frame.lineTo( 4, 3);
frame.lineTo(-4, 3);
//..with a hole:
var hole = new THREE.Path();
hole.moveTo(-3, -2);
hole.lineTo( 3, -2);
hole.lineTo( 3, 2);
hole.lineTo(-3, 2);
frame.holes.push(hole);
//Extrude the shape into a geometry, and create a mesh from it:
var extrudeSettings = {
steps: 1,
depth: 1,
bevelEnabled: false,
};
var geom = new THREE.ExtrudeGeometry(frame, extrudeSettings);
var mesh = new THREE.Mesh(geom, new THREE.MeshPhongMaterial({ color: 0xffaaaa }));
scene.add(mesh);
renderer.render(scene, camera);
body {
margin: 0;
overflow: hidden;
}
canvas {
display: block;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/three.js/102/three.min.js"></script>
<script src="//cdn.rawgit.com/Sphinxxxx/298702f070e34a5df30326cd9943260a/raw/16afc701da1ed8ed267a896907692d8acdce9b7d/init-three.js"></script>
I'm working on a problem with three.js and ExtrudeGeometry.
I do have a wave-like structure which is made from several individual frames. Each of them is extruded using ExtrudeGeometry.
I'd like to apply a texture to each frame of the structure which is "wrapped around" the structure. For some reason (possibly wrong UV-mapping?) the texture does not display correctly on the extruded edges where the wave-like surface is out of level. (There are some tiny sections in the picture where the texture wraps correctly). I'm using the following script to apply the textures:
// create some simple Geometry
var shape = new THREE.Shape();
shape.moveTo( 0,0 );
shape.lineTo( 0,10 );
shape.lineTo( 100,7 );
shape.lineTo( 100,0 );
var extrudeSettings = {
steps: 2,
amount: 10,
bevelEnabled: false,
bevelThickness: 0,
bevelSize: 0,
bevelSegments: 0
};
var geometry = new THREE.ExtrudeGeometry( shape, extrudeSettings );
var texture = new THREE.Texture( image );
texture.wrapS = THREE.ClampToEdgeWrapping;
texture.wrapT = THREE.ClampToEdgeWrapping;
texture.repeat.set( 0.1, 0.1 );
var material = new THREE.MeshBasicMaterial( {map: texture} );
var mesh = new THREE.Mesh( geometry, material ) ;
scene.add( mesh );
Every help is much appreciated! Cheers!
Edit:
I've created this image to better illustrate the problem. White Arrows show, how the texture is supposed to wrap around the object. At some very rare spots it actually does!
Have a look at this example
https://threejs.org/examples/?q=geome#webgl_geometry_shapes
at row 70 there is a comment that states that texture.repeat must be set to (0.008, 0.008)
I have a ribbon that displays a few thumbnails. Just to give a background, the thumbnail images are painted on a canvas, which is then added to Texture.
var texture = new THREE.Texture(textureCanvas);
The mesh is created as follows
loader.load('mesh_blender.js', function(geom) {
var mesh = new THREE.Mesh(geom, new THREE.MeshLambertMaterial({
color: 0xffffffff,
opacity: 0.7,
overdraw: 0.21,
side: THREE.DoubleSide,
transparent: true,
//shading: THREE.SmoothShading,
map: texture
}));
Everything till here is fine. The ribbon is created as follows
I have no complaints with this. But I need this additional effect you see in the image below. As it can be seen, the thumbnail that is in the centre (focus) needs to have a darker effect to show it is being highlighted/selectable. All the remaining thumbnails have a transparent effect depicting they are not selectable.
I am trying to wrap my head around this using Lights in Threejs but not very successful. I thought of using an AmbientLight to throw light on the entire ribbon and then an additional SpotLight only on the centre image (with a darker color maybe) to achieve the desired effect. But that didn't work. I have got something like this
But the centre focused image has no effect. As you can see in the image, I have used a helper to show the Light direction but I can't really see any light on the image. This is the code I use to develop that SpotLight
var spotLight = new THREE.SpotLight( 0xffeedd );
spotLight.position.set( 0, -50, 50 );
spotLight.castShadow = true;
//spotLight.penumbra = 0.2;
spotLight.decay = 2;
spotLight.distance = 300;
spotLight.angle = 0.5;
var helper = new THREE.SpotLightHelper( spotLight, 2.5 );
scene.add(helper);
scene.add( spotLight );
I am very new to Threejs and 3d graphics. Any help will be appreciated. Thanks.I am open to any other suggestion as well, if Lights are not to be used to achieve the end result.
You have given the opacity of the material as 0.7 so adding another light will not exactly give you the expected result. I would suggest using a raycaster to identify the object in the center and making the opacity of that object as 1 and the rest as 0.7.
var intersects = raycaster.intersectObjects( objects );
use this to get the objects that are intersecting in an array. And in the renderer function set the opacity of the first element in the array that is the object in the middle to 1. This only works if the thumbnails are all separate objects.
//set as the center of you vision
var mouse = new THREE.Vector2();
mouse.x = 0;
mouse.y = 0;
function highlightObject() {
// update the picking ray with the camera and mouse position
raycaster.setFromCamera( mouse, camera );
// calculate objects intersecting the picking ray
var intersects = raycaster.intersectObjects( scene.children );
//sets the object in the center opacity = 0.2
if(intersects.length > 0) {
intersects[0].object.material.opacity = 0.2;
}
//sets the opacity of the rest of the objects in scene to opacity = 1.0
for (var i = scene.children.length - 1; i >= 0; i--) {
var obj = scene.children[i];
obj.material.opacity = 1.0;
}
}
I want to make parts of a mesh invisible at runtime. Can I set these parts invisible/transparent, e.g. by changing attributes of single faces? The mesh itself uses only one material.
Exemplary illustration as the editor understands this question: Imagine a mesh (here with a geometry of 20 vertices) where each quad of four vertices builds up a Face4. Now, some parts of the mesh should be made invisible (here two faces are invisible).
Note: This answer applies to legacy versions of three.js
You can assign a different material to each face. Here is an example where the faces share a material, but some faces are transparent:
// geometry
var geometry = new THREE.BoxGeometry( 100, 100, 100, 4, 4, 4 );
// materials
materials = [
new THREE.MeshLambertMaterial( { color: 0xffff00, side: THREE.DoubleSide } ),
new THREE.MeshBasicMaterial( { transparent: true, opacity: 0 } )
];
// assign material to each face
for( var i = 0; i < geometry.faces.length; i++ ) {
geometry.faces[ i ].materialIndex = THREE.Math.randInt( 0, 1 );
}
geometry.sortFacesByMaterialIndex(); // optional, to reduce draw calls
// mesh
mesh = new THREE.Mesh( geometry, materials );
scene.add( mesh );
three.js r.87