Vue3+Three.js星空球体

发布时间:2024年01月03日

结果图

在这里插入图片描述

threejs比例不变自适应

首先是设置相机和render,要注意的就是相机要加上aspect不然如果页面不是正方形看到的样式就会失调。

// ---------相机设置-------------
// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera();
//相机在Three.js三维坐标系中的位置
// 根据需要设置相机位置具体值
const cameraPostion = [20, 20, 20];
camera.position.set(...cameraPostion);
camera.lookAt(mesh.position);//指向mesh对应的位置
// 更新相机的宽高比
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

// ----------渲染器设置------------
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
// 定义threejs输出画布的尺寸(单位:像素px)
const width = window.innerWidth; //宽度
const height = window.innerHeight; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
// renderer.setPixelRatio(window.devicePixelRatio)
renderer.render(scene, camera); //执行渲染操作

在onmounted中加入resize事件的监听,这样即使缩放也不会又问题

window.addEventListener('resize', () => {
    const width = window.innerWidth; //宽度
    const height = window.innerHeight; //高度
    // camera.position.set(20, 20, 20);
    camera.lookAt(mesh.position);//指向mesh对应的位置
    // 更新相机的宽高比
    camera.aspect = width / height;
    // 更新摄像机的投影矩阵
    camera.updateProjectionMatrix();
    renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
    renderer.render(scene, camera); //执行渲染操作
  });

鼠标控制视角

禁止拖拽和缩放是为了以防超出天空盒或者进入地球模型中,也可以设置这两个的范围

const controls = new MapControls(camera, renderer.domElement);
controls.enablePan = false; //禁止右键拖拽
controls.enableZoom = false;//禁止缩放
controls.addEventListener('change', function () {
  // 鼠标右键旋转时候,查看.position变化
  // 鼠标左键拖动的时候,查看.position、.target的位置会变化
  console.log('camera.position', camera.position);
  renderer.render(scene, camera); //执行渲染操作
  // console.log('controls.target', controls.target);
});

天空盒

这边我采用了球体来制作天空盒,因为cube要6张图很难找,刚好我看到了一个长图,就直接用了

//----------天空盒-----------
// 加载天空球纹理
// 创建TextureLoader加载天空盒纹理
let texture = new THREE.TextureLoader().load([
  require('../assets/longbk.jpeg')
]);
// 创建立方体几何体并应用天空盒材质
createGeometry(scene, 'Sphere', [500], [0, 0, 0],
  {
    map: texture, //设置材质环境贴图
    side: THREE.DoubleSide // 双面展示
  }
)

记得天空盒是需要双面贴图的,因为视角在里面,不然是看不见贴图的

具体代码

<template>
  <div ref="webgl"></div>
</template>

<script setup>
// 引入three.js
import * as THREE from 'three';
import { createGeometry } from '../utils/threeFun.js'
import { onMounted, ref } from 'vue';
// 引入相机控件`MapControls`
import { MapControls } from 'three/addons/controls/OrbitControls.js';

const webgl = ref(null);

// 创建3D场景对象Scene
const scene = new THREE.Scene();

// // ----------场景布置------------
let earthTexture = new THREE.TextureLoader().load([
  require('../assets/earth.jpg')
]);
let mesh = createGeometry(scene, 'Sphere', [5], [0, 0, 0], {
  map: earthTexture,
  // color: 0xff0000,//0xff0000设置材质颜色为红色
})

//=========测试用===========
// AxesHelper:辅助观察的坐标系 
// const axesHelper = new THREE.AxesHelper(200)
// scene.add(axesHelper)


//----------天空盒-----------
// 加载天空球纹理
// 创建TextureLoader加载天空盒纹理
let texture = new THREE.TextureLoader().load([
  require('../assets/longbk.jpeg')
]);
// 创建立方体几何体并应用天空盒材质
createGeometry(scene, 'Sphere', [50], [0, 0, 0],
  {
    map: texture, //设置材质环境贴图
    side: THREE.DoubleSide // 双面展示
  }
)

// ---------相机设置-------------
// 实例化一个透视投影相机对象
const camera = new THREE.PerspectiveCamera();
//相机在Three.js三维坐标系中的位置
// 根据需要设置相机位置具体值
const cameraPostion = [20, 20, 20];
camera.position.set(...cameraPostion);
camera.lookAt(mesh.position);//指向mesh对应的位置
// 更新相机的宽高比
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();

// ----------渲染器设置------------
// 创建渲染器对象
const renderer = new THREE.WebGLRenderer();
// 定义threejs输出画布的尺寸(单位:像素px)
const width = window.innerWidth; //宽度
const height = window.innerHeight; //高度
renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
// renderer.setPixelRatio(window.devicePixelRatio)
renderer.render(scene, camera); //执行渲染操作

