Three——一、详解基础场景搭建(结尾含完整代码)

news2024/11/25 2:32:50

速成Three.js——一、详解基础场景搭建(结尾含源码)

给模型添加标签时需要准标签部分
从本章开始会从最初的搭建场景模型开始到插入精灵图部分结尾,便于刚入门three而不知如何去学起的前端工程师去学习,这里可以学到场景搭建的基础知识,引入外部模型以及动画,对模型添加标签以及优化模型方案等。详情可查找Three.js教程

搭建3D场景需要认识一下场景Scene相机Camera渲染器Renderer三个概念,看张图片
请添加图片描述

在创建模型在页面中显示出来时我们需要先创建一个场景(这里所用到的东西都在THREE中,直接new Three.(属性)就可以了)

// 创建一个场景
let scene = new Three.Scene()

物体形状:几何体Geometry

请添加图片描述

例如:

const geometry = new THREE.BoxGeometry(100, 100, 100); 

物体外观:材质Material

如果你想定义物体的外观效果,比如颜色,就需要通过材质Material相关的API实现。
threejs不同材质渲染效果不同,下面就以threejs最简单的网格基础材质MeshBasicMaterial (opens new window)为例给大家实现一个红色材质效果。
请添加图片描述

//创建一个材质对象Material
const material = new THREE.MeshBasicMaterial({
    color: 0xff0000,//0xff0000设置材质颜色为红色
}); 

物体:网格模型Mesh

这里实际将几何体和材质拼接在网络模型中,形成一个完整的几何体模型

// 两个参数分别为几何体geometry、材质material
const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh

模型位置.position

const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
//设置网格模型在三维空间中的位置坐标,默认是坐标原点
mesh.position.set(0,10,0);

.add()方法

在threejs中你创建了一个表示物体的虚拟对象Mesh,需要通过.add()方法,把网格模型mesh添加到三维场景scene中。

scene.add(mesh); 

下面两个方法将是执行渲染效果的核心部分,相机Camera渲染器Renderer

透视投影相机PerspectiveCamera

Threejs提供了正投影相机OrthographicCamera (opens new window)和透视投影相机PerspectiveCamera (opens new window)。本节课先给大家比较常用的透视投影相机PerspectiveCamera。

透视投影相机PerspectiveCamera本质上就是在模拟人眼观察这个世界的规律。

// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera();

相机位置.position

生活中用相机拍照,你相机位置不同,拍照结果也不同,threejs中虚拟相机同样如此。

比如有一间房子,你拿着相机站在房间里面,看到的是房间内部,站在房子外面看到的是房子外面效果。

相机对象Camera具有位置属性.position,通过位置属性.position可以设置相机的位置。

//相机在Three.js三维坐标系中的位置
// 根据需要设置相机位置具体值
camera.position.set(200, 200, 200); 

相机观察目标.lookAt()

你用相机拍照你需要控制相机的拍照目标,具体说相机镜头对准哪个物体或说哪个坐标。对于threejs相机而言,就是设置.lookAt()方法的参数,指定一个3D坐标。

//相机观察目标指向Threejs 3D空间中某个位置
camera.lookAt(0, 0, 0); //坐标原点
camera.lookAt(0, 10, 0);  //y轴上位置10
camera.lookAt(mesh.position);//指向mesh对应的位置

请添加图片描述

判断相机相对三维场景中长方体位置

你可以把三维场景中长方体mesh想象为一个房间,然后根据相机位置和长方体位置尺寸对比,判断两者相对位置。你可以发现设置相机坐标(200, 200, 200),位于长方体外面一处位置。

// 长方体尺寸100, 100, 100
const geometry = new THREE.BoxGeometry( 100, 100, 100 );
const mesh = new THREE.Mesh(geometry,material);
// 相机位置xyz坐标:0,10,0
mesh.position.set(0,10,0);
// 相机位置xyz坐标:200, 200, 200
camera.position.set(200, 200, 200); 

请添加图片描述

说简单一些就是在一个三维场景中,有一个网络模型的坐标,还有一个是相机的坐标

*透视投影相机PerspectiveCamera:视锥体

透视投影相机的四个参数fov, aspect, near, far构成一个四棱台3D空间,被称为视锥体,只有视锥体之内的物体,才会渲染出来,视锥体范围之外的物体不会显示在Canvas画布上。下面这张图解释的已经很清晰了,主要的意思就是这个属性会把相机视为一个锥体,如果你放大缩小的话也只会显示锥体里面的模型样子
请添加图片描述

