WEB 3D技术 three.js 光照与阴影

本文 我们来说 灯光与阴影

之前 我们有接触到光照类的知识 但是阴影应该都是第一次接触
那么 我们先来看光
首先是 AmbientLight 环境光 你在官网中搜索 AmbientLight 官方是就写明了 环境光是不会产生阴影的
因为 它没有反向
WEB 3D技术 three.js 光照与阴影_第1张图片
然后是 DirectionalLight 平行光 它是可以投射阴影的
因为它是类似于太阳 那 太阳照下来 自然是有阴影的
WEB 3D技术 three.js 光照与阴影_第2张图片
还有就是 PointLight 点光源
点光源也是可以产生阴影 但 它是自身为中心 四处发光的
就好像一颗光球 会照向四周
WEB 3D技术 three.js 光照与阴影_第3张图片
SpotLight 聚光灯
WEB 3D技术 three.js 光照与阴影_第4张图片
这个就像舞台聚关灯的一个效果 中心点光很聚集 照向一个放心 越远光越分散 范围越大
WEB 3D技术 three.js 光照与阴影_第5张图片
RectAreaLight 平面光源
比较像 从窗户外面照进来的光
但官网也说明白了 平面光是不支持阴影的
WEB 3D技术 three.js 光照与阴影_第6张图片
大体可以总结为 环境光和平面光是无法产生阴影的
那么 还有一些材质 也是不支持阴影的

首当其冲的就是 MeshBasicMaterial 基础网格材质
官网会告诉你 它有没有光照都是一样的 自然不会有阴影类的反应
WEB 3D技术 three.js 光照与阴影_第7张图片
MeshStandardMaterial 标准网格材质
这种就是 使用Metallic-Roughness工作流程
和光照息息相关的 它就可以产生出阴影
WEB 3D技术 three.js 光照与阴影_第8张图片
MeshLambertMaterial 的话 也有光的效果 但是 这种比较粗糙 不光滑
比较适合做木材等表面粗糙的物体的反射效果
WEB 3D技术 three.js 光照与阴影_第9张图片
MeshPhongMaterial 则相反 它适合做一些表面光滑的物体
WEB 3D技术 three.js 光照与阴影_第10张图片
MeshLambertMaterial 和 MeshPhongMaterial,都是以性能好作为优势的 相对逼真的程度会弱一些

通常情况下 选择 MeshStandardMaterial 标准网格材质 就够了
那么 还有 MeshPhysicalMaterial 物理网格材质
它内部是更高级的渲染引擎 效果会比基础网格材质更加逼真
但是 会消耗更多的性能
他也是能够更光照发生作用的
WEB 3D技术 three.js 光照与阴影_第11张图片
OK 那 我们想在就代码搞起喽

我们先把代码搞成这样

import './style.css'
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

//创建相机
const camera = new THREE.PerspectiveCamera(
    45, //视角 视角越大  能看到的范围就越大
    window.innerWidth / window.innerHeight,//相机的宽高比  一般和画布一样大最好
    0.1,
    1000
);
const scene = new THREE.Scene();

//c创建一个canvas容器  并追加到 body上
const renderer = new THREE.WebGLRenderer(0);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

//设置相机位置   这里 我们设置Z轴  大家可以试试  S Y 和 Z  都是可以的
camera.position.z = 5;
//设置相机默认看向哪里   三个 0  代表 默认看向原点
camera.lookAt(0, 0, 0);
//将内容渲染到元素上
renderer.render(scene, camera);
const controls = new OrbitControls(camera, renderer.domElement);

function animate() {
    controls.update();
    requestAnimationFrame(animate);
    /*cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;*/
    renderer.render(scene, camera);
}
animate();

运行起来 就是 一片黑 暂时什么都没有
WEB 3D技术 three.js 光照与阴影_第12张图片
我们加入如下代码

// 环境光
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);
scene.add(directionallight);
//创建球形几何体
const sphere1 = new THREE .Mesh(
new THREE.SphereGeometry(0.7, 32, 32),
new THREE.MeshStandardMaterial({
}))
scene.add(sphere1);

