上一篇使用原生js在直角坐标系中创建时空立方体,本篇使用vue3在直角坐标系中创建时空立方体。与原生js创建方式类似,但是有个别细节还是有一定的差异,接下来就开启创建简单的时空立方体吧!
1、先避一个坑,在vue3的函数中直接获取dom元素获取到的是null,并不能直接获取到该dom元素。因为获取dom元素执行的是异步操作,此时就需要导入nextTick库并借助nextTick函数。
import { nextTick } from "vue";
const init= async () => {
await nextTick();
document.getElementById("XXX")...
...
}
2、接下来的步骤与原生js大同小异,创建vue3项目,导入需要用到的包,个别原生js中THREE有的方法在vue3中被单独拿了出来,比如FontLoader、TextGeometry等。同时可以查看其文件存在的位置。
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { FontLoader } from "three/examples/jsm/loaders/FontLoader";
import { TextGeometry } from "three/examples/jsm/geometries/TextGeometry";
3、添加场景、摄像机、渲染器、坐标轴、灯光。因为默认坐标系是右手坐标系,z轴朝向屏幕,因此需要设置摄像机的camera.up.z = 1,使得z轴朝上。
// 创建场景
var scene = new THREE.Scene();
// 灯光
var light = new THREE.DirectionalLight(0xffffff);
// 点光源位置
light.position.set(1, 1, 1);
// 点光源添加到场景中
scene.add(light);
// 创建相机对象
var camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 1, 10000);
camera.up.x = 0;
camera.up.y = 0;
camera.up.z = 1;
camera.position.set(30, 0, 0);
camera.lookAt(scene.position);
// 相机设置
var renderer = new THREE.WebGLRenderer({antialias:true});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.setClearColor(0xffffff, 1.0);
document.getElementById("bar_chart").appendChild(renderer.domElement);
// 坐标轴
var axes = new THREE.AxesHelper(10);
scene.add(axes);
4、给坐标轴添加文字。因为前一步对坐标轴做了旋转,因此该步骤需要使用rotation对文字进行旋转。这一步对之前的代码进行整合优化,略简洁一些。这里在添加的时候文字一直无法显示(此处似乎又是一个坑,原生js中没有这个问题),后来经过好久的尝试才发现:给的变量如果是字符串可以正常显示;如果是其他数据类型就使用toString方法转为字符串形式就可以正常显示。(此处只显示x轴,y轴和z轴的添加方法类似,仅仅是位置和旋转稍有不同)
var loader = new FontLoader();
// 坐标轴上文字
loader.load('fonts/helvetiker_regular.typeface.json', function(font) {
// console.log("font", font)
// 坐标轴字体
const options = {
font: font,
size: 0.5,
height: 0.1,
curveSegments: 12,
}
// 坐标轴字体材质
var materialtext = new THREE.MeshPhongMaterial({
color: 0xEEA2AD,
specular:0xEEA2AD,
shininess:0,
});
for(var i=1; i<=10; i++){
// x轴
var meshtextx = new THREE.Mesh(new TextGeometry(i.toString(), options), materialtext);
meshtextx.position.set(i-0.2,10,-0.5);
meshtextx.rotation.x = -Math.PI/2;
meshtextx.rotation.z = Math.PI;
scene.add(meshtextx);
}
});
5、此处添加立方体时CubeGeometry方法会报THREE.CubeGeometry is not a constructor的错误,因此就使用了BoxGeometry方法进行创建并使用add方法添加到场景中。
var boxGeometry = new THREE.BoxGeometry(0.9, 0.9, 0.9)
var material = new THREE.MeshLambertMaterial({color: 0x00ff00*i*j/100 })
material.transparent = true;
material.opacity = 0.8;
var cube = new THREE.Mesh(boxGeometry, material)
cube.position.set(i+0.5, j+0.5, 0.5);
scene.add(cube)
6、同时创建直线的方法也不适用了。原生js中使用LineBasicMaterial方法,在vue3中并不适用。
var geometry = new THREE.BufferGeometry();
var vertices = new Float32Array( [0, 0, 0, 0, 0, 10] );
geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
var material = new THREE.LineBasicMaterial( { color: 0xeeeeee } );
var line = new THREE.Line( geometry, material );
scene.add( line );
7、添加执行渲染函数并运行,完成图像的加载和显示。
var controls = new OrbitControls( camera, renderer.domElement );
function renderScene(){
controls.update();
requestAnimationFrame(renderScene);
renderer.render(scene, camera);
}
以上是vue3中使用three.js创建简单的三维直角坐标系,并添加几何体对象的步骤,如果大家还有其他的方法和思路也欢迎多多交流。