【ThreeJS Basics 09】Debug

文章目录

  • 简介
  • 从 dat.GUI 到 lil-gui
  • 例子
  • 安装 lil-gui 并实例化
  • 不同类型的调整
    • 改变位置
    • 针对非属性的调整
    • 复选框
    • 颜色
  • 功能/按钮
  • 调整几何形状
  • 文件夹
  • 调整 GUI
    • 宽度
    • 标题
    • 关闭文件夹
    • 隐藏
    • 按键切换
  • 结论


简介

每一个创意项目的一个基本方面是能够轻松调整。开发人员和参与项目的其他参与者(如设计师甚至客户)必须能够更改尽可能多的参数。

您必须考虑到这一点,以便他们找到完美的颜色、速度、数量等,获得最佳体验。您甚至可能会得到意想不到的很棒的结果。

首先,我们需要一个调试 UI。

虽然您可以使用 HTML / CSS / JS 创建自己的调试 UI,但已经有多个库:

  • dat.GUI
  • lil-gui
  • control-panel
  • ControlKit
  • Uil
  • Tweakpane
  • Guify
  • Oui

所有这些库都可以做我们想做的事,但我们将使用lil-gui,因为它很流行、维护良好、并且易于使用

从 dat.GUI 到 lil-gui

最初,Three.js 练习都是使用 dat.GUI

一段时间以来,这个库一直没有更新,NPM 在安装它时开始触发漏洞警告。这些漏洞已经修复,但替代方案已经开始出现,这就是 lil-gui 作为 dat.GUI 的替代品越来越受欢迎的原因。额外的好处是它甚至有更好的功能。

所有 Three.js 练习现在都使用 lil-gui

顺便说一下,GUI 代表图形用户界面。

例子

https://bruno-simon.com/#debug

安装 lil-gui 并实例化

npm i lil-gui

引入并使用

import GUI from 'lil-gui'/*** Debug*/
const gui = new GUI()

不同类型的调整

  • 范围— 针对具有最小值和最大值的数字
  • 颜色— 适用于各种格式的颜色
  • 文本— 用于简单文本
  • 复选框— 用于布尔值(true或false)
  • 选择— 从值列表中进行选择
  • 按钮——触发功能

改变位置

const mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)gui.add(mesh.position, 'y')

we

或者写一个范围,这样 ui 就会变成一个滑杆

gui.add(mesh.position, 'y', - 3, 3, 0.01)

在这里插入图片描述

也可以使用链式调用

gui.add(mesh.position, 'y').min(- 3).max(3).step(0.01)

针对非属性的调整

这里需要注意的一点是 lil-gui 只能修改属性。如果你想更新变量,则不能:

let myVariable = 1337
gui.add(myVariable, '???')

但是您可以使用一些技巧来实现这一点,例如创建一个对象,其目的是保存 lil-gui 在该对象上使用的属性:

const myObject = {myVariable: 1337
}
gui.add(myObject, 'myVariable')

复选框

lil-gui 会自动检测你想要调整的属性类型,并使用相应的接口。Object3D visible 的属性就是一个很好的例子。它是一个布尔值,如果,false 则会隐藏对象:

gui.add(mesh, 'visible')

颜色

处理颜色有点麻烦。让我们尝试修改 color 的属性 material

需要通过回调函数里的 value 来设置值, GUI 上的 hex 并不是最终的值

你最终得到了错误的颜色:

这是因为 Three.js 应用了一些颜色管理来优化渲染。因此,调整中显示的颜色值与内部使用的值不同。

我们现在不讨论色彩管理, 有两种方法可以解决这个问题。

gui.addColor(material, 'color')

需要通过回调函数来覆盖掉 ui 上显示的值

debugObject.color = '#3a6ea6'const geometry = new THREE.BoxGeometry(1, 1, 1, 2, 2, 2)
const material = new THREE.MeshBasicMaterial({ color: debugObject.color, wireframe: false })cubeTweaks.addColor(debugObject, 'color').onChange(() =>{material.color.set(debugObject.color)})

功能/按钮

有时,我们只想按需触发指令。现在,当我们点击调试 UI 中的某个位置时,我们希望让立方体执行一点旋转动画。

我们可以通过向包含函数的 tweak 发送一个属性来实现这一点。不幸的是,这意味着我们不能让一个函数像这样独立存在,然后将其发送给 lil-gui

const myFunction = () => {console.log('do something')
}
gui.add(myFunction, '???')

但是我们可以为我们之前创建的对象添加一个spin属性debugObject,并将 GSAP 动画集成到其中:

debugObject.spin = () =>
{gsap.to(mesh.rotation, { duration: 1, y: mesh.rotation.y + Math.PI * 2 })
}

最后,我们可以将调整添加到 debugObject.spin

debugObject.spin = () =>
{// ...
}
gui.add(debugObject, 'spin')

在这里插入图片描述

调整几何形状

