效果展示:
实现思路
利用定位,实现图片的三维分层展示 mesh.position.set(0, 0, i); 加上三维场景的处理实现一些二维图片三维位置展示的效果
1.html部分
<template>
<div>
<div class="import_model"></div>
</div>
</template>
2.js部分
2.1 引入和方法封装
<script setup>
import { reactive, ref, nextTick, onMounted, watch, onUnmounted } from "vue";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
// 引入图片;
import layer_0 from "@/assets/images/comic/layer_0.png";
import layer_1 from "@/assets/images/comic/layer_1.png";
import layer_2 from "@/assets/images/comic/layer_2.png";
import layer_3 from "@/assets/images/comic/layer_3.png";
import layer_4 from "@/assets/images/comic/layer_4.png";
import layer_5 from "@/assets/images/comic/layer_5.png";
import layer_6 from "@/assets/images/comic/layer_6.png";
import layer_7 from "@/assets/images/comic/layer_7.png";
import background from "@/assets/images/comic/background.png";
import boomImage from "@/assets/images/comic/boom.png";
let scene, light, mesh, camera, renderer, axesHelper, grid, controls;
var width = window.innerWidth; //窗口宽度
var height = window.innerHeight; //窗口高度
const publicPath = process.env.BASE_URL;
let container,
step = 0,
animateLayer = null,
layerGroup = new THREE.Group();
var layers = [
layer_0,
layer_1,
layer_2,
layer_3,
layer_4,
layer_5,
layer_6,
layer_7,
];
// 加载材质
let textureLoader = new THREE.TextureLoader();
onMounted(() => {
init();
});
// 初始化
function init() {
// 创建场景
createScene();
// 创建光源
createLight();
// 创建相机
createCamera(width, height);
// 设置背景
createBackground();
// 创建渲染器
createRender();
// 创建控制器
createControls();
// createGrid();
// 辅助坐标系
createAxesHelper();
createGroundMain();
// 创建boom背景
createBoom();
// 渲染
render();
}
</script>
2.2 具体方法
创建场景
function createScene() {
//创建一个三维场景
scene = new THREE.Scene();
}
创建光源
function createLight() {
var point = new THREE.PointLight(0xffffff);
point.position.set(400, 200, 300); //点光源位置
scene.add(point); //点光源添加到场景中
//环境光
// var ambient = new THREE.AmbientLight(0x444444);
var ambient = new THREE.AmbientLight("#ffffff", 1);
scene.add(ambient);
}
创建相机
function createCamera(width, height) {
var k = width / height; //窗口宽高比
var s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
//创建相机对象
// 正交相机
camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
// 透视相机(此处需要全景和透视)
camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
20000
);
// camera.position.set(30, 30, 30); //设置相机位置
// 旋转照相机的角度可以旋转轴
camera.position.set(0, 0, 50); //设置相机位置
camera.lookAt(scene.position); //设置相机方向(指向的场景对象)
// camera.lookAt(new THREE.Vector3(0, 0, 0));
}
创建背景
function createBackground() {
const loader = new THREE.TextureLoader();
const bgTexture = loader.load(background);
scene.background = bgTexture;
}
创建渲染器
function createRender() {
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(width, height); //设置渲染区域尺寸
// renderer.setClearColor(0xffffff, 1); //设置背景颜色
renderer.setPixelRatio(window.devicePixelRatio);
// renderer.outputEncoding = THREE.sRGBEncoding; // 模型颜色偏差
renderer.shadowMap.enabled = true; //开启渲染气阴影效果。
nextTick(() => {
container = document.querySelector(".import_model");
container.appendChild(renderer.domElement);
});
}
创建控制器
function createControls() {
//创建控件对象 相机对象camera作为参数 控件可以监听鼠标的变化,改变相机对象的属性
controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.enableDamping = true;
controls.enablePan = false;
controls.enableZoom = false;
// 控制旋转角度
// 垂直旋转角度限制
// controls.minPolarAngle = 1.2;
// controls.maxPolarAngle = 1.8;
// // 水平旋转角度限制
// controls.minAzimuthAngle = -0.6;
// controls.maxAzimuthAngle = 0.6;
//监听鼠标事件,触发渲染函数,更新canvas画布渲染效果
controls.addEventListener("change", () => {
renderer.render(scene, camera);
});
}
辅助坐标系
function createAxesHelper() {
axesHelper = new THREE.AxesHelper(250);
scene.add(axesHelper);
}
搭建基本场景完成,以下都是场景内容
function createGroundMain() {
/* 首先创建一个 Group,用于添加图层网格,
然后遍历图层背景图片数组,在循环体中创建每个面的网格,
该网格使用平面立方体 PlaneGeometry,
材质使用物理材质 MeshPhysicalMaterial,
对每个网格位置设置相同的x轴和y轴值和不同的z轴值以创建景深效果。
最后将 Group 添加到场景 Scene 中。 */
let aspect = 18;
for (let i = 0; i < layers.length; i++) {
let mesh = new THREE.Mesh(
new THREE.PlaneGeometry(10.41, 16),
new THREE.MeshPhysicalMaterial({
map: new THREE.TextureLoader().load(layers[i]),
transparent: true,
side: THREE.DoubleSide,
})
);
mesh.position.set(0, 0, i);
mesh.scale.set(1 - i / aspect, 1 - i / aspect, 1 - i / aspect);
layerGroup.add(mesh);
//
if (i == 5) {
mesh.material.metalness = 0.6;
// 字的颜色
mesh.material.emissive = new THREE.Color("red");
mesh.material.emissiveIntensity = 1.6;
mesh.material.opacity = 0.9;
}
// 会话框
if (i === 6) {
mesh.scale.set(1.5, 1.5, 1.5);
animateLayer = mesh;
}
}
layerGroup.scale.set(2, 2, 2);
scene.add(layerGroup);
}
创建boom
function createBoom() {
const boom = new THREE.Mesh(
new THREE.PlaneGeometry(36.76, 27.05),
new THREE.MeshPhongMaterial({
map: new THREE.TextureLoader().load(boomImage),
transparent: true,
shininess: 160,
specular: new THREE.Color(0xff6d00),
opacity: 0.7,
})
);
boom.scale.set(0.8, 0.8, 0.8);
boom.position.set(0, 0, -3);
layerGroup.add(boom);
scene.add(layerGroup);
}
创建boom动画,此方法在render方法中加载
function boxAnimation() {
step += 0.01;
animateLayer.position.x = 2.4 + Math.cos(step);
animateLayer.position.y = 0.4 + Math.abs(Math.sin(step));
}