效果示意图如下
一. 添加阴影投影
- 允许渲染器渲染阴影
renderer.shadowMap.enabled = true;
- 设置物体可以产生阴影 对象是否渲染到阴影贴图中,默认值为false
mesh.castShadow = true;
- 设置平面网格为接受阴影的投影面
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); // 生成平面网格
planeMesh.receiveShadow = true; // 设置平面网格为接受阴影的投影面
planeMesh.rotation.x = -Math.PI / 2; //绕X轴旋转90度
scene.add(planeMesh); // 添加到场景中
- 允许光源可以产生阴影
light.castShadow = true; // 允许生成阴影
二. 添加物体移动控件
1.导入包
import {TransformControls} from './three.js-dev/examples/jsm/controls/TransformControls.js';
2.创建TransformControls控件
const transformControls = new TransformControls(camera, renderer.domElement);
transformControls.setSize(0.5);
transformControls.setMode("translate");
//当除了移动控件的其他控件触发时,禁止移动控件
transformControls.addEventListener('dragging-changed', function (event) {
controls.enabled = !event.value;
});
- 绑定控件
scene.add(transformControls);
transformControls.attach(mesh2);
- 键盘切换TransformControls模式
//键盘响应
window.addEventListener('keydown', function (event) {
switch (event.keyCode) {
case 82: // R
transformControls.setMode('rotate');
break;
case 83: // S
transformControls.setMode('scale');
break;
case 84: // T
transformControls.setMode('translate');
break;
case 187:
case 107: // +, =, num+
transformControls.setSize(transformControls.size + 0.1);
break;
case 189:
case 109: // -, _, num-
transformControls.setSize(Math.max(transformControls.size - 0.1, 0.1));
break;
}
});
end 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Three.js实现光照阴影</title>
<style>
* {
margin: 0;
padding: 0;
}
</style>
</head>
<body>
</body>
<script type="module">
// 导入需要的包
import * as THREE from './three.js-dev/build/three.module.js';
import {OrbitControls} from './three.js-dev/examples/jsm/controls/OrbitControls.js';
import {TransformControls} from './three.js-dev/examples/jsm/controls/TransformControls.js';
// 创建div标签 container图层
let container = document.createElement('div');
// 向body中插入一个dom标签元素
document.body.appendChild(container);
// 1. 创建空白场景
let scene = new THREE.Scene();
// 2. 创建相机
/**
* width 窗口宽度
* height 窗口高度
* k 窗口宽高比
* s 三维场景显示范围控制系数,系数越大,显示的范围越大
*/
const width = window.innerWidth;
const height = window.innerHeight;
const k = width / height;
const s = 100;
//创建相机对象
/**
* 正视投影
* left 摄像机视锥体左侧面
* right 摄像机视锥体右侧面
* top 摄像机视锥体上侧面
* bottom 摄像机视锥体下侧面
* near 摄像机视锥体近端面
* far 摄像机视锥体远端面
*/
var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000); //正视投影
/**
* 透视投影 见./pictures/透视投影-视锥体.png
* PerspectiveCamera( fov : Number, aspect : Number, near : Number, far : Number )
* fov 摄像机视锥体垂直视野角度
* aspect 摄像机视锥体长宽比
* near 摄像机视锥体近端面
* far 摄像机视锥体远端面
*/
// const camera = new THREE.PerspectiveCamera(90, width / height, 1, 500);
camera.position.set(50, 50, 50); // 设置相机位置xyz
// camera.lookAt(scene.position); //设置相机方向(指向的场景对象)position
// 3. 创建渲染器
let renderer = new THREE.WebGLRenderer({
antialias: true, // 是否执行抗锯齿
});
renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比率。通常用于HiDPI设备,以防止输出画布模糊。
renderer.setSize(width, height); // 设置渲染器大小 ***
renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
renderer.shadowMap.enabled = true;
container.appendChild(renderer.domElement);
var geometry6 = new THREE.CylinderGeometry(3, 3, 10, 50); // THREE.CylinderGeometry构造圆柱体
var material6 = new THREE.MeshLambertMaterial({
color: 0xFFFF00,
wireframe: false //线框,默认关闭
}); //THREE.MeshLambertMaterial高级材质,构造类似木头、石头等不光滑的表面
var mesh6 = new THREE.Mesh(geometry6, material6); // 网状 Mesh的构造函数是这样的:Mesh( geometry, material ) geometry是它的形状,material是它的材质
mesh6.position.set(20, 0, 0);
;
scene.add(mesh6);
// 4. 材质
// 金属材质
const geometry = new THREE.BoxGeometry(2, 5, 6); //创建一个立方体几何对象Geometry
// 材质对象Material
const material = new THREE.MeshLambertMaterial({
color: 0x7777ff,
specular: 0x7777ff,
shininess: 30
});
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
mesh.castShadow = true;
mesh.position.set(-10, 3, 3); // 设置物体位置
scene.add(mesh); //网格模型添加到场景中
// 圆柱网格模型
const geometry3 = new THREE.CylinderGeometry(3, 3, 10, 50);
const material3 = new THREE.LineDashedMaterial({
color: 0xffffff,
wireframe: false //线框,默认关闭
});
const mesh3 = new THREE.Mesh(geometry3, material3); //网格模型对象Mesh
// mesh3.translateX(120); //球体网格模型沿Y轴正方向平移120
mesh3.position.set(12, 0, 0);//设置mesh3模型对象的xyz坐标为120,0,0
mesh3.castShadow = true; // 对象是否渲染到阴影贴图中,默认值为false
scene.add(mesh3); //
// 创建物体2 网格Lambert材质
const geometry2 = new THREE.BoxGeometry(2, 5, 6);
const material2 = new THREE.MeshLambertMaterial({
color: 0xff00ff, //颜色 16进制
opacity: 0.9, //透明度 0-1
transparent: true, //开启透明度,默认关闭
wireframe: false //线框,默认关闭
}); //材质对象Material
const mesh2 = new THREE.Mesh(geometry2, material2);
mesh2.castShadow = true; // 对象是否渲染到阴影贴图中,默认值为false
mesh2.position.set(1, 3, 3); // 设置物体位置
scene.add(mesh2); // 添加到场景中
camera.lookAt(mesh2.position); //设置相机方向(指向的场景对象)position
// 创建物体4
const geometry4 = new THREE.BoxGeometry(2, 5, 6); //创建一个球体几何对象
const material4 = new THREE.MeshLambertMaterial({
color: 0xff00ff, //颜色 16进制
opacity: 0.9, //透明度 0-1
transparent: true, //开启透明度,默认关闭
wireframe: true //线框,默认关闭
}); //材质对象Material
const mesh4 = new THREE.Mesh(geometry4, material4);
mesh4.castShadow = true; // 对象是否渲染到阴影贴图中,默认值为false
mesh4.position.set(-20, 3, 3); // 设置物体位置
scene.add(mesh4); // 添加到场景中
// 创建平面
const planeGeometry = new THREE.PlaneGeometry(300, 300); // 生成平面几何
const planeMaterial = new THREE.MeshLambertMaterial({
// 生成材质
color: 0xffffff,
});
const planeMesh = new THREE.Mesh(planeGeometry, planeMaterial); // 生成平面网格
planeMesh.receiveShadow = true; // 设置平面网格为接受阴影的投影面
planeMesh.rotation.x = -Math.PI / 2; //绕X轴旋转90度
scene.add(planeMesh); // 添加到场景中
//创建坐标轴
const axisHelper = new THREE.AxisHelper(1000);
scene.add(axisHelper)
//创建光源
const light = new THREE.PointLight(0xffffff, 2); // 点光源 颜色为白色,强度为
light.position.set(40, 40, 20); // 设置灯源位置
light.castShadow = true; // 允许生成阴影
scene.add(light); // 添加到场景中
// // 聚光光源
// var spotLight = new THREE.SpotLight(0xffffff);
// // 设置聚光光源位置
// spotLight.position.set(20, 20, 20);
// // 聚光灯光源指向网格模型mesh2
// spotLight.target = mesh2;
// // 设置聚光光源发散角度
// spotLight.angle = Math.PI / 6
// spotLight.castShadow = true; // 允许生成阴影
// scene.add(spotLight);//光对象添加到scene场景中
//创建环境光
const ambient = new THREE.AmbientLight(0x444444);
scene.add(ambient);
// 创建控制器
let controls = new OrbitControls(camera, renderer.domElement);
// controls.enabled = false;
const transformControls = new TransformControls(camera, renderer.domElement);
transformControls.setSize(0.5);
transformControls.setMode("translate");//
//当除了移动控件的其他控件触发时,禁止移动控件
transformControls.addEventListener('dragging-changed', function (event) {
controls.enabled = !event.value;
});
scene.add(transformControls);
transformControls.attach(mesh2);
//键盘响应
window.addEventListener('keydown', function (event) {
switch (event.keyCode) {
case 82: // R
transformControls.setMode('rotate');
break;
case 83: // S
transformControls.setMode('scale');
break;
case 84: // T
transformControls.setMode('translate');
break;
case 187:
case 107: // +, =, num+
transformControls.setSize(transformControls.size + 0.1);
break;
case 189:
case 109: // -, _, num-
transformControls.setSize(Math.max(transformControls.size - 0.1, 0.1));
break;
}
});
animate();
function animate() {
requestAnimationFrame(animate);
renderer.render(scene, camera);
}
</script>
</html>