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

three.js之初识three.js

什么是three.js

Three.js是一款运行在浏览器中的 3D 引擎(基于WebGL的API的封装)

什么是WebGL?

WebGL(英语:Web Graphics Library)是一种3D绘图协议,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。

three.js

本地环境搭建,因为spring的官方文档是访问起来比较慢,所以我们在本地搭建起来three.js的官方文档和案例

首先访问https://github.com/mrdoob/three.js 通过 git或者压缩包把代码下载到本地

使用parcel搭建three.js开发环境

为什么需要使用parcel 因为parcel不需要配置。webpack需要去进行配置。

第一个Three.js小demo

import * as THREE from "three";
//轨道控制器
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";//创建场景const scence=new THREE.Scene();//创建相机const camera=new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000
)//设置相机位置camera.position.set(0,0,10);//添加相机到场景
scence.add(camera);//创建物体//创建几何体
const geometry=new THREE.BoxGeometry(1,1,1);
//创建材质
const meterial=new THREE.MeshBasicMaterial({color:0x00ff00});//根据几何体和材质,创建物体
const  cube=new THREE.Mesh(geometry,meterial);//控制物体移动let x=0,y=1,z=0;console.log(cube);//缩放cube.scale.set(.5,1,1.5);//旋转//   cube.rotation.set(Math.PI/2,Math.PI*2,Math.PI/3,"YXZ");
cube.rotation.set(Math.PI/4,0,0,"YZX");
//将物体添加到场景中scence.add(cube);//初始化渲染器const renderer=new THREE.WebGLRenderer();//设置渲染器的尺寸大小renderer.setSize(window.innerWidth,window.innerHeight);//将webgl渲染的fcanvas内容添加到bodydocument.body.append(renderer.domElement);
//添加坐标轴辅助器const axesHelper = new THREE.AxesHelper( 5 );
scence.add( axesHelper );//添加控制器,只有添加了控制器才能拖动查看const controller=new OrbitControls(camera,renderer.domElement);//每一帧渲染一次
const render=()=>{x+=0.01;y+=0.01;z+=0.01;if(x >5|| y >5 || z>5){x=0;y=0;z=0;}cube.position.set(x,y,z);cube.rotation.x+=0.01;//使用渲染器,通过相机将场景渲染出来renderer.render(scence,camera);// requestAnimationFrame函数是浏览器提供了,浏览器每次请求一帧则执行一次回调requestAnimationFrame(render);
}
render();

应用requestAnimationFrame

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
const scence=new THREE.Scene();
const camera=new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000
)
camera.position.set(0,0,10);
scence.add(camera);
const geometry=new THREE.BoxGeometry(1,1,1);
const meterial=new THREE.MeshBasicMaterial({color:0x00ff00});
const  cube=new THREE.Mesh(geometry,meterial);let x=0,y=1,z=0;console.log(cube);cube.scale.set(.5,1,1.5);
cube.rotation.set(Math.PI/4,0,0,"YZX");
scence.add(cube);
const renderer=new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth,window.innerHeight);
document.body.append(renderer.domElement);
const axesHelper = new THREE.AxesHelper( 5 );
scence.add( axesHelper );
const controller=new OrbitControls(camera,renderer.domElement);
const render=(time)=>{/*** time参数表示每一帧的时间* * * x+=0.01;y+=0.01;z+=0.01;* * 像这样每次加0.1是不对的,因为电脑的性能问题,会导致物体运动的不一样。* 所以我们需要让物体有规律的运行* * *///比如设置1秒运动多少const t=time/1000 %5;cube.rotation.x=t*1;x=t*1,y=t*1,z=t*1;cube.position.set(x,y,z);renderer.render(scence,camera);requestAnimationFrame(render);
}
render();

Gsap动画库(简单使用)

是一个功能十分强大的动画平台,能够帮助我们实现大部分的动画需求,构建高性能的适用于所有主流浏览器的高性能动画。

