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

news2024/9/24 15:28:18

阴影投射

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

  • 灯光属性设置:.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.coloradmin.cn/o/2138485.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32(十四):USART串口数据包

HEX数据包 0xFF包头&#xff0c;0xFE包尾。 如果数据和包头包尾重复&#xff0c;可能会引起误判。 解决办法&#xff1a; 1. 限制载荷数据的范围 2. 如果无法避免载荷数据和包头包尾重复&#xff0c;就使用尽量使用固定长度数据包。 包头 ‘\r\n 包尾 在载荷数据中间可以出现…

代码23. 合并 K 个升序链表

模拟面试的时候没做出来&#xff0c;心碎了。 题目链接 . - 力扣&#xff08;LeetCode&#xff09; 自己的思考 无思考&#xff0c;直接看答案吧。 正确答案 其实写还是自己写的&#xff0c;看了下题解的思路。 第一种 思路简单&#xff0c;两两合并&#xff0c;注意事项已…

李飞飞任CEO,空间智能公司World Labs亮相,全明星阵容曝光

人工智能的下个大方向已经出现&#xff0c;标志性学者决定下场创业。 本周五&#xff0c;一个重磅消息引爆了 AI 圈&#xff1a;斯坦福大学计算机科学家李飞飞正式宣布创办 AI 初创公司 ——World Labs&#xff0c;旨在向人工智能系统传授有关物理现实的深入知识。 李飞飞说道&…

【检索快,IEEE独立出版】2024年第四届电子信息工程与计算机科学国际会议(EIECS 2024)

大会简介&#xff1a; 2024年第四届电子信息工程与计算机科学国际会议&#xff08;EIECS 2024&#xff09;将于2024年9月27日至29日在中国延吉举行。会议由长春理工大学主办&#xff0c;延边大学、长春理工大学电子信息工程学院、长春理工大学计算机科学技术学院、长春理工大学…

数据结构——栈和队列(栈的顺序存储结构和链式存储结构)

栈的定义 栈是一种重要的线性结构&#xff0c;可以这样讲&#xff0c;栈是前面讲过的线性表的一种具体形式。就像我们刚才的例子&#xff0c;栈这种后进先出的数据结构应用是非常广泛的。在生活中&#xff0c;例如我们的浏览器&#xff0c;每次点击一次“后退”都是退回到最近…

数据库密钥管理的密钥生成

数据库密钥管理是指对数据库中使用的加密密钥进行的一系列安全操作&#xff0c;以确保数据的机密性、完整性和可用性。这一管理过程通常包括密钥的生成、存储、分发、使用和销毁等环节。以下是关于数据库密钥管理的详细解析&#xff1a; 一、密钥的生成 目的&#xff1a;生成用…

谷歌图像生成AI-imagen 3新手入门指南!

1Google 最近推出了 Imagen 3&#xff0c;这是目前为止其最先进的文本生成图像模型。它基于之前的版本进行了改进&#xff0c;提供了更加精确的图像生成&#xff0c;减少了图像中的瑕疵&#xff0c;能够生成逼真、栩栩如生的图像。相比于早期版本&#xff0c;Imagen 3 可以处理…

Linux:重定向以及管道

重定向&#xff08;重新定向命令的输出&#xff09; 将前面命令的输出&#xff0c;作为内容&#xff0c;写入到后面的文件 管道 管道&#xff08;操作符号 | &#xff09; 作用&#xff1a;将前面命令的输出&#xff0c;传递给后面命令&#xff0c;作为后面命令的参数…

通信工程学习:什么是SNI业务节点接口

SNI&#xff1a;业务节点接口 SNI业务节点接口&#xff0c;全称Service Node Interface&#xff0c;是接入网&#xff08;AN&#xff09;和一个业务节点&#xff08;SN&#xff09;之间的接口&#xff0c;位于接入网的业务侧。这一接口在通信网络中扮演着重要的角色&#xff0c…

【机器学习-四-无监督学习unsupervise learning-聚类算法简介】