gui.add(debugObject, 'subdivision').min(1).max(20).step(1).onChange(() =>{console.log('subdivision changed')})

对于 CPU 来说,构建几何图形可能是一个相当漫长的过程。现在,我们正在监听更改事件,如果用户过多地拖放范围调整,则可能会多次触发该事件。

onChange我们不会使用 ,而是使用onFinishChange,它仅当我们停止调整值时才会触发:

gui.add(debugObject, 'subdivision').min(1).max(20).step(1).onFinishChange(() =>{console.log('subdivision finished changing')})

除此之外console.log(),我们还可以使用 构建一个新的几何体,并通过将其分配给其属性来debugObject.subdivision将其与 关联:meshgeometry

gui.add(debugObject, 'subdivision').min(1).max(20).step(1).onFinishChange(() =>{mesh.geometry = new THREE.BoxGeometry(1, 1, 1,debugObject.subdivision, debugObject.subdivision, debugObject.subdivision)})

就是这样,但我们犯了一个小错误。旧几何图形仍位于 GPU 内存中的某个位置,这可能会导致内存泄漏。

dispose()为了解决这个问题,我们可以在创建新的几何图形之前在旧几何图形上调用该方法:

gui.add(debugObject, 'subdivision').min(1).max(20).step(1).onFinishChange(() =>{mesh.geometry.dispose()mesh.geometry = new THREE.BoxGeometry(1, 1, 1,debugObject.subdivision, debugObject.subdivision, debugObject.subdivision)})

文件夹

假设我们有很多调整,调试 UI 开始变得拥挤。我们可以使用此addFolder()方法将它们分成文件夹。

要创建文件夹,请调用addFolder()并发送您想要的名称作为参数。请确保在调整之前执行此操作并将其保存为cubeTweaks:

const cubeTweaks = gui.addFolder('Awesome cube')

然后,不要使用gui来创建调整,而是使用cubeTweaks变量:

const cubeTweaks = gui.addFolder('Awesome cube')cubeTweaks.add(mesh.position, 'y')// ...cubeTweaks.add(mesh, 'visible')cubeTweaks.add(material, 'wireframe')cubeTweaks.addColor(material, 'color')// ...// ...
cubeTweaks.add(debugObject, 'spin')// ...
cubeTweaks.add(debugObject, 'subdivision')// ...

可以默认

const cubeTweaks = gui.addFolder('Awesome cube')
cubeTweaks.close()

调整 GUI

宽度

const gui = new GUI({width: 300
})

标题

const gui = new GUI({width: 300,title: 'Nice debug UI'
})

关闭文件夹

const gui = new GUI({width: 300,title: 'Nice debug UI',closeFolders: true
})

隐藏

const gui = new GUI({width: 300,title: 'Nice debug UI',closeFolders: false,
})
// gui.close()
gui.hide()

按键切换

window.addEventListener('keydown', (event) =>
{if(event.key == 'h')gui.show(gui._hidden)
})

结论

随着你的 项目的进行,来添加各种各样的 gui 参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/29821.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android Native 之 文件系统挂载

一、文件系统挂载流程概述 二、文件系统挂载流程细节 1、Init启动阶段 众所周知,init进程为android系统的第一个进程,也是native世界的开端,要想让整个android世界能够稳定的运行,文件系统的创建和初始化是必不可少的&#xff…

Chain of Draft: 借鉴人类草稿思维让大型语言模型更快地思考

这个研究探讨了大型语言模型(LLMs)在执行复杂推理任务时面临的计算资源消耗与响应延迟问题。研究特别聚焦于思维链(Chain-of-Thought, CoT)提示范式的效率局限性。CoT虽然有效,但在推理过程中需要生成冗长、详尽的逐步…

《A++ 敏捷开发》- 18 软件需求

需求并不是关于需求 (Requirements are not really about requirements) 大家去公共图书馆寄存物品,以前都是扫二维码开箱,有些图书馆升级了使用指纹识别。 “是否新方法比以前好?”我问年轻的开发人员。 “当然用指纹识别好。新技术&#x…

【智能体架构:Agent】LangChain智能体类型ReAct、Self-ASK的区别

1. 什么是智能体 将大语言模型作为一个推理引擎。给定一个任务, 智能体自动生成完成任务所需步骤, 执行相应动作(例如选择并调用工具), 直到任务完成。 2. 先定义工具:Tools 可以是一个函数或三方 API也…

Vue进阶之Vue3源码解析(一)

Vue3源码解析 目录结构编译compiler-corepackage.jsonsrc/index.ts 入口文件src/compile.ts生成ASTsrc/parse.ts 代码转换src/transform.ts几种策略模式src/transforms/transformElement.tssrc/transforms/transformText.tssrc/transforms/transformExpression.ts 代码生成src/…

servlet tomcat

在spring-mvc demo程序运行到DispatcherServlet的mvc处理 一文中,我们实践了浏览器输入一个请求,然后到SpringMvc的DispatcherServlet处理的整个流程. 设计上这些都是tomcat servlet的处理 那么究竟这是怎么到DispatcherServlet处理的,本文将…

