Three.js - How to Rotate Shader Material? - three.js

My problem is trying to get the sky to rotate on its z-axis. For example if I rotate the sky by 180 degrees the shadow from the sun light should display in the opposite direction.
The code sandbox: https://codesandbox.io/s/friendly-cloud-c00zr?file=/src/main.js:
This is where I create the sky in the main.js file:
const createSky = () => {
const sky = new Sky();
sky.scale.setScalar(1000);
sky.castShadow = true;
return sky;
};
I’ve tried rotateZ and sky.rotation to no avail.
The code in the sky.js file:
https://codesandbox.io/s/little-microservice-7nh53?file=/src/sky.js
is a modified iteration of the original three.js sky-sun-shader:
https://threejs.org/examples/webgl_shaders_sky.html
All that I have changed is the up position of the sky and its geometry from boxBuffer to sphereBuffer.
I would post the code here but it but it's over 200 lines of code.
I am wondering if there is a special way to rotate this ShaderMaterial in sky.js?

sky.material.uniforms.sunPosition.value.copy( light.position ); It looks like you can use this line to have the sun move from east to west.
Here the east-west is on the x axis and north-south is on z;
let sunPivot = new THREE.Object3D();
//add the light to the pivot at an offset off 100 units( can be changed );
light.positions.set( -100, 0, 0);
sunPivot.add( light );
in the render loop:
sunPivot.rotateZ( 0.005 ); //arbitrary rotation speed
light.getWorldPosition( sky.material.uniforms.sunPosition.value ); //the uniform value as target (puts the world position of the light into the sunPosition.value

Related

Three.js light looks like something moire

The scene picture
I have put a PointLight to the scene and shadows look like some kind of strips or smth like "moiré pattern"
The code is:
window.light2 = new THREE.PointLight( 0xDDDDDD, 1, 100 );
light2.intensity = 5;
light2.decay = 1;
light2.position.set(-33, 12, 0);
light2.castShadow = true;
light2.receiveShadow = true;
scene.add( light2 );
}
I found that it's occurs when I have gltf objects with "receiveShadow = true" on the scene. This effect apears on the lightened parts.
Update: Alse I found that surface of of my gltf objects (I make them in Blender) is not flat when it is lightened. For example, surface of a cube:
Cube picture
Zoomed cube picture
But this is only when cube has material.

Rotate orthographic camera (shadow camera) in Three.js

I'm trying to rotate a shadow camera by 45 degrees. I've managed to rotate the directional light it's attached to using the following code:
sunlight = new THREE.DirectionalLight(0xffffff, 1);
sunlight.position.x = -camera.position.x ;
sunlight.position.y = 300;
sunlight.position.z = camera.position.z ; //default; light shining from top
var vector = new THREE.Vector3;
vector.subVectors(scene.position, sunlight.position);
var q = new THREE.Quaternion();
q.setFromAxisAngle( vector.normalize(), Math.PI / 4 );
sunlight.applyQuaternion( q );
However the shadow camera does not rotate with the light as I'd expected. Trying to rotate the shadow camera itself using the same code does not work. How do I rotate an orthographic camera around its center point?
In the attached image the shadow camera can be seen as the orange square. The light is the black square, seen rotated 45 degrees. I need to apply the same rotation to the orange square as well, so the blue arrow is pointing north west.
Thanks in advance.
Directional lights in THREE.js don't behave like you'd expect. There is a light.target Vector3 parameter that the light Always points to.. so changing the lights rotation won't really do much. Try changing light.target to aim the light. To affect the roll of the shadow camera, you may be able to set the order of its euler with camera.rotation.order = "ZYX". Let me know if this helps.
#Joe Morgan

How to setup a camera that follows a circle path?

I'm trying to create a camera that follows an object that rotates on a orbit around a sphere. But everytime the camera reaches the polar coordinates of the orbit, the direction changes. I just set the position of the camera according to the object that is has to follow and calling lookAt afterwards:
function render() {
rotation += 0.002;
// set the marker position
pt = path.getPoint( t );
// set the marker position
marker.position.set( pt.x, pt.y, pt.z );
marker.lookAt( new THREE.Vector3(0,0,0) );
// rotate the mesh that illustrates the orbit
mesh.rotation.y = rotation
// set the camera position
var cameraPt = cameraPath.getPoint( t );
camera.position.set( cameraPt.x, cameraPt.y, cameraPt.z );
camera.lookAt( marker.position );
t = (t >= 1) ? 0 : t += 0.002;
renderer.render( scene, camera );
}
Here's a complete fiddle: http://jsfiddle.net/krw8nwLn/69/
I've created another fiddle with a second cube which represents the desired camera behaviour: http://jsfiddle.net/krw8nwLn/70/
What happens is that the camera's lookAt function will always try to align the camera with the horizontal plane (so that the "up" direction is always (0, 1, 0). And when you reach the top and bottom of the ellipse path, the camera will instantaneously rotate 180° so that up is still up. You can also see this in your "desired behaviour" example, as the camera cube rotates so that the colors on the other side are shown.
A solution is to not use lookAt for this case, because it does not support cameras doing flips like this. Instead set the camera's rotation vector directly. (Which requires some math, but you look like a math guy.)