首先进行安装

  • yarn add gsap
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";//创建场景const scence=new THREE.Scene();//创建相机const camera=new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,1000
)//设置相机位置camera.position.set(0,0,10);//添加相机到场景
scence.add(camera);//创建物体//创建集合体
const geometry=new THREE.BoxGeometry(1,1,1);
//创建材质
const meterial=new THREE.MeshBasicMaterial({color:0x00ff00});//根据几何体和材质,创建物体
const  cube=new THREE.Mesh(geometry,meterial);//控制物体移动let x=0,y=1,z=0;console.log(cube);//缩放cube.scale.set(.5,1,1.5);//旋转//   cube.rotation.set(Math.PI/2,Math.PI*2,Math.PI/3,"YXZ");
cube.rotation.set(Math.PI/4,0,0,"YZX");
//将物体添加到场景中scence.add(cube);//初始化渲染器const renderer=new THREE.WebGLRenderer();//设置渲染器的尺寸大小renderer.setSize(window.innerWidth,window.innerHeight);//将webgl渲染的fcanvas内容添加到bodydocument.body.append(renderer.domElement);
//添加坐标轴辅助器const axesHelper = new THREE.AxesHelper( 5 );
scence.add( axesHelper );//添加控制器,只有添加了控制器才能拖动查看const controller=new OrbitControls(camera,renderer.domElement);
controller.enableDamping=true
//使用gsap的动画,来帮助我们设置物体的运动
gsap.to(cube.position, {x:5, duration: 2.5, ease: "power2.in" });
//每一帧渲染一次
const render=(time)=>{//使用渲染器,通过相机将场景渲染出来renderer.render(scence,camera);// requestAnimationFrame函数是浏览器提供了,浏览器每次请求一帧则执行一次回调requestAnimationFrame(render);controller.update();
}
render();

监听画面变化,更新渲染画面

现在可以看到,当我们的浏览器的尺寸变化时,我们的渲染画面是没有跟着变的。所以我们需要监听画面的变化更新渲染页面。

//监听页面变化,更新摄像头
window.addEventListener("resize",()=>{//更新摄像头camera.aspect=window.innerWidth/window.innerHeight;//更新摄影机的摄像矩阵camera.updateProjectionMatrix();//更新渲染器renderer.setSize(window.innerWidth,window.innerHeight);//设置渲染器的像素比renderer.setPixelRatio(window.devicePixelRatio);
})
render();

js控制画面全屏与退出全屏

一般都是双击屏幕进入全屏,所以我们写双击进入&退出全屏