这里 我们设置了 环境光 然后创建了一个球形的几何体
球体材质是 普通的 MeshStandardMaterial
WEB 3D技术 three.js 光照与阴影_第13张图片
我们拖动一下 会发现 这个球还是有一个反光的效果
我们在他下面加一个平面

//添加平面
const plane = new THREE.Mesh(
  new THREE.PlaneGeometry(3, 3),
  new THREE.MeshStandardMaterial({})
);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
scene.add(plane);

也是最普通的材质 然后 position y下移 到 负1的位置 然后 旋转rotation 负90度
WEB 3D技术 three.js 光照与阴影_第14张图片
我们转动一下平面
WEB 3D技术 three.js 光照与阴影_第15张图片
这里 虽然我们有灯光反射的一个效果 但是 显然没有出现阴影的效果

那么 想要有阴影 首先 你要有能达到阴影要求的光照
然后 我们渲染器 要开启这个渲染的计算

我们官网搜索 WebGLRenderer
下面就有一个 shadowMap 阴影贴图效果
这个属性 默认是false 不使用的
WEB 3D技术 three.js 光照与阴影_第16张图片
我们找到 渲染器所在位置 将他的 shadowMap字段下的 enabled 设置为true
WEB 3D技术 three.js 光照与阴影_第17张图片
开启了之后 我们要设置光照 投射我们的阴影

我们官网 进入平行直线光
WEB 3D技术 three.js 光照与阴影_第18张图片
找到属性中的 castShadow 投射阴影
WEB 3D技术 three.js 光照与阴影_第19张图片
他默认 为了避免性能消耗 是关闭的
我们直接在平行光这里 给他 castShadow 设为true即可开启
WEB 3D技术 three.js 光照与阴影_第20张图片
然后 物体 我们也要设置 让它能够投射我们的阴影
我们 官网进入 Object3D
它的这个属性也叫 castShadow
是否投射阴影
WEB 3D技术 three.js 光照与阴影_第21张图片
我们代码中 将球形几何体的 castShadow 给个true 把它打开
WEB 3D技术 three.js 光照与阴影_第22张图片
然后 这个阴影是要映射到我们平面上的
那么 这里 我们平面 要去接受这个阴影效果
Object3D 下的 receiveShadow 属性
WEB 3D技术 three.js 光照与阴影_第23张图片
平面这里 我们将 receiveShadow 属性设为true
WEB 3D技术 three.js 光照与阴影_第24张图片
这培 我们运行代码
WEB 3D技术 three.js 光照与阴影_第25张图片
阴影的效果 就出来啦
WEB 3D技术 three.js 光照与阴影_第26张图片
所有的步骤 一个不能少 否则就出不来

好 我们最后的代码就是这样的

import './style.css'
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";

//创建相机
const camera = new THREE.PerspectiveCamera(
    45, //视角 视角越大  能看到的范围就越大
    window.innerWidth / window.innerHeight,//相机的宽高比  一般和画布一样大最好
    0.1,
    1000
);
const scene = new THREE.Scene();

// 环境光
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);
directionallight.castShadow = true;
scene.add(directionallight);
//创建球形几何体
const sphere1 = new THREE .Mesh(
  new THREE.SphereGeometry(0.7, 32, 32),
  new THREE.MeshStandardMaterial({})
)
sphere1.castShadow = true;
scene.add(sphere1);
//添加平面
const plane = new THREE.Mesh(
  new THREE.PlaneGeometry(3, 3),
  new THREE.MeshStandardMaterial({})
);
plane.position.set(0, -1, 0);
plane.rotation.x = -Math.PI / 2;
plane.receiveShadow = true;
scene.add(plane);


//c创建一个canvas容器  并追加到 body上
const renderer = new THREE.WebGLRenderer(0);
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);

//设置相机位置   这里 我们设置Z轴  大家可以试试  S Y 和 Z  都是可以的
camera.position.z = 5;
//设置相机默认看向哪里   三个 0  代表 默认看向原点
camera.lookAt(0, 0, 0);
//将内容渲染到元素上
renderer.render(scene, camera);
const controls = new OrbitControls(camera, renderer.domElement);

function animate() {
    controls.update();
    requestAnimationFrame(animate);
    /*cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;*/
    renderer.render(scene, camera);
}
animate();

你可能感兴趣的:(前端,3d,javascript)