vue 2 中混入threejs 基本版(一)

4,469 阅读10分钟

前言

很多小伙伴不知道vue中怎么写入js 这其实是由一些门道的 【大家不用着急】很快你就能使用这些简单指令完成一个 基本的threejs 小项目

完整的项目demo

先看一下效果图

image.png

这就是最终的效果 好像看起来并不是一个复杂的东西 没错 所有的东西都是由简单到复杂的

我不想先讲threejs那些理论和图 我打算混到这篇文章里,这样有助与理解这个项目,首先先准备工作 生成一个vue的脚手架 如果你还不会生成没关系,你可以先看vuecli的官方教程 自己安装vue生成一个 也可以参考别人写的博客

安装

命令行工具 必须先安装vue 有版本号

blog.csdn.net/fengzhen802…

这篇文章是讲怎么安装vue的

vue-V

vue init webpack my-app

完成了一个vue脚手架

npm安装 vue-template-compiler three

npm i three

npm i vue-template-compiler

核心的实现代码

先把代码放到这里 这里我就会一断一断讲这个

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

export default {
  name: 'ThreeTest',
  data() {
    return {
      camera: null,
      scene: null,
      renderer: null,
      mesh: null,
      controls:null,
      meshCar:null
    }
  },
  methods: {
    init: function() {
        /**
     * 创建场景对象Scene
     */
    this.scene = new THREE.Scene();
    /**
     * 创建网格模型
     */
    // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
    const geometryCar= new THREE.CylinderGeometry(50,50,100,25)
    const geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry
    const material = new THREE.MeshLambertMaterial({
      color: 0x0000ff,
      opacity:0.7,
      // transparent:true,
      // wireframe:true,
      specular:0x4488ee,
      shininess:12
    }); //材质对象Material
    this.mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
    this.meshCar=new THREE.Mesh(geometryCar,material)
    this.meshCar.position.set(250,0,0)
    this.scene.add(this.mesh); //网格模型添加到场景中
    this.scene.add(this.meshCar); 
    /**
     * 光源设置
     */
    //点光源
    const point = new THREE.PointLight(0xffffff);
    point.position.set(400, 200, 300); //点光源位置
    this.scene.add(point); //点光源添加到场景中
     //环境光
    const ambient = new THREE.AmbientLight(0x444444);
    this.scene.add(ambient);
    // console.log(scene)
    // console.log(scene.children)
    /**
     * 相机设置
     */
    const width = window.innerWidth; //窗口宽度
    const height = window.innerHeight; //窗口高度
    const k = width / height; //窗口宽高比
    const s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
    //创建相机对象
    this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
    this.camera.position.set(200, 300, 200); //设置相机位置
    this.camera.lookAt(this.scene.position); //设置相机方向(指向的场景对象)
    /**
     * 创建渲染器对象
     */
    this.renderer = new THREE.WebGLRenderer();
    this.renderer.setSize(width, height);//设置渲染区域尺寸
    this.renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
    document.body.appendChild(this.renderer.domElement); //body元素中插入canvas对象
    //执行渲染操作   指定场景、相机作为参数
    this.controls = new OrbitControls(this.camera,this.renderer.domElement);//创建控件对象
    // this.controls.addEventListener('change', this.render);
    // renderer.render(scene, camera);

    // 辅助坐标系  参数250表示坐标系大小,可以根据场景大小去设置
    const axisHelper = new THREE.AxisHelper(250);
    this.scene.add(axisHelper);
    },
    render() {
        this.renderer.render(this.scene,this.camera);//执行渲染操作
        this.mesh.rotateY(-0.01);//每次绕y轴旋转0.01弧度
        requestAnimationFrame(this.render);//请求再次执行渲染函数render
        
    }
  },
  mounted() {
      this.init();
      this.render()
  }
}
</script>
<style scoped>
  #container {
    height: 400px;
  }
</style>

————————————— 续更 2021-06-12

直接讲js部分吧 其他部分也没什么好讲的

