Self reflection in three.js - three.js

How to make a part of object visible in reflection on another part of the same object?

Threejs is not a ray tracing engine. Therefore it is not using real ray casts to calculate reflections on surfaces. It actually renders the other objects onto your reflective object.
What your scene is missing is an infinity mirror effect between surfaces, where light rays can bounce between two reflective surfaces multiple times. This is what a ray tracing engine would do.
You can try to fake this. Just split your geometry of into multiple objects and use extra cameras for them to render the scene looking from your reflective object into the scene and using this as a texture for the object.
You can use this example as a starting point: https://threejs.org/examples/#webgl_materials_cubemap_dynamic
Here an example of a material with dynamic environment texture captured by a CubeCamera:
var near = 1
var far = 100
var cubeResolution = 128
var camera1 = new THREE.CubeCamera( near, far, cubeResolution);
camera1.renderTarget.texture.generateMipmaps = true;
camera1.renderTarget.texture.minFilter = THREE.LinearMipMapLinearFilter;
scene.add( camera1 );
var material = new THREE.MeshBasicMaterial( { envMap: camera1.renderTarget.texture } );
var cube = new THREE.Mesh( new THREE.BoxBufferGeometry( 20, 20, 20 ), material );
scene.add(cube)

Related

threejs render text on or next to object

How can I put a text next or in front of it or on its surface with three.js?
If I plot a object like a box, I'd like to give this object a visible name (so similar to tooltip, but always staying visible). Would be great if text size is adjusting to distance like object size.
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
I'm using three.js with react-force-graph to render a diagram. Objects within it are rendered with three.js
https://threejs.org/docs/#api/en/geometries/BoxGeometry.parameters
Two ways to draw text with three.js. First, create a div element, set its position (In your case, you need to write code to calculate the position relative to the canvas according to the position of camera and 3d object). Second, create a text texture.

threejs - creating 3d perspective for a line

I'm working on an app where I visualize ATV trails in a 3d perspective (NAIP imagery draped over elevation data). I am using three.js for the rendering engine.
In the above image, the white line you see is just a THREE.Line instance, where I convert a trails gps coordinates into threejs coordinates. I'd like to add more of 3d perspective to this line. I tried implementing a THREE.TubeGeometry where the path was a THREE.CatmullRomCurve3 using the same Vector3 points as how I built the line you see in the image above. That did not produce a desirable result...
From the many, many THREE examples I have looked at, I really think an extruded geometry would achieve the look I am after... But I cant for the life of me figure out how to extrude a geometry for the line. Any suggestions/thoughts?
UPDATE 1:
Here is my desired look (same trail - no imagery). This image was produced in QGIS using the Q2Threejs plugin
UPDATE 2: Here is a code of how I have attempted to create a tubegeometry. Maybe I am messing something up in there...
// trailVectors are an array of Vector3 - same as ones used to create line
var trailCurve = new THREE.CatmullRomCurve3(trailVectors);
var tubeGeometry = new THREE.TubeGeometry(trailCurve,80,1,15,false);
var material = new THREE.MeshBasicMaterial({color:0x00ff00});
var tubeMesh = new THREE.Mesh(tubeGeometry,material);
var wireframeMaterial = new THREE.LineBasicMaterial({color:0xffffff,lineWidth:2});
var wireframe = new THREE.Mesh(tubeGeometry,wireframeMaterial);
tubeMesh.add(wireframe);
scene.add(tubeMesh);
UPDATE 3
THREE.TubeGeometry(trailCurve,80,4,2,false) per mzartman request
I think that you should be able to achieve what you want with a TubeGeometry. I think the big thing is that your example (from the picture shown) has more than 2 radius segments. That gives it the tubular shape and makes it look sort of like a blob. If you set the radial segment count to 2 (as it's shown below) then I think it would look a lot better.
tubeGeometry = new THREE.TubeBufferGeometry(
[YOUR_PATH_HERE],
params.extrusionSegments, // <--- Edit this for higher resolution on the spline
3, // <--- This defines the height
2, // <--- This 2 keeps 2D (i.e. not a tube!!!!)
true );
var mesh = new THREE.Mesh( geometry, material );
var wireframe = new THREE.Mesh( geometry, wireframeMaterial );
mesh.add( wireframe );
scene.add( mesh );
Update:
I think that you might do better with a material that shows some shadow like the MeshPhong. Also, to do the wireframe you want to add it as an option in the material initialization. Give it a show with the following:
var tubeGeometry = new THREE.TubeGeometry(curve,80,1,2,false);
var material = new THREE.MeshPhongMaterial({color:0x00ff00, wireframe: true});
var tubeMesh = new THREE.Mesh(tubeGeometry,material);
scene.add(tubeMesh);

Three.js - How to prevent a light from shining on an object

Is there a way to prevent a directional light from illuminating a specific object? I guess this would also apply to a spotlight. The reason for this is I would like to use two directional lights, but with one light shining on an object to give it 'self shadowing', and do not want that light it to interfere with another object.
Currently I have a single directional light declared as such :
function addpointlight()
{
var SHADOW_MAP_WIDTH = 4096, SHADOW_MAP_HEIGHT = 2048;
//Enabling this this light just creates serious artifacts on the obj I am trying to shadow.
//var newlight=new THREE.DirectionalLight(0xeeeeee,0.7);
//newlight.position.set( 0, 100, 300 );
//newlight.castShadow=false;
//scene.add(newlight);
// create a directional light
pointLight = new THREE.DirectionalLight(0xeeeeee,0.80);
//pointLight.onlyShadow=true;
pointLight.position.set( 0, 100, 300 );
pointLight.shadowCameraVisible=true;
pointLight.shadowCameraNear = 10;
pointLight.shadowCameraFar = 1500;
pointLight.shadowCameraFov = 90;
pointLight.castShadow=true;
var d = 4;
pointLight.shadowCameraLeft = -d;
pointLight.shadowCameraRight = d;
pointLight.shadowCameraTop = -d;
pointLight.shadowCameraBottom = d;
pointLight.shadowBias = 0.00;
pointLight.shadowDarkness = 0.7;
pointLight.shadowMapWidth = SHADOW_MAP_WIDTH;
pointLight.shadowMapHeight = SHADOW_MAP_HEIGHT;
// add to the scene
scene.add(pointLight);
}
This light wraps nicely around the object I want to self shadow, eliminating shadow artifacts. It moves with a moving object that it is creating a shadow on using this :-
pointLight.position.set(obj.position.x+40,obj.position.y+5,obj.position.z+300);
pointLight.target=obj;
So I'd like to create a second directional light that only affects the other objects, not this one, tnd this one's light must not affect other objects.
I'd create a fiddle, but the models I am testing with together with the textures make it a rather large fiddle in terms of bandwidth.
The three.js version in r70.
You want to limit the objects that a light affects. Until the time at which three.js supports "layers", where a light will only affect objects in its own layer(s), you may be able to achieve what you want with a work-around: two separate scenes and two render passes.
renderer.autoClear = false;
...
renderer.clear();
renderer.render( scene1, camera );
renderer.render( scene2, camera );
If you have transparent objects, they will have to be in the second scene. Also, an object can only be in one scene, so you will have to duplicate a light if you want it in both.
three.js r.70

Custom UVgenerator Three.js for extrudedgeometry

I want to use a texture on the surface of my extruded geometry. I have been researching custom UVgenerators for a while now, and have found these related questions:
1.) How to apply a texture to THREE.ExtrudeGeometry?
2.) Loaded texture appears blurred, or like a single color. How to make the texture crisp and sharp
However, the method proposed to divide my geometry points by 1000 and to mesh.scale.set(1000,1000,1) doesn't work because my geometry is no longer in the correct place. I would prefer to specify the UV Mapping. One answer says to implement a custom uvgenerator based on the source code, but I am stuck & can't figure out what to do.
This is my geometry creation, the material is 512x512px, how can I map a texture onto the top?:
pointList=[[0,0,0],
[0,1000,0],
[750,1000,0],
[750,750,0],
[1000,750,0],
[1000,0,0]]
for (i=0;i < pointList.length; i++) {
point = pointList[i];
x = point[0];
y = point[1];
myPoints.push( new THREE.Vector2 (x,y) );
}
myShape = new THREE.Shape( myPoints );
extrusionSettings = {
amount:height
};
myGeometry = new THREE.ExtrudeGeometry( myShape, extrusionSettings );
resultshape = new THREE.Mesh( myGeometry, material );
You can specify custom UVs for your ExtrudeGeometry by specifying your own UVGenerator, one of the properties of extrusionSettings.
To specify your custom UV generator, you can use as a template THREE.ExtrudeGeometry.WorldUVGenerator, which can be found in src/extras/geometries/ExtrudeGeometry.js.
There is a simpler solution that may work for you, however.
Instead of a custom UV generator, you can take advantage of the offset and repeat properties of your texture. Use the following pattern:
texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
texture.repeat.set( 1 / 500, 1 / 500 );
texture.offset.set( 0.1, 0.5 );
three.js r.68

