[three.js]搭建场景

背景

虽然一直在从事three.js方面的开发工作,但是都是在同事搭建好的场景下工作的。最近接手的任务让我可以从0到1搭建一个场景,顺便复习一下

搭建三维场景

<script lang="ts" setup>
import { ref, onMounted } from 'vue';                                      
import * as THREE from 'three';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
// 导入 DRACOLoader
import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js';
import { KTX2Loader } from 'three/examples/jsm/loaders/KTX2Loader.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { CSS3DRenderer, CSS3DObject } from 'three/examples/jsm/renderers/CSS3DRenderer.js';

onMounted(() => {
  createScene();
});

let scene: any, camera: any, renderer: any, controls: any;                                               
let css3dRenderer: any;

function createScene() {
  //场景
  scene = new THREE.Scene();

  //辅助观察的坐标系
  const axesHelper = new THREE.AxesHelper(100);
  scene.add(axesHelper);

  //光源设置
  const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  directionalLight.position.set(100, 60, 50);
  scene.add(directionalLight);
  const ambient = new THREE.AmbientLight(0xffffff, 0.4);
  scene.add(ambient);

  //渲染器和相机
  let renderCanvas = document.getElementById('renderCanvas');
  const width = renderCanvas.offsetWidth;
  const height = renderCanvas.offsetHeight; 
  camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000); 
  // camera.position.set(292, 223, 185);
  camera.position.set(200, 250, 410); //根据渲染范围尺寸数量级设置相机位置
  // camera.lookAt(0, -23, 41);

  renderer = new THREE.WebGLRenderer();
  renderer.setSize(width, height);
  renderCanvas.appendChild(renderer.domElement);

  // 设置相机控件轨道控制器OrbitControls
  controls = new OrbitControls(camera, renderer.domElement);
  controls.target.set(0, -23, 41);

  // 加载模型
  const loader = new GLTFLoader();

  loader
    .setDRACOLoader(new DRACOLoader().setDecoderPath('/js/draco/')) 
    .setKTX2Loader(new KTX2Loader().setTranscoderPath('/js/basis/').detectSupport(renderer as THREE.WebGLRenderer)); 

  loader.load('./三维图.glb', (gltf: any) => { 
    scene.add(gltf.scene);
  });

  // 加入文字标签
  const textLabel = tag3D('1组');
  css3dRenderer = labelRenderer(renderCanvas);

  scene.add(textLabel);

  render();
}

// 渲染循环
function render() {
  renderer.render(scene, camera); //执行渲染操作
  css3dRenderer.render(scene, camera);
  controls.update();
  // console.log('camera.position: ', camera.position); 
  // console.log('controls.target: ', controls.target); 
  // mesh.rotateY(0.01); //每次绕y轴旋转0.01弧度
  requestAnimationFrame(render); //请求再次执行渲染函数render,渲染下一帧
}

// 创建一个HTML标签
function tag3D(name) {
  // 创建div元素(作为标签)
  let div = document.createElement('div');
  div.innerHTML = name;
  div.classList.add('tag');
  //div元素包装为CSS3模型对象CSS3DObject
  var label = new CSS3DObject(div);
  div.style.pointerEvents = 'none'; //避免HTML标签遮挡三维场景的鼠标事件
  // 设置HTML元素标签在three.js世界坐标中位置
  label.position.set(0, 0, 50);
  //缩放CSS3DObject模型对象
  label.scale.set(0.04, 0.04, 0.04); //根据相机渲染范围控制HTML 3D标签尺寸
  // label.rotateY(Math.PI / 2); //控制HTML标签CSS3对象姿态角度
  label.rotateX(-Math.PI / 2);
  return label; //返回CSS3模型标签
}

// 创建一个CSS2渲染器CSS2DRenderer
function labelRenderer(container) {
  var labelRenderer = new CSS3DRenderer();
  labelRenderer.setSize(container.offsetWidth, container.offsetHeight);
  labelRenderer.domElement.style.position = 'absolute';
  // 相对标签原位置位置偏移大小
  labelRenderer.domElement.style.top = '0px';
  labelRenderer.domElement.style.left = '0px';
  // //设置.pointerEvents=none,以免模型标签HTML元素遮挡鼠标选择场景模型
  labelRenderer.domElement.style.pointerEvents = 'none';
  container.appendChild(labelRenderer.domElement);
  return labelRenderer;
}
</script>
<template>
  <div id="renderCanvas" class="renderCanvas"></div>
