I have the latest threecsg.js library and my use of it has been okay, except when I try to use the subdivision modifier after a CSG operation. Here is example code, modified from the example.html file that comes with the library from github:
var start_time = (new Date()).getTime();
var cube_geometry = new THREE.CubeGeometry( 3, 3, 3 );
var cube_mesh = new THREE.Mesh( cube_geometry );
cube_mesh.position.x = -6;
var cube_bsp = new ThreeBSP( cube_mesh );
var sphere_geometry = new THREE.SphereGeometry( 1.8, 12, 12 );
var sphere_mesh = new THREE.Mesh( sphere_geometry );
sphere_mesh.position.x = -7;
sphere_mesh.position.y -= 0;
var sphere_bsp = new ThreeBSP( sphere_mesh );
var subtract_bsp = cube_bsp.union( sphere_bsp );
var result = subtract_bsp.toMesh( new THREE.MeshLambertMaterial({ shading: THREE.SmoothShading, map: THREE.ImageUtils.loadTexture('texture.png') }) );
result.geometry.computeVertexNormals();
var smooth = result.geometry.clone() ;
smooth.mergeVertices();
var modifier = new THREE.SubdivisionModifier(0.1);
modifier.modify( smooth );
var mesh = new THREE.Mesh( smooth, new THREE.MeshPhongMaterial( { wireframe:true, color: 0xffffff } ) );
mesh.geometry.computeFaceNormals();
scene.add( mesh );
The above code unites a sphere and a cube. After this, it runs the resulting geometry through the subdivision modifier. The final output that is added to the scene has faces that are protruding from the object, other than that, the object does look smooth. Can anyone please help in solving this issue, that is, removing the protruding faces?
Related
in Three.js i'm trying to draw a cube with dashed line edges but the lines are still showing as solid. Here's my code:
var mat_line = new THREE.LineDashedMaterial( { color: "black", dashSize: 1, gapSize: 1 } );
var geometry = new THREE.BoxGeometry( 10, 10, 10 );
geometry.computeLineDistances();
var cube = new THREE.Mesh( geometry, mat_cube );
scene.add( cube )
var edges = new THREE.EdgesGeometry( geometry )
var line = new THREE.LineSegments( edges, mat_line )
scene.add( line )
can anyone see where I'm going wrong here? or is it just not possible with this workflow?
You want use LineDashedMaterial with EdgesGeometry.
To use LineDashedMaterial the line must have line distances specified.
Use a pattern like so:
var material = new THREE.LineDashedMaterial( { color: 0xff0000, dashSize: 1, gapSize: 1 } );
var geometry = new THREE.BoxGeometry( 10, 10, 10 );
geometry = new THREE.EdgesGeometry( geometry );
var line = new THREE.LineSegments( geometry, material );
line.computeLineDistances();
scene.add( line );
three.js r.92
I'm working off an example from the site and would like to add a textured cube to the scene and ideally have it in a specific position. This is what I've tried so far but it's not appearing:
var frametexture = new THREE.ImageUtils.loadTexture( 'https://threejs.org/examples/textures/crate.gif' );
var artwork = new THREE.BoxBufferGeometry( 200, 200, 20 );
var material = new THREE.MeshBasicMaterial( { map: frametexture } );
artframe = new THREE.Mesh( artwork, frametexture );
scene.add( artframe );
artwork.scale( - 1, 1, 1 );
Here's my JSFIDDLE
var frametexture = new THREE.ImageUtils.loadTexture( 'https://threejs.org/examples/textures/crate.gif' );
Should instead be
var frametexture = THREE.ImageUtils.loadTexture( 'https://threejs.org/examples/textures/crate.gif' );
and
artframe = new THREE.Mesh( artwork, frametexture );
needs to be
artframe = new THREE.Mesh( artwork, material);
So I have the following javascript code:
var group = new THREE.Group();
var staffGeometry = new THREE.BoxGeometry(0.5, 6, 0.5);
var staffMaterial = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var staffCube = new THREE.Mesh( staffGeometry, staffMaterial );
staffCube.position.x = -21;
staffCube.position.y = 1;
staffCube.position.z = -19;
group.add(staffCube);
//scene.add( staffCube );
var geometry = new THREE.TorusKnotGeometry( 10, 3, 100, 16 );
var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var torusKnot = new THREE.Mesh( geometry, material );
torusKnot.position.x = -21;
torusKnot.position.y = 4.8;
torusKnot.position.z = -19;
torusKnot.scale.set(0.08, 0.08, 0.08);
group.add(torusKnot);
//scene.add( torusKnot );
var ballGeometry1 = new THREE.IcosahedronGeometry(0.5);
var ballMaterial1 = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var ball1 = new THREE.Mesh(ballGeometry1, ballMaterial1);
ball1.position.x = -22.5;
ball1.position.y = 4.5;
ball1.position.z = -20.5;
group.add(ball1);
//scene.add(ball1);
var ballGeometry2 = new THREE.IcosahedronGeometry(0.5);
var ballMaterial2 = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
var ball2 = new THREE.Mesh(ballGeometry2, ballMaterial2);
ball2.position.x = -22;
ball2.position.y = 6.5;
ball2.position.z = -20;
group.add(ball2);
//scene.add(ball2);
scene.add(group);
The THREE.Group() was an attempt to utilize hierarchy. I can't seem to find ANY useful examples or documentation on THREE.Group so not even sure if I'm using hierarchy correctly. My goal was to set the staff in place, and make it easier to do stuff with the other components through hierarchy.
Mainly, I want ball1 and ball2 to circle around the staff. I am not sure how to access them within the group so that they can use taurusKnots location (head of staff) to translate to, rotate on taurusKnots Y, then translate back.
Any help on utilizing hierarchy with three.js to achieve this would be awesome! Like I said, all I can find online are people saying to use Group() for hierarchy, but nothing is said or can be found (by me at least) on how to access members and actually utilize the hierarchy you establish.
I'm trying to load textures on a THREE.BufferGeometry, but the texture isn't showing up. If I use normal geometry, the texture shows up. Are textures unsupported with BufferGeometry or am I doing something wrong?
This works:
var geom = new THREE.BoxGeometry(1,1,1);
var texture = THREE.ImageUtils.loadTexture("texture.png");
var mat = new THREE.MeshPhongMaterial({ map:texture, side:THREE.DoubleSide });
scene.add( new THREE.Mesh(geom, mat) );
This doesn't:
var geom = new THREE.BoxGeometry(1,1,1);
var buffgeom = new THREE.BufferGeometry();
buffgeom.fromGeometry(geom);
var texture = THREE.ImageUtils.loadTexture("texture.png");
var mat = new THREE.MeshPhongMaterial({ map:texture, side:THREE.DoubleSide });
scene.add( new THREE.Mesh(buffgeom, mat) );
There is a bug in r68's BufferGeometry.fromGeometry().
Its been fixed in r69dev already.
My goal is to create a cube/box with a single texture but different repeat values for each of the sides. Working code is below:
var cubeMaker = function(w,h,d, tName)
{
var g = new THREE.CubeGeometry( 50*w, 50*h, 50*d );
var tx = THREE.ImageUtils.loadTexture( tName );
var ty = THREE.ImageUtils.loadTexture( tName );
var tz = THREE.ImageUtils.loadTexture( tName );
tx.wrapS = tx.wrapT = THREE.RepeatWrapping;
ty.wrapS = ty.wrapT = THREE.RepeatWrapping;
tz.wrapS = tz.wrapT = THREE.RepeatWrapping;
tx.repeat.set(d,h);
ty.repeat.set(w,d);
tz.repeat.set(w,h);
var mx = new THREE.MeshBasicMaterial( {map: tx} );
var my = new THREE.MeshBasicMaterial( {map: ty} );
var mz = new THREE.MeshBasicMaterial( {map: tz} );
var mArray = [mx,mx,my,my,mz,mz];
var m6 = new THREE.MeshFaceMaterial( mArray );
var cube = new THREE.Mesh(g, m6);
return cube;
}
However, it seems wasteful to load the texture three times. Earlier, I instead tried passing a texture as an argument to the function (instead of a string representing the filename), as follows:
var cubeMaker = function(w,h,d, texture)
{
...
var tx = texture.clone();
var ty = texture.clone();
var tz = texture.clone();
...
but then the textures didn't appear in the scene, only solid black images appeared in their place. My best guess is that the texture image hadn't finished loading before the clone methods were called, and perhaps some kind of null value was copied instead. Is there some way to use an onLoad method to wait long enough so that the clone function works as intended?
Note: I have tried the suggestion from Can't clone() Texture but it does not solve my issue.
Thanks for any assistance!
Load your texture once, and move the rest of your code into the loader callback function. You also have to set the needsUpdate flag to true when you clone your texture.
var tx = THREE.ImageUtils.loadTexture( tName, undefined, function() {
var ty = tx.clone();
ty.needsUpdate = true; // important!
var tz = tx.clone();
tz.needsUpdate = true; // important!
tx.wrapS = tx.wrapT = THREE.RepeatWrapping;
ty.wrapS = ty.wrapT = THREE.RepeatWrapping;
tz.wrapS = tz.wrapT = THREE.RepeatWrapping;
tx.repeat.set( 1, 1 );
ty.repeat.set( 2, 1 );
tz.repeat.set( 2, 2 );
var mx = new THREE.MeshBasicMaterial( { map: tx } );
var my = new THREE.MeshBasicMaterial( { map: ty } );
var mz = new THREE.MeshBasicMaterial( { map: tz } );
var mArray = [ mx, mx, my, my, mz, mz ];
var mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial( mArray ) );
scene.add( mesh );
} );
Why don't you create then your texture outside of your function and just use this texture inside of your function, assigning it to special variable for each side? That way for sure you are going to load it just once.