当前位置: 首页 > article >正文

Cannon-es.js之Distance Constrait模拟布料

本文目录

  • 前言
  • 1、Particle
  • 2、前置代码准备
    • 2.1 代码
    • 2.2 效果
  • 3、使用距离约束模拟布料
    • 3.1 代码
    • 3.2 效果

前言

在现代Web开发中,实现逼真的物理效果对于提升用户体验至关重要。Cannon-es.js,作为Cannon.jsES6模块版本,凭借其轻量级、高性能和易于集成的特点,在WebGL环境中进行物理模拟时备受青睐。本文将深入探讨Cannon-es.js在模拟物理效果方面的应用,包括Particle(粒子)的基本使用、前置代码准备,以及如何使用距离约束来模拟布料效果。
粒子系统在游戏开发、动画制作以及物理模拟等领域有着广泛的应用。通过Cannon-es.js,我们可以轻松创建和管理粒子,实现各种复杂的物理效果。此外,距离约束作为一种强大的物理约束类型,允许我们模拟物体之间的连接关系,这在模拟布料、绳索等柔性物体时尤为有用。
在接下来的内容中,我们将详细介绍如何准备前置代码,如何使用Cannon-es.js创建粒子,并通过距离约束来模拟布料效果。希望通过本文的探讨,读者能够掌握Cannon-es.js在物理模拟方面的基本技巧,并在自己的项目中实现更加复杂和逼真的物理效果。

1、Particle

cannon-es(一个轻量级的JavaScript物理引擎,用于处理刚体动力学模拟)中,Particle(粒子)并不是传统意义上的三维几何体(如球体、立方体等),而是一个没有形状、大小或旋转属性的质量点。粒子主要用于模拟点质量的行为,如重力作用下的自由落体、碰撞检测中的接触点,或者作为更复杂刚体的一部分(例如,通过约束将多个粒子连接在一起以形成软体物理效果)。
Particlecannon-es中是一个特殊的Body类型,它只具有位置(position)、速度(velocity)和力(force)等属性,而没有形状(shape)和惯性(inertia)等刚体通常具有的属性。由于粒子没有形状,因此它们不会直接参与碰撞检测中的边界计算;相反,它们通常通过与其他粒子或刚体的接触点来间接参与碰撞。
cannon-es中创建一个Particle通常涉及以下步骤:

  1. 创建一个CANNON.Body实例,但将其形状(shape)属性设置为null或省略(因为粒子没有形状)。
  2. 设置粒子的质量(mass)。
  3. (可选)设置粒子的初始位置(position)和速度(velocity)。

2、前置代码准备

2.1 代码

<template>
    <canvas ref="cannonDemo" class="cannonDemo">
    </canvas>
</template>

<script setup>
import { onMounted, ref } from "vue"
import * as THREE from 'three'
import * as CANNON from 'cannon-es'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
const cannonDemo = ref('null')

onMounted(() => {
    const cannonDemoDomWidth = cannonDemo.value.offsetWidth
    const cannonDemoDomHeight = cannonDemo.value.offsetHeight

    // 创建场景
    const scene = new THREE.Scene
    // 创建相机
    const camera = new THREE.PerspectiveCamera( // 透视相机
        45, // 视角 角度数
        cannonDemoDomWidth / cannonDemoDomHeight, // 宽高比 占据屏幕
        0.1, // 近平面(相机最近能看到物体)
        1000, // 远平面(相机最远能看到物体)
    )
    camera.position.set(0, 2, 70)
    // 创建渲染器
    const renderer = new THREE.WebGLRenderer({
        antialias: true, // 抗锯齿
        canvas: cannonDemo.value
    })
    // 设置设备像素比
    renderer.setPixelRatio(window.devicePixelRatio)
    // 设置画布尺寸
    renderer.setSize(cannonDemoDomWidth, cannonDemoDomHeight)

    const light = new THREE.AmbientLight(0x404040, 200); // 柔和的白光
    scene.add(light);


    let meshes = []
    let phyMeshes = []
    const physicsWorld = new CANNON.World()
    // 设置y轴重力
    physicsWorld.gravity.set(0, -9.82, 0)

    const rows = 15
    const cols = 15
    const sphereGeometry = new THREE.SphereGeometry(0.2, 16, 16)
    const sphereMaterial = new THREE.MeshBasicMaterial({color: 0xff0000})
    const particleShape = new CANNON.Particle()
    let bodies = {}
    for(let i = 0; i < cols; i++) {
       for(let j = 0; j < rows; j++) {
        // 物理世界
        const particleBody = new CANNON.Body({
            mass: 0.5,
            position: new CANNON.Vec3(i - cols * 0.5, 10, j - rows * 0.5),
            shape: particleShape
        })
        bodies[`${i}-${j}`] = particleBody
        physicsWorld.addBody(particleBody)
        phyMeshes.push(particleBody)

        // 渲染世界
        const sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial)
        sphereMesh.position.set(i - cols * 0.5, 10, j - rows * 0.5)
        meshes.push(sphereMesh)
        scene.add(sphereMesh)
       }
    }
    const axesHelper = new THREE.AxesHelper(30);
    scene.add(axesHelper);

    const updatePhysic = () => { // 因为这是实时更新的,所以需要放到渲染循环动画animate函数中
        physicsWorld.step(1 / 60)
        for (let i = 0; i < phyMeshes.length; i++) {
            meshes[i].position.copy(phyMeshes[i].position)
            meshes[i].quaternion.copy(phyMeshes[i].quaternion)
        }
    }

    // 控制器
    const control = new OrbitControls(camera, renderer.domElement)
    // 开启阻尼惯性,默认值为0.05
    control.enableDamping = true

    // 渲染循环动画
    function animate() {
        // 在这里我们创建了一个使渲染器能够在每次屏幕刷新时对场景进行绘制的循环(在大多数屏幕上,刷新率一般是60次/秒)
        requestAnimationFrame(animate)
        updatePhysic()
        // 更新控制器。如果没在动画里加上,那必须在摄像机的变换发生任何手动改变后调用
        control.update()
        renderer.render(scene, camera)
    }

    // 执行动画
    animate()
})