【我的待办(MyTodolists)-免费无内购的 IOS 应用】

我的待办(MyTodolists) 我的待办:智能任务管理助手应用说明主要功能为什么选择"我的待办"?隐私保障使用截图 我的待办:智能任务管理助手 应用说明 "我的待办"是一款智能化的任务管理应用&#x…

GCC RISCV 后端 -- C语言语法分析过程

在 GCC 编译一个 C 源代码时,先会通过宏处理,形成 一个叫转译单元(translation_unit),接着进行语法分析,C 的语法分析入口是 static void c_parser_translation_unit(c_parser *parser); 接着就通过类似递…

Vim复制内容到系统剪切板

参考链接 【Vim】Vim 中将文件内容复制到系统剪切板的方法_vi 复制到系统剪贴板-CSDN博客 [转]vim如何复制到系统剪贴板 - biiigwang - 博客园 1. 确定Vim是否支持复制到系统剪切板 输入命令 vim --version | grep clipboard 如果是开头,说明支持系统剪切板&…

测试用大模型组词

已经把hanzi-writer的js的调用、hanzi-writer调用的数千个汉字的json文件,全都放在本地了。虽然用的办法还是比较笨的。我注意到 大模型也可以部署本地,虽然使用频率低的情况下不划算。 尝试直接通过html的javascript通过api key调用大语言模型&#x…

华为eNSP:配置单区域OSPF

一、什么是OSPF? OSPF(Open Shortest Path First,开放最短路径优先)是一种链路状态路由协议,属于内部网关协议(IGP),主要用于在单一自治系统(AS)内部动态发现…

P62 线程

这篇文章我们来讲一下线程。截止到目前,我们的代码都是在单线程上运行的,现在看起来没有什么问题,但是目前所有的计算机几乎都不只有一个逻辑线程,所以如果我们一直使用单线程运行,这样的话效率会很低。尤其是如果我们…

Android AudioFlinger(五)—— 揭开AudioMixer面纱

前言: 在 Android 音频系统中,AudioMixer 是音频框架中一个关键的组件,用于处理多路音频流的混音操作。它主要存在于音频回放路径中,是 AudioFlinger 服务的一部分。 上一节我们讲threadloop的时候,提到了一个函数pr…

im即时聊天客服系统SaaS还是私有化部署:成本、安全与定制化的权衡策略

随着即时通讯技术的不断发展,IM即时聊天客服系统已经成为企业与客户沟通、解决问题、提升用户体验的重要工具。在选择IM即时聊天客服系统时,企业面临一个重要决策:选择SaaS(软件即服务)解决方案,还是进行私…

DeepSeek系列模型技术报告的阅读笔记

DeepSeek系列模型技术报告的阅读笔记 之前仔细阅读了DeepSeek系列模型的主要技术方面内容与发展脉络,以下是DeepSeek系列模型技术报告的笔记,有错误的地方欢迎指正! 文章目录 DeepSeek系列模型技术报告的阅读笔记GQADeepseek MoEAbstractIn…

【VUE】第二期——生命周期及工程化

目录 1 生命周期 1.1 介绍 1.2 钩子 2 可视化图表库 3 脚手架Vue CLI 3.1 使用步骤 3.2 项目目录介绍 3.3 main.js入口文件代码介绍 4 组件化开发 4.1 组件 4.2 普通组件注册 4.2.1 局部注册 4.2.2 全局注册 1 生命周期 1.1 介绍 Vue生命周期:就是…

Spring-framework源码编译

版本统一(搭配其他版本会遇到不可知错误): 1)spring 5.2.X(5.5.26) 2)JDK8 3)Gradle:5.6.4 可以在gradle-wrapper.properties中修改 https\://services.gradle.org/distribution…

使用 Deepseek + kimi 快速生成PPT

前言 最近看到好多文章和视频都在说,使用 Deepseek 和 kimi 能快速生成精美的 ppt,毕竟那都是别人说的,只有自己尝试一次才知道结果。 具体操作 第一步:访问 deepseek 我们访问 deepseek ,把我们想要输入的内容告诉…

火绒终端安全管理系统V2.0--纵深防御体系(分层防御)之规则拦截层

火绒终端安全管理系统V2.0--多层次主动防御系统。 率先将单步防御和多步恶意监控相结合,监控百个防御点(包含防火墙),有效阻止各种恶意程序对系统的攻击和篡改,保护终端脆弱点。 ✅ 内容拦截层(Content-B…

如何在WPS中接入DeepSeek并使用OfficeAI助手(超细!成功版本)

目录 第一步:下载并安装OfficeAI助手 第二步:申请API Key 第三步:两种方式导入WPS 第一种:本地大模型Ollama 第二种APIKey接入 第四步:探索OfficeAI的创作功能 工作进展汇报 PPT大纲设计 第五步:我的使用体验(体验建议) …