THREE.LineSegments
是Three.js中的一个类,用于创建由线段组成的对象。每个线段由两个顶点定义,多个线段可以组合成一个THREE.LineSegments
对象。它通常用于绘制多条独立的线段,例如边框、网格或粒子连接线。
构造函数
const lineSegments = new THREE.LineSegments(geometry, material);
入参
- geometry:
THREE.BufferGeometry
或THREE.Geometry
对象,包含线段的顶点数据。 - material:
THREE.Material
对象,指定线段的材质属性。
属性
THREE.LineSegments
继承自THREE.Line
,它又继承自THREE.Object3D
,因此它具有这些类的所有属性。以下是一些重要属性:
- geometry: 包含线段顶点数据的
THREE.BufferGeometry
或THREE.Geometry
对象。 - material: 线段的材质,通常是
THREE.LineBasicMaterial
或THREE.LineDashedMaterial
。 - type: 对象的类型,
THREE.LineSegments
的类型为"LineSegments"
。 - position: 3D对象的位置,
THREE.Vector3
类型。 - rotation: 3D对象的旋转,
THREE.Euler
类型。 - scale: 3D对象的缩放,
THREE.Vector3
类型。 - visible: 布尔值,决定对象是否可见。
方法
THREE.LineSegments
继承了THREE.Line
和THREE.Object3D
的所有方法,常用的方法包括:
- copy(source): 复制源对象的所有属性到当前对象。
- clone(): 创建当前对象的一个副本。
- raycast(raycaster, intersects): 用于检测射线与线段的交点。
- updateMatrix(): 更新对象的世界矩阵。
- updateMatrixWorld(force): 更新对象及其子对象的世界矩阵。
- lookAt(vector): 使对象的正面朝向指定的向量。
- translateX(distance), translateY(distance), translateZ(distance): 沿指定轴平移对象。
示例
以下是一个使用THREE.LineSegments
创建线段的简单示例:
// 创建几何体
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
-10, 0, 0,
0, 10, 0,
10, 0, 0
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
// 创建材质
const material = new THREE.LineBasicMaterial({ color: 0xffffff });
// 创建线段对象
const lineSegments = new THREE.LineSegments(geometry, material);
// 将线段添加到场景中
scene.add(lineSegments);
在这个示例中,我们创建了一个包含三个顶点的BufferGeometry
,然后使用LineBasicMaterial
创建材质。最后,我们用这些几何体和材质创建了LineSegments
对象,并将其添加到场景中。
<!DOCTYPE html>
<html lang="en">
<head>
<title>three.js webgl - buffergeometry - lines drawrange</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<link type="text/css" rel="stylesheet" href="main.css">
</head>
<body>
<div id="container"></div>
<div id="info">
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl - buffergeometry drawrange<br/>
by <a href="https://twitter.com/fernandojsg">fernandojsg</a>
</div>
<script type="importmap">
{
"imports": {
"three": "../build/three.module.js",
"three/addons/": "./jsm/"
}
}
</script>
<script type="module">
// 导入three.js库和所需的附加组件
import * as THREE from 'three';
import Stats from 'three/addons/libs/stats.module.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
let group;
let container, stats;
const particlesData = [];
let camera, scene, renderer;
let positions, colors;
let particles;
let pointCloud;
let particlePositions;
let linesMesh;
const maxParticleCount = 1000;
let particleCount = 500;
const r = 800;
const rHalf = r / 2;
// 控制面板参数
const effectController = {
showDots: true,
showLines: true,
minDistance: 150,
limitConnections: false,
maxConnections: 20,
particleCount: 500
};
init();
animate();
function initGUI() {
const gui = new GUI();
// 添加控制面板选项
gui.add( effectController, 'showDots' ).onChange( function ( value ) {
pointCloud.visible = value;
} );
gui.add( effectController, 'showLines' ).onChange( function ( value ) {
linesMesh.visible = value;
} );
gui.add( effectController, 'minDistance', 10, 300 );
gui.add( effectController, 'limitConnections' );
gui.add( effectController, 'maxConnections', 0, 30, 1 );
gui.add( effectController, 'particleCount', 0, maxParticleCount, 1 ).onChange( function ( value ) {
particleCount = value;
particles.setDrawRange( 0, particleCount );
} );
}
function init() {
initGUI();
// 获取容器元素
container = document.getElementById( 'container' );
// 设置相机
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 4000 );
camera.position.z = 1750;
const controls = new OrbitControls( camera, container );
controls.minDistance = 1000;
controls.maxDistance = 3000;
// 创建场景
scene = new THREE.Scene();
// 创建组并添加到场景中
group = new THREE.Group();
scene.add( group );
// 添加辅助框
const helper = new THREE.BoxHelper( new THREE.Mesh( new THREE.BoxGeometry( r, r, r ) ) );
helper.material.color.setHex( 0x474747 );
helper.material.blending = THREE.AdditiveBlending;
helper.material.transparent = true;
group.add( helper );
const segments = maxParticleCount * maxParticleCount;
positions = new Float32Array( segments * 3 );
colors = new Float32Array( segments * 3 );
const pMaterial = new THREE.PointsMaterial( {
color: 0xFFFFFF,
size: 3,
blending: THREE.AdditiveBlending,
transparent: true,
sizeAttenuation: false
} );
particles = new THREE.BufferGeometry();
particlePositions = new Float32Array( maxParticleCount * 3 );
// 初始化粒子位置和速度
for ( let i = 0; i < maxParticleCount; i ++ ) {
const x = Math.random() * r - r / 2;
const y = Math.random() * r - r / 2;
const z = Math.random() * r - r / 2;
particlePositions[ i * 3 ] = x;
particlePositions[ i * 3 + 1 ] = y;
particlePositions[ i * 3 + 2 ] = z;
// 将粒子数据添加到数组中
particlesData.push( {
velocity: new THREE.Vector3( - 1 + Math.random() * 2, - 1 + Math.random() * 2, - 1 + Math.random() * 2 ),
numConnections: 0
} );
}
particles.setDrawRange( 0, particleCount );
particles.setAttribute( 'position', new THREE.BufferAttribute( particlePositions, 3 ).setUsage( THREE.DynamicDrawUsage ) );
// 创建粒子系统
pointCloud = new THREE.Points( particles, pMaterial );
group.add( pointCloud );
const geometry = new THREE.BufferGeometry();
geometry.setAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).setUsage( THREE.DynamicDrawUsage ) );
geometry.setAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).setUsage( THREE.DynamicDrawUsage ) );
geometry.computeBoundingSphere();
geometry.setDrawRange( 0, 0 );
const material = new THREE.LineBasicMaterial( {
vertexColors: true,
blending: THREE.AdditiveBlending,
transparent: true
} );
linesMesh = new THREE.LineSegments( geometry, material );
group.add( linesMesh );
// 初始化渲染器
renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
// 添加统计信息
stats = new Stats();
container.appendChild( stats.dom );
window.addEventListener( 'resize', onWindowResize );
}
// 窗口大小调整处理
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize( window.innerWidth, window.innerHeight );
}
// 动画循环
function animate() {
let vertexpos = 0;
let colorpos = 0;
let numConnected = 0;
for ( let i = 0; i < particleCount; i ++ )
particlesData[ i ].numConnections = 0;
for ( let i = 0; i < particleCount; i ++ ) {
const particleData = particlesData[ i ];
particlePositions[ i * 3 ] += particleData.velocity.x;
particlePositions[ i * 3 + 1 ] += particleData.velocity.y;
particlePositions[ i * 3 + 2 ] += particleData.velocity.z;
// 边界反弹
if ( particlePositions[ i * 3 + 1 ] < - rHalf || particlePositions[ i * 3 + 1 ] > rHalf )
particleData.velocity.y = - particleData.velocity.y;
if ( particlePositions[ i * 3 ] < - rHalf || particlePositions[ i * 3 ] > rHalf )
particleData.velocity.x = - particleData.velocity.x;
if ( particlePositions[ i * 3 + 2 ] < - rHalf || particlePositions[ i * 3 + 2 ] > rHalf )
particleData.velocity.z = - particleData.velocity.z;
if ( effectController.limitConnections && particleData.numConnections >= effectController.maxConnections )
continue;
// 检查碰撞
for ( let j = i + 1; j < particleCount; j ++ ) {
const particleDataB = particlesData[ j ];
if ( effectController.limitConnections && particleDataB.numConnections >= effectController.maxConnections )
continue;
const dx = particlePositions[ i * 3 ] - particlePositions[ j * 3 ];
const dy = particlePositions[ i * 3 + 1 ] - particlePositions[ j * 3 + 1 ];
const dz = particlePositions[ i * 3 + 2 ] - particlePositions[ j * 3 + 2 ];
const dist = Math.sqrt( dx * dx + dy * dy + dz * dz );
if ( dist < effectController.minDistance ) {
particleData.numConnections ++;
particleDataB.numConnections ++;
const alpha = 1.0 - dist / effectController.minDistance;
positions[ vertexpos ++ ] = particlePositions[ i * 3 ];
positions[ vertexpos ++ ] = particlePositions[ i * 3 + 1 ];
positions[ vertexpos ++ ] = particlePositions[ i * 3 + 2 ];
positions[ vertexpos ++ ] = particlePositions[ j * 3 ];
positions[ vertexpos ++ ] = particlePositions[ j * 3 + 1 ];
positions[ vertexpos ++ ] = particlePositions[ j * 3 + 2 ];
colors[ colorpos ++ ] = alpha;
colors[ colorpos ++ ] = alpha;
colors[ colorpos ++ ] = alpha;
colors[ colorpos ++ ] = alpha;
colors[ colorpos ++ ] = alpha;
colors[ colorpos ++ ] = alpha;
numConnected ++;
}
}
}
linesMesh.geometry.setDrawRange( 0, numConnected * 2 );
linesMesh.geometry.attributes.position.needsUpdate = true;
linesMesh.geometry.attributes.color.needsUpdate = true;
pointCloud.geometry.attributes.position.needsUpdate = true;
requestAnimationFrame( animate );
stats.update();
render();
}
function render() {
const time = Date.now() * 0.001;
// 旋转群组
group.rotation.y = time * 0.1;
renderer.render( scene, camera );
}
</script>
</body>
</html>
一个功能强大的图片处理工具,它可以满足用户对于图片压缩、格式转换、质量调节以及长图片分割等多种需求。
【轻松压缩,一键搞定】您的图片处理神器来了!
🎉 您是否曾为图片太大无法上传而烦恼?是否为图片格式不兼容而头疼?现在,有了我们的图片处理工具,这些问题将不复存在!
🌟 功能亮点:
批量压缩:无论您有多少张图片,无论尺寸大小,我们的工具都能一次性处理,让您的工作效率翻倍!
格式转换:支持多种图片格式之间的轻松转换,满足您在不同场景下的使用需求。
压缩质量可调:想要保留更多细节?还是追求更小的文件大小?压缩质量由您说了算!
长图片分割:再也不用担心长图无法完整显示或处理了,我们的工具能轻松将长图分割成多张图片,方便您进行后续编辑和分享。
获取网络图片:可将网络路径图片路径,转化成自己的图片进行处理下载,支持批量转换图片下载
📷 无论是从相机导出的大图,还是手机拍摄的生活照,我们的工具都能轻松应对,让您的图片处理变得简单又高效!
💡