// width和height用来设置Three.js输出的Canvas画布尺寸(像素px)
const width = 800; //宽度
const height = 500; //高度
// 30:视场角度, width / height:Canvas画布宽高比, 1:近裁截面, 3000:远裁截面
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);

参数介绍:

PerspectiveCamera( fov, aspect, near, far )
参数含义推荐默认值
fov视场:即可以看到的角度范围,人的视场大约是180度,一般游戏的视场为60度到90度60
aspect长宽比:这个是渲染结果输出区域的横向长度和纵向长度的比值;长宽比决定了水平视场和垂直视场之间的比例关系,推荐默认值:window.innerWidth/window.innerHeightwindow.innerWidth/window.innerHeight
near近面:基于相机位置,表示从这里开始渲染场景;一般会设置一个很小的值0.1
far远面:基于相机位置,表示停止渲染的位置;要注意设置合适的距离,如果设置太小,部分场景可能渲染不到,但如果设置的太大,会影响渲染的效率1000

渲染器

生活中如果有了景物和相机,那么如果想获得一张照片,就需要你拿着相机,按一下,咔,完成拍照。对于threejs而言,如果完成“咔”这个拍照动作,就需要一个新的对象,也就是WebGL渲染器WebGLRenderer
请添加图片描述

所以想要生成一张渲染在浏览器中的照片,就需要模型,相机以及渲染器

WebGL渲染器WebGLRenderer

通过WebGL渲染器WebGLRenderer (opens new window)可以实例化一个WebGL渲染器对象。

// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();

设置Canvas画布尺寸.setSize()

// 定义threejs输出画布的尺寸(单位:像素px)
const width = 800; //宽度
const height = 500; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)

通常简单来说就是渲染多大的地方,我这里的话就按浏览器全屏来算了
,参数的话可以给clientWidth,clientHeight

渲染器渲染方法.render()

渲染器WebGLRenderer执行渲染方法.render()就可以生成一个Canvas画布(照片),并把三维场景Scene呈现在canvas画布上面,你可以把.render()理解为相机的拍照动作“咔”。这里也很好理解,就是.render()已经生成好了画布,但还没渲染在浏览器中

renderer.render(scene, camera); //执行渲染操作

渲染器Canvas画布属性.domElement

渲染器WebGLRenderer通过属性.domElement可以获得渲染方法.render()生成的Canvas画布,.domElement本质上就是一个HTML元素:Canvas画布。到这里就可以把生成的这个画布canvas放在指定的标签中在浏览器里显示出来

document.body.appendChild(renderer.domElement);

Canvas画布插入到任意HTML元素中

document.getElementById('webgl').appendChild(renderer.domElement);

接下来我们理解了基础用法,来用V3实现一个简单的demo

<!-- author: Mr.J -->
<!-- date: 2023-04-12 11:43:45 -->
<!-- description: Vue3+JS代码块模板 -->
<template>
  <div class="container" ref="container">
  </div>
</template>

<script setup>
import * as THREE from "three";
// 轨道
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { ref, reactive, onMounted } from "vue";
// 三个必备的参数
let scene, camera, renderer, controls;

onMounted(() => {
  // 外层需要获取到dom元素以及浏览器宽高,来对画布设置长宽
  // clientWidth等同于container.value.clientWidth
  let container = document.querySelector(".container");
  const { clientWidth, clientHeight } = container;
  console.log(clientHeight);

  init();
  animate();
  // 首先需要获取场景,这里公共方法放在init函数中
  function init() {
    scene = new THREE.Scene();
    // 给相机设置一个背景
    scene.background = new THREE.Color(0x000000);
    // 透视投影相机PerspectiveCamera
    // 支持的参数:fov, aspect, near, far
    camera = new THREE.PerspectiveCamera(
      60,
      clientWidth / clientHeight,
      0.1,
      1000
    );
    // 相机坐标
    camera.position.set(200, 200, 200);
    // 相机观察目标
    camera.lookAt(scene.position);
    // 渲染器
    renderer = new THREE.WebGLRenderer();
    // 渲染多大的地方
    renderer.setSize(clientWidth, clientHeight);
    container.appendChild(renderer.domElement);
    controls = new OrbitControls(camera, renderer.domElement);
    addBox();
  }

  function addBox() {
    // 模型部分
    // 几何体
    const geometry = new THREE.BoxGeometry(100, 100, 100);
    // 材质
    const material = new THREE.MeshBasicMaterial({
      color: 0x51efe4, //0x51efe4设置材质颜色为红色
    });
    // 网络模型
    const mesh = new THREE.Mesh(geometry, material);
    mesh.position.set(0, 10, 0);
    scene.add(mesh);
  }
  function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
  }
});
</script>