</script>
<style scoped>
.cannonDemo {
    width: 100vw;
    height: 100vh;
}
</style>

2.2 效果

请添加图片描述


3、使用距离约束模拟布料

3.1 代码

在上面的基础添加距离约束代码:

    for(let i = 0; i < cols; i++) {
        for(let j = 0; j < rows; j++) {
            const body = bodies[`${i}-${j}`]
            if (i > 0) {
                const body2 = bodies[`${i - 1}-${j}`]
                const constraint = new CANNON.DistanceConstraint(body, body2, 0.4)
                physicsWorld.addConstraint(constraint)
            }
            if (j > 0) {
                const body2 = bodies[`${i}-${j - 1}`]
                const constraint = new CANNON.DistanceConstraint(body, body2, 0.4)
                physicsWorld.addConstraint(constraint)
            }
        }
    }

3.2 效果

请添加图片描述

在学习的路上,如果你觉得本文对你有所帮助的话,那就请关注点赞评论三连吧,谢谢,你的肯定是我写博的另一个支持。


http://www.kler.cn/news/326507.html

相关文章:

  • 【hot100-java】【合并两个有序链表】
  • MySQL数据库备份详解
  • Ubuntu下安装向日葵:闪退
  • SpirngBoot核心思想之一IOC
  • Leetcode 46 Permutation Leetcode 78 Subsets
  • AndroidStudio依赖报错
  • 力扣(leetcode)每日一题 1014 最佳观光组合
  • Android 开启相机一键拍照,一键录制
  • VirtualService和destinationRule
  • 大数据毕业设计选题推荐-国潮男装微博评论数据分析系统-Hive-Hadoop-Spark
  • Ranger集成CDH6.3.1详细步骤
  • 『功能项目』下载Mongodb【81】
  • C++中string的使用
  • ​​乐​​牛一​面​​​游​​卡​​一​二​​​​面​
  • 什么是IPv6
  • vue中使用jsencrypt加密
  • 超声波清洗机哪家好用又实惠?2024热门超声波清洗机选择推荐!
  • 工作笔记20240927——vscode + jlink调试
  • 数字化AI直播革命:无人直播新纪元,真AI赋能未来!
  • 小程序开发平台源码系统 各行各业适用的小程序开的平台 带完整的安装代码包以及搭建部署教程
  • 本篇4K,立志最细,FreeRtos中Queue使用教程与个人理解!!!
  • 《向量数据库指南》——Fivetran 的 Partner SDK:构建自定义连接器和目标
  • 【学习笔记】手写 Tomcat 四
  • 实战笔记:Vue2项目Webpack 3升级到Webpack 4的实操指南
  • 双指针---(部分地更新)
  • 解决:使用layui.treeTable.updateNode,更新表格数据后,done里面的事件丢失问题
  • PHP 异步编程:从入门到精通
  • 使用 React Router v6 在 React 中实现面包屑
  • docker 部署nacos
  • uniapp路由跳转