How to add reflectionMaterial for an object in threejs - three.js

How to add reflectionMaterial with environment map, am using two cameras and two scene in order to achieve it, based on the webgl_materials_cubemap
and am using Object that is loaded using OBJMTLLoder, i can see the both Environment map, and Object on my scene, but the reflection of environment is not working on the object..
find my code below :
var urls = [
'textures/cube/canary/pos-x.png',
'textures/cube/canary/neg-x.png',
'textures/cube/canary/pos-y.png',
'textures/cube/canary/neg-y.png',
'textures/cube/canary/pos-z.png',
'textures/cube/canary/neg-z.png'
];
var cubemap = THREE.ImageUtils.loadTextureCube(urls); // load textures
cubemap.format = THREE.RGBFormat;
var shader = THREE.ShaderLib['cube']; // init cube shader from built-in lib
shader.uniforms['tCube'].value = cubemap; // apply textures to shader
// create shader material
var skyBoxMaterial = new THREE.ShaderMaterial( {
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms: shader.uniforms,
depthWrite: false,
side: THREE.BackSide
});
skybox = new THREE.Mesh( new THREE.BoxGeometry( 1000, 1000, 1000 ), skyBoxMaterial );
scene.add( skybox );
var object = scene.getObjectByName ("myname", true);
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh )
{
//child.geometry.computeFaceNormals();
var geometry = child.geometry;
var reflectionMaterial = new THREE.MeshBasicMaterial({
color: 0xcccccc,
envMap: cubemap
});
mesh = new THREE.Mesh(geometry, reflectionMaterial);
sceneCube.add(mesh);
}
});
Here am just changing the scene.add(mesh); to sceneCube.add(mesh); the reflection worked but the camera doesn't ..
you can see the differences here
Example 1
Example 2
In the first demo you can see that the scene working fine with the environment and without Object reflection
In the second you can see that the Reflection working fine but the camera behavior gets wired

i fixed it myself by adding following line inside the Object traverse
child.material.map = reflectionMaterial;
child.material.needsUpdate = true;
However i don't know am doing is correct or not but it is worked as like expected,

Related

Three.js: Can I Combine Multiple Mesh Objects into One Scene

Can I add more than one Mesh to the Scene in three.js? Code below shows my attempt to add a second Mesh to the Scene, however, it is not visible.
function setScene() {
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
materials = new THREE.ShaderMaterial({
fragmentShader: Cam.fragmentShader,
vertexShader: Cam.vertexShader,
uniforms: Cam.uniforms,
side: THREE.BackSide,
transparent: true
});
var skyBox = new THREE.Mesh( geometry, materials );
Cam.scene.add( skyBox );
// Add second SkyBox to the Scene
THREE.ImageUtils.crossOrigin = '';
var loader = new THREE.TextureLoader();
loader.load('img/test-circle-sample.png', function ( texture ) {
var geometry = new THREE.PlaneGeometry( 1, 1 );
var material = new THREE.MeshBasicMaterial( {
map:texture,
opacity : 1,
side : THREE.DoubleSide,
transparent : false
} );
var sprite = new THREE.Mesh( geometry, material );
sprite.position.set(0,-3,7);
var rotation = new THREE.Matrix4()
.makeRotationAxis(new THREE.Vector3(1,0,0), 1.57);
sprite.rotation.setFromRotationMatrix(rotation);
Cam.scene.add(sprite);
});
}
Above code adds a panoramic image successfully, which I can see. I then attempt to add an overlay image to the scene that should stay on top of the panoramic image, but it remains hidden.
Note, if I do not add the first object (panoramic image) to the scene (i.e. remove Cam.scene.add( skyBox )) then the second overlay image appears fine.

How to add environment map to custom ShaderMaterial in Three js

I've been trying to add an environment app to a custom Shader Material using three's MeshPhysical fragment shader and my own vertex shader. I am setting the envMap in the custom uniforms and in the material attribute, but it does not work. I will be pasting the code below, any help would be greatly appreciated.
var blobMaterial = new THREE.ShaderMaterial({
uniforms: THREE.UniformsUtils.clone(THREE.ShaderLib.physical.uniforms),
vertexShader: THREE.ShaderLib.physical.vertexShader,//physicalVertexShader,
fragmentShader: THREE.ShaderLib.physical.fragmentShader,
lights: true,
});
// var blobMaterial = new THREE.MeshPhysicalMaterial({
// envMapIntensity:0.5,
// color:0xf67104
// })
blobMaterial.envMap = envMap;
blobMaterial.combine = THREE.MultiplyOperation;
blobMaterial.uniforms.envMap.value = envMap;
// blobMaterial.uniforms.envMapIntensity.value = 1;
blob = new THREE.Mesh(
new THREE.IcosahedronGeometry( 20, 120 ),
blobMaterial
);
I tried following this https://jsfiddle.net/rtemj7va/, but still to no avail.

