three.js 平行光与阴影及其相关属性

基础篇:three.js 基础认识与简单应用

纹理贴图:three.js 纹理贴图的使用

纹理贴图进阶: three.js纹理贴图进阶

一、灯光与阴影的关系与设置 -- 五个步骤缺一不可 (点、聚会再次赘述)

 目标:灯光与阴影

  • 环境光无阴影
  • 平行光(太阳光),点光源(电灯泡-四处发光),聚光灯(八)

 1、材质要满足能够对光照有反应

  •  最常用-标准网格材质(MeshStandardMaterial)
  •  更消耗性能-物理网格材质(MeshPhysicalMaterial)-MeshStandardMaterial的扩展,提供了更高级的基于物理的渲染属性:

 2、设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true;

 3、设置光照投射阴影 directionalLight.castShadow = true;

 4、设置物体投射阴影 sphere.castShadow = true;

 5、设置物体接收阴影 plane.receiveShadow = true; 

示例:运行结果如下

 全部代码如下,解析见代码注释:

/*
 * @Description:  灯光与阴影的关系与设置 -- 五个步骤缺一不可
 */

import * as THREE from "three";
// 导入轨道控制器(鼠标控制)
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

/**
 * 目标:灯光与阴影--环境光无阴影,平行光(太阳光),点光源(电灯泡-四处发光),聚光灯(八)
 * 灯光阴影
 * 1、材质要满足能够对光照有反应
        --最常用-标准网格材质(MeshStandardMaterial)
 *      --更消耗性能-物理网格材质(MeshPhysicalMaterial)-MeshStandardMaterial的扩展,
         提供了更高级的基于物理的渲染属性:
 * 2、设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true;
 * 3、设置光照投射阴影 directionalLight.castShadow = true;
 * 4、设置物体投射阴影 sphere.castShadow = true;
 * 5、设置物体接收阴影 plane.receiveShadow = true;
 */

/*
 *1. 创建场景
 */
const scene = new THREE.Scene();

/*
 * 2.创建相机(这里是 透视摄像机--用来模拟人眼所看到的景象)
 */
const camera = new THREE.PerspectiveCamera(
  75, // 视野角度
  window.innerWidth / window.innerHeight, // 长宽比
  0.1, // 进截面
  1000 // 远截面
);
// 设置相机位置
camera.position.set(7, 7, 7);
scene.add(camera); // 将相机添加到场景中

/*
 *  添加物体
 */
// 创建几何体
const sphereGeometry = new THREE.SphereBufferGeometry(1, 20, 20);

// 1). 设置材质-标准网格材质
const material = new THREE.MeshStandardMaterial();

// 生成几何体
const sphere = new THREE.Mesh(sphereGeometry, material);

// 4). 投射阴影 --对象是否被渲染到阴影贴图中--三维物体(Object3D)
sphere.castShadow = true;

scene.add(sphere);

/**
 * 创建底部平面
 */
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). 接收阴影
plane.receiveShadow = true;

scene.add(plane);

/**
 * 灯光
 */
// 环境光
const light = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(light);
// 直线光源(平行光)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置平行光的位置
directionalLight.position.set(10, 10, 10);

// 3). 设置平行光产生动态阴影
directionalLight.castShadow = true;

scene.add(directionalLight);

/**
 *  3.初始化渲染器
 */
const renderer = new THREE.WebGL1Renderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);

// 2). 开启场景中的阴影贴图--允许在场景中使用阴影贴图
renderer.shadowMap.enabled = true;

// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement);

/**
 * 创建轨道控制器(OrbitControls)
 * 可以使得相机围绕目标进行轨道运动
 */
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼,让控制器更有真是效果,必须在动画循环render()中调用update()
controls.enableDamping = true;
// controls.autoRotate = true;
// controls.autoRotateSpeed = 2; // 自转速度

/**
 * 辅助三维坐标系
 * 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
 */
var axesHelper = new THREE.AxesHelper(7);
scene.add(axesHelper);

// 定义循环渲染方法
function render() {
  renderer.render(scene, camera); // 执行渲染操作
  controls.update(); // 加不加都行
  requestAnimationFrame(render); // 渲染下一帧的时候就会调用render函数
}
render();

// 监听尺寸变化实现自适应画面
window.addEventListener("resize", () => {
  // console.log("画面变化了");
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix();
  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置渲染器的像素比
  renderer.setPixelRatio(window.devicePixelRatio);
});

 

二、平行光THREE.DirectionalLight

 介绍:

        平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光 的效果; 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。

构造器:        

        DirectionalLight( color : Integer, intensity : Float )

                color - (可选参数) 16进制表示光的颜色。 缺省值为 0xffffff (白色)。
                intensity - (可选参数) 光照的强度。缺省值为1。

与点光源和聚光灯的区别:

        最大的区别就是,点光源聚光灯光源距离物体越远光线越暗。光是从一点发出的。
而被平行光照亮的整个区域接收到的光强是一样的。光是平行的。

