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

three.js 模型高亮效果实现说明(结合react)

three.js + react 实现鼠标移入模型高亮选中效果

使用EffectComposer和其附加的渲染效果Passes(如RenderPassOutlinePass)来实现高级渲染效果。首先创建EffectComposer实例,并添加RenderPassOutlinePass,最后在渲染循环中调用EffectComposer的渲染方法。这样可以在保持场景内容不变的情况下,应用光晕效果,增强场景的视觉效果。
在这里插入图片描述

EffectComposer效果合成器

EffectComposer( renderer : WebGLRenderer, renderTarget : WebGLRenderTarget )

  • renderer:用于渲染场景的渲染器。
  • renderTarget:(可选)一个预先配置的渲染目标,内部由 EffectComposer 使用。

属性

  • passes,一个用于表示后期处理过程链(包含顺序)的数组。
  • readBuffer,内部读缓冲区的引用。过程一般从该缓冲区读取先前的渲染结果。
  • renderer,内部渲染器的引用。
  • renderToScreen,最终过程是否被渲染到屏幕(默认帧缓冲区)。

常用方法

  • addPass:将传入的过程添加到过程链。
  • insertPass:将传入的过程插入到过程链中所给定的索引处。
  • render:执行所有启用的后期处理过程,来产生最终的帧。
  • reset:重置所有EffectComposer的内部状态。
  • setPixelRatio:设置设备的像素比。
  • setSize:考虑设备像素比,重新设置内部渲染缓冲和过程的大小为(width, height)。

资源文件说明

  • EffectComposer:所有后期处理效果的容器。
  • RenderPass:用于渲染基础场景到一张纹理上,但不会添加至屏幕上。
  • OutlinePass:添加闪烁效果。
  • FXAA/SMAA Pass:可选地加入抗锯齿Pass,如FXAAShader或SMAAPass,提高边缘平滑度。
  • UnrealBloomPass:如果需要,还可以添加UnrealBloomPass以增强光照和视觉效果。

引入资源文件

import * as three from 'three';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass';
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass';
import { GammaCorrectionShader } from 'three/examples/jsm/shaders/GammaCorrectionShader';

创建THREE.EffectComposer

创建一个 THREE.EffectComposer 对象,传入的参数是WebGLRenderer:

// 创建一个webGL对象
let renderer = new THREE.WebGLRenderer({//增加下面两个属性,可以抗锯齿antialias: true,alpha: true,logarithmicDepthBuffer: true // 解决模型闪烁问题
});
// 创建一个EffectComposer对象
let composer = new EffectComposer(renderer); 

创建renderPass渲染通道

染器通道RenderPass的作用是指定后处理对应的相机camera和场景scene。

// 创建一个渲染器通道,场景和相机作为参数 
const renderPass = new RenderPass(scene, camera);
// 给EffectComposer添加一个渲染器通道 
composer.addPass(renderPass);

创建OutlinePass高亮通道

给three.js场景中模型添加闪烁效果,如果有多个模型的话,可以通过OutlinePass的选择对象属性.selectedObjects设置。

// 模型边缘发光通道
const v2 = new THREE.Vector2(width, height);
// OutlinePass第一个参数的尺寸和canvas画布保持一致
const outlinePass = new OutlinePass(v2, scene, camera);outlinePass.visibleEdgeColor.set('#00FF00'); // 呼吸显示颜色 outlinePass.hiddenEdgeColor.set('#00FF00');// 呼吸消失颜色 
outlinePass.edgeStrength = 5; // 边框的亮度强度 
outlinePass.edgeGlow = 0.5; // 光晕[0,1] 
outlinePass.edgeThickness = 3;// 边缘宽度 
outlinePass.pulsePeriod = 2; // 呼吸闪烁速度 
outlinePass.renderToScreen = true; // 设置这个参数的目的是马上将当前的内容输出// 将OutlinePass通道添加到后处理composer中
composer.addPass(outlinePass);

循环渲染

function renderFn() {composer.render(T);requestAnimationFrame(renderFn);
}

高亮方法封装

