“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第3篇文章,点击查看活动详情”
一、前言
昨天(雾)我们已经创建好项目了,本文我们先配置一下插件工具,然后再看下vue3如何引入threejs,
二、 配置工具插件
俗话说,工欲善其事必先利其器,优秀的提示可以造就我们良好的代码规范。
所以今天来配置下一些插件工具,一共是eslint、volar、TypeLens。
eslint负责代码规范,vite创建的项目需要额外配置一下,同时要支持ts
eslint步骤略长一些,下面单独拎出来讲。
volar代替vetur给我们提供语法支持(两者不兼容,vue3用volar,vue2用vetur,可打开插件配置进行禁用)
TypeLens可以显示每个函数的调用次数,在清除旧代码屎山的时候,很有用!
volar和TypeLens的配置比较简单,就合并一起讲了
1、eslint
安装eslint
npm i -D eslint
初始化配置,接下来按提示选择即可
npx eslint --init
a、选择模式 此处选用第三个严格模式
b、选择语言模块 此处选用javascript
c、选择语言框架 此处选用vue.js
d、使用ts, 选择yes
e、代码运行范围 空格全选 浏览器browser+node
f、选择风格 popular就行
g、风格指南 选standard
h、配置文件格式 选js
i、有出现下面就选yes
j、选npm安装
安装完成后会在根目录生成.eslintrc.cjs文件,先不管,继续安装
npm i -D vite-plugin-eslint
npm i @babel/eslint-parser
然后配置一下.eslintrc.cjs
// .eslintrc.js 文件
module.exports = {
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'standard',
// 新增这里vue3支持,关键
'plugin:vue/vue3-recommended'
],
// 新的内容
parserOptions: {
ecmaVersion: 6,
sourceType: 'module',
ecmaFeatures: {
modules: true
},
requireConfigFile: false
// parser: '@babel/eslint-parser' // 会报错就不要了
},
plugins: [
'vue'
],
rules: {
semi: [2, 'never'], // 禁止尾部使用分号“ ; ”
'no-var': 'error', // 禁止使用 var
indent: ['error', 2], // 缩进2格
'no-mixed-spaces-and-tabs': 'error', // 不能空格与tab混用
quotes: [2, 'single'], // 使用单引号
'vue/html-closing-bracket-newline': 'off', // 不强制换行
'vue/singleline-html-element-content-newline': 'off', // 不强制换行
'vue/max-attributes-per-line': ['error', {
singleline: { max: 5 },
multiline: { max: 5 }
}] // vue template模板元素第一行最多5个属性
// 其它的规则可以去eslint查看,根据自己需要进行添加
}
}
到这里就完成eslint的配置了。
2、volar和typeLens
(1)volar
很重要,再提醒一遍,vue3项目,记得先关闭vetur插件(vue2用的)!
很重要,再提醒一遍,vue3项目,记得先关闭vetur插件(vue2用的)!
很重要,再提醒一遍,vue3项目,记得先关闭vetur插件(vue2用的)!
打开vscode扩展 快捷键 ctrl+shift+x
直接搜索volar,这个骷髅头的就是啦
安装之后可以打开配置项
第一步检查这三个trace是否为off状态,这三个无意义(暂时),而且很占网络,会卡顿
第二步,配置快捷折叠
在setting.json里配置
// 左侧不折叠的标签,其余标签会折叠
"volar.splitEditors.layout.left": [
"template",
"script",
"scriptSetup",
],
// 右侧不折叠的标签,其余标签会折叠
"volar.splitEditors.layout.right": [
"styles",
"customBlocks"
],
然后点击这个小图标就可以自动全部折叠了
第三步,配置ref自动补全
确保下面这个auto complete refs是勾选状态
(2)typeLens
直接搜索下载安装即可,这个见仁见智,建议是配置完后再开启
三、 引入静态图片的方式
1、试试import引入
const imgurl1 = import('../assets/demo.png')
// 采用vue2的常规方式,import引入,且为相对路径
我是在3ddemo.vue文件使用的,所以这个import起始地址为src/components/
没有报错,但是
网页元素也是无法正常解析
2、 试试require引入
const imgurl2 = require('../assets/demo.png')
根据报错提示,安装对应依赖
npm i --save-dev @types/node
控制台不报错了,但是波浪线已经报not found
// 尝试加上default
const imgurl2 = require('../assets/demo.png').default
还是不能正常引入。
后续查了一下,这里的require似乎是webpack提供的api,但我们项目是用的vite构建的,所以不具备。
哈哈骗你们一手。
3、直接当文件引入
import imgurl3 from "../assets/demo.png";
也可以正常引入,src里是路径,不带ip和端口
4、采用new URL(url, import.meta.url).href (vite引入静态图片推荐方式)
const imgurl = new URL('../assets/demo.png', import.meta.url).href
也是相对路径引入
这次是能够正常解析了,src里是ip端口+路径
5、贴个简单的代码
<script setup lang="ts">
import { ref } from 'vue'
import imgurl3 from "../assets/demo.png" // 当文件引入
defineProps<{ msg: string }> (
)
const imgurl = new URL('../assets/demo.png', import.meta.url).href // vite推荐的静态资源引入方式
const imgurl1 = import('../assets/demo.png') // import引入的另一种方式
// const imgurl2 = require('../assets/demo.png').default // require报错,不推荐
</script>
<template>
<div>
threejs3d场景
</div>
<div>
<img :src="imgurl3" alt="">
</div>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>
四、 引入threejs并简单加载mode
1、引入
下面是引入的文件和对应用途,不过ts里使用第三方库比较麻烦(是我暂时还没找到方法┭┮﹏┭┮)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- threejs基本库three.min.js -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/build/three.min.js"></script>
<!-- threejs轨道控制器 orbitControls.js -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/controls/OrbitControls.js"></script>
<!-- 加载器 用于加载 .obj 资源的加载器 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/loaders/OBJLoader.js"></script>
<!-- 加载器 用于加载 .fbx 资源的加载器 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/loaders/FBXLoader.js"></script>
<!-- fbx的依赖 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/libs/inflate.min.js"></script>
<!-- 加载器 用于加载 .gltf 资源的加载器 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/loaders/gltfLoader.js"></script>
<!-- 加载器 用于加载 .mtl 资源的加载器 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/loaders/MTLLoader.js"></script>
<!-- 使用 Draco 库压缩的几何图形加载器 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/loaders/DRACOLoader.js"></script>
<!-- CSS2DRenderer是CSS3DRenderer(CSS 3D渲染器)的简化版本,唯一支持的变换是位移 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/renderers/CSS2DRenderer.js"></script>
<!-- 效果合成器 用于在three.js中实现后期处理效果 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/postprocessing/EffectComposer.js"></script>
<!-- RenderPass.js 可以用来在EffectComposer对象上添加渲染通道 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/postprocessing/RenderPass.js"></script>
<!-- shaderPass.js 用来自定义后期 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/postprocessing/ShaderPass.js"></script>
<!-- copyShader.js 是threejs的内置着色器包 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/shaders/CopyShader.js"></script>
<!-- outlinePass.js 后期处理用,物体边界线条高亮处理 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/postprocessing/OutlinePass.js"></script>
<!-- 主要解决锯齿问题 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/shaders/FXAAShader.js"></script>
<!-- 镜头炫光效果 -->
<script src="http://www.yanhuangxueyuan.com/versions/threejsR92/examples/js/objects/Lensflare.js"></script>
<title>Vite + Vue + TS</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
所以本文采用npm安装的方式,因为是ts所以不是npm install three了
npm install --save @types/three
下载后,要在src文件夹下找到一个.d.ts结尾的文件,我的项目里叫vite-env.d.ts,添加
declare module "@types/three";
然后就可以在项目文件里
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls" // 轨道控制器
// 基本就是后缀在上面的html文件里是一样的,按需引用就好
报错消失了,功能也能正常引入和使用了。
ts似乎还有个抛出全局变量的功能,等后续我琢磨琢磨
2、 使用threejs
最近接触了一些类的写法,今天就用这种方式来带大家调用一下
首先是在vue文件里创建好对应元素设置好宽高,本文是宽1000px,高800px,一般是窗口宽高的,看个人需求吧
<div id="three3d" style="height: 800px;width: 1000px;" />
然后引入我们打算撰写的three.ts文件,这里包含具体初始化和加载逻辑,如果是vue文件需要补充.vue后缀,如果是ts则不用。
import ThreeJsClass from './three'
之后是在onMounted周期里,先创建该类,然后将dom元素的id传递过去,并执行初始化函数
onMounted(() => {
const theejs = new ThreeJsClass()
theejs.setDomId('three3d')
theejs.init()
})
贴个完整的代码
<script setup lang="ts">
import { onMounted } from 'vue'
import ThreeJsClass from './three'
const props = defineProps({
msg: {
type: String,
default: () => { return '测试信息' }
}
})
onMounted(() => {
const theejs = new ThreeJsClass()
theejs.setDomId('three3d')
theejs.init()
})
console.log(props.msg)
</script>
<template>
<!-- threejs要绑定的元素,宽1000px,高800px -->
<div id="three3d" style="height: 800px;width: 1000px;" />
</template>
<style scoped lang="scss">
</style>
3、加载
先看看最终效果,没报错,成功引入图片作为纹理贴到物品上
下面,首先我已经将model放置到public文件夹
然后在同级目录,创建three.ts文件,用来放具体的逻辑
基本就是新建场景scene,新建相机camera,创建渲染器render,
相机和渲染器都需要知道尺寸(本文是宽1000px,高800px),
渲染器还需要知道元素dom,才能绑定到一起(这就是前面我额外传递元素id的原因),
创建灯光并添加到场景,不然黑漆漆的也不知道成功没有,
接下来是引入轨道控制器,方便旋转,
最后才是生成模型和调用requestAnimationFrame实时刷新。
直接放源码吧,基本写法没多大差别
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"
export default class ThreeJsClass {
scene: THREE.Scene | null = null;
camera: THREE.PerspectiveCamera | null = null;
renderer: THREE.WebGLRenderer | null = null;
ambientLight: THREE.AmbientLight | null = null;
mesh: THREE.Mesh | null = null;
domId: '' | string = '';
// 需要提前写好变量,才能用this指向到
constructor() {
// this.init();
// 默认执行的,但由于元素id此时未绑定,渲染会出问题,故不用此
}
setDomId(id:string):void {
this.domId = id
console.log(this.domId)
}
init(): void {
// 第一步新建一个场景
this.scene = new THREE.Scene()
this.setCamera() // 设置相机
this.setLight() // 设置灯光
this.setRenderer() // 设置渲染器
this.setControls() // 设置轨道控制器
this.animate() // 刷新
this.setCube() // 生成物品
}
// 新建透视相机
setCamera(): void {
// 第二参数就是 长度和宽度比 我的元素是w:1000px h:800px 返回以像素为单位的窗口的内部宽度和高度
this.camera = new THREE.PerspectiveCamera(
75,
1000 / 800,
0.1,
1000
);
this.camera.position.set(2, 1, 3)
this.camera.lookAt(10, 100, 10)
this.scene.add(this.camera)
}
// 设置渲染器
setRenderer(): void {
this.renderer = new THREE.WebGLRenderer();
// 设置画布的大小
this.renderer.setSize(1000, 800);
//这里 其实就是canvas 画布 renderer.domElement
// document.body.appendChild(this.renderer.domElement);
if(this.domId) {
document.getElementById(this.domId).appendChild(this.renderer.domElement)
}
}
// 设置环境光
setLight(): void {
if (this.scene) {
this.ambientLight = new THREE.AmbientLight(0xffffff); // 环境光
this.scene.add(this.ambientLight);
// 聚光灯光源
const dirLight = new THREE.SpotLight(0xffffff)
dirLight.position.set(0, 0, 100)
dirLight.intensity = 1.5 // 强度
dirLight.castShadow = true
dirLight.shadow.mapSize.width = 2048 // 暗影贴图宽度设置为2048像素
dirLight.shadow.mapSize.height = 2048 // 暗影贴图高度设置为2048像素
this.scene.add(dirLight)
const spotLightHelper = new THREE.SpotLightHelper(dirLight)
this.scene.add(spotLightHelper)
// 聚光灯光源
const dirLight1 = new THREE.SpotLight(0xffffff)
dirLight1.position.set(100, 0, 100)
dirLight1.intensity = 1.5 // 强度
dirLight1.castShadow = true
dirLight1.shadow.mapSize.width = 2048 // 暗影贴图宽度设置为2048像素
dirLight1.shadow.mapSize.height = 2048 // 暗影贴图高度设置为2048像素
this.scene.add(dirLight1)
// 聚光灯光源
const dirLight2 = new THREE.SpotLight(0xffffff)
dirLight2.position.set(-100, 0, 100)
dirLight2.intensity = 1.5 // 强度
dirLight2.castShadow = true
dirLight2.shadow.mapSize.width = 2048 // 暗影贴图宽度设置为2048像素
dirLight2.shadow.mapSize.height = 2048 // 暗影贴图高度设置为2048像素
this.scene.add(dirLight2)
// 聚光灯光源
const dirLight3 = new THREE.SpotLight(0xffffff)
dirLight3.position.set(-100, 100, -100)
dirLight3.intensity = 1.5 // 强度
dirLight3.castShadow = true
dirLight3.shadow.mapSize.width = 2048 // 暗影贴图宽度设置为2048像素
dirLight3.shadow.mapSize.height = 2048 // 暗影贴图高度设置为2048像素
this.scene.add(dirLight3)
// 环境光
const aLight = new THREE.AmbientLight(0xffffff)
// aLight.position.set(0, 0, 100)
aLight.intensity = 1.2 // 强度
aLight.castShadow = true
aLight.name = 'AmbientLight'
this.scene.add(aLight)
// 平行光光
const DirectionalLight = new THREE.DirectionalLight(0xffffff, 1)
DirectionalLight.position.set(-10, -10, -21)
DirectionalLight.intensity = 3 // 强度
DirectionalLight.castShadow = true
DirectionalLight.shadow.mapSize.width = 2048 // 暗影贴图宽度设置为2048像素
DirectionalLight.shadow.mapSize.height = 2048 // 暗影贴图高度设置为2048像素
this.scene.add(DirectionalLight)
}
}
// 创建网格模型
setCube(): void {
if (this.scene) {
const geometry = new THREE.BoxGeometry(); //创建一个立方体几何对象Geometry
// const material = new THREE.MeshBasicMaterial({ color: 0xff3200 }); //材质对象Material
// 默认路径是public,所以下面纹理图片的路径是public/assets/logo.png
const texture = new THREE.TextureLoader().load(
"/assets/logo.png"
); //首先,获取到纹理
const material = new THREE.MeshBasicMaterial({ map: texture }); //然后创建一个phong材质来处理着色,并传递给纹理映射
this.mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
this.scene.add(this.mesh); //网格模型添加到场景中
this.render();
}
}
setControls():void {
const controls = new OrbitControls(this.camera, this.renderer.domElement)
}
// 渲染
render(): void {
if (this.renderer && this.scene && this.camera) {
this.renderer.render(this.scene, this.camera);
}
}
// 动画
animate(): void {
// console.log(this.scene)
requestAnimationFrame(this.animate.bind(this));
this.render();
if (this.mesh) {
this.mesh.rotation.x += 0.01;
this.mesh.rotation.y += 0.01;
}
}
}
到此我们能正常生成物品,并引入图片给物品贴图啦!可喜可贺可喜可贺。
看我写了这么多,就给个赞吧,至于加载模型的,等下期我再更新。
我是地霊殿__三無,一个又菜又摸鱼的前端。
ps: 这一篇写了好久,断断续续的,求个赞不过分吧