ID Rendering + Diffuse Rendering in THREE.js - javascript

I'm trying to use onBeforeRender to add an id material override function in my THREEjs app. This is a pretty common function for rendering applications, and I'd like to be able to use a scene.overrideMaterial to do it, but from my research it seems like I'm going to roll my own.
My approach is as follows.
When I instantiate objects:
...
m.onBeforeRender = function (){
if(Renderer._renderID){
this.material = new THREE.MeshBasicMaterial(this.userData.idColor.getHex());
this.material.needsUpdate = true;
// Attempt at using a shader material
//this.material = Renderer._idMat;
//this.material.uniforms.idColor.value = this.userData.idColor;
//this.material.uniforms.needsUpdate = true;
}
}
m.onAfterRender = function (){
if(Renderer._renderID){
this.material = this.userData.material;
}
}
...
In my render loop:
...
var idTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
Renderer._renderID = true;
Renderer._renderer.render(Renderer._scene, Renderer._camera, idTarget);
Renderer._renderID = false;
...
Right now the id buffer and diffuse buffer are both rendering with the diffuse material.
Any help would be much appreciated. Please let me know if additional information is needed, I will update this post.

Three.js has an official gpu picking example which can be seen here.
They seem to be rendering things in two different scenes and with vertex colors. That's not a bad approach, and i disagree with the comment and your commented out code. Changing the uniforms is not the only way to achieve this, the official example uses vertex colors and merges all the geometries.
There are many ways to skin this cat.
You should by all means avoid creating new materials in tight loops.
This is suuuuper bad:
m.onBeforeRender = function (){
if(Renderer._renderID){
this.material = new THREE.MeshBasicMaterial(this.userData.idColor.getHex()); //just a big NO
this.material.needsUpdate = true; //no it doesnt! it's a new material it has this true by default
To achieve something like this, or your own custom override:
const myMesh = new Mesh()
myMesh.myMaterials = [
someRenderMaterial,
someIDMaterial,
]
scene.traverse(o=>{if(o.myMaterials) o.material = o.myMaterials[1]})
renderer.render(scene,camera)
scene.traverse(o=>{if(o.myMaterials) o.material = o.myMaterials[0]})
renderer.render(scene,camera)
But again, there's many many ways to do this. You could just make another scene and render vertex colors. You could make an override material and render vertex colors. Many parameters, many permutations.

Related

Three.js r89 memory leak with STL models

I'm having a bit of trouble with a page I'm building. I think it's fairly simple, but I'm quickly running into issues from what I think is a memory leak.
First off, I've spent the majority of the day searching for an answer, so if I've missed something obvious I'm sorry, I promise I tried. Everything I've found has pointed me to the method I'm currently using, I'm at a loss now.
I have 30 STL models, all 120kb or less that I swap between. Only 3 are on screen at a time and the viewer can swap them out to customize the complete model.
I currently change the colors of the models using:
var selectedObject = scene.getObjectByName(object);
newMaterial = '#'+matHex[newMaterial-1];
newMaterial = hexToRgb(newMaterial);
selectedObject.material.color = newMaterial;
That part works just fine and doesn't seem to slow anything down.
When it comes to replacing the model I use:
var mesh = scene.getObjectByName(object);
if (mesh instanceof THREE.Mesh)
{
scene.remove(mesh);
mesh.geometry.dispose();
mesh.geometry = null;
mesh.material.dispose();
mesh.material = null;
mesh = null;
}
After that I call a function that adds the model back into the scene:
function addHandle(){
loader.load( stlPath+'Handle'+handleID+'.stl', function ( geometry ) {
material = '0x'+matHex[handleMat-1]; //set color hex from array
var handleMaterial = new THREE.MeshPhongMaterial( { color: parseInt(material), specular: specular, shininess: shininess } );
var handleMesh = new THREE.Mesh( geometry, handleMaterial );
handleMesh.position.set( 0, 0, 0 );
handleMesh.rotation.set( Math.PI/2, - Math.PI/2, 0 );
handleMesh.scale.set( .008, .008, .008 );
handleMesh.name = "Handle";
handleMesh.id = handleID;
handleMesh.castShadow = true;
handleMesh.receiveShadow = true;
scene.add( handleMesh );
updateHandle(); //check if Handle needs to rotate
} );
}
From everything I have been able to find this is the proper method for disposing of meshes but after running through about a dozen of them the camera rotation starts to slow down, it takes slightly longer to load the next model, etc. It's especially noticeable on mobile devices.
Hopefully someone out there is able to notice something obvious that I'm missing, it would be hugely appreciated!
I think I solved the problem, and it was my fault like I suspected. I discovered that I was calling animate(); every time a model was replaced. After removing those it is running much much smoother. I'll report back if it ends up not being fixed!

How to remove and dispose of all child geometry and meshes from an Object3D?

In this project I am working on I have several Collada models being displayed and then removed when not needed anymore. There seems to be a memory leak somewhere in the project and I am looking for ways to get it to run as smooth as possible as time is not on my sideā€¦
I feel like I don't remove the meshes the right way and that this might cause some of the memory leakage I have.
I load the objects with LoadObject(level_1_character, "Assets/Level_1_Character.dae"); for example, where level_1_character is a Object3D. This calls the following function:
function LoadObject(name, url) {
var mesh, geometry, material, animation;
var loader = new THREE.ColladaLoader();
loader.options.convertUpAxis = true;
loader.load(url, function(col) {
mesh = col;
geometry = col.scene;
name.name = url.toString();
name.add(geometry);
});
}
I add the objects to the scene depending on the level through scene.add(level_1_character); and then remove it by doing the following:
level_1_character.traverse(function(child){
if (child instanceof THREE.Mesh) {
child.material.dispose();
child.geometry.dispose();
}
});
I am not sure if this actually fully removes the object though. It seems as though the objects still are present in memory. Any idea what I'm doing wrong here?

How to automatically update a mesh on changing parameters on THREE.js

I'm new to Threejs and to javascript in general. I'm building a mesh based on a json parameters object and it works great.
Now I'm adding some UI components (button, slider, etc) to change the json and rebuild the mesh. I'm writing some monkey-code and I'm sure it can be avoided. Now my stuff works correctly but I'm sure that the problem can be solved more elegantly.
This is my actual workflow:
on slider change use a callback
that callback calls a setter
the setter change the JSON parameters and rebuild the mesh
I'm sure all this can be automated by simply change the JSON and some javascript magic.
Here is the actual pseudocode:
sliderWidth.onChange( function(newValue) {
MyObject3D.setWidth(newValue);
});
and this is a skelton of my MyObject3D:
var MyObject3D = function(parameters) {
this.parameters = parameters;
this.init();
};
MyObject3D.prototype.init = function() {
var geometry = this.initGeometry();
var material = new THREE.MeshPhongMaterial( { color: this.parameters.color, shading: THREE.FlatShading } );
this.mesh = new THREE.Mesh(geometry, material);
}
MyObject3D.prototype.setWidth = function(n) {
this.parameters.width = n;
scene.remove( this.mesh );
this.init();
scene.add( this.mesh );
}
I'm sure that with the javascript high-dinamicity and with all brand new frameworks this piece of code can be easily automated. I've looked mainly at d3.js and at angular.js. In particular d3.js seems to be perfect with the enter-update-exit paradigm (but I didn't find a standard way to conjugate it with Three.js) and angular for sure has to be something in it.
Any kind of advice on structure, pattern, specific use case or examples based on one of the frameworks mentioned THREE.js, d3.js, angular.js) can be enlightening. Actually I'd prefer a solution with angular.js..
There was an excellent talk about using three.js and angular.js which exactly showcases your problem.
https://www.youtube.com/watch?v=mCIZoLaPJxM&t=8m5s
Im using angular directives that watch on a specific attribute and then execute some logic onchange in my projects.
$scope.$watch($attrs.something, function(changedSomething){
doSomeLogicWith(changedSomething);
});

Three.js: Import and use 3d models

Hello!
I have searched ALOT about this on the web but havnt got anything that is working.
My question is: HOW do I use 3d models like collada, stl, obj, AND MOVE it with example model.position.rotation=10;?
Whitch is the easiest way of importing models in these formats? I only need one format to import to my three.js code.
Tnx!
I always convert my .obj files to JSON and then load them into Three.js.
For that conversion I use convert_obj_three.py script. You just need to run it and it will do all the work with the conversion.
And for the loading part, you can do this (with some examples how to manipulate the mesh):
function addMapMesh()
{
var loader = new THREE.JSONLoader();
loader.load("convertedFile.js", function(geometry){
mesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial(geometry.materials));
mesh.position.x -= 5.0;
mesh.scale.x = mesh.scale.y = mesh.scale.z = 0.05;
mesh.rotation.x = .25*Math.PI;
scene.add(mesh);
//make sure mesh is loaded before renderering
loadRestOfScene()
});
}
can't say much about how to move, rotate or manipulate modells using Three.js, but I remember there were a few converter-scripts and some exporter-scripts for Blender to get different 3D-Modell-types into Three.js.
This link might help you. It provides Links to converter-scripts and even shows a rotation in the example code!

Three js memory management

I have a large scene with a lot of Mesh and MorphAnimMesh. I want to free memory when the meshes are removed. If i know right this is the best way to do:
for ( var i = scene.children.length - 1; i >= 0 ; i -- ) {
var obj = scene.children[i];
scene.remove(obj);
obj.deallocate();
obj.geometry.deallocate();
obj.material.deallocate();
obj.material.map.deallocate();
}
if i check the memory usage at task manager after this, nothing changes. ( tried to wait a few min for GC but nothing. ) Google Chrome memory snapshot shows the objects still there. morphTargets in THREE.Geometry #1862203 etc.
Tried to set the obj to null, but still no memory decrease.
Any idea what am i doing wrong?
Its a game with levels and the player can change from one to another. After a few change memory usage increases to really high. Thats why i want to remove all object from memory before the level change.
Most likely, you need to add some, or all, of the following:
geometry.dispose();
material.dispose();
texture.dispose();
Check out these examples:
http://mrdoob.github.com/three.js/examples/webgl_test_memory.html
http://mrdoob.github.com/three.js/examples/webgl_test_memory2.html
three.js r.60
I did try all the dispose and deallocate methods but nothing worked.
Then I did the following for my ionic application which is using webgl renderer to render a 360 image.
this.renderer = new THREE.WebGLRenderer({ antialias: true });
RicohView.prototype.stopRendering = function () {
this.canRender = false;
this.renderer.forceContextLoss();
this.renderer.dispose();
console.log('renderer disposed');
cancelAnimationFrame(this.requestId);
}
requestId is something which can be captured from
this.requestId = requestAnimationFrame(render);

Categories