How to apply Three.js shaders to nodes - three.js

I'm trying to apply the shaders from the shaderLib but most of them either turn the node to complete white or black. Only the normal shader seem to work.
This is how I apply it:
const shader = THREE.ShaderLib.depth;
const uniforms = shader.uniforms;
const material = new THREE.ShaderMaterial({
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms
})
this._viewer.impl.matman().addMaterial(
data.name, material, true)
And set the material of the fragment with:
function setMaterial(fragIds, material) {
const fragList = this._viewer.model.getFragmentList()
this.toArray(fragIds).forEach((fragId) => {
fragList.setMaterial(fragId, material)
})
this._viewer.impl.invalidate(true)
}
Just like in this example: https://forge.autodesk.com/blog/forge-viewer-custom-shaders-part-1
I also tried to add colors to the uniforms like that example but it didn't help.
Any ideas why they don't work?

As I said in the comment, Forge Viewer is using a privately owned three.js, and its' WebGLRender didn't implement all functionalities as three.js, either. So, it might not support all functions in the three.js.
To identify what happened to this case, you can consider providing a reproducible case demonstrating that, I will gladly pass it to our dev team. Those following items should be in the reproducible case:
A short exact description of what you are trying to achieve. The behavior you observe versus what you expect, and why this is a problem.
A complete yet minimal sample source model to run a test in.
A complete yet minimal Forge app that can be run and debugged with a simple procedure to analyze its behavior lives in the sample model.
A complete yet minimal three.js app that can be run and demonstrated the shader effect you want. Note. Forge Viewer is using r71 three.js.
Detailed step-by-step instructions for reproducing the issue, e.g. which element to pick, what command to launch etc.
If your reproducible case could not be posted here publicly, please send it to the forge.help#autodesk.com and remove sensitive data or information before you send.
======== Old response
Could you provide more detail for further debugging, please?
It seems to works fine on my side. Here are my test codes. It's tested on the Forge RCDB (https://forge-rcdb.autodesk.io/database?id=57efaf0377c8eb0a560ef467).
var shader = THREE.ShaderLib.depth;
var uniforms = shader.uniforms;
var material = new THREE.ShaderMaterial({
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms
})
NOP_VIEWER.impl.matman().addMaterial( 'ShaderLabDepth', material, true );
var sel = NOP_VIEWER.getSelection();
var fragList = NOP_VIEWER.model.getFragmentList();
var it = NOP_VIEWER.model.getData().instanceTree;
it.enumNodeFragments( sel[0], function( fragId ) {
fragList.setMaterial( fragId, material )
});
NOP_VIEWER.impl.invalidate( true );
And Its' result is like this. Did it what you want?

Related

JeelizFaceFilter and THREEJS issue with gltf and texture models

