如何让将你的点云数据文件渲染到threeJS的场景中
1.解析文件
这里我的文件是csv文件。关于我为什么要选择csv文件存储而不是excel文件存储。
原因一
一般使用PapaParse可以直接读取和解析csv文件,使用SheetJ读取和解析excel文件。当然PapaParse也可以用来解析excel文件,但是需要先将excel文件转换为CSV使用。
原因二
考虑到这两个方法的特点和局限性
PapaParse
1.主要用途:PapaParse是一个快速、强大的CSV文件(以及类似文本文件)解析库,专注于大文件和性能。
2.优点:
对大型CSV文件有优化,可以处理巨大的文件而不会冻结或崩溃浏览器支持流式解析,可以逐行解析数据,这有助于处理非常大的文件。
易于使用,有清晰的文档。
3.限制:主要用于解析CSV文件,对于Excel的.x1sx
或.x1s
格式不是直接支持需要先将Excel文件转换为CSV格式。
SheetJS
1.主要用途:SheetJs(xlsx.js)是一个复杂的库,专门用于处理Excel文件(包括’.x1s·等格式)以及其他电子表格格式。xlsx`、
2.优点:
直接支持多种电子表格格式,包括Excel的.x1sx·和
.x1s`格式,无需转换即可直接读取。提供了读取和写入电子表格的丰富功能,能够处理单元格格式、公式、日期等复杂数据。支持将电子表格转换成多种格式,包括JSON。
3.限制:
由于功能丰富,其体积相对较大,可能会影响到页面加载时间。处理非常大的Excel文件时,性能可能不如专门处理文本文件的PapaParse。
所以我选择使用PapaParse来解析csv文件。
2.创建点云材料和几何体
在Three.js中,可以使用PointsMaterial和BufferGeometry来创建点云。PointsMaterial允许定义点的颜色和大小,而BufferGeometry则用于存储点的位置信息。
将点云数据添加到场景中,点云渲染
有了几何体和材料,就可以通过将它们传递给THREE.Points来创建点云,并将该点云添加到场景中。
思路分析完毕现在开始上代码!
在HTML文件中添加这一行代码
<script src="https://cdnjs.cloudflare.com/ajax/libs/papaparse/5.3.0/papaparse.min.js"></script>
<input type="file" id="upload" accept=".csv" />
<div id="3dScene"></div>
这个HTML文件包括一个文件输入,用于上传CSV文件。我会将JavaScript代码放在一个单独的文件中我这里是index.js。
在index.js中添加用于解析文件,创建模型和场景的代码
// 文件上传和解析
document.getElementById('upload').addEventListener('change', function(event) {
const file = event.target.files[0];
if (!file) {
return;
}
const reader = new FileReader();
reader.onload = function(e) {
const text = e.target.result;
const data = parseCSV(text);
addPointCloud(data); // 调用添加点云函数
};
reader.readAsText(file);
});
// CSV解析函数(简单实现,仅适用于此特定格式)
function parseCSV(csvText) {
const lines = csvText.split('\n').map(line => line.trim()).filter(line => line);
// 跳过标题行,解析每行
// return lines.slice(1).map(line => {
// const parts = line.split(',').map(part => parseFloat(part));
// return { x: parts[0], y: parts[1], z: parts[2], value: parts[3] };
// });
const data = lines.slice(1).map(line => {
const parts = line.split(',').map(part => parseFloat(part));
return { x: parts[0], y: parts[1], z: parts[2], value: parts[3] };
});
console.log(data); // 打印解析出的数据查看
return data;
}
// 添加点云到场景的函数
function addPointCloud(data) {
const geometry = new THREE.BufferGeometry();
const positions = [];
const colors = [];
const color = new THREE.Color();
data.forEach(point => {
positions.push(point.x, point.y, point.z);
// 使用value决定颜色,简单映射
color.setHSL(point.value, 1.0, 0.5);
colors.push(color.r, color.g, color.b);
});
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
const material = new THREE.PointsMaterial({ size: 0.05, vertexColors: true });
const points = new THREE.Points(geometry, material);
console.log(`添加了${positions.length / 3}个点到场景中。`);
scene.add(points);
}
接下来让我们分析一下这段代码
文件上传和解析
1.获取上传的文件:这段代码首先通过document.getElementById(‘upload’)获取页面上的文件上传元素(一个元素),然后为它添加一个change事件监听器。这意味着每当用户选择了一个文件,就会触发这个事件。
2.读取文件内容:一旦文件被选择,创建一个FileReader对象来异步读取文件内容。当读取操作完成后,触发onload事件,并执行一个函数来处理读取到的内容。
解析CSV内容:reader.onload函数中,e.target.result包含了文件的文本内容。这个内容被传递给parseCSV函数,该函数负责将CSV文本解析为JavaScript对象的数组。
CSV解析函数
function parseCSV(csvText) {
const lines = csvText.split('\n').map(line => line.trim()).filter(line => line);
const data = lines.slice(1).map(line => {
const parts = line.split(',').map(part => parseFloat(part));
return { x: parts[0], y: parts[1], z: parts[2], value: parts[3] };
});
console.log(data); // 打印解析出的数据查看
return data;
}
1.拆分和清理数据:首先,csvText.split(‘\n’)按行拆分CSV文件的内容,.map(line => line.trim())移除每行前后的空白字符,.filter(line => line)过滤掉空行。
2.跳过标题行,解析数据行:lines.slice(1)跳过第一行(通常是标题行)。对于剩余的每一行,用逗号分隔并将每个部分转换为浮点数,创建一个包含x, y, z, value属性的对象。
3.打印和返回数据:通过console.log(data)打印解析后的数据,以便调试和查看,然后返回这个数据数组供后续使用。
添加点云到场景的函数
// 添加点云到场景的函数
function addPointCloud(data) {
const geometry = new THREE.BufferGeometry();
const positions = [];
const colors = [];
const color = new THREE.Color();
data.forEach(point => {
positions.push(point.x, point.y, point.z);
// 使用value决定颜色,简单映射
color.setHSL(point.value, 1.0, 0.5);
colors.push(color.r, color.g, color.b);
});
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
const material = new THREE.PointsMaterial({ size: 0.05, vertexColors: true });
const points = new THREE.Points(geometry, material);
console.log(`添加了${positions.length / 3}个点到场景中。`);
scene.add(points);
}
1.准备点云数据:创建一个BufferGeometry对象来存储点云。对于每个点,将其x, y, z坐标添加到positions数组中,并根据点的value计算颜色值,添加到colors数组中。
2.设置几何属性:将positions和colors数组设置为几何体的属性,这样每个点的位置和颜色都被正确地定义了。
3.创建和添加点云:使用PointsMaterial和上一步定义的几何体创建一个Points对象(即点云)。这个对象随后被添加到场景中,以便渲染。
4.打印点的数量:最后,打印添加到场景中的点的数量,帮助调试和确认数据被正确处理。
这整个过程将CSV文件中的数据转换为Three.js场景中的点云,其中点的位置由CSV文件决定,颜色基于每个点的value值动态计算。
注意点1:
threeJS原点(0,0,0)默认位于场景的中心。
如果我们希望模型的一个角而不是中心对齐于原点(0,0,0),我们就需要调整模型的位置。我们需要将模型沿x轴和z轴正方向移动其一半的宽度和长度。
这是因为Three.js中的物体是根据它们的中心点进行定位的。当我们说一个物体位于(x,y,z)时,我们实际上是指物体的中心点位于(x,y,z)。因此,要使物体的一个角而不是中心与原点对齐,我们需要将它沿各个轴移动其半个尺寸的距离。
注意点2:
在Three.js中,单位是抽象的,1单位可以代表任何长度。选择厘米作为单位是为了方便与现实世界的数据对接。在3D场景中,无论是选择米、厘米还是其他任何单位,最重要的是保持一致性,并确保场景内的所有元素都是按照相同的比例尺建造的。