1.引入部分

import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

这部分是引入three的 引入必须要使用 * as 千万不能用import THREE from 'three' 否则会报错 然后下面的是引用鼠标控制3D模块的插件, 当然这个工具是threejs 这个包里面已经有的 直接把他引出来用就可以了 如果你直接想用 new THREE.OrbitControls() 这样用不行哦, 这个方法并没有添加到three的方法里面

2.设置核心变量

export default {
 name: 'ThreeTest',
  data() {
    return {
      camera: null, // 相机
      scene: null,  // 场景
      renderer: null, // 渲染器
      mesh: null, // 模型1
      controls:null,  // 鼠标控制
      meshCar:null // 模型2
    }
    
    // todo (下面的先不急着讲)
    }

如注释所写,这些变量是一个基础3D模型里必不可少的,看着这个代码插入一些小知识,threejs的渲染的三个必不可少的东西

整个程序的结构

image.png

对比一下之前的代码 是不是清晰很多了? 而这里的代码将打开three的魅力 能让你更好的了解他

等会继续更

2021-6-14(今天端午节)

没人提点意见吗?我写的好没有动力啊 烦请小编继续给我置顶,这个系列我想从入门开始做到精通

3.(methods方法 模型创建)threejs创建

不知道大家对vue熟悉不熟悉,真怕大家不会,methods是vue提供写方法的地方

现在上代码

export default {
   // ....
   //  todo
  methods: {
    init: function() {
        /**
     * 创建场景对象Scene
     */
    this.scene = new THREE.Scene();
    /**
     * 创建网格模型
     */
    // var geometry = new THREE.SphereGeometry(60, 40, 40); //创建一个球体几何对象
    const geometryCar= new THREE.CylinderGeometry(50,50,100,25)
    const geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry
    const material = new THREE.MeshLambertMaterial({
      color: 0x0000ff,
      opacity:0.7,
      // transparent:true,
      // wireframe:true,
      specular:0x4488ee,
      shininess:12
    }); //材质对象Material
    this.mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
    this.meshCar=new THREE.Mesh(geometryCar,material)
    this.meshCar.position.set(250,0,0)
    this.scene.add(this.mesh); //网格模型添加到场景中
    this.scene.add(this.meshCar); 
    
    // ...todo 
    }
    }

这个todo 就代表还有上下文,这段代码是介绍场景的 我写的 init() 方法是为了生成初始场景的这样,这个init()方法还有下文啊 new THREE.Scene()是直接通过three new出来一个新的场景 ,这个时候你们不知道 new就该打屁股了,赶紧去复习一下 项目中用了很多new

this.scene = new THREE.Scene(); 是把生成的场景挂载到this.scene,这样就可以通过响应式的方式去访问它,我会用这种方式去处理three生成的代码,所以大家务必知道这个思路,用好一个框架真的可以事半功倍。

接下来生成模型,大家可以看到我用的const 而不是 var 这个也请大家注意一下,我们写代码一定要规范,不能想用什么就用什么,习惯用var后,将可能对团队带来麻烦,如果不清楚两者的区别,也请仔细百度一下 这边只是想让大家规范代码

    const geometryCar= new THREE.CylinderGeometry(50,50,100,25)
    const geometry = new THREE.BoxGeometry(100, 100, 100); //创建一个立方体几何对象Geometry

就是这么生成一个模型的,看起来非常的简单实用,这边详情讲一下这个api的用法

BoxGeometry()这个方法里面几个参数 用法参照下面的自己填写就好了

BoxGeometry(width : Float, height : Float, depth : Float, widthSegments : Integer, heightSegments : Integer, depthSegments : Integer)
width — X轴上面的宽度,默认值为1。
height — Y轴上面的高度,默认值为1。
depth — Z轴上面的深度,默认值为1。
widthSegments — (可选)宽度的分段数,默认值是1。
heightSegments — (可选)宽度的分段数,默认值是1。
depthSegments — (可选)宽度的分段数,默认值是1

按照如上的顺序依次填写参数就可以使用

如果还想知道更多的直接去three的文档里找吧

threejs文档:www.yanhuangxueyuan.com/threejs/doc…

这里给你们列个表格吧

API生成模型用列
BoxGeometry()长方体new THREE.BoxGeometry(100, 100, 100)
SphereGeometry()球体new THREE.SphereGeometry(60, 40, 40)
CylinderGeometry()圆柱new THREE.CylinderGeometry( 50, 50, 100, 25 )
OctahedronGeometry()正八面体new THREE.OctahedronGeometry(50)
DodecahedronGeometry()正十二面体new THREE.DodecahedronGeometry(50)
IcosahedronGeometry()正二十面体new THREE.IcosahedronGeometry(50)

当然你可以自定义形状

下次在更吧 先这样


2021-06-16(杭州下雨了,好大的雨)

换了一种代码高亮格式,怕你们看不清楚

接下半部分,讲完模型就可以讲讲应用材质了,材质就是下面这行

    const material = new THREE.MeshLambertMaterial({
      color: 0x0000ff,
      opacity:0.7,
      // transparent:true,
      // wireframe:true,
      specular:0x4488ee,
      shininess:12
    }); //材质对象Material

熟悉css的看里面配置的属性就不会陌生,颜色color 透明度opacity 还有其他的属性,怕有些人理解起来困难就先将这些,反正这些也够用了,我后续会补充的,直接通过MeshLambertMaterial three里面的材质方法 生成这个 material 这个材质接创建好了 意思就是这个物体现在颜色是蓝色 处于透明状态0.7,大家可以用这个属性调出蓝色的水母的颜色,后续会做一个出来

    this.mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
    this.meshCar=new THREE.Mesh(geometryCar,material)
    this.meshCar.position.set(250,0,0) // 将模型定位在离中心位置X轴250 的位置
    this.scene.add(this.mesh); //网格模型添加到场景中
    this.scene.add(this.meshCar); 

这边我生成了两个模型,都是直接将生成的模型类别和材质添加进去的,然后将模型挂载到场景里面,这部分代码很好理解

4. (methods方法 添加光源)threejs创建

    /**
     * 光源设置
     */
    //点光源
    const point = new THREE.PointLight(0xffffff);
    point.position.set(400, 200, 300); //点光源位置
    this.scene.add(point); //点光源添加到场景中
     //环境光
    const ambient = new THREE.AmbientLight(0x444444);
    this.scene.add(ambient);

这部分和添加模型差不多,就是周围的光源设置,环境光顾名思义就是周围环境通过漫反射产生的光,点光源就是从场景中的一个位置发出的散射光,这部分也很好理解,相信大家的物理都学得不错,你可以改变光的明暗来调整模型的亮度 const ambient = new THREE.AmbientLight(0x444444);比如直接从环境光入手改成 0x888888 会发现模型亮度变的很大

image.png

image.png

5.(methods方法 相机创建)threejs创建

  /**
     * 相机设置
     */
    const width = window.innerWidth; //窗口宽度
    const height = window.innerHeight; //窗口高度
    const k = width / height; //窗口宽高比
    const s = 200; //三维场景显示范围控制系数,系数越大,显示的范围越大
    //创建相机对象
    this.camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
    this.camera.position.set(200, 300, 200); //设置相机位置
    this.camera.lookAt(this.scene.position); //设置相机方向(指向的场景对象)

创建相机找个就有点小小的技巧了,数学学的好的人很容易理解相机的摆放位置,这里讲一下 OrthographicCamera这个API

正投影相机 OrthographicCamera

image.png

生活中的物体都是三维的,但是人的眼睛只能看到正面,不能看到被遮挡的背面,三维几何体在人眼睛中的效果就像一张相机拍摄的二维照片,你看到的是一个2D的投影图。 空间几何体转化为一个二维图的过程就是投影,不同的投影方式意味着投影尺寸不同的算法。

这个定义有点难懂啊,不理解的可以仔细阅读这段话,并认真查看这个图片

这个图片看完了可以看一下这篇文章 这样你就更加容易理解相机是个什么东西了 www.cnblogs.com/gaozhiqiang…

穿插优秀文章会让读者更容易理解,也算为优秀作者引流了

this.camera.position.set(200, 300, 200); //设置相机位置 这个就是将相机设置在x,y,z的方向上,这样就可以看清楚模型的具体位置了,要不相机就在原点处加载了,也就是this.camera.position.set(0, 0, 0); 相机直接就加载进模型里面了。但别忘了 this.camera.lookAt(this.scene.position); //设置相机方向(指向的场景对象) 要不还是看不到模型

6.(methods方法 渲染器创建)

   /**
     * 创建渲染器对象
     */
    this.renderer = new THREE.WebGLRenderer();
    this.renderer.setSize(width, height);//设置渲染区域尺寸
    this.renderer.setClearColor(0xb9d3ff, 1); //设置背景颜色
    document.body.appendChild(this.renderer.domElement); //body元素中插入canvas对象
    //执行渲染操作   指定场景、相机作为参数
    this.controls = new OrbitControls(this.camera,this.renderer.domElement);//创建控件对象
    // this.controls.addEventListener('change', this.render);
    // renderer.render(scene, camera);

this.renderer = new THREE.WebGLRenderer();threejs的渲染模式是建立在webGL上的,所以这样引用创建,而其他代码我相信大家可以读懂,都是操作一些简单的

轨道控制器

this.controls = new OrbitControls(this.camera,this.renderer.domElement);//创建控件对象 这个轨道控制器通俗的理解就是你可以用鼠标拖拉移动了,当然它的玩法不止这些,在后续的文中我会一一介绍,鼠标左键点击旋转,右键拖动,滚轮放大缩小场景这些基本的功能

7.其他(一些小功能)

这篇文章总算是到头了,想必各位肯定是有收获的,也就剩下一个坐标系和 render了,当然别写了一大堆忘了mounted生命周期执行方法


    // 辅助坐标系  参数250表示坐标系大小,可以根据场景大小去设置
    const axisHelper = new THREE.AxisHelper(250);
    this.scene.add(axisHelper);

这个写好就有如图的坐标系,这个纯属辅助理解这些模块都在什么位置

 render() {
        this.renderer.render(this.scene,this.camera);//执行渲染操作
        this.mesh.rotateY(-0.01);//每次绕y轴旋转0.01弧度
        requestAnimationFrame(this.render);//请求再次执行渲染函数render
        
    }

这个函数是执行之前的模型渲染器的,被称为开关 requestAnimationFrame是一个动画执行api,js自带的,这样反复执行render函数就可以达到渲染效果了,你们可以看到 this.mesh.rotateY(-0.01);//每次绕y轴旋转0.01弧度正方体旋转了

 mounted() {
      this.init();
      this.render()
  }

挂载需要在vue模块中执行的方法,嗯嗯,终于讲完了,这篇文章真的是干货满满,下一篇文章就要提升难度了,希望各位不要从入门到放弃啊,要从入门到精通再到神

学习本项目

项目地址:github.com/gao-junfeng…

安装的时候要注意,需要安装 vue-template-compiler 这个工具是可以让threejs在vue中运行的插件 这个必须要安装 注意版本号 一定要更vue的版本保持一致 ,否则会报错

` vue@2.6.13

`- vue-template-compiler@2.6.14

`This may cause things to work incorrectly. Make sure to use the same version for both. If you are using vue-loader@>=10.0, simply update vue-template-compiler. If you are using vue-loader@<10.0 or vueify, re-installing vue-loader/vueify should bump vue-template-compiler to the latest.```

说的就是vue@2.6.13 和 vue-template-compiler@2.6.14 的版本不一致

安装的时候最好用cnpm 安装 不清楚的可以百度一下cnpm 是怎么用的