当前位置:   article > 正文

Threejs简单介绍(含案例演示)_three.js

three.js

什么是Three.js

你将它理解成three + js就可以了
three表示3D的意思
js表示javascript的意思
three.js就是使用javascript 来写3D程序的意思
先去下载代码,它的地址是: https://github.com/mrdoob/three.js
可以用script引用

<script src="https://wow.techbrood.com/libs/three.r73.js"></script>
  • 1

三大组建

在Three.js中要渲染物体到网页中我们需要3个组件

场景scene

场景是所有物体的容器,如果要显示一个苹果,就需要将苹果对象加入场景中

let scene = new THREE.Scene();
  • 1

相机camera

另一个组建是相机,相机决定了场景中那个角度的景色会显示出来。相机就像人的眼睛一样,人站在不同位置,抬头或者低头都能够看到不同的景色。
场景只有一种,但是相机却有很多种
只要设置不同的相机参数,就能够让相机产生不一样的效果

透视相机这里使用的是透视相机

let camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000)
  • 1

设置不同的相机需要不同的参数
会出现不同的效果

渲染器renderer

渲染器决定了渲染的结果应该画在页面的什么元素上面
并且以怎样的方式来绘制

let renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
//挂载到页面
document.body.appendChild(renderer.domElement)
  • 1
  • 2
  • 3
  • 4

添加物体

let geometry = new THREE.CubeGeometry(1, 1, 1);
//width:立方体x轴的长度,height:立方体y轴的长度,depth:立方体z轴的长度也是深度
  • 1
  • 2

渲染物体

renderer.render(scene, camera)
//scene:前面定义的场景,camera:前面定义的相机
//renderTarget:渲染的目标默认是是渲染到前面定义的render变量中
//forceClear:每次绘制之前都将画布的内容给清除,即使自动清除标志autoClear为false,也会清除
  • 1
  • 2
  • 3
  • 4
