3D可视化集装箱货柜模型开发 --threejs

教程效果实现效果

 

 

集装箱模型

箱子模型

 

中文文档:three.js docs

1.安装并 引入threejs 创建

安装threejs依赖包

npm install threejs 

在需要用的的代码文件里面引入threejs

import * as THREE from 'three'

2.实现3D模型最基础的渲染骨架部分

以下例子是在vue的项目里面实现一个简单的场景渲染,目前场景除了坐标轴并无其他物体
three 3D中,场景场景主要发:1.场景、2.摄像机、3.渲染器 3个主要模块,也就是每次在写3d模型的时候都需要在代码中出现这三部分的代码

<template>
  <div id="three"></div>
</template>
<script>
import * as THREE from 'three'
export default {
  name: 'fba3d',
  components: {},
  provide() {
    return {
      details: this
    }
  },
  mounted() {
    this.render3d()
  },
  methods: {
    render3d() {
      //1.场景
      var scene = new THREE.Scene()
      scene.background = new THREE.Color('#09152b')
      //2.摄像机
      var camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        1000
      )
      camera.position.set(500, 500, 500)
      camera.lookAt(0, 0, 0) //相机观察目标指向点

      // 其他内容部分       ==========  start  ==========

      // 轴 rgb (r红色表示:x轴,g绿色表示y轴,b蓝色表示z轴)
      const axesHelper = new THREE.AxesHelper(200)
      scene.add(axesHelper)

      // 其他内容部分       ==========   end   ==========

      // 3.渲染器
      var renderer = new THREE.WebGLRenderer()
      renderer.setSize(window.innerWidth, window.innerHeight)
      renderer.render(scene, camera) //渲染
      document.querySelector('#three').appendChild(renderer.domElement)
    }
  }
}
</script>
<style scopted>
#three {
  width: 100%;
  height: 100vh;
  background: #ccc;
}
</style>

3.在内容部分实现一个平面图和场景光

下图中实现了一个简单的平面,平面的颜色为绿色,但是目前还看到的平面是黑色。如果需要看到场景中的物体真实颜色和才材质,必须在场景中使用光源。类似我们在房间中放了一个物体,如果房间内没有开灯没有外部的光,那么那个物体呈现出来的效果就是黑色,什么都看不见。

<template>
  <div id="three"></div>
</template>
<script>
import * as THREE from 'three'
export default {
  name: 'fba3d',
  components: {},
  provide() {
    return {
      details: this
    }
  },
  mounted() {
    this.render3d()
  },
  methods: {
    render3d() {
      //1.场景
      var scene = new THREE.Scene()
      scene.background = new THREE.Color('#ffffff')
      //2.摄像机
      var camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        1000
      )
      camera.position.set(0, 0, 500)
      camera.lookAt(0, 0, 0) //相机观察目标指向点

      // 其他内容部分       ==========  start  ==========
      this.renderContent(scene)

      // 其他内容部分       ==========   end   ==========

      // 3.渲染器
      var renderer = new THREE.WebGLRenderer()
      renderer.setSize(window.innerWidth, window.innerHeight)
      renderer.render(scene, camera) //渲染
      document.querySelector('#three').appendChild(renderer.domElement)
    },
    renderContent(scene) {
      // 画坐标轴
      this.drawAxes(scene)
      // 画一个平面
      this.drawPlane(scene)
    },
    // 画坐标轴
    drawAxes(scene) {
      // 轴 rgb (r红色表示:x轴,g绿色表示y轴,b蓝色表示z轴)
      const axesHelper = new THREE.AxesHelper(200)
      scene.add(axesHelper)
    },

    drawPlane(scene) {
      const geometry = new THREE.PlaneGeometry(200, 150)
      let material = new THREE.MeshLambertMaterial({
        color: '#00ff00', //平面颜色 绿色
        opacity: 1
      })
      const plane = new THREE.Mesh(geometry, material)
      plane.position.set(0, 0, 0)
      scene.add(plane)
    }
  }
}
</script>
<style scopted>
#three {
  width: 100%;
  height: 100vh;
  background: #ccc;
}
</style>