/*** 模型移入高亮* @param { 区域宽度 } width* @param { 区域高度 } height* @param { 场景对象 } scene* @param { 摄像机对象} camera* @param { 渲染回调} renderer*/
function setModelComposer(width, height, scene, camera, renderer) {// 创建一个EffectComposer(效果组合器)对象,在该对象上添加后期处理通道,用于模型高亮const composer = new EffectComposer(renderer);// 新建一个场景通道,const renderPass = new RenderPass(scene, camera);// 给EffectComposer添加一个渲染器通道 composer.addPass(renderPass);// 模型边缘发光通道const v2 = new THREE.Vector2(width, height);// OutlinePass第一个参数的尺寸和canvas画布保持一致const outlinePass = new OutlinePass(v2, scene, camera);outlinePass.visibleEdgeColor.set('#00FF00'); // 呼吸显示颜色outlinePass.hiddenEdgeColor.set('#00FF00');// 呼吸消失颜色outlinePass.edgeStrength = 5; // 边框的亮度强度outlinePass.edgeGlow = 0.5; // 光晕[0,1]outlinePass.edgeThickness = 3;// 边缘宽度outlinePass.pulsePeriod = 2; // 呼吸闪烁速度outlinePass.renderToScreen = true; // 设置这个参数的目的是马上将当前的内容输出// 将OutlinePass通道添加到后处理composer中composer.addPass(outlinePass);// 保持outputEncoding = sRGBEncoding,自定义着色器通道作为参数let effectCopy = new ShaderPass(GammaCorrectionShader);effectCopy.renderToScreen = true;composer.addPass(effectCopy);composer.selectedObjectEffect = function (objs) {let selectedObjects = [];selectedObjects.push(objs);outlinePass.selectedObjects = selectedObjects;};return composer;
}

设置高亮

// 监听鼠标移动事件、获取需要高亮模型,设置高亮
datahubBox.current.addEventListener('mousemove', (event) => {let selectObj = getCanvasIntersects(event, composerData, camera, datahubBox.current);if (selectObj && selectObj.length > 0) {isComposer = true;composer.selectedObjectEffect(selectObj[0].object);} else {isComposer = false;}
});

我想要实现的是子模型高亮,所以我这里取子模型的object。

注意:传入的参数是一个数组,传入那些模型,那些模型就能高亮。
每次点击前需要清空composer。
getCanvasIntersects方法参考链接

完整代码

let scene, camera, renderer, controls;
let stats = null; // 检测动画运行时的帧数
let clock = new THREE.Clock(); // getDelta()方法获得两帧的时间间隔
let FPS = 30;
let renderT = 1 / FPS;
let timeS = 0;const ThreeModel = observer(() => {// 设置灯光function setLight() {let hemiLightTop = new THREE.HemisphereLight(0xffffff, 0xffffff, 0.5);let hemiLightBottom = new THREE.HemisphereLight(0xffffff, 0.5);let lightTop = new THREE.DirectionalLight(0xffffff, 0.1);let lightAfter = new THREE.DirectionalLight(0xffffff, 0.5);hemiLightTop.position.set(0, 2000, 0);hemiLightBottom.position.set(0, 0, 0);lightTop.position.set(4, 6, 4);lightAfter.position.set(0, 0, 2000);scene.add(hemiLightTop);scene.add(hemiLightBottom);scene.add(lightTop);scene.add(lightAfter);lightTop.castShadow = true;// 光源开启阴影lightTop.shadow.mapSize = new THREE.Vector2(1024, 1024);lightTop.shadow.bias = -0.001;}// 渲染函数function renderFn() {requestAnimationFrame(renderFn);if (isComposer && composer) {// 组合渲染器,渲染高亮composer.render(T);} else {// 用相机渲染一个场景renderer.render(scene, camera);}}useEffect(() => {// 监听鼠标移动事件、获取需要高亮模型,设置高亮, composerData需要高亮数据datahubBox.current.addEventListener('mousemove', (event) => {let selectObj = getCanvasIntersects(event, composerData, camera, datahubBox.current);if (selectObj && selectObj.length > 0) {isComposer = true;composer.selectedObjectEffect(selectObj[0].object);} else {isComposer = false;}});}, []);useEffect(() => {// 初始化页面canvas,初始化场景// 定义场景scene = new THREE.Scene();// 灯光setLight();// 获取盒子宽高设置相机和渲染区域大小let width = datahubBox.current.offsetWidth;let height = datahubBox.current.offsetHeight;let k = width / height;// 定义相机camera = new THREE.PerspectiveCamera(45, k, 0.25, 100000);camera.position.set(-547, 15224, 2195);camera.lookAt(scene.position);// 创建一个webGL对象renderer = new THREE.WebGLRenderer({//增加下面两个属性,可以抗锯齿antialias: true,alpha: true,logarithmicDepthBuffer: true // 解决模型闪烁问题});renderer.setSize(width, height); // 设置渲染区域尺寸renderer.setClearColor(0x23284D, 0.0); // 设置颜色透明度// 首先渲染器开启阴影renderer.shadowMap.enabled = true;// 修改渲染模式renderer.setPixelRatio(window.devicePixelRatio);renderer.outputEncoding = THREE.sRGBEncoding;renderer.textureEncoding = THREE.sRGBEncoding;// 挂载到DOM节点datahubBox.current.appendChild(renderer.domElement);// 监听鼠标事件controls = new THREE.OrbitControls(camera, renderer.domElement);//- 拖拽惯性controls.enableDamping = true;controls.dampingFactor = 0.05;// 控制上下旋转范围controls.minPolarAngle = 0;controls.maxPolarAngle = Math.PI / 2;// 限制缩放范围controls.minDistance = 0;controls.maxDistance = cameraDistanceMax;// 高亮设置composer = setModelComposer(width, height, scene, camera, renderer);// 渲染renderFn();}, []);useEffect(() => {// 重置数据return () => {scene = null;camera = null;renderer = null;controls = null;composer = null;isComposer = false;};}, []);{/* canvas盒子 */}return <div className='ui_model_box' ref={datahubBox}></div>;
});
export default ThreeModel;

