当前位置: 首页 > article >正文

【技术调研】三维(4)-ThreeJs阴影投射、光线投射及案例

阴影投射

阴影是灯光经过物体后产生的,几个关键的设置:

  • 灯光属性设置:.castShadow : Boolean 。此属性设置为 true 灯光将投射阴影。注意:这样做的代价比较高,需要通过调整让阴影看起来正确。 查看 DirectionalLightShadow 了解详细信息。 默认值为 false
  • 物体属性设置:
    • .castShadow : Boolean 对象是否被渲染到阴影贴图中。默认值为false
    • .receiveShadow : Boolean 材质是否接收阴影。默认值为false
  • 渲染器设置:.shadowMap : enabled: 如果设置开启,允许在场景中使用阴影贴图。默认是 false

阴影投射动画案例

<!DOCTYPE html>
<html lang="en">

<head>
	<meta charset="utf-8">
	<title>My first three.js app</title>
	<style>
		body {
			margin: 0;
		}
	</style>
</head>

<body>
	<script type="module">
		import * as THREE from "three";
		import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

		const scene = new THREE.Scene();
		const camera = new THREE.PerspectiveCamera(
			75,
			window.innerWidth / window.innerHeight,
			0.1,
			1000
		);
		camera.position.set(0, 50, 100);
		camera.lookAt(0, 0, 0);

		const renderer = new THREE.WebGLRenderer({
			antialias: true
		})
		renderer.setSize(window.innerWidth, window.innerHeight);
		renderer.shadowMap.enabled = true;
		renderer.shadowMapType = THREE.PCFSoftShadowMap;
		document.body.appendChild(renderer.domElement);

		//创建坐标格辅助对象
		// const gridHelper = new THREE.GridHelper(100,20,0xffffff );
		// scene.add( gridHelper );






		/**
		 *  创建地面
		 */
		const geometry2 = new THREE.PlaneGeometry(100, 100);
		const material2 = new THREE.MeshStandardMaterial({ color: 0xffffff });
		const plane = new THREE.Mesh(geometry2, material2);
		plane.rotation.x = -Math.PI / 2;
		plane.receiveShadow = true;
		scene.add(plane);
		//旋转


		/**
		 *  创建一个立方体
		 */
		const geometry = new THREE.BoxGeometry(10, 10, 10);
		const textureLoader = new THREE.TextureLoader();
		const texture = textureLoader.load('./img/Banner.png');
		const material = new THREE.MeshStandardMaterial({ map: texture });
		const cube = new THREE.Mesh(geometry,material);
		cube.position.set(0, 5, 0);
		cube.castShadow = true;
		scene.add(cube);


		/**
		 * 灯光
		 */
		//环境光
		const ambientLight = new THREE.AmbientLight(0x404040); // 柔和的白光
		scene.add(ambientLight);
		// 平行光
		const directionLight = new THREE.DirectionalLight(0xffffff, 1);
		directionLight.castShadow = true;
		//让阴影更清晰
		directionLight.shadow.mapSize.width = 2048;
		directionLight.shadow.mapSize.height = 2048;
		//不设置以下内容看不见
		directionLight.shadow.camera.left = -100;
		directionLight.shadow.camera.right = 100;
		directionLight.shadow.camera.top = 100;
		directionLight.shadow.camera.bottom = -100;
		directionLight.position.set(150, 20, 0);
		const directionalLightHelper = new THREE.DirectionalLightHelper(directionLight, 5);
		scene.add(directionLight, directionalLightHelper);
		// 点光源
		const pointLight = new THREE.PointLight( 0xffffff, 500 );
		const pointLightHelper = new THREE.PointLightHelper(pointLight,1);
		pointLight.castShadow = true;
		pointLight.position.set( 10, 10, 0 );
		scene.add( pointLight,pointLightHelper );
		/**
		 * 用于查看投射相机
		 */
		// const cam = directionLight.shadow.camera;
		// const cameraHelper = new THREE.CameraHelper(cam);
		// scene.add(cameraHelper);
		// cameraHelper.visible = true;




		const controls = new OrbitControls(camera, renderer.domElement);
		controls.enableDamping = true;
		let angle = 0;
		const animete = () => {
			angle += 0.01;
			pointLight.position.set(10*Math.cos(angle),pointLight.position.y,10*Math.sin(angle));
			requestAnimationFrame(animete);
			renderer.render(scene, camera);
		};
		animete();

	</script>
