THREEJS-甜甜圈的掉落| 大帅老猿threejs特训

153 阅读5分钟

渲染第一个物体及场景

1、基本概念

三维的物体要渲染在二维的屏幕上。首先要创建一个场景来放置物体,那么最终怎么显示三维的内容,就应该找一个相机,将相机放在场景的某个位置,然后想要显示就要把相机拍的内容渲染出来。所以就引出三个基本概念:场景、相机、渲染器。

1.1 场景

const scene = new THREE.Scene();

1.2 相机

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10);

three.js里有几种不同的相机,在这里,我们使用的是PerspectiveCamera(透视摄像机)。 第一个参数是视野角度(FOV)。视野角度就是无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。 第二个参数是长宽比(aspect ratio)。 也就是你用一个物体的宽除以它的高的值。比如说,当你在一个宽屏电视上播放老电影时,可以看到图像仿佛是被压扁的。 接下来的两个参数是近截面(near)和远截面(far)。 当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中。或许现在你不用担心这个值的影响,但未来为了获得更好的渲染性能,你将可以在你的应用程序里去设置它。 下图椎体就是上面设置视野角度、长宽比、近截面和远截面的演示的相机透视椎体。

1.3 渲染器

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();
// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);
// console.log(renderer);
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement);

// 使用渲染器,通过相机将场景渲染进来
renderer.render(scene, camera);

除了创建一个渲染器的实例之外,我们还需要在我们的应用程序里设置一个渲染器的尺寸。比如说,我们可以使用所需要的渲染区域的宽高,来让渲染器渲染出的场景填充满我们的应用程序。因此,我们可以将渲染器宽高设置为浏览器窗口宽高。对于性能比较敏感的应用程序来说,你可以使用setSize传入一个较小的值,例如window.innerWidth/2和window.innerHeight/2,这将使得应用程序在渲染时,以一半的长宽尺寸渲染场景。 接下来将renderer(渲染器)的dom元素(renderer.domElement)添加到我们的HTML文档中。渲染器用来显示场景给我们看的canvas元素。 最后就是对将相机对场景进行拍照渲染啦。这一句就可以将画面渲染到canvas上显示出来。

renderer.render(scene, camera);

1.4 加入立方体

要创建一个立方体,我们需要一个BoxGeometry(立方体)对象. 这个对象包含了一个立方体中所有的顶点(vertices)和面(faces)。 接下来,对于这个立方体,我们需要给它一个材质,来让它有颜色。这里我们使用的是MeshBasicMaterial。所有的材质都存有应用于他们的属性的对象。为了简单起见,我们只设置一个color属性,值为0x00ff00,也就是绿色。这里和CSS或者Photoshop中使用十六进制(hex colors)颜色格式来设置颜色的方式一致。 第三步,我们需要一个Mesh(网格)。 网格包含一个几何体以及作用在此几何体上的材质,我们可以直接将网格对象放入到我们的场景中,并让它在场景中自由移动。 默认情况下,当我们调用scene.add()的时候,物体将会被添加到(0,0,0)坐标。但将使得摄像机和立方体彼此在一起。为了防止这种情况的发生,我们只需要将摄像机稍微向外移动一些即可。

// 添加物体
// 创建几何体
const cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
const cubeMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 });
// 根据几何体和材质创建物体
const cube = new THREE.Mesh(cubeGeometry, cubeMaterial);
// 将几何体添加到场景中
scene.add(cube);

2综合上述代码

2.1 在index.html中引入以下js代码:

import * as THREE from "three";

// console.log(THREE);

// 目标:了解three.js最基本的内容

// 1、创建场景
const scene = new THREE.Scene();

// 2、创建相机
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: 0xffff00 });

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

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

// 初始化渲染器
const renderer = new THREE.WebGLRenderer();

// 设置渲染的尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);

// console.log(renderer);
// 将webgl渲染的canvas内容添加到body
document.body.appendChild(renderer.domElement);

// 使用渲染器,通过相机将场景渲染进来
renderer.render(scene, camera);

2.1效果如下图

three1.png

渲染第二个物体及场景(甜甜圈)

场景、相机、渲染器在上面已经描述过,在这就不赘述了。

1.1加载gltf/glb模型:GLTFLoader

new GLTFLoader().load('../resources/models/donuts.glb',(gltf) => {
    scene.add(gltf.scene);

})

1.2加载环境光HDR图片:RGBELoader

new RGBELoader()
    .load('../resources/sky.hdr', function (texture) {
        scene.background = texture
        texture.mapping = THREE.EquirectangularReflectionMapping;
        scene.environment = texture;
        renderer.outputEncoding = THREE.sRGBEncoding;
        renderer.render(scene, camera)
    })

1.3综合上述代码

import * as THREE from 'three';
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';

let mixes;
//创建场景
const scene = new THREE.Scene();
//相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10);

//渲染器
const renderer = new THREE.WebGLRenderer({ antialias: true });
// 渲染器尺寸
renderer.setSize(window.innerWidth, window.innerHeight);
//渲染器添加到页面尚 
document.body.appendChild(renderer.domElement);
// 设置相机的位置
camera.position.set(0.3, 0.3, 0.5)

// 添加控制器可以用鼠标控制物体
const controls = new OrbitControls(camera, renderer.domElement)

// 创建平行光源,平行光是沿着特定方向发射的光。这种光的表现像是无限远,从它发出的光线都是平行的。常常用平行光来模拟太阳光 的效果; 太阳足够远,因此我们可以认为太阳的位置是无限远,所以我们认为从太阳发出的光线也都是平行的。
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.6)
// 把平行光添加到场景中
scene.add(directionalLight)

// 加载甜甜圈模型
let donuts;
new GLTFLoader().load('../resources/models/donuts.glb', (gltf) => {
    scene.add(gltf.scene)
    donuts = gltf.scene
    mixes = new THREE.AnimationMixer(gltf.scene);
    const clips = gltf.animations;
    clips.forEach(function (clip) {

        const action = mixes.clipAction(clip);
        action.loop = THREE.LoopRepeat;
        // 播放动画
        action.play();
        // 停在最后一帧
        action.clampWhenFinished = false;
    })
})


// 加载纹理
new RGBELoader()
    .load('../resources/sky.hdr', function (texture) {
        scene.background = texture
        texture.mapping = THREE.EquirectangularReflectionMapping;
        scene.environment = texture;
        renderer.outputEncoding = THREE.sRGBEncoding;
        renderer.render(scene, camera)
    })
// 播放动画方法
function animate() {
    requestAnimationFrame(animate)

    renderer.render(scene, camera)
    if (donuts) {
        donuts.rotation.y += 0.01
    }
    if (mixes) {
        mixes.update(0.02)
    }
}
animate()

1.4效果如下图

20221229_143258 00_00_00-00_00_30.gif

加入猿创营 (v:dashuailaoyuan),一起交流学习。