How to generate the top and perspective view of an object using ThreeJS? - three.js

I want to generate the top and perspective view of an object.
Input: A 3d object, maybe .obj or .dae file.
Output: the image files presenting the top and front view of the loaded object.
Here is some expected output:
The perspective view of a chair
The top view of a chair:
Can anyone give me some suggestions to solve this problem? Demo may be preferred

You could create a small three.js scene with your obj or collada-file loaded using the appropriate loaders. (see examples of the specific loaders). Then create the necessary cameras you want to have in the scene. See examples for orthographic and perspective cameras that come with three.js, too.
To produce the images you want, you could use the toDataURL function, see this thread here and use google
Three.js and HTML5 Canvas toDataURL
in essence, after the objects are loaded, you could do something like:
renderer.render(scene, topViewCamera);
dataurl = canvas.toDataURL();
renderer.render(scene, perspectiveCamera);
dataurl2 = canvas.toDataURL();
I think you could also use 2 renderTargets and then use those for output, too, but maybe if you are new to three.js, start with the toDataURL() method from HTML5.

Related

I can't get the aoMap showing in three.js using a glb/gltf asset

I’m having a hard time getting an aoMap working in three.js…
I have a glb asset with an aoMap on the red channel or something. When I bring it into to the babylon viewer, I can see the ao just fine, but it wont show up in the three.js viewer or my project. I think this has something to do with a second set of uvs, but I can't find a resource that involves doing that on top of using the gltf loader… I really don't know what to do here. Any response would be greatly appreciated!
Here is my code (I’m using a html-canvas as the texture)
And I get the model’s geometry and diffuse texture (all white) as desired, but the aomap isnt showing…
code
babylon viewer
three.js viewer
working application with shadows included in diffuse
not working, diffuse is just white, and aoMap is not showing
You're right about needing a second set of UVs. The reason behind this is that diffuse textures often repeat (think of a brick wall, or checkered t-shirt). AO shading, however, is more likely to be unique on each part of the geometry, so it's almost never repetitive. Since this often would need an alternative UV mapping method, the default is to use a second set of UVs.
You could do 2 things:
Re-export your GLTF asset with a duplicate set of UVs.
Duplicate existing UVs in Three.js by creating a new BufferAttribute in your geometry:
// Get existing `uv` data array
const uv1Array = mesh.geometry.getAttribute("uv").array;
// Use this array to create new attribute named `uv2`
mesh.geometry.setAttribute( 'uv2', new THREE.BufferAttribute( uv1Array, 2 ) );
.getAttribute and .setAttribute are methods of BufferGeometry, if you want to read more about them.

