活动地址:毕业季·进击的技术er
前言
岁月匆匆,又是一年毕业季,这次做个动态相册展示图片,放些有意思的内容,一起回忆下校园生活吧。
相册展示和点选切换,利用相机旋转和移动来实现一个点击切图平滑过渡的效果。
1、搭建场景
2、放置图片
3、鼠标事件
4、相机运动
工程文件结构如下图:
static:存放静态资源文件
three.js-master:为官网下载的代码包,包含所有需要用到的资源包,链接:https://github.com/mrdoob/three.js/archive/master.zip
index.html:页面代码
<!DOCTYPE html>
<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.js-master/build/three.module.js"
}
}
</script>
<script type="module">
// 下文JS代码位置
// ...
</script>
</body>
</html>
需要导入的内容和提前声明的变量,包含后续不同function中可能用到的场景、相机、渲染器、控制器等要素。
import * as THREE from "three";
import { OrbitControls } from "./three.js-master/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "./three.js-master/examples/jsm/loaders/GLTFLoader.js";
import { TWEEN } from "./three.js-master/examples/jsm/libs/tween.module.min.js";
let scene, camera, renderer, controls; //场景、相机、渲染器、控制器
let pointLight, ambientLight; //光源
let curve = null, rate = 0; // 照片点位
let imgArr = []; //照片url
let imgCut = 50; //照片剪影大小
let rotateImg = true; // 是否继续轮转照片,其实是相机在转
const imgGroup = new THREE.Group(); //照片对象组
const textureLoader = new THREE.TextureLoader(); // 纹理加载器
const pointer = new THREE.Vector2(); //点击坐标
const raycaster = new THREE.Raycaster(); //射线
const threeEl = document.getElementById('container'); //元素获取
场景和部分数据初始化,其中图片这里直接是使用的网络资源图,可以使用本地文件或者自己搭建的服务环境文件。
function init() {
imgArr = [
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg95.699pic.com%2Fphoto%2F40142%2F4204.gif_wh860.gif&refer=http%3A%2F%2Fimg95.699pic.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659077726&t=ea5e3abb8b838546ae9377321744f875",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F019b795b2cc0dba80121bbec95a340.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076627&t=be25ec64df151d68c5dd5296a1d68fcf",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp4.itc.cn%2Fimages01%2F20200707%2Fcc1bec607b1949549f374f3e0e68bc2d.jpeg&refer=http%3A%2F%2Fp4.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659072591&t=34a56c58c383f15a5118d81859cad417",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F019b795b2cc0dba80121bbec95a340.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076255&t=aae752e553bbdeda27a4fa14b242e4e8",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp.qpic.cn%2Fdnfbbspic%2F0%2Fdnfbbs_dnfbbs_dnf_gamebbs_qq_com_forum_202007_05_084137qjj5sjd9pqm9mprr.jpg%2F0&refer=http%3A%2F%2Fp.qpic.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076255&t=bd12aa3f0d060cc19880158e9ef7b16f",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fwww.keaidian.com%2Fuploads%2Fallimg%2F190713%2F13174657_15.jpg&refer=http%3A%2F%2Fwww.keaidian.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076255&t=47296d32109bbffce6844b557a109d24",
"https://img2.baidu.com/it/u=3487630334,1818100496&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2Fedpic_source%2F29%2F09%2F31%2F290931cc8b21f13ff0ca273ff8e4865e.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076255&t=5c77914a690c1b53de57c7bf5692487a",
]
changeImg(threeEl, imgArr[0]);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
// 添加相机并设置在原点
camera.position.set(0, 0, 0);
camera.lookAt(new THREE.Vector3(1, 0, 0));
// 添加一个点光源
pointLight = new THREE.PointLight(0xffffff);
scene.add(pointLight);
// 添加一个环境光
ambientLight = new THREE.AmbientLight(0xffffff);
scene.add(ambientLight);
// 增加坐标系红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
// 添加坐标系到场景中
// const axes = new THREE.AxesHelper(20);
// scene.add(axes);
// 创建渲染器对象
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);//设置渲染区域尺寸
threeEl.appendChild(renderer.domElement); //body元素中插入canvas对象render
// 监听鼠标
pointerListing();
// 初始化控制器
controls = new OrbitControls(camera, renderer.domElement);//创建控件对象
controls.enabled = false;
}
用到了基础网格材质(MeshBasicMaterial)和贴图,用贴图加载器(TextureLoader)将图片贴到放置的平面缓冲几何体(PlaneGeometry)上,再在外层增加一个有一定透明度的立方缓冲几何体(BoxGeometry),让它看上去就像是一个相框。
基础网格材质(MeshBasicMaterial)
一个以简单着色(平面或线框)方式来绘制几何体的材质,这种材质不受光照的影响。构造函数(Constructor)
MeshBasicMaterial( parameters : Object )
parameters - (可选)用于定义材质外观的对象,具有一个或多个属性。材质的任何属性都可以从此处传入(包括从Material继承的任何属性)。
属性color例外,其可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
TextureLoader
加载texture的一个类。 内部使用ImageLoader来加载文件。构造函数
TextureLoader( manager : LoadingManager )
manager — 加载器使用的loadingManager,默认值为THREE.DefaultLoadingManager.
// 图片贴到对应位置
function placeImg() {
imgGroup.name = 'imgGroup';
// 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
// Create a closed wavey loop
curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(75, 0, 0),
new THREE.Vector3(0, 0, 75),
new THREE.Vector3(-75, 0, 0),
new THREE.Vector3(0, 0, -75)
]);
// centripetal、chordal和catmullrom
curve.curveType = "catmullrom";
curve.closed = true;//设置是否闭环
curve.tension = 1; //设置线的张力,0为无弧度折线
// // 为曲线添加材质在场景中显示出来,不添加到场景显示也不会影响运动轨迹,相当于一个Helper
// const points = curve.getPoints(50);
// const geometry = new THREE.BufferGeometry().setFromPoints(points);
// const material = new THREE.LineBasicMaterial({ color: 0x000000 });
// // Create the final object to add to the scene
// const curveObject = new THREE.Line(geometry, material);
// scene.add(curveObject);
const imgNum = imgArr.length;
rate = imgNum <= 0 ? 0 : (1 / imgNum);
imgArr.forEach((item, index) => {
const imgPosition = curve.getPointAt(rate * index);
// 材质对象Material
const material = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
opacity: 0.8,
transparent: true,
name: "material" + index,
map: textureLoader.load(item)
});
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(imgCut, imgCut), material);
mesh.position.set(imgPosition.x, imgPosition.y, imgPosition.z);
mesh.rotation.y = -Math.PI / 2;
mesh.lookAt(scene.position) //设置朝向
mesh.name = item;
// imgGroup.add(mesh);
scene.add(mesh);
// 加一个框
const boxMaterial = new THREE.MeshBasicMaterial({
opacity: 0.1,
transparent: true,
color: 0x0081cc
});
const boxMesh = new THREE.Mesh(new THREE.BoxGeometry(imgCut * 1.1, imgCut * 1.1, imgCut * 0.1), boxMaterial);
boxMesh.position.set(imgPosition.x, imgPosition.y, imgPosition.z);
boxMesh.rotation.y = -Math.PI / 2;
boxMesh.lookAt(scene.position) //设置朝向
boxMesh.name = item;
imgGroup.add(boxMesh);
})
scene.add(imgGroup);
}
当鼠标放到相框上,贴有照片的平面几何体外层立方几何体的透明度改变,达到选中效果,选中贴图剪影时页面背景改变。
// 背景替换
function changeImg(element, url) {
element.style.backgroundImage = `url(${url})`;
// element.style.backgroundSize = '100%';
}
// 添加鼠标监听
function pointerListing() {
threeEl.addEventListener("pointerdown", onPointerDown);
threeEl.addEventListener("pointermove", onPointerMove);
}
function onPointerMove(event) {
// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
pointer.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1
);
// console.log(scene);
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(
[...imgGroup.children],
false
);
// 有照片就换背景
if (intersects.length > 0) {
const intersect = intersects[0];
intersect.object.material.opacity = 0.5;
}else{
imgGroup.children.forEach(item => {
item.material.opacity = 0.1;
});
}
}
function onPointerDown(event) {
// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
pointer.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1
);
// console.log(scene);
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(
[...imgGroup.children],
false
);
// 有照片就换背景
if (intersects.length > 0) {
const intersect = intersects[0];
// console.log(intersect.object);
// 背景替换
changeImg(threeEl, intersect.object.name);
// 相机移动
rotateImg = false;
// 照片旋转停下来
const changePosition = new THREE.Vector3(
intersect.object.position.x*1.5,
intersect.object.position.y*1.5,
intersect.object.position.z*1.5);
animateCamera(camera.position, changePosition);
} else {
// 相机回原点
const o = new THREE.Vector3(0,0,0);
animateCamera(camera.position, o);
rotateImg = true;
}
};
相机本身在旋转,相对的图片看起来就像是在滚动播放,当点击某个图片时,相机移动到对应对象更外层,点击空白再回到原点,达到平滑切换的效果。
function onPointerDown(event) {
// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
pointer.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1
);
// console.log(scene);
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(
[...imgGroup.children],
false
);
// 有照片就换背景
if (intersects.length > 0) {
const intersect = intersects[0];
// console.log(intersect.object);
// 背景替换
changeImg(threeEl, intersect.object.name);
// 相机移动
rotateImg = false;
// 照片旋转停下来
const changePosition = new THREE.Vector3(
intersect.object.position.x*1.5,
intersect.object.position.y*1.5,
intersect.object.position.z*1.5);
animateCamera(camera.position, changePosition);
} else {
// 相机回原点
const o = new THREE.Vector3(0,0,0);
animateCamera(camera.position, o);
rotateImg = true;
}
};
// current1 相机当前的位置
// target1 相机的目标位置
// current2 当前的controls的target
// target2 新的controls的target
function animateCamera(current1, target1,callBack) {
var tween = new TWEEN.Tween({
x1: current1.x, // 相机当前位置x
y1: current1.y, // 相机当前位置y
z1: current1.z, // 相机当前位置z
// x2: current2.x, // 控制当前的中心点x
// y2: current2.y, // 控制当前的中心点y
// z2: current2.z // 控制当前的中心点z
});
tween.to({
x1: target1.x, // 新的相机位置x
y1: target1.y, // 新的相机位置y
z1: target1.z, // 新的相机位置z
// x2: target2.x, // 新的控制中心点位置x
// y2: target2.y, // 新的控制中心点位置x
// z2: target2.z // 新的控制中心点位置x
}, 1000);
tween.onUpdate(function (object) {
camera.position.x = object.x1;
camera.position.y = object.y1;
camera.position.z = object.z1;
// controls.target.x = object.x2;
// controls.target.y = object.y2;
// controls.target.z = object.z2;
// controls.update();
});
tween.onComplete(function () {
callBack && callBack()
});
tween.easing(TWEEN.Easing.Cubic.InOut);
tween.start();
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body {
margin: 0px;
}
#container {
/* background: #000000 url("https://seopic.699pic.com/photo/50041/6756.jpg_wh1200.jpg") no-repeat; */
background: #000000;
background-size: 100vw 100vh;
overflow: hidden;
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<div id="container">
</div>
<script type="importmap">
{
"imports": {
"three": "./three.js-master/build/three.module.js"
}
}
</script>
<script type="module">
import * as THREE from "three";
import { OrbitControls } from "./three.js-master/examples/jsm/controls/OrbitControls.js";
import { GLTFLoader } from "./three.js-master/examples/jsm/loaders/GLTFLoader.js";
import { TWEEN } from "./three.js-master/examples/jsm/libs/tween.module.min.js";
let scene, camera, renderer, controls; //场景、相机、渲染器、控制器
let pointLight, ambientLight; //光源
let curve = null, rate = 0; // 照片点位
let imgArr = []; //照片url
let imgCut = 50; //照片剪影大小
let rotateImg = true; // 是否继续轮转照片,其实是相机在转
const imgGroup = new THREE.Group(); //照片对象组
const textureLoader = new THREE.TextureLoader(); // 纹理加载器
const pointer = new THREE.Vector2(); //点击坐标
const raycaster = new THREE.Raycaster(); //射线
const threeEl = document.getElementById('container'); //元素获取
function init() {
imgArr = [
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg95.699pic.com%2Fphoto%2F40142%2F4204.gif_wh860.gif&refer=http%3A%2F%2Fimg95.699pic.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659077726&t=ea5e3abb8b838546ae9377321744f875",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F019b795b2cc0dba80121bbec95a340.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076627&t=be25ec64df151d68c5dd5296a1d68fcf",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp4.itc.cn%2Fimages01%2F20200707%2Fcc1bec607b1949549f374f3e0e68bc2d.jpeg&refer=http%3A%2F%2Fp4.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659072591&t=34a56c58c383f15a5118d81859cad417",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.zcool.cn%2Fcommunity%2F019b795b2cc0dba80121bbec95a340.jpg%402o.jpg&refer=http%3A%2F%2Fimg.zcool.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076255&t=aae752e553bbdeda27a4fa14b242e4e8",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fp.qpic.cn%2Fdnfbbspic%2F0%2Fdnfbbs_dnfbbs_dnf_gamebbs_qq_com_forum_202007_05_084137qjj5sjd9pqm9mprr.jpg%2F0&refer=http%3A%2F%2Fp.qpic.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076255&t=bd12aa3f0d060cc19880158e9ef7b16f",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fwww.keaidian.com%2Fuploads%2Fallimg%2F190713%2F13174657_15.jpg&refer=http%3A%2F%2Fwww.keaidian.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076255&t=47296d32109bbffce6844b557a109d24",
"https://img2.baidu.com/it/u=3487630334,1818100496&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500",
"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fup.enterdesk.com%2Fedpic_source%2F29%2F09%2F31%2F290931cc8b21f13ff0ca273ff8e4865e.jpg&refer=http%3A%2F%2Fup.enterdesk.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1659076255&t=5c77914a690c1b53de57c7bf5692487a",
]
changeImg(threeEl, imgArr[0]);
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
renderer = new THREE.WebGLRenderer();
// 添加相机并设置在原点
camera.position.set(0, 0, 0);
camera.lookAt(new THREE.Vector3(1, 0, 0));
// 添加一个点光源
pointLight = new THREE.PointLight(0xffffff);
scene.add(pointLight);
// 添加一个环境光
ambientLight = new THREE.AmbientLight(0xffffff);
scene.add(ambientLight);
// 增加坐标系红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
// 添加坐标系到场景中
// const axes = new THREE.AxesHelper(20);
// scene.add(axes);
// 创建渲染器对象
renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
renderer.setSize(window.innerWidth, window.innerHeight);//设置渲染区域尺寸
threeEl.appendChild(renderer.domElement); //body元素中插入canvas对象render
// 监听鼠标
pointerListing();
// 初始化控制器
controls = new OrbitControls(camera, renderer.domElement);//创建控件对象
controls.enabled = false;
}
// 背景替换
function changeImg(element, url) {
element.style.backgroundImage = `url(${url})`;
// element.style.backgroundSize = '100%';
}
// 添加鼠标监听
function pointerListing() {
threeEl.addEventListener("pointerdown", onPointerDown);
threeEl.addEventListener("pointermove", onPointerMove);
}
function onPointerMove(event) {
// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
pointer.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1
);
// console.log(scene);
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(
[...imgGroup.children],
false
);
// 有照片就换背景
if (intersects.length > 0) {
const intersect = intersects[0];
intersect.object.material.opacity = 0.5;
}else{
imgGroup.children.forEach(item => {
item.material.opacity = 0.1;
});
}
}
function onPointerDown(event) {
// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)
pointer.set(
(event.clientX / window.innerWidth) * 2 - 1,
-(event.clientY / window.innerHeight) * 2 + 1
);
// console.log(scene);
raycaster.setFromCamera(pointer, camera);
const intersects = raycaster.intersectObjects(
[...imgGroup.children],
false
);
// 有照片就换背景
if (intersects.length > 0) {
const intersect = intersects[0];
// console.log(intersect.object);
// 背景替换
changeImg(threeEl, intersect.object.name);
// 相机移动
rotateImg = false;
// 照片旋转停下来
const changePosition = new THREE.Vector3(
intersect.object.position.x*1.5,
intersect.object.position.y*1.5,
intersect.object.position.z*1.5);
animateCamera(camera.position, changePosition);
} else {
// 相机回原点
const o = new THREE.Vector3(0,0,0);
animateCamera(camera.position, o);
rotateImg = true;
}
};
// current1 相机当前的位置
// target1 相机的目标位置
// current2 当前的controls的target
// target2 新的controls的target
function animateCamera(current1, target1,callBack) {
var tween = new TWEEN.Tween({
x1: current1.x, // 相机当前位置x
y1: current1.y, // 相机当前位置y
z1: current1.z, // 相机当前位置z
// x2: current2.x, // 控制当前的中心点x
// y2: current2.y, // 控制当前的中心点y
// z2: current2.z // 控制当前的中心点z
});
tween.to({
x1: target1.x, // 新的相机位置x
y1: target1.y, // 新的相机位置y
z1: target1.z, // 新的相机位置z
// x2: target2.x, // 新的控制中心点位置x
// y2: target2.y, // 新的控制中心点位置x
// z2: target2.z // 新的控制中心点位置x
}, 1000);
tween.onUpdate(function (object) {
camera.position.x = object.x1;
camera.position.y = object.y1;
camera.position.z = object.z1;
// controls.target.x = object.x2;
// controls.target.y = object.y2;
// controls.target.z = object.z2;
// controls.update();
});
tween.onComplete(function () {
callBack && callBack()
});
tween.easing(TWEEN.Easing.Cubic.InOut);
tween.start();
}
// 图片贴到对应位置
function placeImg() {
imgGroup.name = 'imgGroup';
// 红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
// Create a closed wavey loop
curve = new THREE.CatmullRomCurve3([
new THREE.Vector3(75, 0, 0),
new THREE.Vector3(0, 0, 75),
new THREE.Vector3(-75, 0, 0),
new THREE.Vector3(0, 0, -75)
]);
// centripetal、chordal和catmullrom
curve.curveType = "catmullrom";
curve.closed = true;//设置是否闭环
curve.tension = 1; //设置线的张力,0为无弧度折线
// // 为曲线添加材质在场景中显示出来,不添加到场景显示也不会影响运动轨迹,相当于一个Helper
// const points = curve.getPoints(50);
// const geometry = new THREE.BufferGeometry().setFromPoints(points);
// const material = new THREE.LineBasicMaterial({ color: 0x000000 });
// // Create the final object to add to the scene
// const curveObject = new THREE.Line(geometry, material);
// scene.add(curveObject);
const imgNum = imgArr.length;
rate = imgNum <= 0 ? 0 : (1 / imgNum);
imgArr.forEach((item, index) => {
const imgPosition = curve.getPointAt(rate * index);
// 材质对象Material
const material = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide,
opacity: 0.8,
transparent: true,
name: "material" + index,
map: textureLoader.load(item)
});
const mesh = new THREE.Mesh(new THREE.PlaneGeometry(imgCut, imgCut), material);
mesh.position.set(imgPosition.x, imgPosition.y, imgPosition.z);
mesh.rotation.y = -Math.PI / 2;
mesh.lookAt(scene.position) //设置朝向
mesh.name = item;
// imgGroup.add(mesh);
scene.add(mesh);
// 加一个框
const boxMaterial = new THREE.MeshBasicMaterial({
opacity: 0.1,
transparent: true,
color: 0x0081cc
});
const boxMesh = new THREE.Mesh(new THREE.BoxGeometry(imgCut * 1.1, imgCut * 1.1, imgCut * 0.1), boxMaterial);
boxMesh.position.set(imgPosition.x, imgPosition.y, imgPosition.z);
boxMesh.rotation.y = -Math.PI / 2;
boxMesh.lookAt(scene.position) //设置朝向
boxMesh.name = item;
imgGroup.add(boxMesh);
})
scene.add(imgGroup);
}
//执行渲染操作 指定场景、相机作为参数
function render() {
renderer.render(scene, camera);//执行渲染操作
if (rotateImg) {
camera.rotateY(0.001);//每次绕y轴旋转0.001弧度
}
TWEEN.update();
// newmesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
requestAnimationFrame(render);//请求再次执行渲染函数render
}
function initWindow() {
let onResize = function () {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
window.addEventListener("resize", onResize, false);
};
init();
placeImg();
initWindow();
render();
</script>
</body>
</html>