Programming a hole / empty space in three.js - javascript

i'd like to programm something like a hole in three.js.
it should be like, e.g. a 3x3x3 cube with an 1x1x1 hole in it. is there a possibility, that i first use something like cubegeometry and afterwards another "geometry" that cuts out the stuff that i want to have deleted? an deletion geometry? :D
Thanks :)

If you are looking to "cut" things out in certain shapes, you may be interested in this post on a Constructive Solid Geometry library. It comes with a wrapper for THREE.js objects.
It lets you do things like this:
var cube = new CSG.cube();
var sphere = CSG.sphere({radius: 1.3, stacks: 16});
var geometry = cube.subtract(sphere);
=>
Here is another short tutorial on the subject.

Related

How to randomize the size of faces on a mesh in three.js?

I recently started experimenting in three.js, and have been wondering if there is a way to randomize the size of the faces in a mesh created from one of their existing geometries.
Three.js is excellent for low-poly work, but the symmetry of the generated meshes ruin the effects somewhat-- I'm looking to find a way to give each face a slightly different size and perhaps jitter/rotation as well, to give it a more "handcrafted" look, so to speak.
I thought there might be a way to do it with math.random, but I'm a javascript newbie and am not sure how to go about using it.
This is the code for the object I want to give a less uniform appearance:
function createObject() {
var geometry = new THREE.SphereGeometry(70, 31, 17);
var material = new THREE.MeshPhongMaterial({
color:Colors.blue,
shading:THREE.FlatShading
});
var sphere = new THREE.Mesh(geometry, material);
sphere.position.set(45,100,0);
sphere.castShadow = true;
sphere.receiveShadow = true;
scene.add(sphere);
}
Here's a fiddle with the rest of the code, but for whatever reason, although the code works locally, I can't get it to run in the browser. Still, it's there if you want to look at it. https://jsfiddle.net/redheadedmandy/f8fy4Lg8/1/
If anyone has a suggestion for how one might go about roughing up the uniformity of a three.js mesh, I would much appreciate it!
There's the jsfiddle example, based on yours. Well, mostly it's your example, just slightly modified, uses the latest version of Three.js.
As an option for "roughing", you can do it like that:
var geometry = new THREE.SphereGeometry(70, 31, 17);
geometry.vertices.forEach(v => {
v.x += THREE.Math.randFloatSpread(2);
v.y += THREE.Math.randFloatSpread(2);
v.z += THREE.Math.randFloatSpread(2);
});
geometry.computeFaceNormals(); // don't forget to do it, when you change vertices
Actually, there are many ways of how to change coordinates of vertices in a geometry. Creativity is up to you.

resizing individual models in a single geometry

I have a 3D model of my home town. I would like to use real time data to change the height of the buildings. In my first try, I loaded the buildings as individual meshes and called scene.add(buildingMesh) during setup.
var threeObjects = []
var buildingMesh = new THREE.Mesh(geometry, material)
threeObjects.push(buildingMesh);
$.each(threeObjects,function(i, buildingMesh)
{
buildingMesh.rotation.x += -3.1415*0.5;
buildingMesh.castShadow = true;
buildingMesh.receiveShadow = true;
scene.add(buildingMesh);
});
Which is too slow as my dataset consists of roughly 10.000 building.
So I took the approach to add all the (geometries of the) meshes to a single geometry and wrap that in a mesh to be added to the scene
singleGeometry.merge(buildingMesh.geometry, buildingMesh.matrix); //in a loop
var faceColorMaterial = new THREE.MeshLambertMaterial( { color: 0xffffff, vertexColors: THREE.VertexColors } );
combinedMesh = new THREE.Mesh(singleGeometry, faceColorMaterial);
scene.add(combinedMesh);
Just to make a proof of concept, I'm trying to change the height of a building when I click it. Alas, this is not working.
By adding a new id field, I can get a reference to the faces and vertices and change the color of the building, but I can not for the life of me, get them to to change height.
In my first version, I would just use something like:
buildingMesh.scale.z=2;
But as I have no meshes anymore, I'm kinda lost.
Can anybody help?
disclaimer: I'm new to Three.js, so my question might be stupid...hope it's not :)
If you combine all of your buildings into a single geometry, you're obliterating everything that makes the buildings distinct from each other. Now you can't tell building A from building B because it's all one big geometry, and geometry at its basic level is literally just arrays of points and polygons with no way of telling any of it apart. So I think it's the wrong approach to merge it all together.
Instead, you should take advantage of three.js's efficient scene graph architecture. You had the right idea at first to just add all the buildings to a single root Object3D ("scene"). That way you get all the efficiencies of the scene graph but can still individually address the buildings.
To make it load more efficiently, instead of creating the scene graph in three.js every time you load the app, you should do it ahead of time in a 3D modeling program. Build the parent/child relationships there, and export it as a single model containing all of the buildings as child nodes. When you import it into three.js, it should retain its structure.
JCD: That was not quite the question I asked.
But anyhow, I found a solution to the problem.
What I did was to merge all the geometries, but in stead of using the standard clone function in geometry.merge() I used a shallow reference, which made it possible for me to use the reference in threeObjects to find the correct building and resize the part of the geometry using Mesh.scale, followed by a geometry.verticesNeedUpdate = true;
For further optimization, I split the model into 5 different geometries and only updated the geometry that contained the building

Distorted UVs on a single object in my Three.js scene