//给window绑定双击事件
window.addEventListener("dblclick",()=>{//获取浏览器当前的全屏对象/*** 这里因为不同浏览器的兼容,所以我们使用两个*/const fullScreenElement =document.fullScreenElement|| document.webkitFullscreenElement//当为null的时候,我们调用canvas的dom,请求进入全屏if(!fullScreenElement){renderer.domElement.requestFullscreen();}else{//直接使用document退出全屏document.exitFullscreen();}});

dat.gui

dat.gui是一个轻量级的控制器,它可以在界面上来进行操作变量。
在webgl里就是一个控制器,通过控制器来进行物体的控制。


import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as datGui from 'dat.gui';
//创建场景const scence = new THREE.Scene();//创建相机const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
)camera.position.set(0, 0, 10);
scence.add(camera);
const geometry = new THREE.BoxGeometry(1, 1, 1);
const meterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
const cube = new THREE.Mesh(geometry, meterial);
let x = 0, y = 1, z = 0;
cube.scale.set(.5, 1, 1.5);
cube.rotation.set(Math.PI / 4, 0, 0, "YZX");scence.add(cube);const renderer = new THREE.WebGLRenderer();renderer.setSize(window.innerWidth, window.innerHeight);document.body.append(renderer.domElement);const axesHelper = new THREE.AxesHelper(5);
scence.add(axesHelper);const controller = new OrbitControls(camera, renderer.domElement);const gui = new datGui.GUI();//添加控制物体移动
gui.add(cube.position, 'x').min(0).max(5).step(0.01).name('移动x轴').onChange(value => {console.log("值被改变", value);}).onFinishChange(value => {{console.log("停止修改", value);}});const params = {color: '#ffff00',fn: () => { //这里的fn与下边的添加事件是对应的gsap.to(cube.position, { x: 5, duration: 2, yoyo: true, repeat: -1 });}
}
//颜色控制
gui.addColor(params, 'color').onChange(value => {cube.material.color.set(value);
});
//选项框
gui.add(cube, 'visible').name('是否显示');
//添加文件夹
const folder = gui.addFolder('设置立方体');
//添加文件夹内容
folder.add(cube.material, 'wireframe');
//添加点击事件
gui.add(params, 'fn').name('点击运动')
const render = () => {renderer.render(scence, camera);requestAnimationFrame(render);
}
render();

认识ThreeJs物体

几何体

在three.js中所有的几何体都是基于BufferGeomatry的基础上来进行构建的。

BufferGeomatry里有三个基础属性postion(位置),normar(法向量),uv(顶点);比如说我们一个矩形的立方体,有6个面,每个面又4个顶点,就是24个顶点,然后每个顶点又x,y,z三个方向上的位置,那么这里的数据就是72个。我们可以根据顶点的位置去进行添加材质和进行贴图。我们可以通过uv来进行我们的一个材质贴图。normal的作用呢就是顶点的法向量它的作用呢就是比如有一束光进行,我们需要知道这个光的一个折射位置和面的一个朝向。

通过BufferGeomatry来创建矩形

三个顶点就可以创建一个面

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as datGui from 'dat.gui';
const scence = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
)
camera.position.set(0, 0, 10);
scence.add(camera);//创建基础的几何体
const geometry = new THREE.BufferGeometry();
const meterial = new THREE.MeshBasicMaterial({ color: 0x00ff00 });//设置材质//顶点位置 (由两个三角形片组成一个矩形,一个三角形片是三个顶点,两个就是六个顶点,一个顶点有三个位置所以是长度是18的一维数组)
const vertices =new Float32Array([-1.0, -1.0, 1.0,1.0, -1.0, 1.0,1.0,1.0,1.0,1.0,1.0,1.0,-1.0,1.0,1.0,-1.0,-1.0,1.0
]);//设置顶点 (每三个数据为一个顶点)
geometry.setAttribute('position',new THREE.BufferAttribute(vertices,3));
const mesh=new THREE.Mesh(geometry,meterial);
scence.add(mesh);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);
const axesHelper = new THREE.AxesHelper(5);
scence.add(axesHelper);
const controller = new OrbitControls(camera, renderer.domElement);
const render = () => {renderer.render(scence, camera);requestAnimationFrame(render);
}
render();

根据顶点创建酷炫三角形

//创建50个三角形,形成凌乱穿插效果
for (let i = 0; i < 50; i++) {const geometry = new THREE.BufferGeometry();//顶点坐标const positionArray = new Float32Array(9);//三个顶点组成一个三角形,每个顶点需要x,y,z三个坐标for (let j = 0; j < 9; j++) {positionArray[j] = Math.random() * 5;}geometry.setAttribute('position', new THREE.BufferAttribute(positionArray, 3));//颜色进行随机const color = new THREE.Color(Math.random(), Math.random(), Math.random());//创建材质const meterial = new THREE.MeshBasicMaterial({color,transparent: true,//保持透明,opacity: .5 //透明度});const mesh = new THREE.Mesh(geometry, meterial);scence.add(mesh);
}

常用的网格几何体

three.js中给我们提供了很多的几何体我们可以去进行使用,不用自己再去进行设置一个很多顶点。

我们都可以通过在文档中去查找几何体,然后通过设置他们的构造参数来得到想要的物体。

认识Three的材质

