I recently started learning about shaders and three.js. I tried to display a shader with a texture but it displays all black.
Here's the codepen: https://codepen.io/LDB95/pen/MxmWNq
These are my uniforms:
uniforms: {
tDiffuse: { value: null },
time: { type: "f", value: 1.0 },
resolution: { type: "v2", value: new THREE.Vector2() },
iChannel0: { type: 't', value: new THREE.TextureLoader().load('https://naqyr37xcg93tizq734pqsx1-wpengine.netdna-ssl.com/wp-content/uploads/2017/11/10-Things-We-Can-Learn-From-the-Incredible-Steve-Jobs.jpg')},
iChannel1: { type: 't', value: new THREE.TextureLoader().load('https://gobelmont.ca/Portals/0/xBlog/uploads/2018/8/30/white%20noise.jpg')},
},
I just can't seem to find the fix. Would be really awesome if someone could help me out here :)
Thanks!
I'm afraid your codepen is full of mistakes. It seems you are trying to port a shader from shadertoy to three.js, right?
I have removed all errors here but the effect still looks broken: https://codepen.io/anon/pen/XGRVew
Anyway, here are a few things to keep in mind:
You have to assign the textures to the uniforms after you have created the shader pass. Uniforms are cloned for the internal material of ShaderPass. That means textures are cloned, too. The respective needsUpdate flag is not set correctly if you load the texture before the material creation.
As mentioned by #Marquizzo, your texture are blocked for security reasons. I've added some textures from the three.js repo for test purposes.
The following line of code is not necessary since uv coordinates are provided with the geometry. It's not necessary to compute them on-the-fly like shadertoy does. Just use the varying vUv in the fragment shader.
vec2 uv = gl_FragCoord.xy / resolution.xy;
For such simple one-pass shaders, it's not necessary to use EffectComposer. Try to use an approach similar to this official example.
You always have to ensure that the example files like ShaderPass or EffectComposer match the three.js version in your code. I've changed this in the codepen in order to remove all deprecation warnings.
Related
Is there a way to export a general threejs shadermaterial of the type:
var the_material = new THREE.ShaderMaterial( { uniforms: u, vertexShader: vs, fragmentShader: fs ,name:id} );
into a .mtl file ?
An .mtl file can only represent specific classic material types, like "phong" or "lambert". See this document: http://paulbourke.net/dataformats/mtl/. As a result, it is not possible to put arbitrary shader code into an .mtl file. To export an arbitrary shader, you'll very likely need to export the entire vertex+fragment shader (e.g. .glsl).
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.
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?
I am trying to apply a decal to the outside of a mesh object using DecalGeometry. However, the decal appears on the inside of the mesh. I've tried rotation and position settings within the DecalGeometry, but can't seem to affect which side of the mesh the decal appears on. FWIW, the mesh is a custom OBJ model. My code is a bit extensive to post here, but you can view the issue here. I have red BoundingBoxHelpers to help visualize the placement.
The materials object has a parameter which allows you to designate the side(s) of the mesh on which it will display (thanks #j-t for posting this question Prevent decal from showing on inside of mesh. My working code looks like this...
var decalMaterial = new THREE.MeshPhongMaterial( {
map: decalNormal,
transparent: true,
depthTest: true,
depthWrite: false,
polygonOffset: true,
polygonOffsetFactor: - 4,
side: THREE.DoubleSide
});
I am very new to three.js. In my project you can move through a series of planes with cross section images of an object. The problem is that the material doesn't load right away and moving up and down too quickly causes some of the planes to display black. I need to change this behavior. Is there a way to either
change some property so the plane is transparent - but the image should still be opaque when loaded
or don't display/render the plane at all until the texture is loaded?
I'm not at all sure I am on the right track, and I am hoping someone more experienced can suggest a specific fix.
Thanks!
Not sure if you already cleared this up but I made a handy little function to take care of this by modifying the opacity setting, the basic of which are:
function loadTexture( path ){
var mat = new THREE.MeshBasicMaterial({
map: new THREE.ImageUtils.loadTexture( path, null, function() {
mat.opacity = 1;
} ),
opacity: 0
});
return mat;
}