Creating a room with Three.js and cannon.js - javascript

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

Related

THREE.JS Multiple groups containing the same objects

I'm currently learning THREE.js and trying to make a playable rubik's cube.
I want to be able to rotate a face as a whole instead of moving every single cube one at a time, and I can do so by creating a THREE.Group and adding the cubes in it. The problem is that a single cube is contained in multiple faces, and I can't find a solution. If I create an object, add it to a first group, then add it to a second group, it is removed from the first group.
I'm pretty sure there is a workaround but can't find it as I'm really new to THREE.js and 3D programming (I only followed a basic course https://www.udemy.com/3d-programming-with-javascript-and-the-threejs-3d-library/).
There is my code but I don't think it will be very usefull anyway.
https://pastebin.com/Hq66UvBU
Thanks
Welcome to Stack Overflow. Please remember to edit your question to include your code, because when the pastebin link dies, your question loses important context.
The correct way to add an object to a THREE.Group is through the add function, like you do. But an object added to multiple groups will only ever be a child of the last group to which it was added. This is because add looks to see if the object already has a defined parent, and removes the object from that parent before setting the new parent (r97 code).
Example:
let obj = new THREE.Object3D()
let p1 = new THREE.Group()
let p2 = new THREE.Group()
p1.add(obj) // obj.parent == p1
p2.add(obj) // 1. three.js calls p1.remove(obj) 2. obj.parent == p2
Beyond this reason, and as #Mugen87 mentioned, your cubes need to not only be able to have multiple memberships, but also to be able to enter and leave face groups as their positions change. To me this says you will almost need to transform the cubes individually. You could use a THREE.Group to make it easier to conceptualize, but there would be extra overhead to actually implement it that way.
Maybe a late answer but try to work in another way and group the cubes that need to turn the moment the turn function is activated and then turn the group around, then empty the group.

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!!!

Three.js outlines

Is it possible to have an black outline on my 3d models with three.js?
I would have graphics which looks like Borderlands 2. (toon shading + black outlines)
I'm sure I came in late. Let's hope this would solve someone's question later.
Here's the deal, you don't need to render everything twice, the overhead actually is not substantial, all you need to do is duplicate the mesh and set the duplicate mesh's material side to "backside". No double passes. You will be rendering two meshes instead, with most of the outline's geometry culled by WebGL's "backface culling".
Here's an example:
var scene = new THREE.Scene();
//Create main object
var mesh_geo = new THREE.BoxGeometry(1, 1, 1);
var mesh_mat = new THREE.MeshBasicMaterial({color : 0xff0000});
var mesh = new THREE.Mesh(mesh_geo, mesh_mat);
scene.add(mesh);
//Create outline object
var outline_geo = new THREE.BoxGeometry(1, 1, 1);
//Notice the second parameter of the material
var outline_mat = new THREE.MeshBasicMaterial({color : 0x00ff00, side: THREE.BackSide});
var outline = new THREE.Mesh(outline_geo, outline_mat);
//Scale the object up to have an outline (as discussed in previous answer)
outline.scale.multiplyScalar(1.5);
scene.add(outline);
For more details on backface culling, check out: http://en.wikipedia.org/wiki/Back-face_culling
The above approach works well if you want to add an outline to objects, without adding a toon shader, and thus losing "realism".
Toon shading by itself supports edge detection. They've developed the 'cel' shader in Borderlands to achieve this effect.
In cel shading devs can either use the object duplication method (done at the [low] pipeline level), or can use image processing filters for edge detection. This is the point at which performance tradeoff is compared between the two techniques.
More info on cel: http://en.wikipedia.org/wiki/Cel_shading
Cheers!
Yes it is possible but not in a simple out-of-the-box way. For toon shading there are even shaders included in /examples/js/ShaderToon.js
For the outlines I think the most commonly suggested method is to render in two passes. First pass renders the models in black, and slightly larger scale. Second pass is normal scale and with the toon shaders. This way you'll see the larger black models as an outline. It's not perfect but I don't think there's an easy way out. You might have more success searching for "three.js hidden line rendering", as, while different look, somewhat similar method is used to achieve that.
Its a old question but here is what i did.
I created a Outlined Cel-shader for my CG course. Unfortunately it takes 3 rendering passes. Im currently trying to figure out how to remove one pass.
Here's the idea:
1) Render NormalDepth image to texture.
In vertex shader you do what you normally do, position to screen space and normal to screen space.
In fragment shader you calculate the depth of the pixel and then create the normal color with the depth as the alpha value
float ndcDepth = (2.0 * gl_FragCoord.z - gl_DepthRange.near - gl_DepthRange.far) / (gl_DepthRange.far - gl_DepthRange.near);
float clipDepth = ndcDepth / gl_FragCoord.w;
2) Render the scene on to a texture with cel-shading. I changed the scene override material.
3)Make quad and render both textures on the quad and have a orto camera look at it. Cel-shaded texture is just renderd on quad but the normaldepth shaded on that you use some edge detection and then with that you know when the pixel needs to be black(edge).

Programming a hole / empty space in three.js

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.

Categories

Resources