webgl中线是没有宽度的,现实的应用中一般做法都是将线拓宽成面来绘制。默认threejs的线宽是无法调节的,需要用有厚度的线 THREE.Line2。
先看效果图:
看下代码:
<!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';
import { Line2 } from 'three/addons/lines/Line2.js';
import { LineMaterial } from 'three/addons/lines/LineMaterial.js';
import { LineGeometry } from 'three/addons/lines/LineGeometry.js';
let stats, labelRenderer, gpuPanel;
let camera, scene, renderer, controls;
const group = new THREE.Group();
const matLines = [];
let once = true;
init();
initHelp();
initLight();
axesHelperWord();
animate();
let data1 = [
{
x: -50,
y: 50,
z: 0
},
{
x: 50,
y: 50,
z: 0
},
{
x: 50,
y: -50,
z: 0
},
{
x: -50,
y: -50,
z: 0
},
{
x: -50,
y: 50,
z: 0
}
];
let data2 = [
{
x: -50,
y: 0,
z: 0
},
{
x: 50,
y: 1,
z: 0
}
];
let data3 = [
{
x: -25,
y: 25,
z: 0
},
{
x: 25,
y: 25,
z: 0
},
{
x: 25,
y: -25,
z: 0
},
{
x: -25,
y: -25,
z: 0
},
{
x: -25,
y: 25,
z: 0
}
];
let positions1 = [];
let positions2 = [];
let positions3 = [];
let colors = [];
let l = data1.length;
let color = new THREE.Color();
data1.map((v, i) => {
positions1.push(v.x, v.y, v.z);
color.setHSL(i / l, 1.0, 0.5);
colors.push(color.r, color.g, color.b);
});
data2.map((v, i) => {
positions2.push(v.x, v.y, v.z);
color.setHSL(i / l, 1.0, 0.5);
colors.push(color.r, color.g, color.b);
});
data3.map((v, i) => {
positions3.push(v.x, v.y, v.z);
});
draw(positions1, colors);
draw(positions2, colors);
drawSolidLine(positions3, '#f00');
function draw(positions, colors) {
let geometry = new LineGeometry();
// 虚线
const matLine = new LineMaterial({
// 只有白色 可以显示出渐变色的效果
color: 0xffffff,
linewidth: 10,
vertexColors: THREE.VertexColors, // 单独设置顶点颜色
//resolution: // renderer.render 时加上这个属性
dashed: true,
dashSize: 1,
gapSize: 1,
defines: {
USE_DASH: ''
}
});
let line = new Line2(geometry, matLine);
line.scale.set(1, 1, 1);
line.visible = true;
scene.add(line);
matLines.push(matLine);
geometry.setPositions(positions);
geometry.setColors(colors);
line.computeLineDistances();
}
function drawSolidLine(positions, color) {
let geometry = new LineGeometry();
// 虚线
const matLine = new LineMaterial({
// 只有白色 可以显示出渐变色的效果
color: color,
linewidth: 10,
// vertexColors: THREE.VertexColors, // 单独设置顶点颜色
// resolution: // renderer.render 时加上这个属性
dashed: false
});
let line = new Line2(geometry, matLine);
line.scale.set(1, 1, 1);
line.visible = true;
line.rotateX(Math.PI / 3);
scene.add(line);
matLines.push(matLine);
geometry.setPositions(positions);
line.computeLineDistances();
}
function init() {
camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 10, 2000 );
camera.up.set(0, 1, 0);
camera.position.set(60, 40, 60);
camera.lookAt(0, 0, 0);
scene = new THREE.Scene();
scene.background = new THREE.Color( '#ccc' );
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 = 1000;
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)'));
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 );
// 这里请注意
// 把渲染窗口尺寸分辨率传值给材质LineMaterial的resolution属性
// resolution属性值会在着色器代码中参与计算
if (matLines.length && once) {
matLines.forEach(matLine => {
matLine.resolution.set(window.innerWidth, window.innerHeight); // resolution of the viewport
});
once = false;
}
stats.update();
controls.update();
labelRenderer.render( scene, camera );
renderer.render( scene, camera );
}
</script>
</body>
</html>