three.js学习笔记

开始

three.js官网地址:Three.js – JavaScript 3D Library

因为官网是部署在国外访问的时候比较卡

我们可以把项目下载下来在本地运行

第一步打开官网找到github选项

 第二步克隆一份

 下载到本地npm i 下载对应依赖启动就可以了

第三步启动项目进入这样的页面点击docs

 进入之后你可以选择语言之后再看文档的时候就不用等待那么长时间了 

如果你有VPN可以省略以上步骤

 npm install three --save      //下载three

创建一个场景(Creating a scene)

这一部分将对three.js来做一个简要的介绍;我们将开始搭建一个场景,其中包含一个正在旋转的立方体。看代码

import * as THREE from 'three'
// console.log(THREE)

// 创建一个场景
const scene = new THREE.Scene();
// 创建一个透视相机
const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000)
// 设置相机位置
camera.position.set(0,0,10)
scene.add(camera)
// 添加物体
// 创建集合体
const cubeGeometry=new THREE.BoxGeometry(1,1,1);
const  cubeMaterial=new THREE.MeshBasicMaterial({color:'red'});
// 根据几何体和材质创建物体
const cube=new THREE.Mesh(cubeGeometry,cubeMaterial)
// 将集几何体添加到场景中
scene.add(cube)
// 初始化渲染器
const renderer=new THREE.WebGL1Renderer()
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 将webGl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement);  
// 使用渲染器,通过相机将场景渲染出来
renderer.render(scene,camera)

three.js里有几种不同的相机,在这里,我们使用的是PerspectiveCamera(透视摄像机)。

第一个参数是视野角度(FOV)。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。

第二个参数是长宽比(aspect ratio)。 也就是你用一个物体的宽除以它的高的值。比如说,当你在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的。

接下来的两个参数是近截面(near)和远截面(far)。 当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中。或许现在你不用担心这个值的影响,但未来为了获得更好的渲染性能,你将可以在你的应用程序里去设置它。

接下来是渲染器。这里是施展魔法的地方。除了我们在这里用到的WebGLRenderer渲染器之外,Three.js同时提供了其他几种渲染器,当用户所使用的浏览器过于老旧,或者由于其他原因不支持WebGL时,可以使用这几种渲染器进行降级。

除了创建一个渲染器的实例之外,我们还需要在我们的应用程序里设置一个渲染器的尺寸。比如说,我们可以使用所需要的渲染区域的宽高,来让渲染器渲染出的场景填充满我们的应用程序。因此,我们可以将渲染器宽高设置为浏览器窗口宽高。对于性能比较敏感的应用程序来说,你可以使用setSize传入一个较小的值,例如window.innerWidth/2window.innerHeight/2,这将使得应用程序在渲染时,以一半的长宽尺寸渲染场景。

如果你希望保持你的应用程序的尺寸,但是以较低的分辨率来渲染,你可以在调用setSize时,将updateStyle(第三个参数)设为false。例如,假设你的<canvas> 标签现在已经具有了100%的宽和高,调用setSize(window.innerWidth/2, window.innerHeight/2, false)将使得你的应用程序以一半的分辨率来进行渲染。

最后一步很重要,我们将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。这就是渲染器用来显示场景给我们看的<canvas>元素。

到这里我们可以看到图形是个二维的图形,那如何显示三位的图形那,如下

渲染场景

现在,如果将之前写好的代码复制到HTML文件中,你不会在页面中看到任何东西。这是因为我们还没有对它进行真正的渲染。为此,我们需要使用一个被叫做“渲染循环”(render loop)或者“动画循环

function render() {
    // 渲染下一帧的时候就会调用render函数
    requestAnimationFrame(render);
    renderer.render(scene, camera);
}
render()

效果如下

效果

可以看到效果图中的辅助线并且让图形自己转动加上以下代码即可

//++++++++++

const axesHelper = new THREE.AxesHelper( 5 );
scene.add( axesHelper );

//++++++++++
function render() {
    // 渲染下一帧的时候就会调用render函数
    requestAnimationFrame(render);
    //++++++++
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    //++++++++
    renderer.render(scene, camera);


}
render()

那我们要沿着轴线移动可以设置物体的position属性如下

// 根据几何体和材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial)

//+++++++++
// 修改物体的位置
cube.position.set(0,0,5)
//我们也可以position.x直接去修改物体所在轴的位置比如cube.position.x=5;
//+++++++++

// 将集几何体添加到场景中
scene.add(cube)

 如果要让物体自己移动直接在渲染循环做一个判断就可以了