const controls = new MapControls(camera, renderer.domElement);
controls.enablePan = false; //禁止右键拖拽
controls.enableZoom = false;//禁止缩放
controls.addEventListener('change', function () {
  // 鼠标右键旋转时候,查看.position变化
  // 鼠标左键拖动的时候,查看.position、.target的位置会变化
  console.log('camera.position', camera.position);
  renderer.render(scene, camera); //执行渲染操作
  // console.log('controls.target', controls.target);
});

// ----------渲染器添加到页面------------
// 一定要放在onmounted里面,因为在onmounted的时候才有webgl这个dom元素
onMounted(() => {
  console.log('mounted');
  webgl.value.appendChild(renderer.domElement);
  // 监听浏览器窗口大小的变化,变化时重新渲染
  window.addEventListener('resize', () => {
    const width = window.innerWidth; //宽度
    const height = window.innerHeight; //高度
    // camera.position.set(20, 20, 20);
    camera.lookAt(mesh.position);//指向mesh对应的位置
    // 更新相机的宽高比
    camera.aspect = width / height;
    // 更新摄像机的投影矩阵
    camera.updateProjectionMatrix();
    renderer.setSize(width, height); //设置three.js渲染区域的尺寸(像素px)
    renderer.render(scene, camera); //执行渲染操作
  });

})

</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
#webgl {
  width: 100px;
  height: 100px;
}
</style>


threeFun.js

import * as THREE from "three";
/**
 *
 * @param {*} scene
 * @param {*} type 几何体类型
 * @param {*} size 几何体参数
 * @param {*} pos 放置位置数组
 * @param {*} material 材质对象
 */
export function createGeometry(scene, type, size, pos, material) {
  console.log(scene, type, size, pos, material);
  let mesh;
  switch (type) {
    case "Box":
      mesh = createBox(scene, size, pos, material);
      break;
    case "Sphere":
      mesh = createSphere(scene, size, pos, material);
      break;
    case "Cylinder":
      mesh = createCylinder(scene, size, pos, material);
      break;
    case "Plane":
      mesh = createPlane(scene, size, pos, material);
      break;
    case "Circle":
      mesh = createCircle(scene, size, pos, material);
      break;
    default:
      console.log("类型错误");
  }
  return mesh;
}

// ----------示例代码---------
// //创建一个长方体几何对象Geometry
// const geometry = new THREE.BoxGeometry(100, 100, 100);
// //创建一个材质对象Material
// const material = new THREE.MeshBasicMaterial({
//   color: 0xff0000,//0xff0000设置材质颜色为红色
// });
// // 两个参数分别为几何体geometry、材质material
// const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
// //设置网格模型在三维空间中的位置坐标,默认是坐标原点
// let pos = [0, 10, 0]
// mesh.position.set(...pos);
// scene.add(mesh); //网格模型添加到场景中

function createBox(scene, size, pos, materialParams) {
  const geometry = new THREE.BoxGeometry(...size);
  //   const geometry = new THREE.BoxGeometry(100, 100, 100);
  //创建一个材质对象Material
  const material = new THREE.MeshBasicMaterial(materialParams);
  const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  mesh.position.set(...pos);
  scene.add(mesh);
  console.log(scene);
  return mesh;
}
function createSphere(scene, size, pos, materialParams) {
  const geometry = new THREE.SphereGeometry(...size);
  //创建一个材质对象Material
  const material = new THREE.MeshBasicMaterial(materialParams);
  const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  mesh.position.set(...pos);
  scene.add(mesh);
  return mesh;
}
function createCylinder(scene, size, pos, materialParams) {
  const geometry = new THREE.CylinderGeometry(...size);
  //创建一个材质对象Material
  const material = new THREE.MeshBasicMaterial(materialParams);
  const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  mesh.position.set(...pos);
  scene.add(mesh);
  return mesh;
}
function createPlane(scene, size, pos, materialParams) {
  const geometry = new THREE.PlaneGeometry(...size);
  //创建一个材质对象Material
  const material = new THREE.MeshBasicMaterial(materialParams);
  const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  mesh.position.set(...pos);
  scene.add(mesh);
  return mesh;
}
function createCircle(scene, size, pos, materialParams) {
  const geometry = new THREE.CircleGeometry(...size);
  //创建一个材质对象Material
  const material = new THREE.MeshBasicMaterial(materialParams);
  const mesh = new THREE.Mesh(geometry, material); //网格模型对象Mesh
  mesh.position.set(...pos);
  scene.add(mesh);
  return mesh;
}

文章来源:https://blog.csdn.net/ArmadaDK/article/details/135345320
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。