vue相关的代码片段
<template>
<div id="my-three"></div>
</template>
<script setup>
import {ref, onMounted, getCurrentInstance} from "vue";
import * as THREE from "three";
import {OrbitControls} from "three/examples/jsm/controls/OrbitControls"
import {FBXLoader} from "three/examples/jsm/loaders/FBXLoader";
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader"; //gltf
import {RGBELoader} from 'three/examples/jsm/loaders/RGBELoader';
import imgurl from "@/assets/bj.png"
import {ElMessage} from "element-plus";
let height = 0, width
const {proxy} = getCurrentInstance();
const emit = defineEmits(['change'])
const scene = new THREE.Scene();
const renderer = new THREE.WebGLRenderer({
antialias: true
});
renderer.outputEncoding = THREE.sRGBEncoding;
// renderer.outputEncoding = THREE.sRGB;
const loader = new GLTFLoader();
var clock = new THREE.Clock();
var mixer = null;
let messagelog = null
let duration = 9999000000
let camera, controls;
onMounted(() => {
document.getElementById("my-three")?.appendChild(renderer.domElement);
height = document.getElementById("three").offsetHeight;
width = document.getElementById("three").offsetWidth;
// console.log(height);
camera = new THREE.PerspectiveCamera(55, width / height, 0.1, 10000);
controls = new OrbitControls(camera, renderer.domElement);
controls.enableRotate = false; // 禁用旋转
if (height > 0) {
init();
renderModel();
gltfModel1();
render();
}
messagelog = ElMessage({
message: '第一步 点击选择养殖蚌',
type: 'success',
duration: duration,
offset: window.screen.height / 2
})
});
function init() {
//光源
const ambient = new THREE.AmbientLight(0xdddddd, 0.4);
scene.add(ambient);
//设置相机位置
// camera.position.set(10, 337, 533);
camera.position.set(30, 1017, 1599);
// camera.position.set(200, 200, 200);
//设置相机方向
// camera.lookAt(0, 400, 0);
//辅助坐标轴
// const axesHelper = new THREE.AxesHelper(200); //参数200标示坐标系大小,可以根据场景大小去设置
// scene.add(axesHelper);
// scene.background = new THREE.Color(0xeaeaea);
const sceneLoader = new THREE.TextureLoader();
let sceneColorTexture = sceneLoader.load(imgurl);
// sceneColorTexture.minFilter = THREE.LinearFilter;
scene.background = sceneColorTexture;
scene.background.matrixAutoUpdate = false;
renderer.setPixelRatio(window.devicePixelRatio);
renderer.antialias = true;
}
let actions = []
// const segmentDurations = [2, 10.5,27.5]
const segmentDurations = [2, 2, 8.5, 57.5]
let currentActionIndex = 0
let currentIndex = 0
let isStop = false
// 关键代码
function fetchLocal(e) {
return new Promise((resolve, reject) => {
plus.io.resolveLocalFileSystemURL(e, entry => {
var reader = null;
entry.file(file => {
reader = new plus.io.FileReader();
reader.onloadend = (read) => {
resolve(read.target.result)
};
reader.readAsDataURL(file);
}, function (error) {
alert(error.message);
});
}, err => {
resolve(e)
})
})
}
function gltfModel1() {
fetchLocal("./xiao.glb").then(res => {
loader.load(res, function (obj) {
// let scale = 100;
// let scale = 300;
let scale = 1000;
obj.scene.scale.set(scale, scale, scale); // 将模型放大两倍
obj.scene.position.set(0, -1000, 0); // 将模型位置设置为长方形模型的中心点/
obj.scene.rotation.set(0, 0, 0); // 可以根据需要调整模型的旋转
// obj.scene.rotation.y += 0.8; // 旋转
obj.scene.translateY(-80);
scene.add(obj.scene)
// obj作为参数创建一个混合器,解析播放obj及其子对象包含的动画数据
mixer = new THREE.AnimationMixer(obj.scene);
// 获取模型中的动画剪辑
const animations = obj.animations;
// 查看动画数据
// obj.animations[0]:获得剪辑对象clip
for (let i = 0; i < animations.length; i++) {
console.log(animations[i], animations[i].name, 'ok')
actions.push(mixer.clipAction(animations[i]));
if (animations[i].name == 'Z_初始锚点') {
const clip = animations[i];
if (clip) {
// 创建动作并播放
const action = mixer.clipAction(clip);
action.play();
// 将动画设置为第一帧
mixer.setTime(0);
action.paused = true;
}
}
}
// console.log(obj)
camera = obj.cameras[0]
// 获取第一个动画剪辑
})
//
})
const pmremGenerator = new THREE.PMREMGenerator(renderer); // 使用hdr作为背景色
pmremGenerator.compileEquirectangularShader();
const rgbeLoader = new RGBELoader();
fetchLocal("./venice_sunset_1k.hdr").then(res => {
rgbeLoader.load(res, function (texture) {
const envMap = pmremGenerator.fromEquirectangular(texture).texture;
pmremGenerator.dispose();
scene.environment = envMap; // 给场景添加环境光效果
console.log(envMap);
// scene.background = envMap; // 给场景添加背景图
})
})
// 根据模型名称
window.addEventListener('click', onMouseClick, false);
}
// let duration = 2000
function onMouseClick(event) {
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
event.preventDefault();
mouse.x = (event.clientX / width) * 2 - 1;
mouse.y = -(event.clientY / height) * 2 + 1; //这里为什么是-号,没有就无法点中
// console.log(event)
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
// console.log(intersects)
const intersectedObject = intersects[0].object;
console.log(intersectedObject.name)
if (
intersectedObject.name == '钳子003'
|| intersectedObject.name == '钳子001'
|| intersectedObject.name == '钳子002'
|| intersectedObject.name == '钳子'
) {
let num = currentActionIndex == 1 ? 2 : 4
play(num)
}
if(intersectedObject.name == '固定钉'){
play(3)
}
if(intersectedObject.name == '拨肉针'||intersectedObject.name == 'FBXASC230FBXASC139FBXASC168FBXASC232FBXASC130FBXASC137FBXASC229'){
play(5)
}
if(intersectedObject.name == '取核针'||intersectedObject.name == 'FBXASC229FBXASC143FBXASC150FBXASC230FBXASC160FBXASC184FBXASC229'){
play(6)
}
}
}
let crrshow = 0
function play(index) {
// duration = 10
// message.close()
if (isStop) return; // duration = 10
if (currentIndex == index) {
currentIndex = index + 1;
crrshow = index + 1
if (currentIndex >= 7) {
currentIndex = 0;
}
} else {
return false;
}
emit('change', 10)
if (messagelog) {
messagelog.close()
messagelog = null
}
currentActionIndex = index;
isStop = true;
actions.forEach((action) => {
// console.log(action)
action.stop();
if (
(currentActionIndex == 0 && action._clip.name == "A_选蚌")
|| (currentActionIndex == 1 && action._clip.name == "B_选珍珠")
|| (currentActionIndex == 2 && action._clip.name == "C_开蚌")
|| (currentActionIndex == 3 && action._clip.name == "D_固定蚌壳")
|| (currentActionIndex == 4 && action._clip.name == "E_放回钳子")
|| (currentActionIndex == 5 && action._clip.name == "F_拨开蚌肉")
|| (currentActionIndex == 6 && action._clip.name == "G_种珍珠")
) {
console.log(action)
// 第一次调用 play 启动播放
let num = parseFloat(action._clip.duration).toFixed(2)
action.clampWhenFinished = true;
action.loop = THREE.LoopOnce;
action.enabled = true;
action.clampWhenFinished = true;
action.play()
playNextSegment(num)
}
})
// playNextSegment()
}
let Tem = null
function playNextSegment(num) {
Tem = setTimeout(() => {
isStop = false;
if (currentActionIndex == 0) {
messagelog = ElMessage({
message: '第二步 点击选择珍珠核',
type: 'success',
duration: duration,
offset: window.screen.height / 2
})
}
if (currentActionIndex == 1 || currentActionIndex == 3 || currentActionIndex == 5) {
let message = currentActionIndex == 1 ? "第三步 点击选择右侧托盘里的钳子" :
currentActionIndex == 3 ? "第五步 点击上方钳子放回托盘" : "第七步 点击右侧托盘里的送片针"
messagelog = ElMessage({
message,
type: 'success',
duration: duration,
offset: window.screen.height / 2
})
}
if (currentActionIndex == 2 || currentActionIndex == 4) {
let message = currentActionIndex == 2 ? "第四步 点击左侧托盘里的固定器" : "第六步 点击左侧托盘里的开口针"
messagelog = ElMessage({
message: message,
type: 'success',
duration: duration,
offset: window.screen.height / 2
})
}
if (currentActionIndex == 6) {
messagelog = ElMessage({
message: '育珠结束,请重新开始',
type: 'success',
duration: duration,
offset: window.screen.height / 2
})
setTimeout(() => {
initialization()
}, 6000)
}
emit('change', crrshow)
}, num * 1000);
}
function initialization() {
if (messagelog) {
messagelog.close()
messagelog = null
}
isStop = false;
crrshow = 0;
currentActionIndex = 0;
currentIndex = 0;
if (Tem) {
clearTimeout(Tem)
}
actions.forEach((action) => {
// console.log(action)
action.stop();
if (action._clip.name == 'Z_初始锚点') {
action.play();
mixer.setTime(0);
action.paused = true;
}
})
messagelog = ElMessage({
message: '第一步 点击选择养殖蚌',
type: 'success',
duration: duration,
offset: window.screen.height / 2
})
emit('change', crrshow)
}
function renderModel() {
//渲染
renderer.setSize(width, height); //设置渲染区尺寸
renderer.render(scene, camera); //执行渲染操作、指定场景、相机作为参数
// renderer.setClearColor(0x00ff00); // 设置背景颜色为绿色
renderer.toneMapping = THREE.ACESFilmicToneMapping;
// 设置曝光度
renderer.toneMappingExposure = 1.5; // 适当调整曝光度
controls.minPolarAngle = Math.PI / 4; // 最小极角为 45 度
controls.maxPolarAngle = Math.PI / 2; // 最大极角为 90 度
}
function render() { //校正不同通道颜色
requestAnimationFrame(render);
if (mixer !== null) {
//clock.getDelta()方法获得两帧的时间间隔
// 更新混合器相关的时间
mixer.update(clock.getDelta());
}
renderer.autoClear = false
renderer.clear()
renderer.outputEncoding = null //THREE.RGBDEncoding
controls.update();
renderer.render(scene, camera);
}
// 画布跟随窗口变化
window.onresize = function () {
renderer.setSize(width, height);
camera.aspect = width / height;
camera.updateProjectionMatrix();
};
// 交互事件
// addEventListener("dblclick", onMouseDblclick, false);
function onMouseDblclick(event) {
let intersects = getIntersects(event);
if (intersects.length !== 0 && intersects[0].object instanceof THREE.Mesh) {
const selectedObject = intersects[0].object;
let selectedObjects = [];
selectedObjects.push(selectedObject);
// console.log(selectedObjects);
// outlinePass.selectedObjects = selectedObjects;
}
}
//获取与射线相交的对象数组
function getIntersects(event) {
let rayCaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
//通过鼠标点击位置,计算出raycaster所需点的位置,以屏幕为中心点,范围-1到1
mouse.x = (event.clientX / width) * 2 - 1;
mouse.y = -(event.clientY / height) * 2 + 1; //这里为什么是-号,没有就无法点中
//通过鼠标点击的位置(二维坐标)和当前相机的矩阵计算出射线位置
rayCaster.setFromCamera(mouse, camera);
return rayCaster.intersectObjects(scene.children);
}
defineExpose({
play,
initialization
})
</script>
<style scoped lang="scss"></style>
vue打包导入uniapp 的代码片段运行之后可以在安卓app正在运行显示
<template>
<view class="">
<web-view :src="src"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
src: ''
}
},
onLoad() {
let num =(new Date()).getTime()
this.src = '/static/dist/index.html?id='+num;
},
methods: {
}
}
</script>