</template>

注意点

一定要有renderer.render(scene, camera);否则屏幕上啥也看不见;加了CSS3DRenderer,也要有相应的css3dRenderer.render(scene, camera);

如果有OrbitControls,相机就不用设置lookAt,直接设置OrbitControls的target就行了

GLTFLoader也不是上来就能load的,需要加上下面的东西才能load,原因我暂时也没弄清楚

loader
    .setDRACOLoader(new DRACOLoader().setDecoderPath('/js/draco/'))  
    .setKTX2Loader(new KTX2Loader().setTranscoderPath('/js/basis/').detectSupport(renderer as THREE.WebGLRenderer));

后记

刚学three.js的时候,按照教程也没遇到这么多问题,好久不写,问题一堆,感觉基础摇摇欲坠,所以特地记录一下

参考

参考1
参考2

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++感受2-逐字逐句,深入理解C++最小例程

以 “Hello World” 例程为载体、线索&#xff0c;在完成 “间接名字空间限定” 写法转换到“直接名字空间限定”的过程&#xff0c;同时掌握函数、主函数、函数调用、级联操作、声明、类型、int、字符串类型、头文件包含、行为数据、流输出操作符、标准输出流对象、标准库名字…

1~5节. 编程训练习题课

疯狂练一练 每一题都有非常详细的注释, 如果大家有其他更简单的思路, 可以在评论区交流, 或者私信一起讨论. 1、定义一个方法&#xff0c;该方法能够找出两个小数中的较小值并返回。 package com.itheima.lxh_exercise;public class Exercise {public static void main(Stri…

2024年,真的别裸辞....

作为IT行业的大热岗位——软件测试&#xff0c;只要你付出了&#xff0c;就会有回报。说它作为IT热门岗位之一是完全不虚的。可能很多人回说软件测试是吃青春饭的&#xff0c;但放眼望去&#xff0c;哪个工作不是这样的呢&#xff1f;会有哪家公司愿意养一些闲人呢&#xff1f;…

理论学习:Softmax层和全连接层 全连接层之前的数据

Softmax层和全连接层 Softmax层和全连接层在深度学习模型中通常是紧密相关的&#xff0c;经常一起使用。 全连接层&#xff08;也称为线性层或密集连接层&#xff09;是深度学习模型中常见的层之一&#xff0c;它将输入张量与权重矩阵相乘&#xff0c;并添加偏置项&#xff0c;…

PaddleOCR表格识别运行实例

目录 PaddleOCR 开源项目地址 一、数据集 1. 训练数据下载 2.数据集介绍 &#xff08;1&#xff09;PubTabNet数据集 &#xff08;2&#xff09; 好未来表格识别竞赛数据集 &#xff08;3&#xff09;WTW中文场景表格数据集 二、训练步骤 1.数据放置 2.环境配置 &…

k8s-生产级的k8s高可用(2) 25

部署containerd k8s2、k8s3、k8s4在配置前需要重置节点&#xff08;reset&#xff09;在上一章已完成 禁用所有节点docker和cri-docker服务 所有节点清除iptables规则 重置后全部节点重启 由于之前部署过docker&#xff0c;因此containerd默认已安装 修改配置 启动containe…

OpenCV学习笔记(一)——Anaconda下载和OpenCV的下载

OpenCV是图象识别中有巨大的应用场景&#xff0c;本篇文章以Python为基础。当初学OpenCV的时候&#xff0c;推使用在Anaconda编写代码&#xff0c;原因比较方便&#xff0c;下面我们对于Anaconda的下载过程进行演示。 Anaconda的下载 首先打开官网www.anaconda.com/download找…

Midjourney绘图欣赏系列(十)

Midjourney介绍 Midjourney 是生成式人工智能的一个很好的例子&#xff0c;它根据文本提示创建图像。它与 Dall-E 和 Stable Diffusion 一起成为最流行的 AI 艺术创作工具之一。与竞争对手不同&#xff0c;Midjourney 是自筹资金且闭源的&#xff0c;因此确切了解其幕后内容尚不…

力扣701. 二叉搜索树中的插入操作

思路&#xff1a;往二叉搜索树中插入一个值&#xff0c;树的结构有多种符合的情况&#xff0c;那我们可以选一种最容易的插入方式&#xff0c;反正只需要插入一个值而已&#xff0c;我们不难发现&#xff0c;不管插入什么值&#xff0c;都可以安排插入到叶子节点上。 再利用二叉…