Three.js transform controls not interactive (won't click or hover)

I'm playing about with three.js and webGL with an attempt to get html objects overlaid on a webGL model.
I intend to use three.js object loaders to render a 3D model, where I can then allow users to overlay HTML DOM objects in 3D space via a custom UI.
I've mainly been using the various different examples in the three.js docs (https://threejs.org/examples/ and https://codepen.io/AdamEDGE/pen/RRjEwz).
In order to allow the user to move the overlaid HTML objects via the UI, I've added the transform controls (https://threejs.org/examples/misc_controls_transform.html).
Things seemed to be going relatively well up to this point, but now I see that the controls are not hoverable or clickable to move the element.
I suspect I'm either missing code or an issue with the camera not aligning correctly, but I'm very new to this so I'm guessing.
I have also experimented with Jerome Etienne's blending tutorials, but on testing that caused other issues and I think may not be worth the trouble for what I'm going for (http://learningthreejs.com/blog/2013/04/30/closing-the-gap-between-html-and-webgl/index.html).
I have created an example that shows the problem (click on an object and the controls should show).
Its a simple webGL torus with two HTML images overlaid and mapped to a Mesh so I can link the controls to the HTML elements which are on a different scene.
https://jsfiddle.net/mattscotty/h5wuq86y/
control = new THREE.TransformControls(camera, glRenderer.domElement);
control.addEventListener('change', render);
The controls show on all the correct places when clicked as expected and I can use the keyboard to change the transform type (again see https://threejs.org/examples/misc_controls_transform.html for how it should work).
As I can't click or hover, I can't hook up to the relevant events.
I'm brand new to this and I'm quite sure I'm missing something obvious, so any help is appreciated.

Render single Object / Mesh immediatly into a renderTarget

I need to render a single specific mesh from a scene into a texture using a THREE.WebGLRenderTarget. I already achieved that during the rendering of the scene, all other meshes, except this one, are being ignored. So, I basically achieved my goal. The thing i hate is, that there is still a lot of unnecessary work going on for my whole scene graph, during the render process of the scene. I need to render this texture every frame, so with my current method i get extrem fps drop downs. (There are lots of meshes in the whole scene graph).
So what i found was the function "renderBufferImmediate" from the THREE.WebGLRenderer. (Link to the renderer source code here) My pseudo code to achieve my goal would look like this:
var mesh = some_Mesh;
var renderer = some_WebGLRenderer;
var renderTarget = some_WebGLRenderTarget;
renderer.setRenderTarget(renderTarget);
var materialProperties = renderer.properties.get(mesh.material);
var program = materialProperties.program;
renderer.renderBufferImmediate(mesh, program, mesh.material);
var texture = renderTarget.texture;
The renderBufferImmediate function takes an instance of an THREE.Object3D, a WebGLShaderProgram and a THREE.Material. Problem i see here: The implementation of this function tries to lookup properties of the Object3D which, afaik doesn't exist. (Like "hasPositions" or "hasNormals"). In short: my approach doesn't work.
I would be grateful if someone could tell me if i can use this function for my purpose (Meaning i am currently using it wrong) or if there is another solution for my problem.
Thanks in advance.

Occlusion of real-world objects using three.js

I’m using three.js inside an experimental augmented-reality web browser. (The browser is called Argon. Essentially, Argon uses Qualcomm’s Vuforia AR SDK to track images and objects in the phone camera. Argon sends the tracking information into Javascript, where it uses transparent web pages with three.js to create 3D graphics on top of the phone video feed.) My question is about three.js, however.
The data Argon sends into the web page allows me to align the 3D camera with the physical phone camera and draw 3D graphics such that they appear to align with the real world as expected. I would also like to have some of the things in the physical world occlude the 3D graphics (I have 3D models of the physical objects, because I’ve set the scene up or because they are prepared objects like boxes that are being tracked by Vuforia).
I’m wondering if folks have suggestions on the best way to accomplish this occlusion with three.js. Thanks.
EDIT: it appears that the next version of three.js (R71) will have a simpler way to do this, so if you can use the dev branch (or just wait), you can do this much more easily. See this post: three.js transparent object occlusion
MY ORIGINAL ANSWER (without using the new features in R71):
I think the best way to do this is (to avoid extra work by creating new rendering passes for example) to modify the WebGL renderer (src/renderers/WebGLRenderer.js) and add support for a new kind of object, perhaps call them “occlusionObjects”.
If you look in the renderer, you will see two current object lists, opaqueObjects and transparentObjects. The renderer sorts the renderable objects into these two lists, so that it can render the opaque objects first, and then the transparent objects after them. What you need to do is store all of your new objects into the occlusionObjects list rather than those two. You will see that the opaque and transparent objects are sorted based on their material properties. I think here, you may want to add a property to an object you want to be an occluder (“myObject.occluder = true”, perhaps), and just pull those objects out.
Once you have the three lists, look what the render() function does with these object lists. You’ll see a couple of places with rendering calls like this:
renderObjects( opaqueObjects, camera, lights, fog, true, material );
Add something like this before that line, to turn off writing into the color buffers, render the occlusion objects into the depth buffer only, and then turn color buffer writes back on before you render the remaining objects.
context.colorMask( false, false, false, false);
renderObjects( occluderObjects, camera, lights, fog, true, material );
context.colorMask(true, true, true, true);
You’ll need to do this in a couple of places, but it should work.
Now you can just mark any objects in your scene as “occluder = true” and they will only render into the depth buffer, allowing the video to show through and occluding any opaque or transparent objects rendered behind them.

Threejs objmtlloader black model

I'm new to ThreeJS and I made this example which shows one of our model.
http://petrie3dtesting.museums.ucl.ac.uk/3DFootCover/index.html
I created a Petrie3Dviewer and in the HTML page created a viewer object which takes as input an .obj and .mtl file. Strangely tho, the objects shows up BLACK and then when I start interacting the texture comes up. I tried everything I think: different browsers, making the texture smaller, different computers, nothing I get a random behaviour all the time.
I tried on FIrefox, Chrome mainly.
It seems that I need to force the rendering once the obj file is loaded but the OBJMTLLoader.js does not provide any event for it.
Really many thanks for the help.
Best,
GC
You should call this.DoRender in your Animate function to render the frame.
this.Animate = function() {
this.orbitControls.update();
this.Animate();
requestAnimationFrame(this.Animate.bind(this));
}
At the moment you call your render function only when the user changes the perspective with the OrbitControls. And because your texture is loaded asynchronously it is not ready the first time when you render the frame.

Resources