上一个我们说到了物体,也就是几何体,我们通过几何体与材质进行一个贴合,才构建成了我们的一个物体。

基本颜色材质搭建

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as datGui from 'dat.gui';
const scence = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
)
camera.position.set(0, 0, 10);
scence.add(camera);
const renderer = new THREE.WebGLRenderer();
// 创建一个正方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
//导入纹理
const textureLoader=new THREE.TextureLoader().load('./public/door.jpg');
//创建材质
/*** map是颜色材质纹理,具体的我们可以看文档*/
const material = new THREE.MeshBasicMaterial({ map:textureLoader});
const cube = new THREE.Mesh(geometry, material);
scence.add(cube);
renderer.setSize(window.innerWidth, window.innerHeight);document.body.append(renderer.domElement);const axesHelper = new THREE.AxesHelper(5);
scence.add(axesHelper);const controller = new OrbitControls(camera, renderer.domElement);const render = () => {renderer.render(scence, camera);requestAnimationFrame(render);
}
render();

纹理偏移 旋转 重复

three.js给我们提供了,纹理在物体上如何进行设置(旋转,偏移,重复)

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as datGui from 'dat.gui';
const scence = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
)
camera.position.set(0, 0, 10);
scence.add(camera);
const renderer = new THREE.WebGLRenderer();
const geometry = new THREE.BoxGeometry(1, 1, 1);
const texture = new THREE.TextureLoader().load('./public/door.jpg');
//纹理偏移
// texture.offset.set(0.5,0.5);//纹理旋转
//texture.rotation=Math.PI/4;
//texture.center.set(0.5,0.5); //设置旋转原点//纹理重复texture.repeat.set(2, 3);
texture.wrapS=THREE.MirroredRepeatWrapping;
texture.wrapT=THREE.RepeatWrapping;
/*** wrapS 指代的是水平方向上纹理重复如何包裹* wrapT 指代的是垂直方向上纹理重复如何包裹* MirroredRepeatWrapping和RepeatWrapping是three.js提供的常量值*/
const material = new THREE.MeshBasicMaterial({ map: texture });
const cube = new THREE.Mesh(geometry, material);
scence.add(cube);
renderer.setSize(window.innerWidth, window.innerHeight);document.body.append(renderer.domElement);const axesHelper = new THREE.AxesHelper(5);
scence.add(axesHelper);const controller = new OrbitControls(camera, renderer.domElement);const render = () => {renderer.render(scence, camera);requestAnimationFrame(render);
}
render();

纹理的显示算法

magFilter,就是在渲染时一个纹素覆盖多个屏幕项目的情况下如何对这些纹素采样确定最终的颜色,
当使用THREE.LinerFilter时,它表示贴图将使用四个最接近的纹素,并在它们之间进行双线性插值。
当设置为THREE.NearestFilter时,它表示贴图将使用最接近的单个纹素的值,这意味着只会考虑最接近的一个纹素,而不考虑周围其他的纹素。

minFilter 当一个纹素小于一个屏幕像素时的设置

透明纹理