添加光源效果

<template>
  <div id="three"></div>
</template>
<script>
import * as THREE from 'three'
export default {
  name: 'fba3d',
  components: {},
  provide() {
    return {
      details: this
    }
  },
  mounted() {
    this.render3d()
  },
  methods: {
    render3d() {
      //1.场景
      var scene = new THREE.Scene()
      scene.background = new THREE.Color('#ffffff')
      //2.摄像机
      var camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        1000
      )
      camera.position.set(0, 0, 500)
      camera.lookAt(0, 0, 0) //相机观察目标指向点

      // 其他内容部分       ==========  start  ==========
      this.renderContent(scene)

      // 其他内容部分       ==========   end   ==========

      // 3.渲染器
      var renderer = new THREE.WebGLRenderer()
      renderer.setSize(window.innerWidth, window.innerHeight)
      renderer.render(scene, camera) //渲染
      document.querySelector('#three').appendChild(renderer.domElement)
    },
    renderContent(scene) {
      // 画坐标轴
      this.drawAxes(scene)
      // 添加光源
      this.renderLight(scene)
      // 画一个平面
      this.drawPlane(scene)
    },
    // 画坐标轴
    drawAxes(scene) {
      // 轴 rgb (r红色表示:x轴,g绿色表示y轴,b蓝色表示z轴)
      const axesHelper = new THREE.AxesHelper(200)
      scene.add(axesHelper)
    },
    renderLight(scene) {
      // 光源m
      const AmbientLight = new THREE.AmbientLight(0xffffff)
      scene.add(AmbientLight)
      // 点光
      var light = new THREE.PointLight(0x000011, 30, 1000)
      light.position.set(500, 400, 500) //default; light shining from top
      scene.add(light)
      // 平行光
      const directionalLight = new THREE.DirectionalLight(0xffffff, 0.2)
      scene.add(directionalLight)
    },
    drawPlane(scene) {
      const geometry = new THREE.PlaneGeometry(200, 150)
      let material = new THREE.MeshLambertMaterial({
        color: '#00ff00', //平面颜色 绿色
        opacity: 1
      })
      const plane = new THREE.Mesh(geometry, material)
      plane.position.set(0, 0, 0)
      scene.add(plane)
    }
  }
}
</script>
<style scopted>
#three {
  width: 100%;
  height: 100vh;
  background: #ccc;
}
</style>

4.实现基础3D模型 与箱子纹理效果

// 画单个箱子
    drawBox(scene, box, axes, info) {
      let { l, w, h } = box
      let { x, y, z } = axes
      let geometry = new THREE.BoxGeometry(l, w, h)
      let material = new THREE.MeshLambertMaterial({
        color: '#ce9e6a',
        opacity: 1
      })
      let cube = new THREE.Mesh(geometry, material)
      cube.position.set(x, y, z)

      cube.boxType = 'BOX'
      cube.boxInfo = JSON.stringify(info)
      scene.add(cube)
    },
    //  圆立体
    drawSphere(scene) {
      // 球体网格模型
      var geometry2 = new THREE.SphereGeometry(20, 20, 20)
      var material2 = new THREE.MeshLambertMaterial({
        color: 0xfdd500
      })
      var mesh2 = new THREE.Mesh(geometry2, material2) //网格模型对象Mesh
      // 设置 坐标
      mesh2.position.set(200, 100, 100)
      scene.add(mesh2)
    }

盒子添加纹理效果

 

// 引入纹理图片
import boxwl from './img/box.jpg'

// 画单个箱子
    drawBox(scene, box, axes, info) {
      let { l, w, h } = box
      let { x, y, z } = axes
      let geometry = new THREE.BoxGeometry(l, w, h)
      // 箱子图片纹理
      let textureLoader = new THREE.TextureLoader()
      let plasterTexture = textureLoader.load(boxwl)

      let material = new THREE.MeshLambertMaterial({
        color: '#ce9e6a',
        // wireframe: true,
        map: plasterTexture,
        opacity: 1
      })
      let cube = new THREE.Mesh(geometry, material)
      cube.position.set(x, y, z)

      cube.boxType = 'BOX'
      cube.boxInfo = JSON.stringify(info)
      scene.add(cube)
    },