<style>
.container {
  width: 100%;
  height: 100vh;
  position: relative;
  z-index: 1;
}
</style>

效果展示:
请添加图片描述

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

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

相关文章

【微服务笔记12】微服务组件之Hystrix和OpenFeign结合使用

这篇文章&#xff0c;主要介绍微服务组件之Hystrix和OpenFeign结合使用。 目录 一、Hystrix和OpenFeign结合使用 1.1、引入依赖 1.2、openfeign启用hystrix 1.3、编写FeignClient接口 1.4、编写FeignClient实现类 1.5、编写Controller控制器 1.6、启动类启动OpenFeign …

Apache网页的优化,安全与防盗链

在企业中&#xff0c;部署Apache后只采用默认的配置参数&#xff0c;会引发网站很多问题&#xff0c;换言之默认配置是针对以前较低的服务器配置的&#xff0c;以前的配置已经不适用当今互联网时代。 为了适应企业需求&#xff0c;就需要考虑如何提升Apache的性能与稳定性&…

智慧水务系统-全域孪生驾驶舱-三维实景模型

平台概述 柳林智慧水务系统平台是以物联感知技术、大数据、智能控制、云计算、人工智能、数字孪生、AI算法、虚拟现实技术为核心&#xff0c;以监测仪表、通讯网络、数据库系统、数据中台、模型软件、前台展示、智慧运维等产品体系为支撑&#xff0c;以城市水资源、水生态、水…

LeetCode-152. 乘积最大子数组

目录思路动态规划题目来源 152. 乘积最大子数组 思路 这题跟LeetCode-53. 最大子数组和很像 最后把整个 dp 数组看一遍求最大值即可。因此状态转移方程可能是&#xff1a; dp[i] Math.max(dp[i-1]nums[i],nums[i]);说明&#xff1a;牢记状态的定义&#xff0c;一定以下标 i…

Android13 PMS是如何启动的?

作者&#xff1a;Arthas0v0 平常使用安卓实际就是在使用各种app&#xff0c;而下载的app实际是一个apk文件。这个apk文件的安装就交给了PackageManagerService来实现。PackageManagerService的启动也是在SystemServer中。这个过程比较长需要长一点的时间来理。 SystemServer.s…

2023-04-09 有向图及相关算法

有向图及相关算法 1 有向图的实现 有向图的的应用场景 社交网络中的关注互联网连接程序模块的引用任务调度学习计划食物链论文引用无向图是特殊的有向图&#xff0c;即每条边都是双向的 改进Graph和WeightedGraph类使之支持有向图 Graph类的改动WeightedGraph类的改动 2 …

肖 sir_就业课__004项目流程(H模型)

项目流程&#xff1a; 一、面试提问&#xff08;h模型&#xff09; 1、你说下你们公司测试流程&#xff1f; 2、给你一个需求你会怎么做? 3、你讲下你的工作&#xff1f; 4、谈谈你是如何去测试&#xff1f; 答案&#xff1a;h模型 要求第一人称来写 讲解简化文字流程&#x…

基于Python实现的深度学习技术在水文水质领域应用

目录 一、深度学习的基本概念和发展现状 二、Python系列开源软件包基本用法 三、前馈神经网络模型、原理和代码实现 四、前馈神经网络模型在水质、水位预测中的应用 五、卷积神经网络模原理、结构和应用&#xff0c;与支持向量机进行比较 六、循环神经网络原理与结构 七…

web 页面在浏览器运行eval性能分析和优化

公司有个低代码老项目&#xff0c;里面有一些自定义脚本运行使用了大量的eval 动态运行。 分析 网上对eval 的争论也非常激烈&#xff0c;大部分不建议使用&#xff0c;一些人观点是用不好才导致问题。 eval 是否真的存在效率问题&#xff1f; eval is evil 我们知道new Fun…

定时任务-常用的cron表达式

