Can we apply custom shaders to three.js objects dynamically - javascript

I have a MeshBasicMaterial with VideoTexture. Can I apply custom shaders to the material dynamically. I was able to apply shader to the complete scene using THREE.EffectComposer but what if I want to apply custom filters to a specific element inside the scene. I want to test simple filters like sepia, hue-saturation. Also I must be able to switch between the two without reloading the project.
I did not go with js libraries like seriously.js or glfx.js because it may cause problem at later stages when I will work with three.js objects not having canvas/img/video as map.
videoTexture = new THREE.VideoTexture(video);
videoTexture.minFilter = THREE.LinearFilter;
videoTexture.magFilter = THREE.LinearFilter;
material = new THREE.MeshBasicMaterial({
map: videoTexture,
side: THREE.DoubleSide,
transparent: true,
depthTest: false,
depthWrite: false
});
composer = new THREE.EffectComposer( renderer );
composer.addPass( new THREE.RenderPass( scene, camera ) );
var effect = new THREE.ShaderPass( THREE.SepiaShader );
effect.renderToScreen = true;
composer.addPass( effect );
composer.render();
Edit 1: filter css( https://developer.mozilla.org/en-US/docs/Web/CSS/filter) won't work either as it only changes visual media and hence though it can manipulate final canvas it can not manipulate internal object textures.

THREE.EffectComposer has a .reset function that you could use to wipe it, and then add the new filters you want. So just load the different filters you want to cycle through into an array, then reset and add passes from that array.
EDIT I thought you were talking about changing shaders in the composer. To change shaders on an object, you can create multiple shadermaterials with different shaders but referencing the same texture, and swap the materials out on the object. So you can write a shader that reinterprets the texture colorspace to sepia, one that reinterprets the texture colorspace to bnw, or swizzles hue and saturation with r,g, or b.
Then you swap multiple materials out on the fly. These effects are basic glsl, but if you have trouble writing the shaders, just post another thread with specific problems. If you're a glsl novice, I highly recommend the book of shaders. It's a great, fast, interactive crash course on glsl.
But the solution to your problem is to create multiple shadermaterials, or create one shader material that does everything and then use uniforms to enable/lerp between the different effects.

Related

Three.js: flip image loaded with loadTextureCube

I have a legacy code snippet that has long since been part of a web application. The goal is to render a cube from 6 image urls via three.js. The problem is, that the bottom image is flipped around on its y axis. All other sides look fine.
There is no way to flip the original image, since they are provided by an external service. Also when I open the bottom image directly, it is displayed correctly, only in the three.js cube its flipped.
Since I have no prior experience with three.js, I first looked at the documentation for this functionality and realized that the code used in our script is deprecated. unfortunately there is no detailed documentation of the old function (THREE.ImageUtils.loadTextureCube) - or I was simply unable to find it (if someone knows where it is, a link would be great!).
I know that for the long term, a reimplementation to replace all deprecated functions would in order, but since this would take a lot more time (for someone unfamiliar with three.js), I first wanted to check if the problem can be fixed using the existing code base.
I read in various other posts/issues that this is a known issue because three.js for some internal reason defaults to flipY=true on textures. The problem I have is that I don't know (due to lack of documentation) how to change this parameter on one side of the cube only. I expect a function can be applied to the loader that could update this parameter for one of the images or a transformation could be applied to the loaded image afterwards.
I really hope somebody knows (remembers) how this can be achieved with the old loader function.
The following partial code is from my script:
// passed list of urls (images.bottom is flipped around)
var urls = [ images.left, images.right, images.top, images.bottom, images.back, images.front ];
// SCENE
scene = new THREE.Scene();
// TEXTURES
textureCube = THREE.ImageUtils.loadTextureCube( urls );
textureCube.format = THREE.RGBFormat;
textureCube.mapping = THREE.CubeReflectionMapping;
// MATERIALS
var cubeShader = THREE.ShaderLib[ "cube" ];
var cubeMaterial = new THREE.ShaderMaterial( {
fragmentShader: cubeShader.fragmentShader,
vertexShader: cubeShader.vertexShader,
uniforms: cubeShader.uniforms,
depthWrite: false,
side: THREE.BackSide
} );
cubeMaterial.uniforms[ "tCube" ].value = textureCube;
var cubeGeometry = new THREE.BoxGeometry(50,50,50);
cube = new THREE.Mesh( cubeGeometry, cubeMaterial );
scene.add( cube );
// RENDER
renderer = new THREE.WebGLRenderer();
renderer.autoClear = false;
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( containerWidth, containerHeight );
renderer.setFaceCulling( THREE.CullFaceNone );
$container.append( renderer.domElement );
...

Using CanvasTexture with a Sprite

I am upgrading some code that used to work with three.js r61 to three.js r74. I know, it's a big jump, but things are not always as they should be.
One of the remaining things that I still didn't get to work properly is a texture built using a canvas, used in a SpriteMaterial which is then used for a THREE.Sprite.
So far, I did the following:
Changed Texture to CanvasTexture
In SpriteMaterial, commented out the usage of useScreenCoordinates, alignment and sizeAttenuation
I tried various stuff, but it seems like this thing just doesn't display at all. Is there any such example anywhere? I just want to display an artifact that is built in a canvas.
Update: the code below is what I tried so far:
var loader = new THREE.TextureLoader();
loader.load(canvas.toDataURL(), function(texture) {
var material = new THREE.SpriteMaterial({
map: texture,
blending: THREE.AdditiveBlending,
color: me.color,
opacity: me.opacity,
transparent: me.transparent,
visible: me.visible
});
var sprite = new THREE.Sprite(material);
scene.add(sprite);
});
You're quite light on details but here's one good way to do it:
https://jsfiddle.net/_jered/xcej4ec6/
var loader = new THREE.TextureLoader();
loader.load(canvas.toDataURL(), function(d){
// 'd' is the loaded texture
// apply it to the object here
});
Basically, just use the built in Loader classes to load the assets you need, including from canvas. It's important to use Loaders and callbacks because assets will become ready asynchronously, and you need to wait until they're done before you make use of them. In my example, I create the mesh with a placeholder texture, and apply it in the Loader's callback.

Three.js - Load a model with material that doesn't require a light source to be seen

I'm currently using Three.js, version 71. I first create my models using blender, and then I export them as a JSON file. I then use THREE.JSONLoader to load the models into my scene using the following:
this.jsonLoader.load(pathToModelFile, function(geometry, materials) {
//...
});
The materials list only contains THREE.MeshPhongMaterial at index 0. This material seems to require a light source (like THREE.SpotLight for example) to be in my scene. Otherwise, my model will be black.
I basically just want to be able to load my models and not need to use a light source in order to see them. Therefore, I have the following questions, and answering any one of them would solve my problem:
Is there some flag or property in THREE.MeshPhongMaterial I could change that would allow my model to be seen without a light source?
If number 1 isn't possible, is there a way to use THREE.JSONLoader to give me a different kind of material that doesn't need a light source? For example, like THREE.MeshBasicMaterial?
Is there some way to export my models from blender that will already have the required flags/properties set (if possible)?
It sounds like I'm having the same problem that this guy mentions in the following link, but he never received an answer: Switch lighting of THREE.MeshPhongMaterial on / off dynamically
1 dont know, think not
2 yes
var jsonLoader = new THREE.JSONLoader();
jsonLoader.load(model, addthree1ToScene);
function addthree1ToScene( geometry, materials )
{
material = new THREE.MeshBasicMaterial(blahblah);
three1 = new THREE.Mesh( geometry, material );
scene.add( three1 );
console.log(three1);
}
3 yes, in Blender you can set a material type on mesh before exporting, or you can edit material variables in the exported file
EDIT:
Or most stupid way, it is possible to edit Material in expoted Json File, via discussion to this answer.

Three.js - Extreme shadow on face of mesh

I've created a chest model using blender, created a handpainted texture for it and set the whole thing up in an environment rendered with Three.js. The chest front face however has a unusually extreme shadow:
Here's my Renderer setup:
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
return renderer;
This is the light source (in the screenshot, it's the only light source) causing this shadow:
var envLight = new THREE.PointLight(color, 0.5, 320);
envLight.position.set(0, 80, zPos);
return envLight;
Material setup:
var material = new THREE.MeshPhongMaterial();
//diffuse texture setup
material.map = THREE.ImageUtils.loadTexture(textureURL);
material.map.wrapS = material.map.wrapT = THREE.RepeatWrapping;
material.map.repeat.set(repeatX, repeatY);
// specular map setup
material.specularMap = THREE.ImageUtils.loadTexture(specularMapURL);
material.specularMap.wrapS = material.specularMap.wrapT = THREE.RepeatWrapping;
material.specularMap.repeat.set(repeatX, repeatY);
material.specular = that.specularLightingColor;
return material;
The mesh is created using this material together with the JSON data containing the geometry and UV mapping exported from Blender. I use THREE.JSONLoader to get the data at runtime.
Here's a screenshot from blender showing the mesh and UV map unwrapped, it seems to be an issue with the selected face as it matches the exact shape and position of the weird shadow.
I've tried disabling the shadow with Object3D's castShadow/receiveShadow attributes but that doesn't show any effect at all.
Another screenshot of the normals orientation of the mesh
(source: front-a-little.de)
I've updated to the latest three.js release (r70) and updated the completely re-written Blender Export addon.
The described issue was most likely a bug in a previous version of this exporter, an exported model using the new addon doesn't show the weird shadow.
The new exporter comes with new settings in the save screen, I had to make sure the "UVs" box under "Materials" is checked in order to load the model via Three.JSONLoader

How to texture animated js model exported from blender ? [Three.js]

I have successfully animated a model in blender using bone animation technique and i have also textured it in blender using uv texturing. Then Using three.js export add-on in blender i have exported the model making sure uv and animation in checked in. However i don't know the technique to load the texture for the animated model. I viewed the morph normal example included in three.js where there is simple color texture is used using Lambert material. I have texture from external file. How do i load the texture. In js animated model file there is location for the texture and it is in same location. But it doesn't load. i used the face material technique as well.
the location for three.js example that i used to modify:
http://threejs.org/examples/webgl_morphnormals.html
Here is my code:
var loader = new THREE.JSONLoader();
loader.load( "bird_final.js", function( geometry, materials ) {
morphColorsToFaceColors( geometry );
geometry.computeMorphNormals();
// the old code to set color to the model
//var material = new THREE.MeshLambertMaterial( { color: 0xffffff, morphTargets: true, morphNormals: true, vertexColors: THREE.FaceColors, shading: THREE.SmoothShading } );
// my code
var meshAnim = new THREE.MorphAnimMesh( geometry, new THREE.MeshFaceMaterial( materials ) );
meshAnim.duration = 500;
meshAnim.scale.set( 20, 20, 20 );
meshAnim.position.y = 150;
meshAnim.position.x = -100;
scene1.add( meshAnim );
morphs.push( meshAnim );
} );
Except the documentation and some basic tutorials scattered across the web, is there anywhere i can learn three.js from ground up. like i know setting up scene and creating basic geometry stuffs but some detail info like loading textured model loading scenes etc.
I have created a series of commented examples for Three.js that illustrate features one at a time, starting with very basic features and progressing to more advanced ones (including loading models).
http://stemkoski.github.io/Three.js
Hope this helps!
Working with complex geometry, materials, textures, and animations are some of the hardest things to figure out in THREE.js - that's why we started there with our editor.
We make all of these easy. Export an FBX file (or OBJ/MTL, or Collada) from Blender. Bring it into a project in Verold Studio, then load it into your THREE.js program using our loader. Service is free for use, you pay us if you want enablement services or have a client who wants a maintenance/support agreement.
See the example below, couldn't be easier to bring your scene to THREE.js,
http://jsfiddle.net/rossmckegney/EeMCk/
// 1. Set and then start the animation :)
this.model.setAnimation("mixamo.com");
this.model.playAnimation(true);
//this.model.pauseAnimation();
// 2. Get the threedata for a model
console.log(this.model.threeData);
// 3. Move the model
this.tweenObjectTo(
this.model.threeData, // the model
new THREE.Vector3(1, 0, 0), // go to
new THREE.Quaternion(), // rotation
1, // time, in seconds
false, // smooth start
true); // smooth end
// 4. Clone the model
that = this;
this.model2 = this.model.clone({
success_hierarchy: function(clonedModel) {
that.veroldEngine.getActiveScene().addChildObject(clonedModel);
}
});

Categories