画箱子标签和顶部封口

 

// 纹理图片
import boxwl from './img/box.jpg'
//标签
import tagwl from './img/tag.png'
//箱子顶部
import boxTopwl from './img/boxtop.jpg'

    
// 创建一个平面 标签
    drawTagPlane(scene, box, axes) {
      let { l, h, w } = box
      let { x, y, z } = axes
      const geometry = new THREE.PlaneGeometry(20, 15)
      let textureLoader = new THREE.TextureLoader()
      let plasterTexture = textureLoader.load(tagwl)
      let material = new THREE.MeshLambertMaterial({
        map: plasterTexture,
        opacity: 1
      })
      const plane = new THREE.Mesh(geometry, material)
      plane.position.set(
        x + (l / 2 - 20) + 1,
        y - w / 2 + 10 + 1,
        z + h / 2 + 1.01
        // 100 - this.cabinetSize.h / 2 + 1
      ) // 偏移设置立方体坐标
      scene.add(plane)
    },
    // 创建一个平面 顶部封口
    drawTopPlane(scene, box, axes) {
      let { l, w, h } = box
      let { x, y, z } = axes
      const geometry = new THREE.PlaneGeometry(l, w)
      let textureLoader = new THREE.TextureLoader()
      let plasterTexture = textureLoader.load(boxTopwl)
      let material = new THREE.MeshLambertMaterial({
        color: '#ce9e6a',
        map: plasterTexture,
        opacity: 1
      })
      const plane = new THREE.Mesh(geometry, material)
      plane.rotateX(-Math.PI / 2) //旋转网格模型
      plane.position.set(x + 1, y + h / 2 + 0.01, z / 2 + 1) // 偏移设置立方体坐标
      scene.add(plane)
    },

纹理图片

 

集装箱实现

// 画集装箱
    drawContainer(scene, box, axes = { x: 0, y: 0, z: 0 }) {
      let { l, w, h } = box
      let { x, y, z } = axes
      var JGeometry = new THREE.BoxGeometry(l, w, h)
      // 箱子图片纹理
      let textureLoader = new THREE.TextureLoader()
      let plasterTexture = textureLoader.load(jzxwl)
      var jMmaterial = new THREE.MeshLambertMaterial({
        color: '#00229',
        transparent: true,
        opacity: 1,//透明度
        map: plasterTexture
      })
      var cube = new THREE.Mesh(JGeometry, jMmaterial)
      cube.position.set(x, y, z) // 设置立方体坐标
      cube.custType = 'jzx'
      scene.add(cube)
    },

5.添加工具

给场景添加 控制器,能随意切换拖拽物体角度观看

给外面集装箱添加透明度,能透视看到具体柜子消息

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

sceneControls(scene, camera, renderer) {
      // 控制器渲染
      var controls = new OrbitControls(camera, renderer.domElement)
      controls.addEventListener('change', function() {
        // 直接渲染
        renderer.render(scene, camera) //渲染
      })
    }

全部实现代码

<template>
  <div id="three"></div>
</template>
<script>
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'