Animating a THREE.Points object

I'm trying to load a model from Blender, apply a PointsMaterial to it and animate it. So far, I've been able to load the model and animate it successfully as long as I use a material other than THREE.PointsMaterial to create the mesh.
When I create a THREE.Points object, the animation doesn't play. I noticed that when I set the PointsMaterial's morphTargets property to true, there's a warning saying that there is no such property of PointsMaterial. Does Threejs not support animation of Points objects using morph targets?
monster refers to a mesh that works when animated. It uses the loaded geometry and material. ParticleSystem is the the THREE.Points object.
Code:
function loadObject(path){
var loader = new THREE.JSONLoader();
loader.load(
path,
function(geometry, materials){
var material = materials[ 0 ];
material.morphTargets = true;
material.color.setHex( 0xffaaaa );
monster = new THREE.Mesh( geometry, materials );
monster.position.set( 0, 0, 0 );
var s = .003;
monster.scale.set( s, s, s );
var particleMaterial = new THREE.PointsMaterial({
color: 0xffffff,
size: .005,
morphTargets: true
});
particleSystem = new THREE.Points(geometry, particleMaterial);
particleSystem.morphTargetInfluences = monster.morphTargetInfluences;
particleSystem.morphTargetDictionary = monster.morphTargetDictionary;
particleSystem.position.set(0, 0, 0);
particleSystem.scale.set(s, s, s);
particleSystem.matrixAutoUpdate = false;
particleSystem.updateMatrix();
particleSystem.geometry.verticesNeedUpdate = true;
scene.add(particleSystem);
mixer.clipAction( geometry.animations[ 0 ], particleSystem )
.setDuration( 5 ) // one second
.startAt( - Math.random() ) // random phase (already running)
.play(); // let's go
}
)
}

how to change Environment map texture dynamically on reflection material

in threejs i want to change the skybox textures dynamically, am added 2 scenes here so i attached one scene to my skybox, so i decided to remove the skybox before switch from on texture to another, and the skybox textures are reflecting Environmentmap on the object, if i change the textures by select from the given list, am checking textures with the switch case and adding the texture , the reflection on the object is working, but if i switch skyBoxMaterial to selected texture Enviromentmap changed successfully but the reflection on the object is not changed to current Enviromentmap
Following is my code:
function envmap(envmap)
{
switch(envmap)
{
case 'canary':
var urls = [
'textures/cube/canary/pos-x.png',
'textures/cube/canary/neg-x.png',
'textures/cube/canary/pos-y.png',
'textures/cube/canary/neg-y.png',
'textures/cube/canary/pos-z.png',
'textures/cube/canary/neg-z.png'
];
//var cubemap = THREE.ImageUtils.loadTextureCube(urls); // load textures
break;
case 'Park2':
var urls = [
'textures/cube/Park2/posx.jpg',
'textures/cube/Park2/negx.jpg',
'textures/cube/Park2/posy.jpg',
'textures/cube/Park2/negy.jpg',
'textures/cube/Park2/posz.jpg',
'textures/cube/Park2/negz.jpg'
];
//var cubemap = THREE.ImageUtils.loadTextureCube(urls); // load textures
break;
case 'Park3Med':
var urls = [
'textures/cube/Park3Med/px.jpg',
'textures/cube/Park3Med/nx.jpg',
'textures/cube/Park3Med/py.jpg',
'textures/cube/Park3Med/ny.jpg',
'textures/cube/Park3Med/pz.jpg',
'textures/cube/Park3Med/nz.jpg'
];
//var cubemap = THREE.ImageUtils.loadTextureCube(urls); // load textures
break;
case 'Bridge2':
var urls = [
'textures/cube/Bridge2/posx.jpg',
'textures/cube/Bridge2/negx.jpg',
'textures/cube/Bridge2/posy.jpg',
'textures/cube/Bridge2/negy.jpg',
'textures/cube/Bridge2/posz.jpg',
'textures/cube/Bridge2/negz.jpg'
];
//var cubemap = THREE.ImageUtils.loadTextureCube(urls); // load textures
break;
case 'pisa':
var urls = [
'textures/cube/pisa/px.png',
'textures/cube/pisa/nx.png',
'textures/cube/pisa/py.png',
'textures/cube/pisa/ny.png',
'textures/cube/pisa/pz.png',
'textures/cube/pisa/nz.png'
];
//var cubemap = THREE.ImageUtils.loadTextureCube(urls); // load textures
break;
default:
var urls = [
'textures/cube/canary/pos-x.png',
'textures/cube/canary/neg-x.png',
'textures/cube/canary/pos-y.png',
'textures/cube/canary/neg-y.png',
'textures/cube/canary/pos-z.png',
'textures/cube/canary/neg-z.png'
];
break;
}
var cubemap = THREE.ImageUtils.loadTextureCube(urls,undefined, render); // load textures
cubemap.needsUpdate = true;
cubemap.format = THREE.RGBFormat;
var shader = THREE.ShaderLib['cube']; // init cube shader from built-in lib
shader.uniforms['tCube'].value = cubemap; // apply textures to shader
// create shader material
var skyBoxMaterial = new THREE.ShaderMaterial( {
fragmentShader: shader.fragmentShader,
vertexShader: shader.vertexShader,
uniforms: shader.uniforms,
depthWrite: false,
side: THREE.BackSide
});
alert(skybox);
if (skybox)
{
sceneCube.remove(skybox);
}
skybox = new THREE.Mesh( new THREE.BoxGeometry( 1000, 1000, 1000 ), skyBoxMaterial );
sceneCube.add( skybox );
var reflectionMaterial = new THREE.MeshBasicMaterial({
color: 0xcccccc,
envMap: cubemap
});
var object = scene.getObjectByName ("myname", true);
object.traverse( function ( child ) {
if ( child instanceof THREE.Mesh )
{
//child.geometry.computeFaceNormals();
var geometry = child.geometry;
//console.log(geometry);
material = child.material;
material.transparent = true;
child.material.needsUpdate = true;
child.material.map = reflectionMaterial;
mesh = new THREE.Mesh(geometry, reflectionMaterial);
scene.add(mesh);
}
});
}
After the work around fixed it myself
i used child.material=reflectionMaterial; instead of child.material.map = reflectionMaterial; and the refection is worked on the object material
So now while switch from one environment to another environment the reflection applied to my Object too
and there is no need of add new mesh below
mesh = new THREE.Mesh(geometry, reflectionMaterial);
scene.add(mesh);