Make environment map scale when moving from the object

I use CubeCamera to build a simple reflection model. The setup can be seen on the picture below.
If the camera is close enough to the cube - the reflection looks fine. However, if i move away from the objects - the reflection just gets bigger. See the picture below.
This is not the way i want it. I'd like the reflection to proportionally get smaller. I tried to play with different settings, then I thought this could be achieved using a proper shader program (just squish the cube texture, kind of), so i've tried to mess with the existing PhongShader, but no luck there, i'm too newbie to this.
Also, i've noticed that if i change the width and height of the cubeCamera.renderTarget, i.e.
cubeCamera.renderTarget.width = cubeCamera.renderTarget.height = 150;
i can get the proper dimensions of the reflection, but its position on the surface is wrong. It's visible from the angle presented on the picture below, but not visible if i place the camera straight. Looks like the texture needs to be centered.
The actual code is pretty straightforward:
var cubeCamera = new THREE.CubeCamera(1, 520, 512);
cubeCamera.position.set(0, 1, 0);
cubeCamera.renderTarget.format = THREE.RGBAFormat;
scene.add(cubeCamera);
var reflectorObj = new THREE.Mesh(
new THREE.CubeGeometry(20, 20, 20),
new THREE.MeshPhongMaterial({
envMap: cubeCamera.renderTarget,
reflectivity: 0.3
})
);
reflectorObj.position.set(0, 0, 0);
scene.add(reflectorObj);
var reflectionObj = new THREE.Mesh(
new THREE.SphereGeometry(5),
new THREE.MeshBasicMaterial({
color: 0x00ff00
})
);
reflectionObj.position.set(0, -5, 20);
scene.add(reflectionObj);
function animate () {
reflectorObj.visible = false;
cubeCamera.updateCubeMap(renderer, scene);
reflectorObj.visible = true;
renderer.render(scene, camera);
requestAnimationFrame(animate);
}
Appreciate any help!
Environment mapping in three.js is based on the assumption that the object being reflected is "infinitely" far away from the reflective surface.
The reflected ray used in the environment map look-up does not emanate from the surface of the reflective material, but from the CubeCamera's center. This approximation is OK, as long as the reflected object is sufficiently far away. In your case it is not.
You can read more about this topic in this tutorial.
three.js r.58

Resources