赞
踩
主要方式是通过renderjs来实现的, 因为使用threejs的话需要获取页面上的dom节点, 然后需要把threejs创建出来的canvans添加到页面的dom节点上. 就避免不了要获取dom了.
官网地址: https://uniapp.dcloud.net.cn/tutorial/renderjs.html#renderjs
很草率… 而且连例子都是vue2的. 放在vue3中肯定跑不起来, 例子也不是3D
下面例子使用的是网络地址, 使用前请确保项目安装了threejs, 只需npm i three即可.
<template>
<view class="content">
<image class="logo" src="/static/logo.png" @click="chanage" />
<view class="text-area">
<text class="title">{{ title }}</text>
</view>
<view id="map" :prop="isHide" :change:prop="leaflet.handleAction" />
</view>
</template>
<script setup lang="ts">
import {
onHide
} from '@dcloudio/uni-app'
import {
ref,
onDeactivated
} from 'vue'
const title = ref('Hello')
const type = ref(0)
const isHide = ref(false)
const chanage = () => {
console.log('隐藏')
isHide.value = true
}
onHide(() => {
isHide.value = true
})
onDeactivated(() => {
isHide.value = true
})
setInterval(() => {
// console.log('触发')
type.value = Date.now()
}, 1000)
</script>
<script module="leaflet" lang="renderjs">
// @ts-nocheck
import * as THREE from 'three'
// OrbitControls 是对 Threejs 的三维场景进行缩放、平移、旋转操作
import {
OrbitControls
} from 'three/examples/jsm/controls/OrbitControls.js'
// 导入 glb 格式模型,若要导入其他格式模型,可尝试在 loaders 目录下加载其他文件
import {
GLTFLoader
} from 'three/examples/jsm/loaders/GLTFLoader.js'
import {
FBXLoader
} from 'three/examples/jsm/loaders/FBXLoader.js'
var renderer;
var scene;
var camera;
var controls;
var ambient;
export default {
data() {
return {
ownerInstance: {}
}
},
methods: {
handleAction(newValue, oldValue, ownerInstance, instance) {
this.ownerInstance = ownerInstance
if (newValue) {
console.log(document.querySelector('canvas'))
console.log(document.querySelector('#app'))
document.querySelector('.threeId').removeChild(document.querySelector('.canvasId'))
// document.querySelector('canvas').remove()
}
// console.log('newValue', newValue)
// console.log('oldValue', oldValue)
// console.log('该停止渲染了')
},
leadModel() {
let loader = new GLTFLoader();
// 导入本地或者服务器上的模型都可以
loader.load('https://dtmall-tel.alicdn.com/edgeComputingConfig/upload_models/1591673169101/RobotExpressive.glb',
(gltf) => {
scene.add(gltf.scene);
});
},
animate() {
requestAnimationFrame(this.animate);
controls.update(); //自动旋转
// console.log('渲染', scene.value, camera)
renderer.render(scene, camera); //执行渲染操作
},
initThree() {
// 如果返回的不是未定义,说明threejs成功引入
// console.log('打印场景API', THREE.Scene);
/* 创建场景对象Scene */
scene = new THREE.Scene();
// 环境光
ambient = new THREE.AmbientLight(0xffffff);
scene.add(ambient);
/*
相机设置
*/
// var width = window.innerWidth; // 窗口宽度
// var height = window.innerHeight; // 高度
var width = 400; // 窗口宽度
var height = 300; // 高度
// 相机位置
var cameraZ = 10;
// var k = width / height; // 窗口宽高比
var s = 400; // 三维场景显示范围控制系数,系数越大,显示的范围越大
// 创建相机对象(正射投影)
camera = new THREE.PerspectiveCamera(45, width / height, 0.1, 1000);
camera.position.set(0, 0, cameraZ); //设置相机的摆放位置
camera.lookAt(new THREE.Vector3(0, 0, 0)); // 控制相机的焦点(镜头)位置,决定相机的朝向(取值为3维坐标对象-THREE.Vector3(x,y,z))
/*
创建渲染器对象
*/
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true //设置透明,为true时,背景颜色需要注释掉
});
renderer.setSize(width, height); // 设置渲染区域尺寸
// renderer.setClearColor(0XECF1F3, 1); // 设置背景颜色
// 改成vue去操作dom
// console.log(threeViwe.value)
// const element = document.getElementById('threeView')
let div = document.createElement('uni-view')
div.classList.add("threeId")
renderer.domElement.style.position = 'absolute'
renderer.domElement.style.left = '0'
renderer.domElement.style.top = '500px'
renderer.domElement.classList.add("canvasId")
// renderer.domElement.style.display = 'none'
div.appendChild(renderer.domElement)
// console.log('查看App', document.querySelector('#app'))
console.log(document.querySelector('.text-area'))
document.querySelector('.text-area').appendChild(div)
// 执行渲染操作,指定场景,相机作为参数
renderer.render(scene, camera);
// 加载控件
controls = new OrbitControls(camera, renderer.domElement)
controls.enabled = true;
controls.enableRotate = true;
controls.enableZoom = false;
controls.autoRotate = true;
controls.minPolarAngle = Math.PI / 4;
controls.maxPolarAngle = 3 - (Math.PI / 4);
}
},
created() {
setTimeout(() => {
this.initThree(); //加载场景
this.leadModel(); //导入模型
this.animate(); //动画
})
}
}
</script>
就是这样了, 然后离开页面的时候销毁这个canvas, 下次进来再创建. 注意下面不能用setup来整, 下面要用vue2的写法来就可以了, 用vue3的setup会出现拿不到dom的情况
注意server层和renderjs层之间的通讯
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
注意在浏览器和App中是不一样的
如果相加样式的话, 直接在添加节点到dom前设置即可
如下:
才发现可以这样玩
不过现在一般在网页内嵌3D时, 都会给一个压缩的版本, 所以需要解压. 解压依赖于DRACOLoader
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。