Is there ANY way to have the three.js camera lookat being rendered off-center?

Is there a way to setup the Three.js renderer in such a way that the lookat point of the camera is not in the center of the rendered image?
To clarify: image a scene with just one 1x1x1m cube at ( 0, 0, 0 ). The camera is located at ( 0, 0, 10 ) and the lookat point is at the origin, coinciding with the center of the cube. If I render this scene as is, I might end up with something like this:
normal render
However I'd like to be able to render this scene in such a way that the lookat point is in the upper left corner, giving me something like this:
desired render
If the normal image is 800x600, then the result I envision would be as if I rendered a 1600x1200 image with the lookat in the center and then cropped that normal image so that only the lower right part remains.
Of course, I can change the lookat to make the cube go to the upper left corner, but then I view the cube under an angle, giving me an undesired result like this:
test.moobels.com/temp/cube_angle.jpg
I could also actually render the full 1600x1200 image and hide 3/4 of the image, but one would hope there is a more elegant solution. Does anybody know it?
If you want your perspective camera to have an off-center view, the pattern you need to use is:
camera = new THREE.PerspectiveCamera( for, aspect, near, far );
camera.setViewOffset( fullWidth, fullHeight, viewX, viewY, viewWidth, viewHeight );
See the docs: https://threejs.org/docs/#api/cameras/PerspectiveCamera
You can find examples of this usage in this example and this example.
three.js r.73
Here's a simple solution:
Assuming your cube is 4 x 4 x 4, at position 0, 0, 0:
var geometry = new THREE.BoxGeometry( 4, 4, 4 );
var material = new THREE.MeshBasicMaterial( { color: 0x777777 } );
var cube = new THREE.Mesh( geometry, material );
cube.position.set( 0, 0, 0 );
Get cube's position:
var Vx = cube.position.x,
Vy = cube.position.y,
Vz = cube.position.z;
Then deduct by 2 from x position, then add 2 to y and z position, and use the values to create a new Vector3:
var newVx = Vx - 2,
newVy = Vy + 2;
newVz = Vz + 2;
var xyz = new THREE.Vector3(newVx, newVy, newVz)
Then camera lookAt:
camera.lookAt(xyz);
Using console log, it would show that the camera is now looking at -2, 2, 2, which is the upper-left of your cube.
console.log(xyz);

Unexpected mesh results from ThreeCSG boolean operation

I am creating a scene & have used a boolean function to cut out holes in my wall. However the lighting reveals that the resultant shapes have messed up faces. I want the surface to look like one solid piece, rather than fragmented and displaying lighting backwards. Does anyone know what could be going wrong with my geometry?
The code that booleans objects is as follows:
//boolean subtract two shapes, convert meshes to bsps, subtract, then convert back to mesh
var booleanSubtract = function (Mesh1, Mesh2, material) {
//Mesh1 conversion
var mesh1BSP = new ThreeBSP( Mesh1 );
//Mesh2 conversion
var mesh2BSP = new ThreeBSP( Mesh2 );
var subtract_bsp = mesh1BSP.subtract( mesh2BSP );
var result = subtract_bsp.toMesh( material );
result.geometry.computeVertexNormals();
return result;
};
I have two lights in the scene:
var light = new THREE.DirectionalLight( 0xffffff, 0.75 );
light.position.set( 0, 0, 1 );
scene.add( light );
//create a point light
var pointLight = new THREE.PointLight(0xFFFFFF);
// set its position
pointLight.position.x = 10;
pointLight.position.y = 50;
pointLight.position.z = 130;
// add to the scene
scene.add(pointLight);
EDIT: Using WestLangley's suggestion, I was able to partially fix the wall rendering. And by using material.wireframe=true; I can see that after the boolean operation my wall faces are not merged. Is there a way to merge them?
Your problems are due to two issues.
First, you should be using FlatShading.
Second, as explained in this stackoverflow post, MeshLambert material only calculates the lighting at each vertex, and interpolates the color across each face. MeshPhongMaterial calculates the color at each texel.
You need to use MeshPhongMaterial to avoid the lighting artifacts you are seeing.
three.js r.68

Resources