透明纹理的含义的就是,比如我们的门的图片,它展示的不仅仅是一个门的形状,它还包括边缘的一些形状,那么怎么办呢?three.js的材质里提供了属性alphaMap,它可以通过导入进来的材质图片,导入的材质图片吧必须只有黑色和白色,黑色就是完全透明,白色就是完全不透明,贴入之后,来展示形状,比如我们第二个导入进来的黑白图片,白色的就只是一个门的形状,在贴入之后我们就只能看到门了。

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as datGui from 'dat.gui';
const scence = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
)
camera.position.set(0, 0, 10);
scence.add(camera);
const renderer = new THREE.WebGLRenderer();
const geometry = new THREE.BoxGeometry(1, 1, 1);
const texture = new THREE.TextureLoader().load('./public/door.jpg');
//导入透明材质纹理图片
const alphaMap=new THREE.TextureLoader().load('./public/door_opticy.jpeg');
const material = new THREE.MeshBasicMaterial({ map: texture,alphaMap, // 透明材质transparent:true, //透明side:THREE.DoubleSide  //单面 || 双面显示});
const cube = new THREE.Mesh(geometry, material);
scence.add(cube);
renderer.setSize(window.innerWidth, window.innerHeight);document.body.append(renderer.domElement);const axesHelper = new THREE.AxesHelper(5);
scence.add(axesHelper);const controller = new OrbitControls(camera, renderer.domElement);const render = () => {renderer.render(scence, camera);requestAnimationFrame(render);
}
render();

环境遮挡贴图

环境贴图,就是比如我们的门,门上的一些纹理,我们需要显示的更加真实。

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import gsap from "gsap";
import * as datGui from 'dat.gui';
const scence = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75,window.innerWidth / window.innerHeight,0.1,1000
)
camera.position.set(0, 0, 10);
scence.add(camera);
const renderer = new THREE.WebGLRenderer();
const geometry = new THREE.BoxGeometry(1, 1, 1);
const texture = new THREE.TextureLoader().load('./public/door.jpg');
const alphaMap=new THREE.TextureLoader().load('./public/door_opticy.jpeg');
//引入环境贴图的图片
const aoMap=new THREE.TextureLoader().load('./public/aoDoor.jpg');
const material = new THREE.MeshBasicMaterial({ map: texture,alphaMap,transparent:true,aoMap,side:THREE.DoubleSide });//规定,使用aoMap环境贴图的话需要给几何体添加第二组uv
geometry.setAttribute('uv2',new THREE.BufferAttribute(geometry.attributes.uv.array,2));
const cube = new THREE.Mesh(geometry, material);scence.add(cube);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.append(renderer.domElement);const axesHelper = new THREE.AxesHelper(5);
scence.add(axesHelper);const controller = new OrbitControls(camera, renderer.domElement);const render = () => {renderer.render(scence, camera);requestAnimationFrame(render);
}
render();
http://www.lryc.cn/news/195597.html

相关文章:

  • 二维码智慧门牌管理系统:地址管理的现代革命
  • BricsCAD 23 for Mac:轻松驾驭CAD建模的强大工具
  • 如何利用Web应用防火墙应对未知威胁
  • 四、多线程服务器
  • 基于vue实现滑块动画效果
  • 探寻蓝牙的未来:从蓝牙1.0到蓝牙5.4,如何引领无线连接革命?
  • openssl 之 RSA加密数据设置OAEP SHA256填充方式
  • js将带标签的内容转为纯文本
  • 如何通过内网穿透实现远程连接NAS群晖drive并挂载电脑硬盘?
  • 4.2 抽象类
  • ITextRenderer将PDF转换为HTML详细教程
  • c#设计模式-行为型模式 之 备忘录模式
  • ffmpeg+安卓+yolo+RK3399部署
  • 发电机教程:小白必学的柴油发电机技巧
  • 基础课1——人工智能的分类和层次
  • C语言复杂表达式与指针高级
  • 【Python从入门到进阶】39、使用Selenium自动验证滑块登录
  • 利用FPGA和CPLD数字逻辑实现模数转换器
  • 上海亚商投顾:沪指震荡调整跌 减肥药、华为概念股持续活跃
  • 间歇性微服务问题...
  • 小程序开发平台源码系统+ 带前后端完整搭建教程
  • 外部统一设置了::-webkit-scrollbar { display: none; }如何单独给特定元素开启滚动条设置样式-web页面滚动条样式设置
  • 【计算机网络】网络原理
  • 力扣第39题 组合总和 c++ 回溯剪枝题
  • qt软件正常运行的崩溃了定位行号方法
  • 软件工程与计算总结(十五)详细设计中面向对象方法下的信息隐藏
  • 鸿蒙初体验
  • hive复合类型的数据查询
  • Notes/Domino 14 Early Access Drop3发布
  • 前端、后端开发者常用到的免费API整理