theeJs--表面采样器实现3D模型粒子化

效果

在这里插入图片描述
所用插件:
threeJs,
MeshSurfaceSampler.js —webgl表面采样器

MeshSurfaceSampler表面采样器

用于采集模型表面随机一个点,根据这个原理我可以创建一个三维向量:

const sum = 20000;//创建20000个点
const sampler = new THREE.MeshSurfaceSampler(mesh).build();//为模型添加采样器
const tempPosition = new THREE.Vector3();//三维向量
const vertices = [];
 for (let i = 0; i < sum; i ++) {
 	sampler.sample(tempPosition);//通过采样器随机位置采样--(x,y,z)
 	vertices.push(tempPosition.x, tempPosition.y, tempPosition.z);//每次的随机位置保存在vertices数组
 }

通过这样我们得到了一个模型表面的20000个点的位置信息。

正式开始我的粒子化

首先我需要明确流程:

  1. 采样 15000 个坐标并将它们存储在一个数组中
  2. 从坐标和材质创建几何体
  3. 将几何体和材质组合成一个 Points 对象
  4. 将它们添加到场景中
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 7, 10);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const controls = new THREE.OrbitControls(camera, renderer.domElement);

const group = new THREE.Group();
scene.add(group);
const geometry = new THREE.TorusKnotGeometry(4, 1.3, 100, 16);
const torusKnot = new THREE.Mesh(geometry);
//为torusKnot 添加采样器
const sampler = new THREE.MeshSurfaceSampler(torusKnot).build();
const vertices = [];
const tempPosition = new THREE.Vector3();
//采样 15000 个坐标并将它们存储在一个数组中
for (let i = 0; i < 15000; i ++) {
  sampler.sample(tempPosition);
  vertices.push(tempPosition.x, tempPosition.y, tempPosition.z);
}
//从坐标和材质创建几何体
const pointsGeometry = new THREE.BufferGeometry();
pointsGeometry.setAttribute('position', new THREE.Float32BufferAttribute(vertices, 3));
//将几何体和材质组合成一个 Points 对象
const pointsMaterial = new THREE.PointsMaterial({
  color: 0xff61d5,
  size: 0.03
});
const points = new THREE.Points(pointsGeometry, pointsMaterial);
group.add(points);

function render () {  
  group.rotation.y += 0.01;
  renderer.render(scene, camera);
}
renderer.setAnimationLoop(render);

function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', onWindowResize);

在这里插入图片描述

使用 3D 模型

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
);

const renderer = new THREE.WebGLRenderer({
  antialias: true,
  alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

camera.position.z = 230;

const controls = new THREE.OrbitControls(camera, renderer.domElement);

const group = new THREE.Group();
scene.add(group);
const vertices = [];
const colors = [];
const sparklesGeometry = new THREE.BufferGeometry();
const sparklesMaterial = new THREE.PointsMaterial({
  size: 3,
  alphaTest: 0.2,
  map: new THREE.TextureLoader().load("https://assets.codepen.io/127738/dotTexture.png"),
  vertexColors: true // Let Three.js knows that each point has a different color
});
const points = new THREE.Points(sparklesGeometry, sparklesMaterial);
group.add(points);

let sampler = null;
let elephant = null;
new THREE.OBJLoader().load(
"https://assets.codepen.io/127738/Mesh_Elephant.obj",
  (obj) => {
    elephant = obj.children[0];
    elephant.material = new THREE.MeshBasicMaterial({
      color: 0x000000,
      transparent: true,
      opacity: 0.05
    });
    group.add(obj);
    addPoint(elephant)
    renderer.setAnimationLoop(render);
  },
  (xhr) => console.log((xhr.loaded / xhr.total) * 100 + "% loaded"),
  (err) => console.error(err)
);

function addPoint(obj) {
	const sum = 3500;
	/* 随机3种颜色 */
	const palette = [new THREE.Color("#FAAD80"), new THREE.Color("#FF6767"), new THREE.Color("#FF3D68"), new THREE.Color("#A73489")];
  	const sampler = new THREE.MeshSurfaceSampler(obj).build();
  	const tempPosition = new THREE.Vector3();
  	let vertices = new Float32Array(sum*3);
  	let colors = new Float32Array(sum*3);
	for (let i = 0; i < sum; i ++) {
	      sampler.sample(tempPosition);//随机位置采样
	      vertices[i*3+0] = (tempPosition.x);
	      vertices[i*3+1] = (tempPosition.y);
	      vertices[i*3+2] = (tempPosition.z);
	      const color = palette[Math.floor(Math.random() * palette.length)];
	      colors[i*3+0] = (color.r);
	      colors[i*3+1] = (color.g);
	      colors[i*3+2] = (color.b);
	  }
  sparklesGeometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3)  );
  sparklesGeometry.setAttribute("color", new THREE.BufferAttribute(colors, 3));
  console.log(obj);
}

function render(a) {
  group.rotation.y += 0.002;
  controls.update();
  renderer.render(scene, camera);
}
window.addEventListener("resize", onWindowResize, false);
function onWindowResize() {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(window.innerWidth, window.innerHeight);
}

在这里插入图片描述
代码参考:https://codepen.io/Mamboleoo/pen/rNmRqeK

结语

我们可以在这的基础上添加辉光效果,可以参考threeJs官网案例:https://threejs.org/examples/#webgl_postprocessing_unreal_bloom;
实现开头的效果。
我希望你今天学到了一些东西

资料参考:https://tympanus.net/codrops/2021/08/31/surface-sampling-in-three-js/

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值