无监督学习unsupervise learning 聚类聚类的过程相似度度量方法聚类的方法划分式层次聚类基于密度的聚类 上一节讲的无监督学习&#xff0c;但是很多人可能会很疑惑&#xff0c;没有目标&#xff0c;那算法是怎么学会该怎样分类的呢&#xff1f;今天就简介一下其中的聚类算法。…

使用 SpringBoot 基础web开发的支持

首先导入项目相关的依赖&#xff1a; pom.xml 文件&#xff1a; 导入相关项目依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-in…

句子成分——每日一划(八)

目录 一、原句 二、第一部分 三、第二部分 一、原句 In class society everyone lives as a member of a particular class, and every kind of thinking, without exception, is stamped with the brand of a class. 来源&#xff1a;二、阶级和阶级斗争 二、第一部分 In…

免费像素画绘制软件 | Pixelorama v1.0.3

Pixelorama 是一款开源像素艺术多工具软件&#xff0c;旨在为用户提供一个强大且易于使用的平台来创作各种像素艺术作品&#xff0c;包括精灵、瓷砖和动画。这款软件以其丰富的工具箱、动画支持、像素完美模式、剪裁遮罩、预制及可导入的调色板等特色功能&#xff0c;满足了像素…

凑数字dp解决

前言&#xff1a;没有想到这个题目可以用dp来做&#xff0c;我们之前能够达到的最大的数字 当前的这一个数字为当前最大的数 ‘题目地址 #include<bits/stdc.h> using namespace std;#define int long long const int N (int)1e510;signed main() {int t; cin >>…

[全网首发]怎么让国行版iPhone使用苹果Apple Intelligence

全文共分为两个部分&#xff1a;第一让苹果手机接入AI&#xff0c;第二是让苹果手机接入ChatGPT 4o功能。 一、国行版iPhone开通 Apple Intelligence教程 打破限制&#xff1a;让国行版苹果手机也能接入AI 此次发布会上&#xff0c;虽然国行 iPhone16 系列不支持 GPT-4o&…

【Vue】2

1 Vue 生命周期 Vue生命周期&#xff1a;一个 Vue 实例从 创建 到 销毁 的整个过程 创建(create)阶段&#xff1a;组件实例化时&#xff0c;初始化数据、事件、计算属性等挂载(mount)阶段&#xff1a;将模板渲染并挂载到 DOM 上更新(update)阶段&#xff1a;当数据发生变化时…

Qt:饿汉单例(附带单例使用和内存管理)

前言 本文主要写饿汉单例以及单例的释放&#xff0c;网上很多教程只有单例的创建&#xff0c;但是并没有告诉我们单例的内存管理&#xff0c;这就很头疼。 正文 饿汉式单例 // SingletonClass.h #ifndef SINGLETONCLASS_H #define SINGLETONCLASS_H #include <QObject&g…

【Android Studio】使用雷电模拟器调试

文章目录 进入开发者模式使雷电模拟器adb连接PC测试 进入开发者模式 多次点击版本号 -开区USB调试 使雷电模拟器adb连接PC 写cmd脚本 雷电模拟器端口为5555 &#xff0c;脚本内容如下&#xff1a; adb.exe connect 127.0.0.1:5555双击bat脚本文件 测试

华为应用权限初次申请及二次申请

应用权限概述 系统提供了一种允许应用访问系统资源&#xff08;如&#xff1a;通讯录等&#xff09;和系统能力&#xff08;如&#xff1a;访问摄像头、麦克风等&#xff09;的通用权限访问方式&#xff0c;来保护系统数据&#xff08;包括用户个人数据&#xff09;或功能&…

10.4K Star,高性能富文本编辑器

Hi&#xff0c;骚年&#xff0c;我是大 G&#xff0c;公众号「GitHub 指北」会推荐 GitHub 上有趣有用的项目&#xff0c;一分钟 get 一个优秀的开源项目&#xff0c;挖掘开源的价值&#xff0c;欢迎关注。 在现代 Web 开发中&#xff0c;富文本编辑器是不可或缺的一部分&…