function render() {
    // 渲染下一帧的时候就会调用render函数

    requestAnimationFrame(render);
    
    //++++++++++++
    cube.position.z += 0.01
    if (cube.position.z>5) {
        cube.position.z=0
    }else if(cube.position==0){
        cube.position.z += 0.01
    }
    //++++++++++++
    renderer.render(scene, camera);


}
render()

物体的缩放和旋转

// 物体的缩放
cube.scale.set(3,2,1)
// 物体的旋转 前三个参数是xyz第四个参数可以是字符串比如'ZXY'来设置旋转顺序注意字母要大写
cube.rotation.set(Math.PI/4,0,0)

应用requestAnimationFrame

render()函数有默认参数time我们打印看看

 我们看出当我们渲染的时候这个频率有的差距会比较高,我们可以让他没一段时间让物体移动多少,如下;

//这里的%5就是对步长取余,每次进入渲染循环就对时间经行取余,比如1%5=1,一直到5%5=0来实现以上的if判断进行的循环
let t = (time / 1000) % 5;
cube.position.x = t * 1;
  

这样的计算方式太复杂我们可以使用psap动画库

psap动画库基本使用原理

gsap - npm 官网

下载并引入

npm install gsap
// 导入gsap
import gsap from 'gsap';
//控制cube的位置属性position x让x移动到5的位置 duration在5秒内
gsap.to(cube.position,{x:5,duration:5})
//控制cube的位置旋转rotation x让x旋转360度 duration在5秒内
gsap.to(cube.rotation,{x:2*Math.PI,duration:5})
function render(time) {
    // 渲染下一帧的时候就会调用render函数
    renderer.render(scene, camera);
    requestAnimationFrame(render);

}

接下来我看如何设置速度

进入之后可以看到一下的效果 有不同的实现线的实现

 

 我们还可以设置动画完成和结束的回调函数 

var animate1 =gsap.to(cube.position,{
        x:5,
        // 重复的次数 无线循环为-1
        repeat:2,
        // 往返的运动
        yoyo:true,
        // 延迟2秒移动
        delay:2,
        duration:5,ease:'power1.inOUt',
        onComplete:()=>{
            console.log('动画完成');
        },
        onStart:()=>{
            console.log('动画开始');
        }
    })

    // 监听事件 dbclick监听鼠标双击
    window.addEventListener('dblclick',()=>{
        // 判断是否是运动状态 
        if(animate1.isActive()){
            // 如果是 停止
            animate1.pause();
        }else{
            // 否 运动
            animate1.resume()
        }
    })

设置阻尼 拖动物体结束时产生惯性

// 将其设置为true以启用阻尼(惯性),这将给控制器带来重量感。默认值为false。
// 请注意,如果该值被启用,你将必须在你的动画循环里调用.update()。
controls.enableDamping=true
function render(time) {
    // 渲染下一帧的时候就会调用render函数
    controls.update()
    renderer.render(scene, camera);
    requestAnimationFrame(render);

}

根据尺寸变化实现自适应

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

})

调用js接口控制画布全屏和退出全屏

// 调用js接口控制画布全屏和退出全屏
window.addEventListener('dblclick',()=>{
    const fullScreenElement=document.fullscreenElement;
    if (!fullScreenElement){
        // 双击控制屏幕进入全屏,退出全屏
        // 让画布全屏
        renderer.domElement.requestFullscreen();

    }else{
        // 退出全屏 使用document对象
        document.exitFullscreen();
    }
})

应用图形用户界面更改变量

我们需要下载gui库👉官网 dat.gui - npm 

 npm install --save dat.gui
// 导入data.gui
import * as dat from 'dat.gui'
const gui=new dat.GUI();
// min 最小值 max最大值 step每移动多少距离 name名字 onChange值被修改时触发该事件  onFinishChange修改完成时触发的事件
gui.add(cube.position,'x').min(0).max(5).step(0.01).name('移动x轴').onChange((value)=>{console.log('修改时触发的函数');}).onFinishChange((value)=>{console.log('修改完成时触发的事件');})
// 修改物体的颜色
const params={
    color:'#ffff00',
    fn:()=>{
     gsap.to(cube.position,{x:5,duration:2,yoyo:true,repeat:-1})

    }
}
gui.addColor(params,'color').onChange((value)=>{
    console.log('值被修改',value);
    cube.material.color.set(value)
})