uview upicker时间选择器(附Demo)

目录 前言正文 前言 uniapp时间选择器&#xff0c;是upicker&#xff0c;与微信小程序还是有些区别 补充官网的基本知识&#xff1a;uview官网 官网的展示例子如下&#xff1a;&#xff08;但是没Demo&#xff09; 正文 通过上面的展示图&#xff0c;复刻一个类似Demo图&am…

小兔鲜鲜项目(前端vue3)

成果图 大家喜欢给一个赞被&#xff0c; 项目地址&#xff1a;gitee 注意&#xff1a;项目克隆下去之后先运行 npm i之后安装项目插件包之后在npm run dev 运行就可以了

【Mysql】事务与索引

目录 MySQL事务 事务的特性 并发事务的问题&#xff1f; 事务隔离级别&#xff1f; MySQL索引 数据结构 索引类型 聚簇索引与非聚簇索引 聚集索引的优点 聚集索引的缺点 非聚集索引的优点 非聚集索引的缺点 非聚集索引一定回表查询吗(覆盖索引)? 覆盖索引 联合索…

识别恶意IP地址的有效方法

在互联网的环境中&#xff0c;恶意IP地址可能会对网络安全造成严重威胁&#xff0c;例如发起网络攻击、传播恶意软件等。因此&#xff0c;识别恶意IP地址是保护网络安全的重要一环。IP数据云将探讨一些有效的方法来识别恶意IP地址。 IP地址查询&#xff1a;https://www.ipdata…

springboot265基于Spring Boot的库存管理系统

基于Spring Boot库存管理系统 Inventory Meanagement System based on Spring Boot 摘 要 当下&#xff0c;如果还依然使用纸质文档来记录并且管理相关信息&#xff0c;可能会出现很多问题&#xff0c;比如原始文件的丢失&#xff0c;因为采用纸质文档&#xff0c;很容易受潮…

Redis底层核心对象RedisObject源码分析

文章目录 1. redis底层数据结构2. 插入KV底层源码流程分析 1. redis底层数据结构 redis 6数据结构和底层数据结构的关系 String类型本质是SDS动态字符串&#xff0c;即redis层面的数据结构底层会有对应的数据结构实现&#xff0c;上面是redis 6之前的实现 redis 7数据结构和底…

Terrace联合创始人兼CEO Jesse Beller确认出席Hack.Summit() 2024区块链开发者大会

在科技创新的浪潮中&#xff0c;区块链技术以其独特的去中心化、透明性和安全性&#xff0c;正逐渐成为引领未来发展的重要力量。在这样的背景下&#xff0c;备受瞩目的Hack.Summit() 2024区块链开发者大会即将于4月9日至10日在香港数码港盛大举行。本次大会的亮点之一&#xf…

程序员春招攻略:金三银四的求职智慧与机遇

文章目录 程序员的金三银四求职宝典方向一&#xff1a;面试技巧分享自我介绍的艺术技术问题的回答策略团队协作经验的有效展示压力面试的应对结束语的巧妙运用 方向二&#xff1a;面试题解析数据结构与算法题系统设计题编程题 方向三&#xff1a;公司文化解读腾讯&#xff08;T…

软件设计不是CRUD(14):低耦合模块设计理论——行为抽象与设计模式(上)

是不是看到“设计模式”四个字,各位读者就觉得后续内容要开始讲一些假大空的内容了?各位读者是不是有这样的感受,就是单纯讲设计模式的内容,网络上能找到很多资料,但是看过这些资料后读者很难将设计模式运用到实际的工作中。甚至出现了一种声音:设计模式是没有用的,应用…

机试:最大子序列的和

问题描述: 算法思想: 若第(i-1)个序列的小于0,则第i个序列的最大值为nums[i]; 若第(i-1)个序列的小于0,则第i个序列的最大值为max(i-1) nums[i]; 如果max(i-1)>0,max(i)max(i-1)Nums(i) 如果max(i-1)<0,max(i)Nums(i)代码示例: #include <bits/stdc.h> //该算法…

ULTRAL SCALE FPGA TRANSCEIVER速率

CPLL支持2-6.25速率 QPLL支持速率 实际使用CPLL最高可以超过这个&#xff0c;QPLL最低也可以低于这个&#xff0c;xilinx留的阈量还是比较大。
最新文章