Goal
I'm stuck since yesterday with an issue on modifying a JeelizFilterFace example. My goal is to create my own filters, so I started the the luffy's hat tutorial, which explains that : https://jeeliz.com/blog/creating-a-snapchat-like-filter-with-jeelizs-facefilter-api-part-1-creating-your-first-filter/
Quick description of the problem
My problem is simple : I can't have the glTF example working with glTF models. It always show me a black shape, without the texture.
Details of the problem
The tutorial explains that the model have to be generated with a Blender exporter addons, in order to create the json file which is the model. But the Blender exporter is not supported anymore.
This is why I try to use ThreeJS with the GLTF loader (which is the best solution according to all the tutorials).
My problem is that I can't see any texture on any of my models, when I load it with JeelizFaceFilter/Threejs. I only have the black shape.
Here is what I did :
First, I did all the tutorial to be sure I can run the FilterFace tool, except for the exporting model from Blender part. So, I just copied the exported resources from the Jeeliz repo. The FilterFace works well : the hat is visible, with the texture and I can play with the THREEJS params.
Because I couldn't export the JSON from blender, i wanted to try to use the GLTF 2.0 model, I tried this model, which is working in the gltf-viewer tool (see picture below) : https://s3.eu-west-3.amazonaws.com/com.julianlecalvez/LuffysHat.zip
So far everything seems ok, but when I try to use this glTF loader example in the glTF demos (https://github.com/jeeliz/jeelizFaceFilter/tree/master/demos/threejs/gltf_fullScreen), it displays my hat in black. I have the good shape, but no texture (or no light?). I just replaced the model URL in this file. And I'm not even sure that the default model (the helmet) is displaying any texture.
I tried with a model from SketchFab, and I have the same : Black shape, no texture.
I put here the code to init the view, when I was trying to redo it outside of the demo file :
let init_view = function(spec) {
const threeStuffs = THREE.JeelizHelper.init(spec, null);
const SETTINGS = {
gltfModelURL: 'objects/luffys_hat_gltf/luffys_hat.gltf',
offsetYZ: [1,0],
scale: 2.2
};
// const loader = new THREE.GLTFLoader();
const gltfLoader = new THREE.GLTFLoader();
gltfLoader.load( SETTINGS.gltfModelURL, function ( gltf ) {
gltf.scene.frustumCulled = false;
// center and scale the object:
const bbox = new THREE.Box3().expandByObject(gltf.scene);
// center the model:
const centerBBox = bbox.getCenter(new THREE.Vector3());
gltf.scene.position.add(centerBBox.multiplyScalar(-1));
gltf.scene.position.add(new THREE.Vector3(0,SETTINGS.offsetYZ[0], SETTINGS.offsetYZ[1]));
// scale the model according to its width:
const sizeX = bbox.getSize(new THREE.Vector3()).x;
gltf.scene.scale.multiplyScalar(SETTINGS.scale / sizeX);
// dispatch the model:
threeStuffs.faceObject.add(gltf.scene);
});
// CREATE THE CAMERA
THREECAMERA = THREE.JeelizHelper.create_camera();
}

Aframe Load lightmap after loading GLTF - lightmap not showing

I'm trying to add a lightmap to some mesh after loading them from a GLTF file.
All my objects have 2UV channel.
I'm waiting 'object3dset' and here is my code :
const mesh = this.el.getObject3D('mesh');
var textureLoader = new THREE.TextureLoader();
textureLoader.load("lightmap.png", function(lmap){
mesh.traverse((node) => {
if (!node.isMesh) return;
node.material.lightMap = lmap;
lmap.flipY = node.material.map.flipY; //needed to flip the texture
node.material.needsUpdate = true;
});
});
If I replace the material with a new one and set the lightmap, it's working.
But I want to find a way without recreating all materials.
The lightmap was loaded, but not easy to see.
By default metalness from Khronos Blender Exporter converted in threejs after loading GLTF result to a level 1.0. With this configuration, the lightmap is hard to see and is not corresponding to what we see in Blender.
I hope my mistake can help someone else losing too much time.

Three.js cylinder example keeps drawing torus

I'm attempting to get a basic THREE.js example to work and modify it from there on out but it just keeps outputting a torus, no matter what I change.
I've copied the exact code from the docs page into a JSFiddle and again I get a torus.
Here is the docs page example:
CylinderGeometry
And here is the jsfiddle with the torus: https://jsfiddle.net/ded9grxn/
I've tried adding the code from the docs page to the example like so:
var geometry = new THREE.CylinderGeometry( 5, 5, 20, 32 );
var material = new THREE.MeshPhongMaterial(
{
color: 0x156289,
emissive: 0x072534,
side: THREE.DoubleSide,
shading: THREE.FlatShading
});
mesh.add(
new THREE.Mesh(
geometry,
material
)
);
But to no avail. Any help is appreciated!
The reason you fiddle does not work is that the script you invoke (https://threejs.org/docs/scenes/js/geometry.js) looks at the hash in the URL of the window to select the object.
If you go to
https://threejs.org/docs/scenes/geometry-browser.html#CylinderGeometry
you get the cylinder.
If you go to
https://threejs.org/docs/scenes/geometry-browser.html
you get the default, which is a torus.
For the reason why your modification does not work, we need more information about how you performed the modif (what did you remove, where did you add).
(Edit) in the fiddle, after doing your modification, do not forget to remove the line
var options = chooseFromHash( mesh );
this is where your script invokes the function in geometry.js that will set the mesh according to the hash in the URL

Loading multiple objects in Three.js from Blender

I have a quite complex shape (dressed girl) that in Blender is broken down into different objects and it's loaded into Three.js with the JSON loader (with a little hack I made, that uses zipped files instead of just JSON files, as there are a lot of vertices).
As I want to change dynamically the style of the dress from a Web page, I was wondering how I can show/hide different pieces (e.g. sleeves) in the scene.
I tried traversing the THREE.Mesh, but there are no children.
When I export from Blender with the JSON exporter, I don't see anything referring to the names of the objects in the JSON. Is the structure lost?
If you are using meshes containing lots of vertices, I would advise you to use the openCTM webGL loader instead of zip hacking. Here is a link to the loader : http://threejs.org/examples/webgl_loader_ctm.html
This mesh compression tool uses LZMA compression method and can reduce the size of your files by 93%...
Concerning the JSONLoader, using an array might help:
var meshes = [];
...
var loader = new THREE.JSONLoader();
var onGeometry = function(geom)
{
var mesh = new THREE.SceneUtils.createMultiMaterialObject(geom, [material]);
meshes.push( mesh );
...
scene.add(mesh);
};
loader.load("yourfile.js", onGeometry);
Hope this helps
It is possible to load an entire scene with several meshes from a json file exported from Blender and handle them separately!
You can follow the complete process of exporting a entire scene from Blender and the right way of handling the exported meshes on my answer of this post.
So, you can get the different meshes and manipulate them separately using the getObjectByName method. But it is important to know that the loaded object isn't a Geometry anymore. It is labeled with the Scene type by now and it must be handled in a different way.
The loading code must look like this one:
loader = new THREE.JSONLoader();
loader.load( "obj/Books.json", function ( loadedObj ) {
var surface = loadedObj.getObjectByName("Surface");
var outline = loadedObj.getObjectByName("Outline");
var mask = loadedObj.getObjectByName("Mask");
scene.add(surface);
scene.add(outline);
scene.add(mask);
} );
Besides, you can handle the multiple materials of single mesh using THREE.MeshFaceMaterial like in the following code:
var mat1 = new THREE.MeshLambertMaterial( { map: texture1 } );
var mat2 = new THREE.MeshLambertMaterial( { map: texture2 } );
var materials = [mat1, mat2];
var faceMat = new THREE.MeshFaceMaterial(materials);
mesh = new THREE.Mesh( geometry, faceMat );
scene.add( mesh );
Hope this helps :)

Three.js - Is FlatShading implemented for BufferGeometry

It seems that setting THREE.FlatShading for a material doesn't work for BufferGeometry. Is it implemented?
I'm creating BufferGeometry with CTMLoader (useBuffers = true) and applying either MeshLambertMaterial or MeshNormalMaterial with shading: THREE.FlatShading.
Three.js still renders everything as SmoothShading.
If I switch to ClassicGeometry (useBuffers = false), everything works as expected. Unfortunately, that would not work for us since our models are huge and that was exactly the reason to use BufferGeometry.
Is it just not implemented or is it very difficult/time-consuming/not-possible to implement?
Thank you in advance for any hints or suggestions. I'm using the latest r58 version.
P.S.
I found a recent Ryan Rix' post on the same topic http://rix.si/2013/04/15/threejs-ctm-and-you/ where he had to switch to ClassicGeometry to make it work.
In three.js r73 flat shading is working with THREE.MeshPhongMaterial for sure. You can use it like this:
geometry = new THREE.BufferGeometry();
//... make your geometry
material = new THREE.MeshPhongMaterial({
color: 0xff0000,
shading: THREE.FlatShading
});
mesh = new THREE.Mesh( geometry, material );
This doesn't work for THREE.MeshLambertMaterial yet. But they are working on it. Check the related issue here on GitHUB.
flatShading does work in MeshPhongMaterial or any other, the property for
flatShading is boolean
flatShading : Boolean
Define whether the material is rendered with flat shading. Default is false.
const PlaneMaterial = new THREE.MeshPhongMaterial({color:'blue',
side:THREE.DoubleSide,
flatShading:true})
Code Snipet

Resources