three.js parallel light and shadow and related properties

Basic articles: basic knowledge and simple application of three.js

Texture map: the use of three.js texture map

Advanced Texture Mapping: Three.js Texture Mapping Advanced

1. The relationship and setting of light and shadow — five steps are indispensable (points, parties will repeat again)

Goal: Lights and Shadows

  • Ambient light without shadows
  • Parallel light (sun light), point light source (light bulb – glowing everywhere), spotlight (eight)

1. The material should be able to respond to light

  • Most commonly used – MeshStandardMaterial
  • More performance-consuming – MeshPhysicalMaterial – an extension of MeshStandardMaterial that provides more advanced physically-based rendering properties:

2. Set the renderer to enable shadow calculation renderer.shadowMap.enabled = true;

3. Set the light cast shadow directionalLight.castShadow = true;

4. Set the object to cast shadow sphere.castShadow = true;

5. Set the object to receive shadow plane.receiveShadow = true;

Example: The result of the operation is as follows

All codes are as follows, see code comments for analysis:

/*
 * @Description: The relationship and setting of light and shadow -- five steps are indispensable
 */

import * as THREE from "three";
// import track controller (mouse control)
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

/**
 * Target: Lighting and shadows - ambient light without shadows, parallel light (sun light), point light source (light bulb - glowing everywhere), spotlight (eight)
 * light shadow
 * 1. The material should be able to respond to light
        --Most commonly used-MeshStandardMaterial
 * -- More performance-consuming - the extension of MeshPhysicalMaterial-MeshStandardMaterial,
         More advanced physically based rendering properties are provided:
 * 2. Set the renderer to enable shadow calculation renderer.shadowMap.enabled = true;
 * 3. Set the light casting shadow directionalLight.castShadow = true;
 * 4. Set the object to cast shadow sphere.castShadow = true;
 * 5. Set the object to receive shadow plane.receiveShadow = true;
 */

/*
 *1. Create a scene
 */
const scene = new THREE. Scene();

/*
 * 2. Create a camera (here is a perspective camera--used to simulate what the human eye sees)
 */
const camera = new THREE. PerspectiveCamera(
  75, // view angle
  window.innerWidth / window.innerHeight, // aspect ratio
  0.1, // entry section
  1000 // far section
);
// set camera position
camera.position.set(7, 7, 7);
scene.add(camera); // add the camera to the scene

/*
 * add object
 */
// create geometry
const sphereGeometry = new THREE. SphereBufferGeometry(1, 20, 20);

// 1). Set material - standard mesh material
const material = new THREE. MeshStandardMaterial();

// generate geometry
const sphere = new THREE. Mesh(sphereGeometry, material);

// 4). Cast shadow -- whether the object is rendered into the shadow map -- three-dimensional object (Object3D)
sphere.castShadow = true;

scene. add(sphere);

/**
 * Create bottom plane
 */
const planeGeometry = new THREE. PlaneBufferGeometry(10, 10);
const plane = new THREE. Mesh(planeGeometry, material);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;

// 5). Receive shadow
plane. receiveShadow = true;

scene. add(plane);

/**
 * lights
 */
// ambient light
const light = new THREE. AmbientLight(0xffffff, 0.5);
scene. add(light);
// Linear light source (parallel light)
const directionalLight = new THREE. DirectionalLight(0xffffff, 0.5);
// Set the position of parallel light
directionalLight.position.set(10, 10, 10);

// 3). Set parallel light to generate dynamic shadow
directionalLight.castShadow = true;

scene. add(directionalLight);

/**
 * 3. Initialize the renderer
 */
const renderer = new THREE. WebGL1Renderer();
// set renderer size
renderer.setSize(window.innerWidth, window.innerHeight);

// 2). Turn on the shadow map in the scene--allow the use of shadow maps in the scene
renderer.shadowMap.enabled = true;

// Add the canvas content rendered by webgl to the body
document.body.appendChild(renderer.domElement);

/**
 * Create orbit controllers (OrbitControls)
 * Can make the camera orbit around the target
 */
const controls = new OrbitControls(camera, renderer.domElement);
// Set the controller damping to make the controller more realistic. You must call update() in the animation loop render()
controls.enableDamping = true;
// controls. autoRotate = true;
// controls.autoRotateSpeed = 2; // autorotation speed

/**
 * Auxiliary 3D coordinate system
 * Red stands for X-axis. Green stands for Y-axis. Blue stands for Z-axis.
 */
var axesHelper = new THREE. AxesHelper(7);
scene. add(axesHelper);

