전주곡:
먼저 공식 문서와 사례 라이브러리 주소를 첨부하세요.
파노라마 절단 도구: HDRI에서 CubeMap으로
전제 지식:
Three.js는 3D 그래픽을 생성하고 렌더링하기 위한 JavaScript 라이브러리입니다. WebGL 기술을 기반으로 합니다.
three.js에는 three.module.min.js, three.module.js, three.min.js, three.js라는 네 가지 참조 리소스가 있습니다. 차이점은 다음과 같습니다.
three.module.min.js
프로덕션 환경을 위해 최소화되고 모듈화된 버전입니다.three.module.js
개발 환경에서 사용하기 위한 모듈식이지만 압축되지 않은 버전입니다.three.min.js
모듈화되지 않은 압축된 이전 버전으로, ES 모듈을 지원하지 않는 이전 프로젝트나 환경에 적합합니다.three.js
이전 버전의 압축되지 않은 간단한 버전입니다.
먼저 3D 자동 회전 형상을 구현합니다.
- BootCDN에서 three.module.js를 다운로드하세요.
- 공식 문서에 따라 다음 코드를 작성합니다.
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<script type="module">
// script标签中加入type="module" 浏览器将把该脚本作为 ES6 模块来处理
// 通过es6的方式导入THREE
import * as THREE from './three.module.js';
// 创建场景
const scene = new THREE.Scene();
// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 相机的位置
camera.position.z = 5;
// 渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 添加立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
// 创建材质
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
// 创建物体
const cube = new THREE.Mesh(geometry, material);
// 将物体添加到场景中
scene.add(cube);
// 动画循环又叫渲染循环
function animate() {
requestAnimationFrame(animate);
// 使立方体动起来
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
// 渲染场景和相机
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
효과는 다음과 같습니다.
3D 자동 회전 형상을 마우스 회전 가능으로 변경
OrbitControl이 필요합니다.
- 먼저 Three 리소스 라이브러리를 다운로드하세요.
- 그런 다음 three/examples/jsm/controls/OrbitControls 경로에 따라 OrbitControls.js를 가져옵니다.
- 코딩 수정 시작
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<!-- 在 HTML 中使用 JavaScript 模块的新特性,被称为 Import Maps(导入映射) -->
<!-- 当浏览器加载该 three 文件时,它会根据导入映射的规则来解析 JavaScript 中的模块导入语句 -->
<script type="importmap">
{
"imports": {
"three": "./three.module.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from './OrbitControls.js'
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry(1, 1, 1);
const colors = [
{ color: 0xff0000 },
{ color: 0x00ff00 },
{ color: 0x0000ff },
{ color: 0xff00ff },
{ color: 0xffff00 },
{ color: 0x00ffff }
]
const material = []
// 将6个面涂上不同的颜色
for (let i = 0, len = colors.length; i < len; i++) {
material.push(new THREE.MeshBasicMaterial(colors[i]))
}
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
// renderer.domElement 表示 Three.js 渲染器(renderer)所输出的 HTML 元素,通常是一个 <canvas> 元素
const container = renderer.domElement
// 创建了一个 OrbitControls 对象 OrbitControls 类会基于鼠标和触摸手势来控制相机在场景中的移动、旋转和缩放
const controls = new OrbitControls(camera, container)
// 启用了阻尼效果,使得相机在停止操作之后会自动减速停止
controls.enableDamping = true
// 设置了相机可以向外拉近或向内推离目标物体的最大距离。超过这个距离,相机将无法再拉近或推离
controls.maxDistance = 2
// 渲染
const render = () => {
renderer.render(scene, camera)
requestAnimationFrame(render)
}
render()
</script>
</body>
</html>
- 효과는 그림과 같습니다.
집의 전경
내가 이해한 바에 따르면, 현재 파노라마 집 보기 효과를 얻기 위해 일반적으로 사용되는 두 가지 방법, 즉 스카이박스 와 파노라마 사진 지도가 있습니다 .
스카이박스
이 방법이 가장 이해하기 쉬우며, 우리가 있는 장면에서는 상하, 앞과 뒤, 왼쪽과 오른쪽의 6개 변밖에 없습니다. 이 6개 얼굴의 비전을 사진으로 처리하면 다음과 같이 서로 다른 방향의 6개의 비전 사진이 생성됩니다.
- 먼저 큐브의 6개 면에 시각적 그림 6개를 붙여 공간을 만듭니다.
- 그런 다음 비전을 큐브 중앙으로 이동하고 지도를 안쪽으로 뒤집어 집의 전경을 확인하세요.
최종 렌더링:
전체 코드는 다음과 같습니다.
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "./three.module.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from './OrbitControls.js'
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 5;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 添加立方体 参数分别是立方体的宽度、高度和深度
const geometry = new THREE.BoxGeometry(10, 10, 10)
// 左右、上下、后前
const urls = [
'https://cdn.huodao.hk/upload_img/20220620/3e532822bd445485d27677ca55a79b10.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/cebf6fbcafdf4f5c945e0881418e34ec.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/273081d1896fc66866842543090916d3.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/8747f61fd2215aa748dd2afb6dce3822.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/c34262935511d61b2e9f456b689f5c1c.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/722d2bf88f6087800ddf116511b51e73.jpg?proportion=1'
]
const boxMaterial = []
urls.forEach((item, index) => {
// 纹理加载
const texture = new THREE.TextureLoader().load(item)
// 通过旋转修复天花板和地板
if (index == 2 || index == 3) {
texture.rotation = Math.PI
texture.center = new THREE.Vector2(0.5, 0.5)
}
// 创建材质
boxMaterial.push(new THREE.MeshBasicMaterial({ map: texture }))
})
// 创建一个三维物体
const house = new THREE.Mesh(geometry, boxMaterial)
house.geometry.scale(1, 1, -1)
scene.add(house)
const container = renderer.domElement
const controls = new OrbitControls(camera, container)
controls.enableDamping = true
controls.maxDistance = 2
// 渲染
const render = () => {
renderer.render(scene, camera)
requestAnimationFrame(render)
}
render()
</script>
</body>
</html>
파노라마 지도
저는 파노라마 매핑이 가장 간단하고 효과적인 방법이라고 생각합니다. 글을 쓰기 전에 파노라마 사진이 필요하며, SLR의 파노라마 모드를 사용하여 다음과 같이 사진을 찍을 수 있습니다.
- 구를 추가합니다. 그리고 파노라마를 텍스처로 구에 붙여넣으면 다음과 같은 효과가 나타납니다.
- 마찬가지로 비전을 공 안에 넣고 텍스처를 반전시킵니다.
최종 효과는 위와 같습니다.
전체 코드:
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body {
margin: 0;
}
</style>
</head>
<body>
<script type="importmap">
{
"imports": {
"three": "./three.module.js"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from './OrbitControls.js'
const scene = new THREE.Scene();
const defaultMap = {
x: 20,
y: 20,
z: 20,
}
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const { x, y, z } = defaultMap
camera.position.set(x, y, z)
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// 添加立方体 参数分别是立方体的宽度、高度和深度
let geometry = new THREE.SphereGeometry(16, 50, 50)
let texture = new THREE.TextureLoader().load("./assets/quanjing.webp");
let sphereMaterial = new THREE.MeshBasicMaterial({ map: texture });
const house = new THREE.Mesh(geometry, sphereMaterial);
house.geometry.scale(16, 16, -16);
scene.add(house)
const container = renderer.domElement
const controls = new OrbitControls(camera, container)
controls.enableDamping = true
controls.maxDistance = 1000
// 渲染
const render = () => {
renderer.render(scene, camera)
requestAnimationFrame(render)
}
render()
</script>
</body>
</html>
확장된 기록
다음 코드는 장면 배경에 텍스처를 할당하고 여러 개의 개별 그림을 회전하고 조정하는 방법을 지정합니다.
function sceneBackground() {
scene = new THREE.Scene();
var urls = [
'https://cdn.huodao.hk/upload_img/20220620/3e532822bd445485d27677ca55a79b10.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/cebf6fbcafdf4f5c945e0881418e34ec.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/273081d1896fc66866842543090916d3.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/8747f61fd2215aa748dd2afb6dce3822.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/c34262935511d61b2e9f456b689f5c1c.jpg?proportion=1',
'https://cdn.huodao.hk/upload_img/20220620/722d2bf88f6087800ddf116511b51e73.jpg?proportion=1'
];
var cubeTextureLoader = new THREE.CubeTextureLoader();
var textureCube = cubeTextureLoader.load(urls, function (texture) {
// 确定要旋转的面索引,例如右侧面为第 0 个面(索引从 0 开始)
var faceIndex = [2, 3];
for (let i = 0; i < faceIndex.length; i++) {
// 获取指定面的纹理
var faceTexture = texture.image[faceIndex[i]];
// 创建一个 canvas 元素用于绘制纹理
var canvas = document.createElement("canvas");
canvas.width = faceTexture.width;
canvas.height = faceTexture.height;
var ctx = canvas.getContext("2d");
// 在 canvas 上进行旋转操作
ctx.translate(canvas.width / 2, canvas.height / 2);
ctx.rotate(Math.PI); // 旋转 90 度
ctx.drawImage(faceTexture, -canvas.width / 2, -canvas.height / 2);
// 将修改后的 canvas 赋值给纹理对象的指定面
texture.image[faceIndex[i]] = canvas;
texture.needsUpdate = true;
}
// 将纹理赋给场景背景
scene.background = texture;
});
// scene.fog = new THREE.Fog(0xa0a0a0, 200, 1000); //雾
}
new THREE.TextureLoader().load()와 new THREE.CubeTextureLoader().load()의 기능 및 차이점
THREE.TextureLoader().load()
지도, 사진, 기타 평면 이미지와 같은 일반적인 2D 텍스처 이미지를 로드하는 데 사용되는 방법입니다.
THREE.CubeTextureLoader().load()
환경 맵이라고도 하는 큐브 맵을 로드하는 데 메서드가 사용됩니다. 큐브맵은 6개의 텍스처 이미지로 구성된 맵으로, 각 이미지는 3차원 공간의 면을 나타냅니다.