ThreeJS-3D教学九-line的绘制

three.js 画线比较繁琐一些,我们先展示正常的操作,先看效果图:

本案例用到的方法是:

LineBasicMaterial 和 LineSegments。

1、材质

Three.js中提供了两种线条材质:

LineDashedMaterial

const material = new THREE.LineDashedMaterial( {
	color: 0xffffff,
	linewidth: 1,
	scale: 1,
	dashSize: 3,  // 破折号的大小 。这是与笔划之间的间隙
	gapSize: 1  // 间隙的大小
} );

LineBasicMaterial

const material = new THREE.LineBasicMaterial( {
	color: 0xffffff,
	linewidth: 1
} );

2、geometry

Three.js中比较常用的三种线条Line,LineLoop,LineSegments

Line

Line用于将一系列点绘制成一条连续的线

LineLoop

用于将一系列点绘制成一条连续的线,它和Line几乎一样,唯一的区别就是所有点连接之后会将第一个点和最后一个点相连接

LineSegments

用于将两个点连接为一条线,它会将我们传递的一系列点自动分配成两个为一组,然后将分配好的两个点连接,这种先天实际项目中主要用于绘制具有相同开始点,结束点不同的线条

代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <style>
    body {
      width: 100%;
      height: 100%;
    }
    * {
      margin: 0;
      padding: 0;
    }
    .label {
      font-size: 20px;
      color: #000;
      font-weight: 700;
    }
  </style>
</head>
<body>
<div id="container"></div>
<script type="importmap">
  {
    "imports": {
      "three": "../three-155/build/three.module.js",
      "three/addons/": "../three-155/examples/jsm/"
    }
  }
</script>
<script type="module">
import * as THREE from 'three';
import Stats from 'three/addons/libs/stats.module.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GPUStatsPanel } from 'three/addons/utils/GPUStatsPanel.js';
import { CSS2DRenderer, CSS2DObject } from 'three/addons/renderers/CSS2DRenderer.js';
let stats, labelRenderer, gpuPanel, material;
let camera, scene, renderer, controls;
const group = new THREE.Group();
const r = 50;
let widthImg = 200;
let heightImg = 200;
init();
// initHelp();
initLight();
// axesHelperWord();
animate();

let parameters = [
  [0.25, 0xff7700, 1, 5],
  [0.5, 0xff9900, 1, 5],
  [0.75, 0xffaa00, 0.75, 5],
  [1, 0xffaa00, 0.5, 5],
  [1.25, 0x000833, 0.8, 5],
  [3.0, 0xaaaaaa, 0.75, 50],
  [3.5, 'blue', 0.5, 1],
  [4.5, 'yellow', 0.25, 1],
  [5.5, 0xffffff, 0.125, 50]
];

let geometry = createGeometry();

for (let i = 0; i < parameters.length; ++i) {

  let p = parameters[i];

  material = new THREE.LineBasicMaterial({color: p[1], opacity: p[2], linewidth: p[3]});

  let line = new THREE.LineSegments(geometry, material);
  line.scale.x = line.scale.y = line.scale.z = p[0];
  line.userData.originalScale = p[0];
  // line.rotation.y = Math.random() * Math.PI;
  line.updateMatrix();
  scene.add(line);

}

function createGeometry() {

  let geometry = new THREE.BufferGeometry();
  let vertices = [];

  let vertex = new THREE.Vector3();

  for (let i = 0; i < 2000; i++) {

    vertex.x = Math.random() * 2 - 1;
    vertex.y = Math.random() * 2 - 1;
    vertex.z = Math.random() * 2 - 1;
    vertex.normalize();
    vertex.multiplyScalar(r);

    vertices.push(vertex.x, vertex.y, vertex.z);

    vertex.multiplyScalar(Math.random() * 0.09 + 1);

    vertices.push(vertex.x, vertex.y, vertex.z);

  }

  geometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));

  return geometry;

}

