MarsCode赋能Three.js:如何轻松实现3D模型点云效果

前言

点云技术正成为三维视觉开发的热门方向,而 MarsCode 作为强大的交互逻辑工具,与 Three.js 的采样器结合,为复杂点云效果的实现提供了高效解决方案。本文将重点展示如何借助 MarsCode 快速实现动物点云效果,解析其在数据处理与渲染中的核心作用,为开发者打开点云艺术的新思路。文章末尾会放源码地址

项目预览:

一. 项目初始化

使用html/css/js 模版

项目初始化详情(默认安装了vite),点击顶部运行按钮或使用命令行npm run start即可启动项目

安装项目依赖, package.json概览

json 复制代码
{
  "name": "web-test",
  "version": "1.0.0",
  "description": "",
  "scripts": {
    "start": "vite --host --port=8000"
  },
  "devDependencies": {
    "vite": "^5.2.12",
    "vite-plugin-full-reload": "^1.1.0"
  },
  "dependencies": {
    "three": "0.163.0"
  }
}

二. 代码实现

1. threejs初始化配置

初始化场景、相机、渲染器和控制器,代码较为基础,不多赘述

js 复制代码
import * as THREE from 'three';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader.js';
import { MeshSurfaceSampler } from 'three/examples/jsm/math/MeshSurfaceSampler.js';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.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 control = new OrbitControls(
    camera,
    renderer.domElement,
);

2. 模型加载

  • 本文使用模型为obj格式,所以使用OBJLoader加载模型资源
  • 使用MeshSurfaceSampler初始化模型采样器
  • 使用采样器的sample方法提取点坐标并存储,方便后续点云绘制
js 复制代码
// 添加模型
function addModel() {
    new OBJLoader().load(
        '/models/Elephant.obj',
        (obj) => {
            const model = obj.children[0];
            model.material = new THREE.MeshBasicMaterial({
                wireframe: true,
                color: new THREE.Color('#7264B5'),
                transparent: true,
                opacity: 5,
            });
            sampler = new MeshSurfaceSampler(model).build();

            const tempPosition = new THREE.Vector3();
            // 采样点坐标存储
            for (let i = 0; i < particleNums; i++) {
                sampler.sample(tempPosition);
                vertices.push(tempPosition.x, tempPosition.y, tempPosition.z);
            }
            addParticle(vertices);
        }
    );
}

3. 点云绘制

通过上述采样器获取的点坐标利用BufferGeometry绘制点云。

js 复制代码
// 点云绘制
function addParticle(vertices) {
    let colors = [];
    const palette = [
        new THREE.Color('#88C9B9'), // 青绿色
        new THREE.Color('#673AB7'), // 深紫色
        new THREE.Color('#009688'), // 深绿色
        new THREE.Color('#9C27B0'), // 深紫色
        new THREE.Color('#FFC107'), // 深橙色
        new THREE.Color('#03A9F4'), // 深蓝色
        new THREE.Color('#4CAF50'), // 深绿色
        new THREE.Color('#FF5722'), // 深橙色
    ];
    const pointGeometry = new THREE.BufferGeometry();
    for (let i = 0; i < particleNums; i++) {
        const color = palette[Math.floor(Math.random() * palette.length)];
        colors.push(color.r, color.g, color.b);
    }
    pointGeometry.setAttribute(
        'color',
        new THREE.Float32BufferAttribute(colors, 3),
    );
    pointGeometry.setAttribute(
        'position',
        new THREE.Float32BufferAttribute(vertices, 3),
    );
    const pointMaterial = new THREE.PointsMaterial({
        size: 0.1,
        alphaTest: 0.2,
        vertexColors: true,
    });
    const particles = new THREE.Points(pointGeometry, pointMaterial);
    scene.add(particles);
}

3.1 详解BufferGeometry

BufferGeometry的核心属性是attributes中的position,uv和color

  • position:存储三角面坐标,存储方式为Float32Array,相对于普通的数组读写效率会优秀很多

例如创建一个简单的矩形,我们需要俩个三角面,每个三角面需要三个点坐标,一个矩形由两个三角面构成所以需要六个点坐标。