// Define the loop rendering method
function render() {
  renderer.render(scene, camera); // perform rendering operation
  controls.update(); // Add or not
  requestAnimationFrame(render); // The render function will be called when the next frame is rendered
}
render();

// Monitor size changes to achieve adaptive screen
window. addEventListener("resize", () => {
  // console.log("The screen has changed");
  // update camera
  camera.aspect = window.innerWidth / window.innerHeight;
  // Update the camera's projection matrix
  camera.updateProjectionMatrix();
  // update the renderer
  renderer.setSize(window.innerWidth, window.innerHeight);
  // Set the pixel ratio of the renderer
  renderer.setPixelRatio(window.devicePixelRatio);
});

2. Parallel light THREE.DirectionalLight

Introduction:

Parallel light is light emitted along a specific direction. This light behaves as if it is infinitely far away, and the rays of light emanating from it are all parallel. Parallel light is often used to simulate the effect of sunlight; the sun is far enough away that we can consider the sun’s position to be infinitely far away, so we believe that the rays of light emitted from the sun are also parallel.

Constructor:

DirectionalLight( color : Integer, intensity : Float )

color – (optional parameter) the color of the light in hexadecimal. The default is 0xffffff (white).
intensity – (optional) The intensity of the light. The default value is 1.

The difference between point light source and spotlight:

The biggest difference is that point light and spot light the farther the light source is from the object, the darker the light. Light is emitted from a point.
The entire area illuminated by parallel light receives the same light intensity. Light is parallel.

Characteristics of parallel light:

Since the shadow rendering of the model consumes a lot of performance, we need to set the area related to the parallel light to be able to display shadows, and how well the shadows are displayed. The following properties:

//These two values determine how many pixels are used to generate shadows, the default is 512
directionalLight.shadow.mapSize.height = 2048;
directionalLight.shadow.mapSize.width = 2048;

or

directionalLight.shadow.mapSize.set(2048, 2048);

//Set shadow map blur

directionalLight.shadow.radius = 20;

// Set the properties of the parallel light projection camera

directionalLight.shadow.camera.near = 0.5; //The closest distance to generate shadows
directionalLight.shadow.camera.far = 500; //The farthest distance to generate shadows
directionalLight.shadow.camera.left = -5; //The leftmost position of the shadow distance position
directionalLight.shadow.camera.right = 5; //rightmost
directionalLight.shadow.camera.top = 5; //topmost
directionalLight.shadow.camera.bottom = -5; //bottom

Example: The running result is as follows

Variation via near:

// Set shadow map blur

directionalLight.shadow.radius = 20;

// Set the resolution of the shadow map

directionalLight.shadow.mapSize.set(2048, 2048);

// Set the properties of the parallel light projection camera

directionalLight.shadow.camera.near = 0.5;

directionalLight.shadow.camera.far = 500;

directionalLight.shadow.camera.top = 5;

directionalLight.shadow.camera.bottom = -5;

directionalLight.shadow.camera.left = -5;

directionalLight.shadow.camera.right = 5;

By changing the resolution (2048 –> 512):

// Set shadow map blur

directionalLight.shadow.radius = 20;

// Set the resolution of the shadow map

directionalLight.shadow.mapSize.set(512, 512);

// Set the properties of the parallel light projection camera

directionalLight.shadow.camera.near = 0.5;

directionalLight.shadow.camera.far = 500;

directionalLight.shadow.camera.top = 5;

directionalLight.shadow.camera.bottom = -5;

directionalLight.shadow.camera.left = -5;

directionalLight.shadow.camera.right = 5;

By changing the blurriness (20 — > 120):

// Set shadow map blur

directionalLight.shadow.radius = 120;

// Set the resolution of the shadow map

directionalLight.shadow.mapSize.set(2048, 2048);

// Set the properties of the parallel light projection camera

directionalLight.shadow.camera.near = 0.5;

directionalLight.shadow.camera.far = 500;

directionalLight.shadow.camera.top = 5;

directionalLight.shadow.camera.bottom = -5;

directionalLight.shadow.camera.left = -5;

directionalLight.shadow.camera.right = 5;

All codes are as follows, see code comments for analysis:

/*
 * @Description: Parallel light (DirectionalLight) shadow attribute and shadow camera principle
 */

// import dat.gui visualization tool
import * as dat from "dat.gui";
import * as THREE from "three";
// import track controller (mouse control)
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