// 纹理图片
import boxwl from './img/box.jpg'
import tagwl from './img/tag.png'
import boxTopwl from './img/boxtop.jpg'
import jzxwl from './img/jzx.jpg'
export default {
  name: 'fba3d',
  components: {},
  provide() {
    return {
      details: this
    }
  },
  mounted() {
    this.render3d()
  },
  methods: {
    render3d() {
      //1.场景
      var scene = new THREE.Scene()
      scene.background = new THREE.Color('#ffffff')
      //2.摄像机
      var camera = new THREE.PerspectiveCamera(
        45,
        window.innerWidth / window.innerHeight,
        1,
        1000
      )
      // 摄像机摆放位置
      camera.position.set(500, 500, 500)
      camera.lookAt(0, 0, 0) //相机观察目标指向点


      // 其他内容部分       ==========  start  ==========
      this.renderContent(scene)


      // 其他内容部分       ==========   end   ==========


      // 3.渲染器
      var renderer = new THREE.WebGLRenderer()
      renderer.setSize(window.innerWidth, window.innerHeight)
      setTimeout(() => {
        renderer.render(scene, camera) //渲染
      }, 100)
      document.querySelector('#three').appendChild(renderer.domElement)


      // 控制器
      this.sceneControls(scene, camera, renderer)
    },
    renderContent(scene) {
      // 画坐标轴
      // this.drawAxes(scene)
      // 添加光源
      this.renderLight(scene)
      // 画一个平面
      // this.drawPlane(scene)
      // 画一个3D立体 正方形
      this.drawBox(
        scene,
        { l: 100, w: 100, h: 100 },
        { x: 0, y: 0, z: 0 },
        { id: '001' }
      )
      // 集装箱
      this.drawContainer(scene, { l: 450, w: 200, h: 200 })
      // this.drawSphere(scene)
    },
    // 画坐标轴
    drawAxes(scene) {
      // 轴 rgb (r红色表示:x轴,g绿色表示y轴,b蓝色表示z轴)
      const axesHelper = new THREE.AxesHelper(200)
      scene.add(axesHelper)
    },
    renderLight(scene) {
      // 光源m
      const AmbientLight = new THREE.AmbientLight(0xffffff)
      scene.add(AmbientLight)
      // 点光
      var light = new THREE.PointLight('#ffffff', 0, 1)
      light.position.set(200, 200, 200) //default; light shining from top
      scene.add(light)
      // 平行光
      // const directionalLight = new THREE.DirectionalLight(0xffffff, 0.2)
      // scene.add(directionalLight)
    },
    drawPlane(scene) {
      const geometry = new THREE.PlaneGeometry(200, 150)
      let material = new THREE.MeshLambertMaterial({
        color: '#00ff00', //平面颜色 绿色
        opacity: 1
      })
      const plane = new THREE.Mesh(geometry, material)
      plane.position.set(0, 0, 0)
      scene.add(plane)
    },
    // 画单个箱子
    drawBox(scene, box, axes, info) {
      let { l, w, h } = box
      let { x, y, z } = axes
      let geometry = new THREE.BoxGeometry(l, w, h)
      // 箱子图片纹理
      let textureLoader = new THREE.TextureLoader()
      let plasterTexture = textureLoader.load(boxwl)


      let material = new THREE.MeshLambertMaterial({
        color: '#ce9e6a',
        // wireframe: true,
        map: plasterTexture,
        opacity: 1
      })


      // 根据箱子画出响应 标签
      this.drawTagPlane(scene, box, axes)
      // 箱子顶部封口
      this.drawTopPlane(scene, box, axes)
      let cube = new THREE.Mesh(geometry, material)
      cube.position.set(x, y, z)


      cube.boxType = 'BOX'
      cube.boxInfo = JSON.stringify(info)
      scene.add(cube)
    },
    // 画集装箱
    drawContainer(scene, box, axes = { x: 0, y: 0, z: 0 }) {
      let { l, w, h } = box
      let { x, y, z } = axes
      var JGeometry = new THREE.BoxGeometry(l, w, h)
      // 箱子图片纹理
      let textureLoader = new THREE.TextureLoader()
      let plasterTexture = textureLoader.load(jzxwl)
      var jMmaterial = new THREE.MeshLambertMaterial({
        color: '#00229',
        transparent: true,
        opacity: 0.6,
        map: plasterTexture
      })
      var cube = new THREE.Mesh(JGeometry, jMmaterial)
      cube.position.set(x, y, z) // 设置立方体坐标
      cube.custType = 'jzx'
      scene.add(cube)
    },
    // 创建一个平面 标签
    drawTagPlane(scene, box, axes) {
      let { l, h, w } = box
      let { x, y, z } = axes
      const geometry = new THREE.PlaneGeometry(20, 15)
      let textureLoader = new THREE.TextureLoader()
      let plasterTexture = textureLoader.load(tagwl)
      let material = new THREE.MeshLambertMaterial({
        map: plasterTexture,
        opacity: 1
      })
      const plane = new THREE.Mesh(geometry, material)
      plane.position.set(
        x + (l / 2 - 20) + 1,
        y - w / 2 + 10 + 1,
        z + h / 2 + 1.01
        // 100 - this.cabinetSize.h / 2 + 1
      ) // 偏移设置立方体坐标
      scene.add(plane)
    },
    // 创建一个平面 顶部封口
    drawTopPlane(scene, box, axes) {
      let { l, w, h } = box
      let { x, y, z } = axes
      const geometry = new THREE.PlaneGeometry(l, w)
      let textureLoader = new THREE.TextureLoader()
      let plasterTexture = textureLoader.load(boxTopwl)
      let material = new THREE.MeshLambertMaterial({
        color: '#ce9e6a',
        map: plasterTexture,
        opacity: 1
      })
      const plane = new THREE.Mesh(geometry, material)
      plane.rotateX(-Math.PI / 2) //旋转网格模型
      plane.position.set(x + 1, y + h / 2 + 0.01, z / 2 + 1) // 偏移设置立方体坐标
      scene.add(plane)
    },
    //  圆立体
    drawSphere(scene) {
      // 球体网格模型
      var geometry2 = new THREE.SphereGeometry(20, 20, 20)
      var material2 = new THREE.MeshLambertMaterial({
        color: 0xfdd500
      })
      var mesh2 = new THREE.Mesh(geometry2, material2) //网格模型对象Mesh
      // 设置 坐标
      mesh2.position.set(200, 100, 100)
      scene.add(mesh2)
    },
    sceneControls(scene, camera, renderer) {
      // 控制器渲染
      var controls = new OrbitControls(camera, renderer.domElement)
      controls.addEventListener('change', function() {
        // 直接渲染
        renderer.render(scene, camera) //渲染
      })
    }
  }
}
</script>
<style scopted>
#three {
  width: 100%;
  height: 100vh;
  background: #ccc;
}
</style>