js 复制代码
const vertices= new Float32Array( [ 
    -1.0, -1.0, 1.0, 
    -1.0, 1.0, 1.0, 
    1.0, 1.0, 1.0, 

    1.0, 1.0, -1.0, 
    1.0, 1.0, -1.0,
    -1.0, 1.0,  1.0 
] ); 
// itemSize = 3 因为每个顶点都是一个三元组。 
geometry.setAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );

ps:观察仔细的同学应该能发现其实有俩个点是重复共用的,这个时候可以通过设置索引缓冲区来共用顶点,从而降低顶点数量的生成,优化渲染效率。

js 复制代码
geometry.setIndex(new THREE.BufferAttribute(indices, 1));
  • uv:定义纹理坐标,大致同上,不过纹理uv坐标是俩俩一组
  • color:颜色数组,注意点数量会和position保持一致,每三个一组,position中是xyz,而color中是rgb,和position一一对应关系

4. 绘制点云之间的连线

通过采样器选取一个初始点,随机选取和初始点距离不超过30的点绘制两点之间的连线,直至没有孤立点

js 复制代码
// 添加线条
function addLines() {
    if (sampler) {
        const tempPosition = new THREE.Vector3();
        const first = previousPoint ? previousPoint.clone() : new THREE.Vector3();
        const lineGeometry = new THREE.BufferGeometry();
        const lineMaterial = new THREE.LineBasicMaterial({
            color: new THREE.Color("#808080"),
            opacity: 0.5,
        });
        let line = new THREE.Line(lineGeometry, lineMaterial);
        !previousPoint && sampler.sample(first);
        previousPoint = first.clone();
        let pointFound = false;
        while (!pointFound) {
            sampler.sample(tempPosition);
            if (tempPosition.distanceTo(previousPoint) < 30) {
                lineGeometry.setAttribute(
                    'position',
                    new THREE.Float32BufferAttribute(
                        [
                            first.x, first.y, first.z,
                            tempPosition.x, tempPosition.y, tempPosition.z
                        ],
                        3,
                    ),
                );
                previousPoint = tempPosition.clone();
                pointFound = true;
            }
        }
        scene.add(line);
    }
}

此时我发现我的代码好像缺少点注释, 于是就问了下豆包MarcodeAI

js 复制代码
const particleNums = 15000; 
const vertices = []; 
let sampler = null; 
let previousPoint; 
let lineIndex = 0; 
let angle = 0; 

回答的很不错,对代码的理解很充分,专有名称也能很好的解释出来,很棒👍️👍

同时还有一个功能出乎我的意料,可以一键将我的代码替换成豆包回答的代码,省去手动cv,这个交互很方便👍️

三. 项目提交至仓库

豆包支持代码上传到github,配置好认证信息就可以提交啦!

四. 结语

如果大家感兴趣可以点击下方链接自行体验一下,欢迎大家在评论区交流,希望可以一键三连,感谢。

豆包体验地址: marscode

代码仓库地址: github

相关推荐
低代码布道师26 分钟前
家校通小程序实战教程08搭建部门管理前端界面
前端·低代码·小程序
张3蜂1 小时前
Blazor(.razor)+VUE+elementUI适合一起用吗
前端·vue.js·elementui
编织幻境的妖1 小时前
使用JavaScrip和HTML搭建一个简单的博客网站系统
前端·html
神膘护体小月半2 小时前
el-table 动态计算合并行
前端·javascript·vue.js
m0_748256782 小时前
【前端】HTML
前端·html
王解4 小时前
企业级包管理器之搭建 npm 私有服务器 (6)
服务器·前端·npm
m0_748237156 小时前
海康威视监控web实时预览解决方案
前端
清风孤客6 小时前
Vue.js 如何塑造现代网络体验
前端·网络·vue.js
一棵开花的树,枝芽无限靠近你7 小时前
【PPTist】历史记录功能
前端·笔记·学习
licy__8 小时前
Vue 2 中 v-text 和 v-html 指令的使用详解
开发语言·前端·javascript