I've been putting together a 3d model of a house and right now I'm stuck with yet another aggravating roadblock like those three.js has gotten me accustomed to.
I'm creating my scene in Maya and using the OBJ exporter to write obj and mtl files that I then import into three.js. I have about 9 objects in my scene, ungrouped, children only to the world, history deleted, and with texture maps that have ambient occlusion and lighting baked into them assigned to them via shadingMaps.
I've actually had little luck actually using the mtl file, so I just copied my texture maps and loaded them separately and created materials out of them in three.js.
Now, all of these objects look just fine in the browser, except for the simplest one, the walls and floor object. This is what the object looks like in Maya:
As you can see, a rather simple mesh with minimal polys looking beautiful in Maya.
I've learned that when I export objects into obj files, only one UV channel is supported, so I copy my UVs into the default channel and delete all other UV channels before exporting. This is the UV map:
But when I assign this material in the browser, I get a strange texture distortion like so:
It's like the UVs are all over the place. I would seriously doubt that my approach is anywhere close to being on target if it weren't for those 8 other (more complex, mind you) objects which all display fine.
, including part of the wall that I've cut out of the problematic piece, which is part of the bathroom.
Does anyone have a clue as to how I can troubleshoot this? I've tried exporting straight to js from Maya, but I'm having even more problems with that approach. I've tried converting the obj file into js using the packaged browser-based converter. I've spent days on this and am not making any progress.
Here's some relevant code.
scene = new THREE.Scene();
renderer = new THREE.WebGLRenderer({antialias: true} );
var wallTexture = THREE.ImageUtils.loadTexture("obj/final_walls.jpg");
var wallMaterial = new THREE.MeshLambertMaterial( {color: 0x929EAC, map:wallTexture} );
var manager = new THREE.LoadingManager();
var loader = new THREE.OBJMTLLoader( manager );
loader.load( 'obj/wallOnly.obj','obj/wallOnly.mtl', function ( object ) {
object.children[2].material = wallMaterial;
floorplan.add(object);
camera.lookAt( object );
} );
Please help!!
OMG! After running my head through the wall, I finally found the solution!
I've discovered that the problem was not as much a distortion of the texture as it was a random swapping of uv faces. That's right! For some reason, the webGL renderer randomly swapped some faces of the object with others.
Out of total coincidence I turned my mesh into quads instead of triangles and, voila!, that fixed everything. QUADS!!! I wasted friggin 3 solid days on triangles!!!

BufferGeometry MeshFaceMaterial implementation r68

We recently switched to r68 and are moving all our geometries to THREE.BufferGeometry.
We were using THREE.MeshFaceMaterial in a lot of places and according to BufferGeometry faces materials THREE.BufferGeometry does not support it. The solution seems to be to create multiple meshes, I tried this but it doesn't seem to work and I don't get any errors.
My approach is as follows:
var oldGeometry = ... // THREE.Geometry from our loader
var materials = ... // Material array from our loader, uses lightmaps, normalmaps etc.
var bufferGeometry = new THREE.BufferGeometry();
var geometry = bufferGeometry.fromGeometry(oldGeometry);
var group = new THREE.Object3D();
materials.forEach(function(material){
group.add(new THREE.Mesh(geometry, material));
});
geometry.attributes.uv = geometry.attributes.uvs;
This works fine without errors, but when rendered, all the lightmaps etc don't seem to work, the geometry looks fine but has just one color.
Any hints on how to implement this properly?
Edit:
UV issue: https://github.com/mrdoob/three.js/issues/5118
Edit 2:
After digging through the WebGLRenderer Source Code, I think implementing this is a lot more work then it's worth it right now. We will stick with the old geometry for now, but I'm still open for suggestions ;)
Edit 3:
A basic way to to do this yourself can be found here: https://github.com/mrdoob/three.js/issues/5268
There is work being done here https://github.com/mrdoob/three.js/issues/5417 to improve the three.js exporter, e.g. exporting buffergeometries with multiple materials.
There is a bug in bufferGeometry.fromGeometry() when handling the uvs in r68.
Try this workaround:
bufferGeometry.attributes.uv = bufferGeometry.attributes.uvs;

Creating a room with Three.js and cannon.js

I'm just getting started with Three.js and cannon.js and I've been trying to create a simple room for a while with no success. I'm working off of this example and I've been trying to add walls and a ceiling. What is the easiest way to do this? Right now I have
// wall?
wallGeometry = new THREE.PlaneGeometry( 300, 300 );
wallGeometry.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI));
wallMesh = new THREE.Mesh( wallGeometry, material );
wallMesh.castShadow = false;
wallMesh.receiveShadow = true;
scene.add(wallMesh);
But it's light up weird and I don't bump into it.... And if I try to add it through cannon.js I get an invisible wall but can't see it. Can anyone point me to the right direction?
THREE.js itself has no physics included so when you create any object in it, it will never make you 'bump' into them by itself. You have to code such features yourself or use another library for that (as you are already trying to do with cannon.js).
Next - per default, THREE js will only create one ambient light for your scene. If you want dynamic lightning and shadows, all lights must be provided by you and objects you want to react to lights must be using MeshLambertMaterial or MeshPhongMaterial, for shadows you will have to set couple of properies and use specific types of lights.
In your example, you don't seem to define wall material anywhere - this might be why walls are invisible.
check these and steal pieces of code you need (and it seems like you will need a lot :-)
http://threejs.org/examples/
http://stemkoski.github.io/Three.js/index.html

Categories

Resources