6.监听点击效果

// 监听点击到的箱子
    listenerClickBox(scene, camera, renderer) {
      let that = this
      const raycaster = new THREE.Raycaster()
      const mouse = new THREE.Vector2()
      window.addEventListener('click', async event => {
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
        raycaster.setFromCamera(mouse, camera)
        let result = []
        let sceneChildren = scene.children


        // result是被点击到的所有 物体
        // 可以通过之前箱子标记的类型来判断点击到的物体
        result = raycaster.intersectObjects(sceneChildren)


        let curr = ''
        // 获取第一个被点击到的箱子
        for (let i = 0; i < result.length; i++) {
          if (result[i].object && result[i].object?.boxType == 'BOX') {
            if (curr == '') {
              curr = i
            }
          }
        }
      })
    }

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
1. 准备OBJ校园模型文件 首先,需要准备一个校园模型的OBJ文件,可以使用3D建模软件(如Blender)制作,也可以从网上找到已有的OBJ文件。 2. 引入three.js库文件 在HTML文件中引入three.js库文件,可以通过以下方式: ```html <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> ``` 3. 创建场景、相机和渲染器 ```javascript // 创建场景 var scene = new THREE.Scene(); // 创建相机 var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 0, 10); // 创建渲染器 var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); ``` 4. 加载OBJ文件 使用THREE.OBJLoader()加载OBJ文件,并将其添加到场景中: ```javascript // 加载OBJ文件 var loader = new THREE.OBJLoader(); loader.load('path/to/campus.obj', function (object) { scene.add(object); }); ``` 5. 其他设置 可以设置一些其他的属性,如光照和控制器等: ```javascript // 添加光照 var light = new THREE.PointLight(0xffffff, 1, 100); light.position.set(0, 0, 50); scene.add(light); // 添加控制器 var controls = new THREE.OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.25; controls.enableZoom = true; // 渲染场景 function render() { requestAnimationFrame(render); renderer.render(scene, camera); controls.update(); } render(); ``` 完成以上步骤,就可以在浏览器中看到导入的OBJ校园模型了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值