// 设置选项框 
gui.add(cube,'visible').name('是否显示')
// 设置按钮点击触发某个事件
gui.add(params,'fn').name('立方运动');
// 功能太多的话 可以加个文件夹如下
var folder=gui.addFolder('设置立方体');
//显示物体的结构线
folder.add(cube.material,'wireframe')

使用BufferGeometry创建一个面片

// 创建多个三角形小案例
const geometry=new THREE.BufferGeometry();
// 创建一个一维数组每三个点都是(x,y,z)
// 立方体的每个面实际上是由2个三角形组成的。所以我们必须单独映射每个三角形
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 cubeMaterial = new THREE.MeshBasicMaterial({ color: 'red' });
// 根据几何体和材质创建物体
const mash=new THREE.Mesh(geometry,cubeMaterial)
scene.add(mash);

来做一个小案例

// 创建多个三角形小案例
for (let i=0;i<50;i++){
    // 每一个三角形,需要3个顶点,每个顶点需要3个值
    const geometry=new THREE.BufferGeometry();
    // 创建一个一维数组每三个点都是(x,y,z) 
    const positionArray=new Float32Array(9)

    for (let j=0;j<9;j++){
        // 创建一个随机三角形面
        positionArray[j]=Math.random()*10-5;
    }
    // 创建一个随机的颜色
    let color=new THREE.Color(Math.random(),Math.random(),Math.random())
    // 创建位置告诉他这个一个一维数组每三个值为一个坐标
    geometry.setAttribute('position',new THREE.BufferAttribute(positionArray,3));

    const cubeMaterial = new THREE.MeshBasicMaterial({
         color: color,
         transparent:true,//为true可以设置材质为透明
         opacity:0.5});
    // 根据几何体和材质创建物体
    const mash=new THREE.Mesh(geometry,cubeMaterial)
    console.log(mash,'??');
    scene.add(mash);
}

其实官网已经提供了这这些模型

geometry 几何体

 我们可以拿官网给的这些模型去做自己想做的东西

设置纹理显示算法与mipmap

mctextture.minFilter=THREE.NearestFilter;
mctextture.magFilter=THREE.NearestFilter;

 透明纹理

// 导入纹理

var ylj = require('../assets/imgs/img.webp')
const textureLoader=new THREE.TextureLoader()
const texture= textureLoader.load(ylj)
// mctextture.minFilter=THREE.NearestFilter;

// 添加物体
// 创建集合体
const cubeGeometry = new THREE.BoxGeometry( 1, 1, 1 );
const cubeMaterial = new THREE.MeshBasicMaterial({
     color: '#fff',
     map:texture,
     alphaMap:texture,
     transparent:true,
     // 透明度
     opacity:0.5,
    //  默认显示一面 THREE.DoubleSide属性两面都显示
    side:THREE.DoubleSide
    });
    // 构建完设置也可以
    // cubeMaterial.side=THREE.DoubleSide;
//添加平面
const plane=new THREE.Mesh(
    new THREE.PlaneGeometry(1,1),
    cubeMaterial
)
plane.position.set(3,0,0);
scene.add(plane);

 环境遮挡贴图

 

// 环境贴图
var chartlet = require('../assets/imgs/mc.webp')
const textAoTexture=textureLoader.load(
    chartlet
)
// mctextture.minFilter=THREE.NearestFilter;

// 添加物体
// 创建集合体
const cubeGeometry = new THREE.BoxGeometry( 1, 1, 1 );
const cubeMaterial = new THREE.MeshBasicMaterial({
     color: '#fff',
     map:texture,
     alphaMap:texture,
     transparent:true,
     //环境遮挡贴图
     aoMap:textAoTexture,
     // 阴影亮度
    //  aoMapIntensity:0.5,
     // 透明度
     //  opacity:0.5,
     //  默认显示一面 THREE.DoubleSide属性两面都显示
    side:THREE.DoubleSide
    });
    // 构建完设置也可以
    // cubeMaterial.side=THREE.DoubleSide;
//添加平面 
const PlaneGeometry=new THREE.PlaneGeometry(1,1);
const plane=new THREE.Mesh( PlaneGeometry,cubeMaterial);
// 给平面设置二组uv  第一组uv控制的是颜色贴图,第二组uv控制的是光照效果,和虚幻4引擎一个意思
PlaneGeometry.setAttribute(
    'uv2',//第二组uv
    new THREE.WebGLRenderer(PlaneGeometry.attributes.uv.array,2) //本身的uv 2个值作为一个点
)
plane.position.set(3,0,0);
scene.add(plane);

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Z_Xshan

你的鼓励是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值