赞
踩
项目内嵌到uniapp开发的h5页面中,
第一步先引入three.js
npm install three
然后代码里面引入,我的模型是FBX文件,引入的fbxloader加载器,如果出现找不到指定的版本号错误则检查引入模型文件的时候地址,需要放在公共文件夹
- import * as THREE from 'three'
- import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader';
- import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
html页面是这样的,代码里面的<tabbar>标签是我项目需要的导航栏,如果借用的话请删除,不然会引起报错。
- <template>
- <view>
- <button @click="changeClothes()">缩小</button>
- <button @click="hoMing()">归位</button>
- <button @click="changeOld('裤子','../../static/fbx/2.fbx')">切换裤子</button>
- <button @click="changeOld('卫衣','../../static/fbx/weiyi.fbx')">切换卫衣</button>
- <view id="canvas">
- </view>
- <!-- <view id="loading">Loading...</view> -->
- <!-- <image src="../../static/images/No.2.png"></image> -->
- <tabbar></tabbar>
- </view>
- </template>
下面是JS部分
- <script>
- import * as THREE from 'three'
- import {
- FBXLoader
- } from 'three/examples/jsm/loaders/FBXLoader';
- import {
- OrbitControls
- } from 'three/examples/jsm/controls/OrbitControls'
-
- export default {
- name: 'HelloWorld',
- data() {
- return {
- scene: null,
- camera: null,
- renderer: null,
- model: null,
- materials: [],
- controls: null,
- mixer: null,
- meshes: [],
- newMaterial: null, //新模型的材质
- pants: null,
- manager: null,
- aspectOld: null, //旧的等宽比
- heightOld: null, //初始设备的高度
- widthOld: null, //初始设备的宽度
- Newaspect: null, //新的宽比
- }
- },
- methods: {
- /**
- * 初始化场景、相机、灯光、模型等
- */
- init() {
-
- this.aler()
- //记录设备初始宽高
- this.scene = new THREE.Scene()
- console.log(this.camera)
- this.aspectOld = this.camera.aspect //记录设备初始等宽比!!!
-
- console.log(window.innerWidth)
-
- // this.camera.aspect = window.innerWidth / window.innerHeight;
- // this.camera.updateProjectionMatrix();
- document.getElementById('canvas').appendChild(this.renderer.domElement)
- this.controls = new OrbitControls(this.camera, this.renderer.domElement)
- // this.renderer.domElement.style.height='390px'
- // this.renderer.domElement.style.width='50%'
-
- this.renderer.setClearColor(0xffffff); // 设置背景颜色为白色
- // this.loading()
- this.load('../../static/fbx/boy.fbx')
- this.render()
- },
- /**
- * 加载 FBX 模型
- */
-
- load(modelUrl) {
- let that = this
- // const loader = new FBXLoader(that.manager);
- const loader = new FBXLoader();
- loader.load(modelUrl, (fbx) => {
- console.log(fbx)
- fbx.scale.set(0.3, 0.3, 0.3)
-
- this.camera.lookAt(0, 0, 0)
-
- //模型居中
- const box = new THREE.Box3().setFromObject(fbx);
- const center = new THREE.Vector3();
- box.getCenter(center);
- fbx.position.sub(center);
- fbx.traverse((child) => {
- if (child.name == "Camera") {
- this.camera.position.set(child.position.x, child.position.y, child.position.z)
- }
- if (child.type == "PointLight") {
- child.intensity = 1
- }
- if (child.type == 'DirectionalLight') {
- child.intensity = 1
- }
- })
- //有动画的模型默认加载第一个动画
- if (fbx.animations.length != 0) {
- that.mixer = new THREE.AnimationMixer(fbx)
- const action = that.mixer.clipAction(fbx.animations[0])
- action.play()
- that.methse(fbx)
- }
- that.model = fbx
- that.scene.add(fbx);
- })
- },
- // 对象数据保存到数组中
- methse(fbx) {
- fbx.traverse((child) => {
- if (child instanceof THREE.Mesh) {
- this.meshes.push(child)
- }
- })
- },
- changeOld(num, path) {
- let that = this
- this.switching_model(num, path)
- },
- //页面回到默认
- hoMing() {
- this.camera.aspect = this.aspectOld;
- this.renderer.setSize(window.innerWidth, window.innerHeight)
- this.camera.updateProjectionMatrix(); //更新相机!!!
- },
- aler() {
- this.heightOld = window.innerHeight
- this.widthOld = window.innerWidth
- this.Newaspect = window.innerWidth / window.innerWidth
- this.camera = new THREE.PerspectiveCamera(20, window.innerWidth / window.innerHeight, 0.1, 10000);
- this.renderer = new THREE.WebGLRenderer({
- alpha: true,
- antialias: true
- })
- this.renderer.setSize(window.innerWidth, window.innerHeight)
- },
- changeClothes() {
- let that = this
- this.camera.aspect = this.Newaspect;
- this.renderer.setSize(this.widthOld, this.widthOld)
- this.camera.updateProjectionMatrix(); //更新相机!!!
- console.log(this.camera)
- // that.render()
- },
- //切换衣服
- switching_model(num, path) {
- const loader = new FBXLoader();
- let that = this
- loader.load(path, (newPants) => {
- that.model.traverse((child) => {
- if (child.name == num) {
- let newPantsGroup = null
- newPants.traverse((newchild) => {
- console.log(newchild.name)
- if (newchild.name == num) {
- newPantsGroup = newchild;
- }
- })
- console.log(newPantsGroup)
- child.material = newPantsGroup.material
- child.material.needsUpdate = true;
- }
-
- })
- that.renderer.render(that.scene, that.camera);
-
- }), undefined,
- function(error) {
- console.error(error);
- }, undefined,
- function(error) {
- console.error(error);
- }
- },
- /**
- * 执行渲染操作
- */
- render() {
- this.renderer.render(this.scene, this.camera)
- this.controls.update()
- requestAnimationFrame(this.render.bind(this))
- //更新动画
- if (this.mixer) {
- this.mixer.update(0.01)
- }
- }
- },
- mounted() {
- this.init()
- }
- }
- </script>
样式代码
- <style lang="scss">
- #canvas {
- text-align: center;
- height: 100vh;
- display: flex;
- align-items: center;
- justify-content: center;
-
- }
- </style>
完整代码如下,FBX我引入的是本地的,大家如果有需要可以去网上找一些开源的文件
- <template>
- <view>
- <button @click="changeClothes()">缩小</button>
- <button @click="hoMing()">归位</button>
- <button @click="changeOld('裤子','../../static/fbx/2.fbx')">切换裤子</button>
- <button @click="changeOld('卫衣','../../static/fbx/weiyi.fbx')">切换卫衣</button>
- <view id="canvas">
- </view>
- <tabbar></tabbar>
- </view>
- </template>
-
- <script>
- import * as THREE from 'three'
- import {
- FBXLoader
- } from 'three/examples/jsm/loaders/FBXLoader';
- import {
- OrbitControls
- } from 'three/examples/jsm/controls/OrbitControls'
-
- export default {
- name: 'HelloWorld',
- data() {
- return {
- scene: null,
- camera: null,
- renderer: null,
- model: null,
- materials: [],
- controls: null,
- mixer: null,
- meshes: [],
- newMaterial: null, //新模型的材质
- pants: null,
- manager: null,
- aspectOld: null, //旧的等宽比
- heightOld: null, //初始设备的高度
- widthOld: null, //初始设备的宽度
- Newaspect: null, //新的宽比
- }
- },
- methods: {
- /**
- * 初始化场景、相机、灯光、模型等
- */
- init() {
-
- this.aler()
- //记录设备初始宽高
- this.scene = new THREE.Scene()
- console.log(this.camera)
- this.aspectOld = this.camera.aspect //记录设备初始等宽比!!!
-
- console.log(window.innerWidth)
-
- // this.camera.aspect = window.innerWidth / window.innerHeight;
- // this.camera.updateProjectionMatrix();
- document.getElementById('canvas').appendChild(this.renderer.domElement)
- this.controls = new OrbitControls(this.camera, this.renderer.domElement)
- // this.renderer.domElement.style.height='390px'
- // this.renderer.domElement.style.width='50%'
-
- this.renderer.setClearColor(0xffffff); // 设置背景颜色为白色
- // this.loading()
- this.load('../../static/fbx/boy.fbx')
- this.render()
- },
- /**
- * 加载 FBX 模型
- */
-
- load(modelUrl) {
- let that = this
- // const loader = new FBXLoader(that.manager);
- const loader = new FBXLoader();
- loader.load(modelUrl, (fbx) => {
- console.log(fbx)
- fbx.scale.set(0.3, 0.3, 0.3)
-
- this.camera.lookAt(0, 0, 0)
-
- //模型居中
- const box = new THREE.Box3().setFromObject(fbx);
- const center = new THREE.Vector3();
- box.getCenter(center);
- fbx.position.sub(center);
- fbx.traverse((child) => {
- if (child.name == "Camera") {
- this.camera.position.set(child.position.x, child.position.y, child.position.z)
- }
- if (child.type == "PointLight") {
- child.intensity = 1
- }
- if (child.type == 'DirectionalLight') {
- child.intensity = 1
- }
- })
- //有动画的模型默认加载第一个动画
- if (fbx.animations.length != 0) {
- that.mixer = new THREE.AnimationMixer(fbx)
- const action = that.mixer.clipAction(fbx.animations[0])
- action.play()
- that.methse(fbx)
- }
- that.model = fbx
- that.scene.add(fbx);
- })
- },
- // 对象数据保存到数组中
- methse(fbx) {
- fbx.traverse((child) => {
- if (child instanceof THREE.Mesh) {
- this.meshes.push(child)
- }
- })
- },
- changeOld(num, path) {
- let that = this
- this.switching_model(num, path)
- },
- //页面回到默认
- hoMing() {
- this.camera.aspect = this.aspectOld;
- this.renderer.setSize(window.innerWidth, window.innerHeight)
- this.camera.updateProjectionMatrix(); //更新相机!!!
- },
- aler() {
- this.heightOld = window.innerHeight
- this.widthOld = window.innerWidth
- this.Newaspect = window.innerWidth / window.innerWidth
- this.camera = new THREE.PerspectiveCamera(20, window.innerWidth / window.innerHeight, 0.1, 10000);
- this.renderer = new THREE.WebGLRenderer({
- alpha: true,
- antialias: true
- })
- this.renderer.setSize(window.innerWidth, window.innerHeight)
- },
- changeClothes() {
- let that = this
- this.camera.aspect = this.Newaspect;
- this.renderer.setSize(this.widthOld, this.widthOld)
- this.camera.updateProjectionMatrix(); //更新相机!!!
- console.log(this.camera)
- // that.render()
- },
- //切换衣服
- switching_model(num, path) {
- const loader = new FBXLoader();
- let that = this
- loader.load(path, (newPants) => {
- that.model.traverse((child) => {
- if (child.name == num) {
- let newPantsGroup = null
- newPants.traverse((newchild) => {
- console.log(newchild.name)
- if (newchild.name == num) {
- newPantsGroup = newchild;
- }
- })
- console.log(newPantsGroup)
- child.material = newPantsGroup.material
- child.material.needsUpdate = true;
- }
-
- })
- that.renderer.render(that.scene, that.camera);
-
- }), undefined,
- function(error) {
- console.error(error);
- }, undefined,
- function(error) {
- console.error(error);
- }
- },
- /**
- * 执行渲染操作
- */
- render() {
- this.renderer.render(this.scene, this.camera)
- this.controls.update()
- requestAnimationFrame(this.render.bind(this))
- //更新动画
- if (this.mixer) {
- this.mixer.update(0.01)
- }
- }
- },
- mounted() {
- this.init()
- }
- }
- </script>
-
- <style lang="scss">
- #canvas {
- text-align: center;
- height: 100vh;
- display: flex;
- align-items: center;
- justify-content: center;
-
- }
- </style>
效果如下:
个人思路:
—————————————————————————————————————————
因为以后要换不同款式的衣服,有可能是裙子,短裤等,所以我替换的是模型的材质,如果只是固定的服装,只是颜色图案不同的话可以用最简单的替换贴图来解决。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。