/**
 * Target: Lighting and shadows - ambient light without shadows, parallel light (sun light), point light source (light bulb - glowing everywhere), spotlight (eight)
 * light shadow
 * 1. The material should be able to respond to light
        --Most commonly used-MeshStandardMaterial
 * -- More performance-consuming - the extension of MeshPhysicalMaterial-MeshStandardMaterial,
         More advanced physically based rendering properties are provided:
 * 2. Set the renderer to enable shadow calculation renderer.shadowMap.enabled = true;
 * 3. Set the light casting shadow directionalLight.castShadow = true;
 * 4. Set the object to cast shadow sphere.castShadow = true;
 * 5. Set the object to receive shadow plane.receiveShadow = true;
 */
/*
 *1. Create a scene
 */
const scene = new THREE. Scene();

/*
 * 2. Create a camera (here is a perspective camera--used to simulate what the human eye sees)
 */
const camera = new THREE. PerspectiveCamera(
  75, // view angle
  window.innerWidth / window.innerHeight, // aspect ratio
  0.1, // entry section
  1000 // far section
);
// set camera position
camera.position.set(7, 7, 7);
scene.add(camera); // add the camera to the scene

/*
 * add object
 */
// create geometry
const sphereGeometry = new THREE. SphereBufferGeometry(1, 20, 20);
// 1). Set the material
const material = new THREE. MeshStandardMaterial();
// generate geometry
const sphere = new THREE. Mesh(sphereGeometry, material);
// 4). Cast shadow -- whether the object is rendered into the shadow map -- three-dimensional object (Object3D)
sphere.castShadow = true;
scene. add(sphere);

/**
 * create plane
 */
const planeGeometry = new THREE. PlaneBufferGeometry(10, 10);
const plane = new THREE. Mesh(planeGeometry, material);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
// 5). Receive shadow
plane. receiveShadow = true;
scene. add(plane);

/**
 * lights
 */
// ambient light
const light = new THREE. AmbientLight(0xffffff, 0.5);
scene. add(light);

// Linear light source (parallel light)
const directionalLight = new THREE. DirectionalLight(0xffffff, 0.5);
// Set the position of parallel light
directionalLight.position.set(10, 10, 10);
// 3). Set parallel light to generate dynamic shadow
directionalLight.castShadow = true;

// Set shadow map blur
directionalLight.shadow.radius = 20;
// Set the resolution of the shadow map
directionalLight.shadow.mapSize.set(2048, 2048);

// Set the properties of the parallel light projection camera
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 500;
directionalLight.shadow.camera.top = 5;
directionalLight.shadow.camera.bottom = -5;
directionalLight.shadow.camera.left = -5;
directionalLight.shadow.camera.right = 5;

scene. add(directionalLight);

const gui = new dat. GUI();
gui
  .add(directionalLight. shadow. camera, "near")
  .min(0)
  .max(20)
  .step(0.1)
  .onChange(() => {
    directionalLight.shadow.camera.updateProjectionMatrix();
  });

/**
 * 3. Initialize the renderer
 */
const renderer = new THREE. WebGL1Renderer();
// set renderer size
renderer.setSize(window.innerWidth, window.innerHeight);

// 2). Turn on the shadow map in the scene--allow the use of shadow maps in the scene
renderer.shadowMap.enabled = true;

// Add the canvas content rendered by webgl to the body
document.body.appendChild(renderer.domElement);

/**
 * Create orbit controllers (OrbitControls)
 * Can make the camera orbit around the target
 */
const controls = new OrbitControls(camera, renderer.domElement);
// Set the controller damping to make the controller more realistic. You must call update() in the animation loop render()
controls.enableDamping = true;
// controls. autoRotate = true;
// controls.autoRotateSpeed = 2; // autorotation speed

/**
 * Auxiliary 3D coordinate system
 * Red stands for X-axis. Green stands for Y-axis. Blue stands for Z-axis.
 */
var axesHelper = new THREE. AxesHelper(7);
scene. add(axesHelper);

// Define the loop rendering method
function render() {
  renderer.render(scene, camera); // perform rendering operation
  controls.update(); // Add or not
  requestAnimationFrame(render); // The render function will be called when the next frame is rendered
}
render();

// Monitor size changes to achieve adaptive screen
window. addEventListener("resize", () => {
  // console.log("The screen has changed");
  // update camera
  camera.aspect = window.innerWidth / window.innerHeight;
  // Update the camera's projection matrix
  camera.updateProjectionMatrix();
  // update the renderer
  renderer.setSize(window.innerWidth, window.innerHeight);
  // Set the pixel ratio of the renderer
  renderer.setPixelRatio(window.devicePixelRatio);
});