threejs加载高度图渲染点云,不支持tiff

问题点

使用的point来渲染高度图点云,大数据图片无效渲染点多(可以通过八叉树过滤掉无效点增加效率,这个太复杂),但是胜在简单能用

效果图

img

在这里插入图片描述

code

代码可运行,无需npm

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js Heightmap Visualization</title>
    <style>
        body {
     
      margin: 0; }
        canvas {
     
      display: block; }
    </style>
</head>
<body>
    <button id="loadImageButton">Load Image</button>
    <!-- 引入Three.js和OrbitControls -->
    <!-- <script src="https://cdn.jsdelivr.net/npm/three@v0.149.0/build/three.module.js" type="module"></script> -->
    <script src="https://seikichi.github.io/tiff.js/tiff.min.js"></script>
    <script src="orb.js"></script>
    <script type="module">
        import * as THREE from "https://cdn.jsdelivr.net/npm/three@v0.149.0/build/three.module.js";
        console.log(THREE)
        var {
     
     OrbitControls, MapControls} = Orb(THREE.EventDispatcher,
        THREE.MOUSE,
            THREE.Quaternion,
            THREE.Spherical,
            THREE.TOUCH,
            THREE.Vector2,
            THREE.Vector3)
        // 设置基本的Three.js场景、相机和渲染器
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer();
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);
        // const OrbitControls = threeTsorbitControls;
        // 创建 OrbitControls 控件,并绑定到相机和渲染器
        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true; // 启用阻尼感(惯性效果)
        controls.dampingFactor = 0.25; // 阻尼系数
        controls.screenSpacePanning = true; 
        controls.maxPolarAngle = Math.PI; 

        camera.position.set(100, 100, 500);  // 设置相机位置
        camera.lookAt(0, 0, 0);

        // 加载高度图
        // const textureLoader = new THREE.TextureLoader();
        // textureLoader.load('https://threejsfundamentals.org/threejs/resources/images/heightmap-96x64.png', );

        const createGeometryFn = (texture) => {
     
     
            const img = texture.image;
            const canvas = document.createElement('canvas');
            canvas.width = img.width;
            canvas.height = img.height;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(img, 0, 0);

            const imgData = ctx.getImageData(0, 0, img.width, img.height).data;

            const geometry = new THREE.BufferGeometry();
            const positions = [];
            const colors = [];

            for (let y = 0; y < img.height; y++) {
     
     
                for (let x = 0; x < img.width; x++) {
     
     
                    // 获取像素的灰度值作为高度
                    const index = (y * img.width + x) * 4;
                    const height = imgData[index] / 255 * 50; // 0-255映射为高度范围
                    
                    // 设置每个点的位置 (x, y, height)
                    positions.push(x - img.width / 2, y - img.height / 2, height);

                    // 颜色映射,越高越鲜艳
                    const color = new THREE.Color(`hsl(${ 
       (height / 50) * 240}, 100%, 50%)`);
                    colors.push(color.r, color.g, color.b);
                }
            }

            // 将位置和颜色数据添加到BufferGeometry中
            geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
            geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));

            // 创建点材质,启用顶点颜色
            const material = new THREE.PointsMaterial({
     
     
                size: 1.5,
                vertexColors: true
            });

            // 创建点云对象
            const points = new THREE.Points(geometry, material);
            scene.add(points);

            // 渲染循环
            function animate() {
     
     
                requestAnimationFrame(animate);

                // 更新OrbitControls状态
                controls.update();

                // 渲染场景
                renderer.render(scene, camera);
            }

            animate();
        }

        const createGeometryTiffFn = (canvas) => {
     
     
            const img = texture.image;
            canvas.width = img.width;
            canvas.height = img.height;
            const ctx = canvas.getContext('2d');


            const imgData = ctx.getImageData(0, 0, img.width, img.height).data;

            const geometry = new THREE.BufferGeometry();
            const positions = [];
            const colors = [];

            for (let y = 0; y < img.height; y++) {
     
     
                for (let x = 0; x < img.width; x++) {
     
     
                    // 获取像素的灰度值作为高度
                    const index = (y * img.width + x) * 4;
                    const height = imgData[index] / 255 * 50; // 0-255映射为高度范围
                    
                    // 设置每个点的位置 (x, y, height)
                    positions.push(x - img.width / 2, y - img.height / 2, height);

                    // 颜色映射,越高越鲜艳
                    const color = new THREE.Color(`hsl(${ 
       (height / 50) * 240}, 100%, 50%)`);
                    colors.push(color.r, color.g, color.b);
                }
            }

            // 将位置和颜色数据添加到BufferGeometry中
            geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
            geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));

            // 创建点材质,启用顶点颜色
            const material = new THREE.PointsMaterial({
     
     
                size: 1.5,
                vertexColors: true
            });

            // 创建点云对象
            const points = new THREE.Points(geometry, material);
            scene.add(points);

            // 渲染循环
            function animate() {
     
     
                requestAnimationFrame(animate);

                // 更新OrbitControls状态
                controls.update();

                // 渲染场景
                renderer.render(scene, camera);
            }

            animate();
        }

        Tiff.initialize({
     
     TOTAL_MEMORY: 16777216 * 10});

        function loadFile(){
     
     
            const inputElement = document.createElement('input');
            inputElement.type = 'file';
            inputElement.accept = 'image/*';

            inputElement.addEventListener('change', (event) => {
     
     
                const file = event.target.files[0];
                const reader = new FileReader();
                console.log(file.name)
                reader.onload = function(e) {
     
     
                    let fname = file.name
                    if(fname.includes('tif')){
     
     //todo 我这里没有调试成功
                        const buffer = new Uint8Array(e.target.result);
                        var tiff = new Tiff({
     
     buffer: buffer});
                        console.log(tiff)
                        var canvas = tiff.toCanvas();
                        createGeometryTiffFn(canvas)
                    }else{
     
     
                        const img = new Image();
                        img.src = e.target.result;
                        
                        img.onload = function() {
     
     
                            console
Three.js 中加载百万级别的点云数据时,性能优化是关键。Three.js 本身提供了多种方式来处理大规模点云,但需要合理使用 GPU 加速、数据压缩和渲染优化等技术。 以下是一个使用 `BufferGeometry` 和 `Points` 的示例,可以高效加载百万级别点云: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Three.js 百万点云加载</title> <style> body { margin: 0; } canvas { display: block; } </style> </head> <body> <script src="https://cdn.jsdelivr.net/npm/three@0.155.0/build/three.min.js"></script> <script> // 创建场景、相机、渲染器 const scene = new THREE.Scene(); scene.background = new THREE.Color(0x000000); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.z = 5; const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // 创建点云 const numPoints = 1_000_000; // 百万点 const positions = new Float32Array(numPoints * 3); // 每个点有 x, y, z 三个坐标 // 生成随机点数据(可以替换为真实点云数据) for (let i = 0; i < numPoints; i++) { positions[i * 3 + 0] = (Math.random() - 0.5) * 100; // x positions[i * 3 + 1] = (Math.random() - 0.5) * 100; // y positions[i * 3 + 2] = (Math.random() - 0.5) * 100; // z } const geometry = new THREE.BufferGeometry(); geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); // 点云材质 const material = new THREE.PointsMaterial({ color: 0xffffff, size: 0.05, sizeAttenuation: true // 点的大小随距离变化 }); const points = new THREE.Points(geometry, material); scene.add(points); // 渲染循环 function animate() { requestAnimationFrame(animate); points.rotation.y += 0.001; renderer.render(scene, camera); } animate(); // 自适应窗口大小 window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); </script> </body> </html> ``` --- ### 代码解释: 1. **Three.js 初始化**: - 创建了 `Scene`、`PerspectiveCamera` 和 `WebGLRenderer`,这是 Three.js 的基础结构。 2. **点云数据生成**: - 使用 `Float32Array` 存储百万级别的点云数据,每个点包含 x、y、z 三个浮点数。 - 使用 `BufferGeometry` 来高效管理 GPU 数据,避免 CPU 到 GPU 的频繁传输。 3. **点云渲染**: - 使用 `PointsMaterial` 来定义点云的外观(颜色、点大小等)。 - 使用 `Points` 对象将几何体和材质结合,添加到场景中。 4. **性能优化**: - 使用 `BufferGeometry` 替代传统的 `Geometry`,减少内存开销。 - 使用 `sizeAttenuation: true` 让点的大小随视角距离变化,提升视觉效果。 - 所有点数据一次性上传到 GPU,避免逐帧更新。 --- ### 相关问题: 1. 如何从外部文件(如 `.ply` 或 `.pcd`)加载点云数据? 2. 如何对大规模点云进行 LOD(细节层次)优化? 3. 如何使用 GPU Instancing 提升大规模点云渲染性能? 4. 如何在 Three.js 中实现点云颜色渐变或高度映射? 如果你需要这些扩展功能的实现方法,我可以继续为你提供详细的代码和解释。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值