程序员教你用代码制作3d爱心跳动特效,正好拿去送给女神给她个惊喜

简介: 使用HTML、CSS和JavaScript实现了一个三维网格采样器`MeshSurfaceSampler`,适用于任意浏览器,推荐谷歌。代码创建了一个类,从缓冲几何体的三角形网格中进行随机采样。提供了设置权重属性、构建分布和自定义随机数生成器的功能。用户只需将代码复制到文本文档并保存为HTML文件,即可运行。适合编程爱好者尝试,也可分享给他人。

HTML+CSS+JavaScript实现

先点赞后观看,养成好习惯

效果图

注:任意浏览器都可以,建议使用谷歌浏览器

代码部分

代码如下仅供参考
可以直接拿去复制粘贴

(function () {
const _face = new THREE.Triangle();

const _color = new THREE.Vector3();

class MeshSurfaceSampler {

constructor(mesh) {

  let geometry = mesh.geometry;

  if (!geometry.isBufferGeometry || geometry.attributes.position.itemSize !== 3) {

    throw new Error('THREE.MeshSurfaceSampler: Requires BufferGeometry triangle mesh.');

  }

  if (geometry.index) {

    console.warn('THREE.MeshSurfaceSampler: Converting geometry to non-indexed BufferGeometry.');
    geometry = geometry.toNonIndexed();

  }

  this.geometry = geometry;
  this.randomFunction = Math.random;
  this.positionAttribute = this.geometry.getAttribute('position');
  this.colorAttribute = this.geometry.getAttribute('color');
  this.weightAttribute = null;
  this.distribution = null;

}

setWeightAttribute(name) {

  this.weightAttribute = name ? this.geometry.getAttribute(name) : null;
  return this;

}

build() {

  const positionAttribute = this.positionAttribute;
  const weightAttribute = this.weightAttribute;
  const faceWeights = new Float32Array(positionAttribute.count / 3); // Accumulate weights for each mesh face.

  for (let i = 0; i < positionAttribute.count; i += 3) {

    let faceWeight = 1;

    if (weightAttribute) {

      faceWeight = weightAttribute.getX(i) + weightAttribute.getX(i + 1) + weightAttribute.getX(i + 2);

    }

    _face.a.fromBufferAttribute(positionAttribute, i);

    _face.b.fromBufferAttribute(positionAttribute, i + 1);

    _face.c.fromBufferAttribute(positionAttribute, i + 2);

    faceWeight *= _face.getArea();
    faceWeights[i / 3] = faceWeight;

  } // Store cumulative total face weights in an array, where weight index
  // corresponds to face index.


  this.distribution = new Float32Array(positionAttribute.count / 3);
  let cumulativeTotal = 0;

  for (let i = 0; i < faceWeights.length; i++) {

    cumulativeTotal += faceWeights[i];
    this.distribution[i] = cumulativeTotal;

  }

  return this;

}

setRandomGenerator(randomFunction) {

  this.randomFunction = randomFunction;
  return this;

}

sample(targetPosition, targetNormal, targetColor) {

  const cumulativeTotal = this.distribution[this.distribution.length - 1];
  const faceIndex = this.binarySearch(this.randomFunction() * cumulativeTotal);
  return this.sampleFace(faceIndex, targetPosition, targetNormal, targetColor);

}

binarySearch(x) {

  const dist = this.distribution;
  let start = 0;
  let end = dist.length - 1;
  let index = - 1;

  while (start <= end) {

    const mid = Math.ceil((start + end) / 2);

    if (mid === 0 || dist[mid - 1] <= x && dist[mid] > x) {

      index = mid;
      break;

    } else if (x < dist[mid]) {

      end = mid - 1;

    } else {

      start = mid + 1;

    }

  }

  return index;

}

sampleFace(faceIndex, targetPosition, targetNormal, targetColor) {

  let u = this.randomFunction();
  let v = this.randomFunction();

  if (u + v > 1) {

    u = 1 - u;
    v = 1 - v;

  }

  _face.a.fromBufferAttribute(this.positionAttribute, faceIndex * 3);

  _face.b.fromBufferAttribute(this.positionAttribute, faceIndex * 3 + 1);

  _face.c.fromBufferAttribute(this.positionAttribute, faceIndex * 3 + 2);

  targetPosition.set(0, 0, 0).addScaledVector(_face.a, u).addScaledVector(_face.b, v).addScaledVector(_face.c, 1 - (u + v));

  if (targetNormal !== undefined) {

    _face.getNormal(targetNormal);

  }

  if (targetColor !== undefined && this.colorAttribute !== undefined) {

    _face.a.fromBufferAttribute(this.colorAttribute, faceIndex * 3);

    _face.b.fromBufferAttribute(this.colorAttribute, faceIndex * 3 + 1);

    _face.c.fromBufferAttribute(this.colorAttribute, faceIndex * 3 + 2);

    _color.set(0, 0, 0).addScaledVector(_face.a, u).addScaledVector(_face.b, v).addScaledVector(_face.c, 1 - (u + v));

    targetColor.r = _color.x;
    targetColor.g = _color.y;
    targetColor.b = _color.z;
  }
  return this;

}

}

THREE.MeshSurfaceSampler = MeshSurfaceSampler;

})();