相关文章:

three.js 模型高亮效果实现说明(结合react)

three.js react 实现鼠标移入模型高亮选中效果 使用EffectComposer和其附加的渲染效果Passes&#xff08;如RenderPass和OutlinePass&#xff09;来实现高级渲染效果。首先创建EffectComposer实例&#xff0c;并添加RenderPass和OutlinePass&#xff0c;最后在渲染循环中调用…...

入营测评题解

第一题&#xff1a;first 第二题&#xff1a;chengji 打擂台&#xff0c;每个数跟当前最大、最小值比较&#xff0c;维护当前最值即可。 #include<bits/stdc.h> using lllong long; using namespace std;const int N1e610;int n; int x;//1e9, ll最大9e18 ll maxn0,minn…...

制造知识普及(十)-- 常见的工业软件介绍

「 1. ERP」 企业资源计划&#xff08;enterprise resource planning&#xff0c;ERP&#xff09;是制造企业的核心管理软件。ERP系统的基本思想是以销定产&#xff0c;协同管控企业的产、供、销、人、财、物等资源&#xff0c;帮助企业按照销售订单&#xff0c;基于产品的制造…...

Windows系统设置网络IPv4和IPv6优先访问级

Windows系统设置网络IPv4和IPv6优先访问级 资源宝整理分享&#xff1a;www.httple.net 在数字化的世界中&#xff0c;我们离不开互联网&#xff0c;而互联网协议&#xff08;IP协议&#xff09;则扮演着至关重要的角色。IPv4曾是互联网的主要标准&#xff0c;但随着IP地址枯竭问…...

yolov8 剪枝 - DepGraph

2024年8月5 5000张图片&#xff0c;2个类别。 yolov8n 初始&#xff1a; 185 layers, 3151904 parameters, 31936 gradients, 8.7 GFLOPs 经过三次finetune后&#xff1a; 185 layers, 2327024 parameters, 31936 gradients, 6.6 GFLOPs 经过第四次fintune后&#xff1a; …...

【网络】套接字socket编程预备知识

1.源IP地址和目的IP 计算机网络中的源地址和目的地址是用来标识网络中的不同主机的。 源地址是指发送数据包的主机的地址&#xff0c;而目的地址则是指接收数据包的主机的地址&#xff0c;在数据包传输过程中&#xff0c;每经过一个路中器感交换机&#xff0c;都会根据目的地址…...

【学习笔记】Day 8