平行光的特点:

        由于模型的阴影渲染会消耗很多的性能,所以我们需要设置平行光相关的区域能够显示阴影,和阴影显示的良好程度。如下几个属性:

        

        //这两个值决定使用多少像素生成阴影 默认512
        directionalLight.shadow.mapSize.height = 2048;
        directionalLight.shadow.mapSize.width = 2048;

        或者 

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

        // 设置阴影贴图模糊度

        directionalLight.shadow.radius = 20;

        // 设置平行光投射相机的属性

        directionalLight.shadow.camera.near = 0.5; //产生阴影的最近距离
        directionalLight.shadow.camera.far = 500; //产生阴影的最远距离
        directionalLight.shadow.camera.left = -5; //产生阴影距离位置的最左边位置
        directionalLight.shadow.camera.right = 5; //最右边
        directionalLight.shadow.camera.top = 5; //最上边
        directionalLight.shadow.camera.bottom = -5; //最下面

 示例:运行结果如下

通过 near 的变化:

// 设置阴影贴图模糊度

directionalLight.shadow.radius = 20;

// 设置阴影贴图的分辨率

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

// 设置平行光投射相机的属性

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;

  通过更改分辨率(2048 --> 512):

// 设置阴影贴图模糊度

directionalLight.shadow.radius = 20;

// 设置阴影贴图的分辨率

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

// 设置平行光投射相机的属性

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;

通过更改模糊度(20 -- > 120):

// 设置阴影贴图模糊度

directionalLight.shadow.radius = 120;

// 设置阴影贴图的分辨率

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

// 设置平行光投射相机的属性

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;

  全部代码如下,解析见代码注释:

/*
 * @Description:  平行光(DirectionalLight)阴影属性与阴影相机原理
 */

// 导入dat.gui可视化工具
import * as dat from "dat.gui";
import * as THREE from "three";
// 导入轨道控制器(鼠标控制)
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

/**
 * 目标:灯光与阴影--环境光无阴影,平行光(太阳光),点光源(电灯泡-四处发光),聚光灯(八)
 * 灯光阴影
 * 1、材质要满足能够对光照有反应
        --最常用-标准网格材质(MeshStandardMaterial)
 *      --更消耗性能-物理网格材质(MeshPhysicalMaterial)-MeshStandardMaterial的扩展,
         提供了更高级的基于物理的渲染属性:
 * 2、设置渲染器开启阴影的计算 renderer.shadowMap.enabled = true;
 * 3、设置光照投射阴影 directionalLight.castShadow = true;
 * 4、设置物体投射阴影 sphere.castShadow = true;
 * 5、设置物体接收阴影 plane.receiveShadow = true;
 */
/*
 *1. 创建场景
 */
const scene = new THREE.Scene();

/*
 * 2.创建相机(这里是 透视摄像机--用来模拟人眼所看到的景象)
 */
const camera = new THREE.PerspectiveCamera(
  75, // 视野角度
  window.innerWidth / window.innerHeight, // 长宽比
  0.1, // 进截面
  1000 // 远截面
);
// 设置相机位置
camera.position.set(7, 7, 7);
scene.add(camera); // 将相机添加到场景中

/*
 *  添加物体
 */
// 创建几何体
const sphereGeometry = new THREE.SphereBufferGeometry(1, 20, 20);
// 1). 设置材质
const material = new THREE.MeshStandardMaterial();
// 生成几何体
const sphere = new THREE.Mesh(sphereGeometry, material);
// 4). 投射阴影 --对象是否被渲染到阴影贴图中--三维物体(Object3D)
sphere.castShadow = true;
scene.add(sphere);

/**
 * 创建平面
 */
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). 接收阴影
plane.receiveShadow = true;
scene.add(plane);

/**
 * 灯光
 */
// 环境光
const light = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(light);

// 直线光源(平行光)
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
// 设置平行光的位置
directionalLight.position.set(10, 10, 10);
// 3). 设置平行光产生动态阴影
directionalLight.castShadow = true;

// 设置阴影贴图模糊度
directionalLight.shadow.radius = 20;
// 设置阴影贴图的分辨率
directionalLight.shadow.mapSize.set(2048, 2048);

// 设置平行光投射相机的属性
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.初始化渲染器
 */
const renderer = new THREE.WebGL1Renderer();
// 设置渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);

// 2). 开启场景中的阴影贴图--允许在场景中使用阴影贴图
renderer.shadowMap.enabled = true;

// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement);

/**
 * 创建轨道控制器(OrbitControls)
 * 可以使得相机围绕目标进行轨道运动
 */
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼,让控制器更有真是效果,必须在动画循环render()中调用update()
controls.enableDamping = true;
// controls.autoRotate = true;
// controls.autoRotateSpeed = 2; // 自转速度

/**
 * 辅助三维坐标系
 * 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
 */
var axesHelper = new THREE.AxesHelper(7);
scene.add(axesHelper);

// 定义循环渲染方法
function render() {
  renderer.render(scene, camera); // 执行渲染操作
  controls.update(); // 加不加都行
  requestAnimationFrame(render); // 渲染下一帧的时候就会调用render函数
}
render();

// 监听尺寸变化实现自适应画面
window.addEventListener("resize", () => {
  // console.log("画面变化了");
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新摄像机的投影矩阵
  camera.updateProjectionMatrix();
  // 更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置渲染器的像素比
  renderer.setPixelRatio(window.devicePixelRatio);
});

猜你喜欢

转载自blog.csdn.net/weixin_48594833/article/details/129667842