function render() {
    cube.rotation.x += 0.1
    cube.rotation.y += 0.1
    renderer.render(scene, camera)
    requestAnimationFrame(render)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

操作流程

  1. 模型操作:

    生成几何体 => 生成材质 => 混合生成模型
    商城模型 => 添加到场景中

  2. 场景操作

    生成场景(配置参数…) => 模型导入场景

  3. 相机操作

    生成相机 = > 添加控制器(控制相机)

  4. 渲染器操作

    生成渲染器 => 场景和相机添加到渲染器中 => 建立和canvas 关联

  5. 更新模块(动画模块)

    动画的连续 ,相机 ,场景的更新控制

案例演示 :创建一个简单的立方体

three.js 里面的颜色是 new THREE.Color()

简单的控制相机

//真是世界的相机 : 近大远小
const camera = new THREE.PerspectiveCamera(75, width / height, 0.01, 1000);
//摆放向机的位置 相机的朝向
camera.position.z = 6;camera.lookAt(0, 0, 0);

//简单的控制相机
const control = new THREE.OrbitControls(camera);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

创建好后在动画渲染里面更新控制器

//更新控制器
control.update();
  • 1
  • 2

案例演示: 简单的控制相机

常见的几何体 Geometry

生成一个辅助网格体
就是带有辅助线的立方体
THREE.WireframeGeometry

THREE.BoxGeometry : 立体矩形

​ 构造函数: 前面三个参数(x, y, z)默认1
​ 后面还有三个参数(每个面的分段)

THREE.CircleGeometry : 圆

//创建圆形  CircleGeometry: 半径 分段 第一个分段的起始角度 旋转角度/弧度
//分段越多越像圆
const geometry = new THREE.CircleGeometry(3,30,Math.PI * 2)
  • 1
  • 2
  • 3

THREE.CylinderGeometry : 圆柱

//创建圆柱  CylinderGeometry : 顶部半径  底部半径  高
const geometry = new THREE.CylinderGeometry(2,2,5);
  • 1
  • 2

THREE.ConeGeometry : 圆锥

//圆锥 ConeGeometry : 底面半径 高
const geometry = new THREE.ConeGeometry(2,5);
  • 1
  • 2

THREE.DodecahedronGeometry :十二面几何体(球)

//十二面几何体 DodecahedronGeometry :半径 第二个参数越大越接近球
const geometry = new THREE.DodecahedronGeometry(2,2);
  • 1
  • 2

PlaneGeometry 平面几何体 (重要)生成底面

//平面几何体 生成底面 PlaneGeometry : 宽 高 宽分段 高分段
const geometry = new THREE.PlaneGeometry(10,10,30,30);
  • 1
  • 2

RingGeometry 平面圆环几何体

//圆环几何体 RingGeometry : 内部半径 外部半径 圆的分段数越大越圆  圆环表面的分段数
const geometry = new THREE.RingGeometry(2,5,20,8);
  • 1
  • 2

TorusGeometry :圆环几何体

//圆环几何体 TorusGeometry : 圆环的半径  管道的半径 圆环的分段 管道的分段越多越圆
const geometry = new THREE.TorusGeometry( 4,1,10,20 );
  • 1
  • 2

案例演示: 常见的几何体

自定义几何体

  1. 必须要有端点(定义制作)
  2. 必须要有面(三点形成一个面 手动添加面的关联)

建立一个坐标系 AxesHelper

//建立一个简单的坐标系 坐标系的长度
const axesHelper = new THREE.AxesHelper(5);
scene.add( axesHelper );
  • 1
  • 2
  • 3

创建自定义

描述一个点 THREE.Vector3()
描述一个面 THREE.Faces()

//生成Geometry的实例
const geometry = new THREE.Geometry();
//添加点
geometry.vertices.push(new THREE.Vector3(1,0,0));
geometry.vertices.push(new THREE.Vector3(0,1,0));
geometry.vertices.push(new THREE.Vector3(0,0,1));
//根据这些点确定一个面
geometry.faces.push(new THREE.Face3(0,1,2, normal, color));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

创建点可以写坐标 也可以写极坐标
Vector3().applyEuler 参数里面要生成一个欧拉角 Euler

geometry.vertices.push(new THREE.Vector3(5,0,0).applyEuler(new THREE.Euler(0,0,1,'XYZ')));//参数 前三个是根据多少值 旋转 对应 XYZ
  • 1

案例演示: 自定义几何体

几何体组合

Object3D 实例对象内部可以存放多个mesh ,每个mesh都是独立控制的

THREE.Object3D

let obj = new THREE.Object3D();
//模型对象添加子模型
obj.add(mesh1);
obj.add(mesh2);
//模型对象添加到场景中
scene.add(obj);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

案例演示 :小案例

线条

LineBasicMaterial() 基础线条

/生成Geometry的实例
const geometry = new THREE.Geometry();

//添加关键点
geometry.vertices.push(new THREE.Vector3(1,1,1));
geometry.vertices.push(new THREE.Vector3(3,3,3));
//将线条按顺序连接起来
const material = new THREE.LineBasicMaterial();
new THREE.Line(geometry,material)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

线条渐变色

//生成Geometry的实例
const geometry = new THREE.Geometry();
//添加关键点
geometry.vertices.push(new THREE.Vector3(1,1,1));
geometry.vertices.push(new THREE.Vector3(3,3,3));
geometry.vertices.push(new THREE.Vector3(5,3,2));
geometry.colors.push(
    new THREE.Color(0xff0000),
    new THREE.Color(0x0000ff)
)
//线条是被点来进行染色的
const material = new THREE.LineBasicMaterial({  vertexColors:true});
new THREE.Line(geometry,material)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

案例演示: 线的绘画

材质

法线网格材质(初学) MeshNormalMaterial

物体内部有光

const material = new THREE.MeshNormalMaterial({  
    //内部也有光  
    side:THREE.DoubleSide
});
  • 1
  • 2
  • 3
  • 4

基础网格材质 MeshBasicMaterial

一个以简单着色(平面或线框)方式来绘制几何体的材质。
基础材质可以进行贴图

new THREE.MeshNormalMaterial({side:THREE.DoubleSide})
//wireframe 显示线条
const material = new THREE.MeshNormalMaterial({
    side:THREE.DoubleSide,
    wireframe:true
})
const geometry = new THREE.BoxGeometry( 2, 2, 2, 2, 2, 2);

const mesh = new THREE.Mesh( geometry, material );

mesh.position.x = index * 3 - meshList.length;
scene.add(mesh);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

可以载入纹理

Lambert网格材质MeshLambertMaterial

一种非光泽表面的材质,没有镜面高光。

new THREE.MeshLambertMaterial({map:texture})
//flatShading 每一个面接受光照
new THREE.MeshLambertMaterial({map:texture,flatShading:true})
  • 1
  • 2
  • 3

Phong网格材质 MeshPhongMaterial

具有镜面高光的光泽表面的材质

new THREE.MeshPhongMaterial({flatShading:true,envMap:scene.background})
//envMap 环境贴图
  • 1
  • 2

卡通网格材质 MeshToonMaterial

new THREE.MeshToonMaterial({map:texture,side:THREE.DoubleSide})
  • 1

案例演示: 材质

纹理和材质

纹理 : 本质是一张图片或者Canvas ,或视频
材质: 包含了贴图的纹理 ,相当于实际物体的质感, 物体在场景中的表现

纹理(texture)

需要引入贴图 , 加载纹理贴图到物体表面, 或者是作为镜面反射或折射的贴图

简单的纹理引入 : TextureLoader
//引入纹理
//创建纹理引入工具
const loader = new THREE.TextureLoader();
const texture = loader.load("图片地址");
//材质
const material = new THREE.MeshBasicMaterial({
    map:texture,
    side:THREE.DoubleSide
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

例如下面这个案例
案例演示 : 几何体的纹理

盒子世界纹理引入 CubeTextureLoader
const loader = new THREE.CubeTextureLoader();
//场景引入
scene.background = loader.setPath( '../lib/textures/cube/Park3Med/' )    
    .load( [
    'px.jpg','nx.jpg',      
    'py.jpg','ny.jpg',      
    'pz.jpg','nz.jpg'
] );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

例如下面这个案例
案例演示 : 世界纹理

相机

PerspectiveCamera 透视相机(近大远小)

//透视相机 近大远小 :垂直视野角度  锥体长宽比  物体近端面 物体远端面
const camera = new THREE.PerspectiveCamera(75, width / height, 0.01, 1000);//摆放向机的位置 相机的朝向
camera.position.z = 10;
//看向哪里
camera.lookAt(0, 0, 0);
  • 1
  • 2
  • 3
  • 4
  • 5

OrthographicCamera 正交相机

光源

环境光 AmbientLight

没有一个固定光源的时候, 周围的物体会根据环境折射光线
不能投射阴影

//环境光的颜色  光照强度
const ambientLight = new THREE.AmbientLight( 0xffffff, 0.3 );
scene.add( ambientLight );
  • 1
  • 2
  • 3

点光源 PointLight

固定光源

//十六进制光照颜色  光照强度  从光源到光照强度为0的位置
const light2 = new THREE.PointLight( 0xffffff, 1, 1000 );
//设置位置
light2.position.set( 0, 8, 8 );
scene.add( light2 );
  • 1
  • 2
  • 3
  • 4
  • 5

点光源辅助线THREE.PointLightHelper

平行光 DirectionalLight

模拟太阳

//两个参数 光的颜色及其光照强度
const directionalLight = new THREE.DirectionalLight( 0xffffff, 0.5 );
scene.add( directionalLight );
  • 1
  • 2
  • 3

DirectionalLightHelper 平行光的辅助线

半球光 HemisphereLight

模拟日出日落
不能投射阴影

const hemisphereLight = new THREE.HemisphereLight( 0xffffff, 0x000000, 1 );
scene.add( hemisphereLight );
  • 1
  • 2

聚光灯 SpotLight

//灯光的颜色
const spotLight = new THREE.SpotLight( 0xffffff );
spotLight.position.set( 0, 10, 0 );
//聚光灯的弧度大小
spotLight.angle = Math.PI/6;
scene.add( spotLight );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

平面光光源 RectAreaLight

从一个矩形平面上均匀地发射光线
不支持阴影

//颜色  强度 宽度 高度
const rectLight = new THREE.RectAreaLight( 0xffffff, 1,  10, 10 );
rectLight.position.set( 5, 5, 0 );
rectLight.lookAt( 0, 0, 0 );
scene.add( rectLight );
  • 1
  • 2
  • 3
  • 4
  • 5

阴影

特殊的光源 比如 点光源 聚光灯
必须有 产生阴影的物体
必须要有 显示(接收)阴影的物体

  1. 灯光照射产生阴影

    const spotLight = new THREE.SpotLight( 0xffffff );//聚光灯
    spotLight.position.set( 0, 10, 0 );
    spotLight.angle = Math.PI/6;
    this.spot.castShadow = true;//照射产生阴影
    scene.add( spotLight );
    
    • 1
    • 2
    • 3
    • 4
    • 5
  2. 物体要产生阴影

    const geometry =new THREE.BoxGeometry(3, 3, 3);
    const material = new THREE.MeshLambertMaterial({
        color:new THREE.Color(0xffffff),
        side:THREE.DoubleSide,
        map:new THREE.TextureLoader().load('图片地址')
    });
    const mesh = new THREE.Mesh(geometry,material);
    scene.add(mesh);
    //物体产生阴影
    mesh.castShadow = true;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  3. 底面接收阴影

    const geometry = new THREE.PlaneGeometry(100,100,10,10);
    const material = new THREE.MeshPhongMaterial({
        color: 0xeeeeee,
        side: THREE.DoubleSide
    });
    const mesh = new THREE.Mesh(geometry,material);
    //旋转90度
    mesh.rotateX(- Math.PI / 2);
    mesh.position.set(0, -5 ,0);
    scene.add(mesh);
    //接收阴影
    mesh.receiveShadow = true;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  4. 产生阴影要开启阴影模式

    renderer.shadowMap.enabled = true;
    
    • 1

模型加载

加载方式是一个异步加载: 使用回调函数添加到场景当中

GLTFLoader 加载器

const loader = new THREE.GLTFLoader()//获取加载器的实例方法
//path/to/sourse 资源的加载地址
loader.load("path/to/sourse",res=>{
    //res 是加载的资源
    //res.scene是模型的场景
    scene.add(res.scene)
    //res的材质十多个面
    //数组遍历每一个面设置不同的反光效果
    //res.scene.traverse 相当于 res.scene是一个数组, 遍历数组的每一个面设置不同的反光
    res.scene.traverse(mesh=>{
        if (mesh.isMesh){
            //观看模型的内部
            mesh.material.side = THREE.BackSide
            //背景对所有的面进行一一映射
            mesh.material.envMap = scene.background;
        }
    })
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

MMDLoader 加载器

const loader = new THREE.MMDLoader();

loader.load('pmd后缀的文件',mesh=>{
    //调整位置
    mesh.position.set(0,-10,0)
    scene.add(mesh);
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

MMD 动画效果

需要引入AMMO 物理引擎
MMDAnimationHelper 动画效果

//需要一个pmd后缀文件和vmd后缀文件
const helper = new THREE.MMDAnimationHelper();
const loader = new THREE.MMDLoader();
loader.loadWithAnimation(
    'pmd后缀文件',
    'vmd后缀文件',
    mmd => {
        helper.add(mmd.mesh, {
            animation: mmd.animation,
            physics: true
        });
        scene.add( mmd.mesh );
    }
)
//在动画渲染的地方写上
//动画实时渲染
const clock = new THREE.Clock();
helper.update(clock.getDelta());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

镜面效果Reflector

import {Reflector} from "three/examples/jsm/objects/Reflector";
const geometry = new THREE.PlaneGeometry(10,10);
//设置镜子材质
const mirrorMesh = new Reflector(geometry,{
    color:new THREE.Color(0x7f7f7f)//镜子的颜色
});
//设置位置
mirrorMesh.position.set(0,0,-5);
//镜子的朝向
mirrorMesh.lookAt(0,0,0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

控制器

拖拽控制 OrbitControls

//传入相机和控制的标签
let control = new OrbitControls(camera,renderer.domElement);
control.enabled = true//禁止事件
//在动画里渲染
control.update();
  • 1
  • 2
  • 3
  • 4
  • 5

进阶拖拽控制器 TrackballControls

let control = new TrackballControls(camera,renderer.domElement);
control.noPan = true//禁止平移
control.noZoom = true//是否允许放大
control.noRotate = true//禁止拖拽
control.rotateSpeed = 5//拖拽的速度
control.zoomSpeed = 5//滚轮的速度
control.panSpeed = 5//平移的速度
//在动画里渲染
control.update();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

飞行控制器 FlyControls

let control = new FlyControls(camera,renderer.domElement);
control.movementSpeed = 10;//移动的速度
control.rollSpeed = 3;//平移旋转速度
control.autoForward = true;//自动飞行
control.dragToLook = true;//拖拽调整方向
//在动画里渲染 需要传入一个时间的参数
const clock = new THREE.Clock()
control.update(clock.getDelta());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

第一人称控制器FirstPersonControls

let control = new FirstPersonControls(camera,renderer.domElement);
control.lookSpeed = 0.15//鼠标移动速度 默认值 0.001
control.movementSpeed = 10//移动速度 默认值 1
//在动画里渲染 需要传入一个时间的参数
const clock = new THREE.Clock()
control.update(clock.getDelta());
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

锁定鼠标控制器 PointerLockControls

3D游戏的最佳选择

let control = new PointerLockControls(camera,renderer.domElement);
//需要锁定指针 
canvas.addEventListener("click",()=>{
    control.lock()
})
//监听lock事件
controls.addEventListener( 'lock',  ()=> {
	//锁定指针
} );

controls.addEventListener( 'unlock',  ()=> {
	//没有锁定指针
} );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/代码探险家/article/detail/993474
推荐阅读
相关标签
  

闽ICP备14008679号