写在开头&#xff1a; 最近老板突然提出一个全新的组会主题&#xff0c;是关于 “最近我犯的傻”&#xff0c;其目的在于提供乐子的同时引以为戒。本来我还在愁到底去哪里找干的啥事儿&#xff0c;结果今天直接拉了个大的。什么叫无心插柳柳成荫啊&#xff0c;悲。 一…...

springboot整合libreoffice(两种方式,使用本地和远程的libreoffice);docker中同时部署应用和libreoffice

一、 背景 因为项目中需要使用word转pdf功能&#xff0c;因为转换速度原因&#xff0c;最后选用了libreoffice&#xff0c;原因及部署请参考 linux ubuntu环境安装libreoffice&#xff0c;word转pdf 远程调用的话可选docker部署&#xff0c;请看2.3.1 二、springboot整合libr…...

从入门到精通:大学生编程技能提升全攻略

文章目录 每日一句正能量前言编程语言选择编程语言选择&#xff1a;为新手导航Python&#xff1a;初学者的友好伙伴JavaScript&#xff1a;Web开发的核心Java&#xff1a;企业级应用的经典C&#xff1a;系统编程的基石Ruby&#xff1a;优雅高效的编程Swift&#xff1a;iOS开发的…...

C# .NET Framework的特殊委托

C# .NET Framework的特殊委托 .NET Framework中定义了几种特殊的委托类型&#xff0c;以简化委托的使用。以下是一些常用的特殊委托类型&#xff1a; Predicate<T> 这是一个返回布尔值的委托&#xff0c;接受一个类型为T的参数。常用于定义过滤条件。 using System; …...

C# 判断电脑是否联网

项目中连接webAPI需要判断是否联网&#xff0c;故找到这个方法&#xff0c;不需要引用任何dll&#xff0c;代码复制一下&#xff0c;直接使用。wininet.dll是系统自带的 public void Initial(){try{ if (IsNetworkConnected){SvMaster.Log.WriteInfo("网络…...

爬虫解析代码结构

在设计中加入一个顶层接口是有益的&#xff0c;特别是当您希望实现统一的接口来处理所有类型的排行榜数据时。这样做可以提供更好的灵活性和扩展性&#xff0c;同时保持代码的整洁和易于维护。 设计概述 接口: 定义一个 RankingDataCollector 接口&#xff0c;它定义了所有数…...

day 23 进程间通信—管道

注意事项&#xff1a; 1、如果管道中至少有一个写端&#xff1a; 如果管道中有数据,直接读出 如果管道中没有数据&#xff0c;会阻塞等待直到有数据写入后读出 2、如果管道中没有写端&#xff1a; 如果管道中有数据&#xff0c;直接…...

Python酷库之旅-第三方库Pandas(073)

目录 一、用法精讲 296、pandas.Series.dt.as_unit方法 296-1、语法 296-2、参数 296-3、功能 296-4、返回值 296-5、说明 296-6、用法 296-6-1、数据准备 296-6-2、代码示例 296-6-3、结果输出 297、pandas.Series.dt.days属性 297-1、语法 297-2、参数 297-3、…...

使用easyexcel导出,发生了Exception: could not find acceptable repesentation

报错信息&#xff1a; 原因以及解决方案&#xff1a; 原因是我的代码使用Resp响应返回实体&#xff0c;其实使用EasyExcel导出已经设置了响应编码&#xff0c;导致重复了。 当你通过 HttpServletResponse 的输出流写入文件时&#xff0c;你已经直接控制了响应体。如果此时还尝…...

android display 笔记(五)HWC(Hardware Composer)

HWC 简单来说HWC是用来合成图形和显示图形的&#xff0c;可以把多个图形缓存传给硬件混合渲染器&#xff0c;让硬件混合渲染器执行合成操作&#xff0c;显示图形就是直接将图形缓存显示到屏幕。 android 14 /hardware/interfaces/graphics/composer/2.1/IComposer.hal 19 im…...

【模电笔记】——集成运算放大电路

tips&#xff1a;本章节的笔记已经打包到word文档里啦&#xff0c;建议大家下载文章顶部资源&#xff08;有时看不到是在审核中&#xff0c;等等就能下载了。手机端下载后里面的插图可能会乱&#xff0c;建议电脑下载&#xff0c;兼容性更好且易于观看&#xff09;&#xff0c;…...