Offsetting environment map texture in three.js

I'm trying to offset a texture that's being used as an environment map, but not having much luck.
The texture is loaded with the loadTextureCube() method, which gets applied to my mesh just fine, but the offsets don't seem to have any effect.
The texture is just a big gray circle to give a little bit of gloss.
Any thoughts on what I'm doing wrong?
var urls = [
'pos-x.png',
'neg-x.png',
'pos-y.png',
'neg-y.png',
'pos-z.png',
'neg-z.png'
];
var cubemap = THREE.ImageUtils.loadTextureCube(urls);
cubemap.offset.y = -.5;
cubemap.offset.x = -.5;
cubemap.needsUpdate=true;
I'm assuming based on loadTextureCube that your utilizing the cube shader approach to skyboxes. So far everything with your code is fine. The problem your seeing is that while your texture has offset properties, the material (or more specifically the cube shader program therein) does not have uniforms to pass this along to the fragmentation shader. This of course is assuming your doing something like this:
Eg. cube shader material
var skyboxGeo = new THREE.CubeGeometry( 5000, 5000, 5000 );
var cubeShader = THREE.ShaderUtils.lib[ "cube" ];
cubeShader.uniforms[ "tCube" ].value = cubemap;
var skyboxMat = new THREE.ShaderMaterial( {
fragmentShader: cubeShader.fragmentShader,
vertexShader: cubeShader.vertexShader,
uniforms: cubeShader.uniforms,
side: THREE.BackSide
});
var skybox = new THREE.Mesh( skyboxGeo, skyboxMat );
scene.add( skybox );
There's likely a number of work arounds, but you could alway try something like a MeshFaceMaterial on a standard cube to achieve the desired result:
Eg. standard material
var skyboxGeo = new THREE.CubeGeometry( 5000, 5000, 5000 );
var materialArray = [];
for (var i = 0; i < 6; i++) {
var cubeTex = THREE.ImageUtils.loadTexture( urls[i] );
cubeTex.offset.x = -.5;
cubeTex.offset.y = -.5;
materialArray.push( new THREE.MeshBasicMaterial({
map: cubeTex,
side: THREE.BackSide
}));
}
var skyboxMat = new THREE.MeshFaceMaterial( materialArray );
var skyBox = new THREE.Mesh( skyboxGeo, skyboxMat );
Hope that helps
~D

Resources