常用cron表达式例子&#xff1a; &#xff08;1&#xff09;0/2 * * * * ? 表示每2秒 执行任务 &#xff08;1&#xff09;0 0/2 * * * ? 表示每2分钟 执行任务 &#xff08;1&#xff09;0 0 2 1 * ? 表示在每月的1日的凌晨2点调整任务 &#xff08;2&#xff09;0 15 1…

宝塔设置PHP定时任务实战记录(定时任务、ajax异步刷新API、shell脚本、访问url)

文章目录项目需求生产环境一、php定时任务二、实战开发1.创建mysql数据表2.入库封装函数&#xff08;1&#xff09;封装入库&#xff08;2&#xff09;入库操作3.定时任务的实现&#xff08;1&#xff09;$ajax异步调用法&#xff08;2&#xff09;宝塔定时访问url&#xff08;…

http请求头部(header)详解

通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机的响应消息。这两种类型的消息由一个起始行&#xff0c;一个或者多个头域&#xff0c;一个只是头域结束的空行和可 选的消息体组成。HTTP的头域包括通用头&#xff0c;请求头&#xff0c;响应头和实体头四个部分。每个…

OpenShift 4 - 通过 SSH 远程访问 OpenShift Virtualization 的虚拟机

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在支持 OpenShift 4.12 的 OpenShift 环境中验证 在《OpenShift 4 - 用 OpenShift Virtualization 运行容器化虚拟机 &#xff08;视频&#xff09;》一文中使用了 OpenShift 控制台直接访问运行在 OpenSh…

【Python实战】从架构设计到实现:一个Powerful的图书管理系统

&#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是Zeeland&#xff0c;全栈领域优质创作者。&#x1f4dd; CSDN主页&#xff1a;Zeeland&#x1f525;&#x1f4e3; 我的博客&#xff1a;Zeeland&#x1f4da; Github主页: Undertone0809 (Zeeland) (github.com)&…

栈的压入,栈的弹出,最小栈,用队列实现栈,设计循环队列

栈的压入&#xff0c;栈的弹出 输入两个整数序列&#xff0c;第一个序列表示栈的压入序列&#xff0c;判断第二个序列是否可能是该栈的弹出序列&#xff0c;假设压入栈中的所有数字均不相等&#xff0c;如pushA:1&#xff0c;2&#xff0c;3&#xff0c;4&#xff0c;5是某栈的…

day11 有名管道和无名管道

无名管道基础 进程间的通信 概念&#xff1a; 进程间的通信就是进程和进程之间交换信息&#xff1b; 常用方式&#xff1a; 无名管道&#xff08;pipe&#xff09; 有名管道&#xff08;fifo&#xff09; 信号&#xff08;signal&#xff09; 共享内存&#xff08;mmap…

DOS批处理文件---内嵌参数变量扩充功能

1 内嵌参数变量 1.1 介绍 内嵌参数变量指&#xff1a;%i&#xff0c;其中i为大于等于0的整数。如%0&#xff0c; %1&#xff0c; %2&#xff0c;... 1.2 作用 可以客制化功能。 1.3 案例 批处理文件&#xff1a;main_Param.bat echo off && setlocal ENABLEDELA…

游戏分析之引擎的基本概念及常见的游戏引擎介绍

一、引擎的基本概念 关于游戏引擎和中间件 过去开发游戏的时候&#xff0c;游戏机生产商提供的只是硬件的规格书和非常基本的“库”。所以&#xff0c;游戏需要的各种程序功能都需要游戏开发团队自己开发。从PC&#xff0c;FC的8位机时代开始&#xff0c;到SFC&#xff0c;MD的…

Java经典笔试题—day01

Java经典笔试题—day01&#x1f50e;选择题&#x1f50e;编程题&#x1f95d;组队竞赛&#x1f95d;删除公共字符&#x1f50e;结尾&#x1f50e;选择题 (1) 在 Java 中&#xff0c;存放字符串常量的对象属于&#xff08; &#xff09;类对象。 A. Character B. String C. Str…

类ChatGPT项目的部署与微调(下):从ChatGLM-6b到ChatDoctor

前言 随着『GPT4多模态/Microsoft 365 Copilot/Github Copilot X/ChatGPT插件』的推出&#xff0c;绝大部分公司的技术 产品 服务&#xff0c;以及绝大部分人的工作都将被革新一遍 类似iPhone的诞生 大家面向iOS编程 有了App Store现在有了ChatGPT插件/GPT应用商店&#xff…