Android Studio Gradle多渠道打包

原理使用Android Studio打一次渠道包&#xff0c;用反编译工具反编译后&#xff0c;修改渠道信息重新编译 准备文件 分渠道配置文件&#xff1a;channel.txt ↓ # 多渠道配置里“统计平台”、“市场名称”、“渠道编号”分别代表什么意思&#xff1f; # 统计平台&#xff1a;…...

什么是DNS缓存?DNS缓存有哪些作用和危害?

在互联网世界的运转机制中&#xff0c;DNS&#xff08;域名系统&#xff09;是其中的关键&#xff0c;而DNS缓存则是这一系统的重要环节。它既能加快网站的访问速度&#xff0c;同时也会对网络安全造成影响&#xff0c;因此了解DNS缓存对于网站的日常管理至关重要。 什么是DNS…...

web基础与http协议与配置

目录 一、web基础 1.1 DNS与域名&#xff08;详解看前面章节&#xff09; 1.2 网页的概念&#xff08;HTTP/HTTPS&#xff09; 1.2.1 基本概念 1.2.2 HTML文档结构(了解) 1.2.3 web相关重点 1.2.4 静态资源和动态资源 二、http协议 2.1 概述 2.2 cookie和session&…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)

本期内容并不是很难&#xff0c;相信大家会学的很愉快&#xff0c;当然对于有后端基础的朋友来说&#xff0c;本期内容更加容易了解&#xff0c;当然没有基础的也别担心&#xff0c;本期内容会详细解释有关内容 本期用到的软件&#xff1a;yakit&#xff08;因为经过之前好多期…...

关于easyexcel动态下拉选问题处理

前些日子突然碰到一个问题&#xff0c;说是客户的导入文件模版想支持部分导入内容的下拉选&#xff0c;于是我就找了easyexcel官网寻找解决方案&#xff0c;并没有找到合适的方案&#xff0c;没办法只能自己动手并分享出来&#xff0c;针对Java生成Excel下拉菜单时因选项过多导…...

消息队列系统设计与实践全解析

文章目录 &#x1f680; 消息队列系统设计与实践全解析&#x1f50d; 一、消息队列选型1.1 业务场景匹配矩阵1.2 吞吐量/延迟/可靠性权衡&#x1f4a1; 权衡决策框架 1.3 运维复杂度评估&#x1f527; 运维成本降低策略 &#x1f3d7;️ 二、典型架构设计2.1 分布式事务最终一致…...

保姆级【快数学会Android端“动画“】+ 实现补间动画和逐帧动画!!!

目录 补间动画 1.创建资源文件夹 2.设置文件夹类型 3.创建.xml文件 4.样式设计 5.动画设置 6.动画的实现 内容拓展 7.在原基础上继续添加.xml文件 8.xml代码编写 (1)rotate_anim (2)scale_anim (3)translate_anim 9.MainActivity.java代码汇总 10.效果展示 逐帧…...

比特币:固若金汤的数字堡垒与它的四道防线

第一道防线&#xff1a;机密信函——无法破解的哈希加密 将每一笔比特币交易比作一封在堡垒内部传递的机密信函。 解释“哈希”&#xff08;Hashing&#xff09;就是一种军事级的加密术&#xff08;SHA-256&#xff09;&#xff0c;能将信函内容&#xff08;交易细节&#xf…...

信息系统分析与设计复习

2024试卷 单选题&#xff08;20&#xff09; 1、在一个聊天系统(类似ChatGPT)中&#xff0c;属于控制类的是&#xff08;&#xff09;。 A. 话语者类 B.聊天文字输入界面类 C. 聊天主题辨别类 D. 聊天历史类 ​解析 B-C-E备选架构中分析类分为边界类、控制类和实体类。 边界…...

SE(Secure Element)加密芯片与MCU协同工作的典型流程

以下是SE&#xff08;Secure Element&#xff09;加密芯片与MCU协同工作的典型流程&#xff0c;综合安全认证、数据保护及防篡改机制&#xff1a; 一、基础认证流程&#xff08;参数保护方案&#xff09; 密钥预置‌ SE芯片与MCU分别预置相同的3DES密钥&#xff08;Key1、Key2…...