</body>

</html>

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

光线投射

RayCaster可以向特定方向投射光线,并测试哪些对象与其相交。光线投射用于进行鼠标拾取(在三维空间中计算出鼠标移过了什么物体)。

应用场景:

  1. 测试相机前方是否有一堵墙(障碍)
  2. 光线是否击中目标
  3. 当鼠标移动时测试是否有物体位于光标下方,以此模拟鼠标事件
  4. 当物体朝向特定某处时提示信息

光线投射动画

1.动态的三个小球使用了一个固定方向的光线投射,被光线穿透会变绿色。

2.静态的三个小球,使用的是鼠标+相机方向进行光线投射,鼠标点击时触发。即鼠标点击会变黄色。

<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="utf-8">
		<title>My first three.js app</title>
		<style>
			body {
				margin: 0;
			}
		</style>
	</head>

	<body>
		<script type="module">
			import * as THREE from "three";
			import {
				OrbitControls
			} from 'three/addons/controls/OrbitControls.js';

			const scene = new THREE.Scene();
			const camera = new THREE.PerspectiveCamera(
				75,
				window.innerWidth / window.innerHeight,
				0.1,
				1000
			);
			camera.position.set(0, 5, 5);
			camera.lookAt(0, 0, 0);

			const renderer = new THREE.WebGLRenderer({
				antialias: true
			})
			renderer.setSize(window.innerWidth, window.innerHeight);
			renderer.shadowMap.enabled = true;
			renderer.shadowMapType = THREE.PCFSoftShadowMap;
			document.body.appendChild(renderer.domElement);




			/**
			 *  创建地面
			 */
			const geometry2 = new THREE.PlaneGeometry(100, 100);
			const material2 = new THREE.MeshStandardMaterial({
				color: 0xffffff
			});
			const plane = new THREE.Mesh(geometry2, material2);
			//旋转
			plane.rotation.x = -Math.PI / 2;
			plane.receiveShadow = true;
			plane.position.y = -5;
			scene.add(plane);


			/**
			 * 球1
			 */
			const sphere1 = new THREE.Mesh(
				new THREE.SphereGeometry(0.5, 32, 32),
				new THREE.MeshBasicMaterial({
					color: 0xff0000
				})
			)
			sphere1.position.x = -2
			const sphere2 = new THREE.Mesh(
				new THREE.SphereGeometry(0.5, 32, 32),
				new THREE.MeshBasicMaterial({
					color: 0xff0000
				})
			)

			const sphere3 = new THREE.Mesh(
				new THREE.SphereGeometry(0.5, 32, 32),
				new THREE.MeshBasicMaterial({
					color: 0xff0000
				})
			)
			sphere3.position.x = 2;
			scene.add(sphere1, sphere2, sphere3)
			const sphere4 = new THREE.Mesh(
				new THREE.SphereGeometry(0.5, 32, 32),
				new THREE.MeshBasicMaterial({
					color: 0xff0000
				})
			)
			sphere4.position.x = -2
			sphere4.position.z = -5
			const sphere5 = new THREE.Mesh(
				new THREE.SphereGeometry(0.5, 32, 32),
				new THREE.MeshBasicMaterial({
					color: 0xff0000
				})
			)
			sphere5.position.z = -5
			const sphere6 = new THREE.Mesh(
				new THREE.SphereGeometry(0.5, 32, 32),
				new THREE.MeshBasicMaterial({
					color: 0xff0000
				})
			)
			sphere6.position.x = 2;
			sphere6.position.z = -5
			scene.add(sphere4, sphere5, sphere6)


			/**
			 * 灯光
			 */
			//环境光
			const ambientLight = new THREE.AmbientLight(0x404040); // 柔和的白光
			scene.add(ambientLight);

			/**
			 * 创建光线投射
			 */
			const raycaster = new THREE.Raycaster()
			//射线原点
			const rayOrigin = new THREE.Vector3(-3, 0, 0)
			//射线方向
			const rayDirection = new THREE.Vector3(10, 0, 0)
			//将该向量的方向设置为和原向量相同,但是其长度
			rayDirection.normalize()
			raycaster.set(rayOrigin, rayDirection)
			// 检测和射线相交的物体。
			const intersect = raycaster.intersectObject(sphere1)
			console.log(intersect)
			// 检测和射线相交的一组物体。
			const intersects = raycaster.intersectObjects([sphere1, sphere2, sphere3])
			console.log(intersects)
			console.log(raycaster)


			/**
			 * 创建用于鼠标控制的光线投射
			 */
			const raycaster2 = new THREE.Raycaster();
			const objectsToTests = [sphere4, sphere5, sphere6];
			/**
			 * 获取鼠标位置,转换为x,y形成射线原点
			 */
			const mouse = new THREE.Vector2();
			window.addEventListener("mousedown", (event) => {

				mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
				mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
				//设置后会根据鼠标和相机 进行光线投射
				console.log(camera.position);
				raycaster2.setFromCamera(mouse, camera);
				console.log(raycaster2);
				console.log(mouse);
				const intersectObjects = raycaster2.intersectObjects(objectsToTests);
				console.log(intersectObjects);
				for (const object of objectsToTests) {
					object.material.color.set(0xff0000);
				}
				for (const intersect of intersectObjects) {
					intersect.object.material.color.set(0xFFFF00)
				}

			})


			const controls = new OrbitControls(camera, renderer.domElement);
			controls.enableDamping = true;
			const clock = new THREE.Clock()
			const animete = () => {

				const elapsedTime = clock.getElapsedTime();

				sphere1.position.y = Math.sin(elapsedTime * 0.3) * 1.5
				sphere2.position.y = Math.sin(elapsedTime * 0.7) * 1.5
				sphere3.position.y = Math.sin(elapsedTime * 1.4) * 1.5
				const objectsToTests = [sphere1, sphere2, sphere3]
				const intersectObjects = raycaster.intersectObjects(objectsToTests)

				for (const object of objectsToTests) {
					object.material.color.set(0xff0000)
				}
				for (const intersect of intersectObjects) {
					intersect.object.material.color.set(0x008000)
				}
				
				controls.update()
				requestAnimationFrame(animete);
				renderer.render(scene, camera);
			};
			animete();
		</script>
	</body>