运行步骤,在桌面新建个文本文档,将代码全部复制到文档后保存,然后重命名将.txt文件修改成.html文件最后点击文件就能运行成功啦,运行成功了快快发给爱慕女孩,说不定就能收获到爱情啦。(如果有不想动手的小伙伴可以私聊博主获取哦!!!!)

相关文章
|
存储 移动开发 前端开发
七夕特辑——3D爱心(可监听鼠标移动)
七夕特辑——3D爱心(可监听鼠标移动)
|
Python
李峋同款爱心Python代码版来了
李峋同款爱心Python代码版来了
11558 132
李峋同款爱心Python代码版来了
|
Ubuntu 虚拟化
VMWare Tools没有正确安装或者版本过低导致的
VMWare Tools没有正确安装或者版本过低导致的
1588 2
|
JSON 数据格式 Docker
docker load导入镜像报错:open /var/lib/docker/tmp/docker-import-970689518/bin/json: no such file or directo...
docker load导入镜像报错:open /var/lib/docker/tmp/docker-import-970689518/bin/json: no such file or directo...
7981 0
|
Kubernetes NoSQL 测试技术
在 K8S 中快速部署 Redis Cluster & Redisinsight
在 K8S 中快速部署 Redis Cluster & Redisinsight
2238 0
在 K8S 中快速部署 Redis Cluster & Redisinsight
|
8月前
|
Web App开发 人工智能 机器人
OpenClaw能做什么?我用OpenClaw(Clawdbot) AI自动考试答题,部署+GLM-4.7接入+浏览器自动化教程
2026年,OpenClaw(曾用名Moltbot/Clawdbot)凭借强大的浏览器自动化与AI交互能力,成为智能答题、问卷填写等场景的高效工具。其核心优势在于能深度识别网页内容、自动解析题目选项,并结合大模型完成精准作答,彻底解放人工重复操作。本文将完整拆解**2026年阿里云OpenClaw极简部署**、**GLM-4.7模型接入**、**QQ机器人配置**、**SSH隧道安全访问**及**浏览器自动化答题**全流程,所有代码命令可直接复制执行,全程规避无关平台信息,从云端部署到实战答题一站式落地,适合学生、办公人士及各类需要高效完成线上答题的用户。
2204 15
|
JavaScript 前端开发 数据安全/隐私保护
vue3+ts+elementplus写一个登录页面教程
【6月更文挑战第3天】本文介绍了如何使用 Vue 3 和 TypeScript 创建一个登录页面。首先,需安装 Vue CLI,然后创建新项目并启用 TypeScript 支持。接着,创建 `Login.vue` 组件,设计登录表单,包括用户账号、密码和验证码字段,并实现相关验证规则。页面样式包括背景、登录框和按钮等元素的布局与样式。最后,展示了`&lt;script&gt;`部分的代码,包括表单验证逻辑、生成验证码的函数以及登录提交处理。文章还提供了一个登录页面的截图和完整代码示例。
6545 1
|
存储 移动开发 小程序
校园圈子系统小程序(圈子论坛、私信聊天、资料共享、二手交易、兼职,跑腿)开源码开发/微信公众号、小程序、H5多端账号同步/搭建多城市的综合社交生活平台
基于开源技术栈构建的校园圈子系统小程序,整合社交与生活服务功能,涵盖兴趣圈子、私信聊天、资料共享、二手交易、兼职跑腿等六大核心模块。通过多端账号同步(微信公众号/小程序/H5),实现数据实时交互,满足学生群体的多元化需求。项目精准锚定校园市场,以“社交+服务”双轮驱动,提供一站式解决方案,支持快速部署与多校区运营,同时具备广告、佣金、会员等多元变现能力,是打造校园生态的理想工具。
1884 3
校园圈子系统小程序(圈子论坛、私信聊天、资料共享、二手交易、兼职,跑腿)开源码开发/微信公众号、小程序、H5多端账号同步/搭建多城市的综合社交生活平台

热门文章

最新文章