function init() {

  camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 10, 3000 );
  camera.up.set(0, 1, 0);
  camera.position.set(60, 700, 60);
  camera.lookAt(0, 0, 0);

  scene = new THREE.Scene();
  scene.background = new THREE.Color( '#000' );

  renderer = new THREE.WebGLRenderer( { antialias: true } );
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  document.body.appendChild( renderer.domElement );

  labelRenderer = new CSS2DRenderer();
  labelRenderer.setSize( window.innerWidth, window.innerHeight );
  labelRenderer.domElement.style.position = 'absolute';
  labelRenderer.domElement.style.top = '0px';
  labelRenderer.domElement.style.pointerEvents = 'none';
  document.getElementById( 'container' ).appendChild( labelRenderer.domElement );

  controls = new OrbitControls( camera, renderer.domElement );
  // 设置最大最小视距
  controls.minDistance = 20;
  controls.maxDistance = 3000;

  window.addEventListener( 'resize', onWindowResize );

  stats = new Stats();
  stats.setMode(1); // 0: fps, 1: ms
  document.body.appendChild( stats.dom );

  gpuPanel = new GPUStatsPanel( renderer.getContext() );
  stats.addPanel( gpuPanel );
  stats.showPanel( 0 );

  scene.add( group );
}

function initLight() {
  const AmbientLight = new THREE.AmbientLight(new THREE.Color('rgb(255, 255, 255)'), 0.2);
  scene.add( AmbientLight );
}

function initHelp() {
  // const size = 100;
  // const divisions = 5;
  // const gridHelper = new THREE.GridHelper( size, divisions );
  // scene.add( gridHelper );

  // The X axis is red. The Y axis is green. The Z axis is blue.
  const axesHelper = new THREE.AxesHelper( 100 );
  scene.add( axesHelper );
}

function axesHelperWord() {
  let xP = addWord('X轴');
  let yP = addWord('Y轴');
  let zP = addWord('Z轴');
  xP.position.set(50, 0, 0);
  yP.position.set(0, 50, 0);
  zP.position.set(0, 0, 50);
}

function addWord(word) {
  let name = `<span>${word}</span>`;
  let moonDiv = document.createElement( 'div' );
  moonDiv.className = 'label';
  // moonDiv.textContent = 'Moon';
  // moonDiv.style.marginTop = '-1em';
  moonDiv.innerHTML = name;
  const label = new CSS2DObject( moonDiv );
  group.add( label );
  return label;
}

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize( window.innerWidth, window.innerHeight );
}

function animate() {
  requestAnimationFrame( animate );

  let time = Date.now() * 0.0001;
  for (let i = 0; i < scene.children.length; i++) {

    let object = scene.children[i];

    if (object.isLine) {

      object.rotation.y = time * (i < 4 ? (i + 1) : -(i + 1));

      // if (i < 5) {

      // let scale = object.userData.originalScale * (i / 5 + 1) * (1 + 0.5 * Math.sin(7 * time));

      let scale = object.userData.originalScale * (i / 5 + 1) * (1 + 0.5 * Math.sin(10 * time));

      object.scale.x = object.scale.y = object.scale.z = scale;

      // }

    }

  }

  stats.update();
  controls.update();
  labelRenderer.render( scene, camera );
  renderer.render( scene, camera );
}
</script>
</body>
</html>

我们看到,并不那么复杂,但这里有个问题,我们会发现:LineBasicMaterial 的 linewidth 怎么设置都没有起作用,按照官方解释是:由于opengl核心库文件的限制,webgl渲染器在大部分平台上linewidth一直是1,无视你设置的值;上面两种材质都是这样,至于有宽度的线 后面我们会讲到

相关推荐
Android_Trot1 小时前
Android Compose 下拉选择框 ExposedDropdownMenu下拉选择
android·前端
Qredsun1 小时前
Vue2升级Vue3填坑笔记
前端·javascript·vue.js
陆业聪2 小时前
利用Nginx反向代理优化Web应用的性能与安全
前端·nginx·安全
夏天想2 小时前
vue3+elementPlus:无法清空问题,清空表单没效果
javascript·vue.js·elementui
pan_junbiao2 小时前
Vue表单元素绑定:v-model 指令
前端·javascript·vue.js
黑客大佬3 小时前
漏洞挖掘 | 记一次伪静态页面的SQL注入
前端·数据库·sql·nginx·安全·小程序·yapi
●VON3 小时前
【HarmonyOS NEXT星河版开发实战】页面跳转
开发语言·前端·学习·华为·harmonyos
洋芋土豆3 小时前
Tomcat涡轮:企业级WEB动力引擎全解析
java·运维·前端·tomcat
落霞的思绪3 小时前
Axios 中的相关参数
前端·javascript·html
Code成立3 小时前
CSS3页面布局-三栏-中栏流动布局
前端·html·css3·三栏-中栏流动布局