</html>

http://www.kler.cn/news/306330.html

相关文章:

  • three.js KeyframeTrack
  • SpringMVC 入门案例详解
  • 免费像素画绘制软件 | Pixelorama v1.0.3
  • ArrayList动态数组
  • react18基础教程系列--安装环境及packagejson文件分析
  • llama网络结构及源码
  • 【MySQL学习】基础指令全解:构建你的数据库技能
  • OPENAIGC开发者大赛高校组金奖 | 基于混合大语言模型与多模态的全过程通用AI Agent
  • 【搜索算法】以扩召回为目标,item-tag不如query-tag能扩更多数量
  • 软件设计师——程序设计语言
  • 【短距离通信】【WiFi】精讲Android WiFi P2P架构及代码示例
  • SpringBoot教程(安装篇) | RabbitMQ的安装
  • MySQl篇(数据类型)(持续更新迭代)
  • 面试常见题之Spring Cloud
  • Redis常见应用场景
  • fsck 命令:修复文件系统错误
  • 读构建可扩展分布式系统:方法与实践05分布式缓存
  • 2-3.Android 存储之存储空间(私有空间、公共空间)
  • 【Android】Room—数据库的基本操作
  • 第108集《大佛顶首楞严经》
  • CAD_Electrical 2022使用记录
  • [Python学习日记-23] Python v2 和 v3 中的字符编码
  • python定时任务,定时爬取水质和天气
  • Navicat On-Prem Server 2.0 | MySQL与MariaDB基础管理功能正式上云
  • Windows电脑A远程连接电脑B
  • Java面试篇基础部分-Java反射机制是什么
  • 镜舟科技与中启乘数科技达成战略合作,共筑数据服务新生态
  • Lua闭包
  • 基于yolov5的混凝土缺陷检测系统python源码+onnx模型+评估指标曲线+精美GUI界面
  • 【Linux C | 终端设备】Linux下 tty、ttyS*、ttyAMA*、console 的区别,以及系统输出重定向(附带代码)