new Ammo.btSoftBodyHelpers() 是 Ammo.js 中的一个构造函数,用于创建软体物体的辅助对象,提供了一些方法来创建软体物体

demo案例
在这里插入图片描述

new Ammo.btSoftBodyHelpers() 是 Ammo.js 中的一个构造函数,用于创建软体物体的辅助对象,提供了一些方法来创建软体物体。以下是它的一些重要信息:

  • 入参:通常不需要传入参数。

  • 出参:创建的新的软体辅助对象。

  • 属性:该构造函数返回的对象通常没有额外的属性,它主要用于提供方法来创建软体物体。

  • 方法

    • CreateFromTriMesh(worldInfo, vertices, indices, numIndices, randomizeConstraints):基于三角网格创建软体物体。它接受以下参数:
      • worldInfo:物理世界信息对象。
      • vertices:顶点数组。
      • indices:索引数组。
      • numIndices:索引数量。
      • randomizeConstraints:是否随机化约束。
    • 其他用于创建软体物体的方法。

new Ammo.btTransform 是 Ammo.js 中的一个构造函数,用于创建表示刚体变换的对象。以下是它的一些重要信息:

  • 入参:通常不需要传入参数。如果需要初始化变换矩阵,可以传入一个矩阵对象。

  • 出参:创建的新的变换对象。

  • 属性

    • origin:表示变换的位置的向量。
    • rotation:表示变换的旋转的四元数。
  • 方法

    • setIdentity():将变换设置为单位变换。
    • setOrigin(origin):设置变换的位置。
    • setRotation(rotation):设置变换的旋转。
    • 其他用于获取和设置变换的位置和旋转的方法。

Ammo.js 物理软体体积的核心代码是在 createSoftVolume 函数中。具体来说,以下是该函数的关键部分:

function createSoftVolume( bufferGeom, mass, pressure ) {processGeometry( bufferGeom );const volume = new THREE.Mesh( bufferGeom, new THREE.MeshPhongMaterial( { color: 0xFFFFFF } ) );volume.castShadow = true;volume.receiveShadow = true;volume.frustumCulled = false;scene.add( volume );// 创建软体体积物理对象const volumeSoftBody = softBodyHelpers.CreateFromTriMesh(physicsWorld.getWorldInfo(),bufferGeom.ammoVertices,bufferGeom.ammoIndices,bufferGeom.ammoIndices.length / 3,true );const sbConfig = volumeSoftBody.get_m_cfg();sbConfig.set_viterations( 40 );sbConfig.set_piterations( 40 );// 设置软体的碰撞参数sbConfig.set_collisions( 0x11 );// 设置摩擦、阻尼和压力sbConfig.set_kDF( 0.1 );sbConfig.set_kDP( 0.01 );sbConfig.set_kPR( pressure );// 设置软体的刚度volumeSoftBody.get_m_materials().at( 0 ).set_m_kLST( 0.9 );volumeSoftBody.get_m_materials().at( 0 ).set_m_kAST( 0.9 );volumeSoftBody.setTotalMass( mass, false );Ammo.castObject( volumeSoftBody, Ammo.btCollisionObject ).getCollisionShape().setMargin( margin );physicsWorld.addSoftBody( volumeSoftBody, 1, - 1 );volume.userData.physicsBody = volumeSoftBody;// 禁用去激活volumeSoftBody.setActivationState( 4 );softBodies.push( volume );}

这段代码首先调用 processGeometry 函数对几何体进行处理,然后创建一个 THREE.Mesh 对象表示软体体积的图形表示。接着,通过 softBodyHelpers.CreateFromTriMesh 方法创建了一个 Ammo.js 的软体体积物理对象,设置了软体的各种物理参数,最后将软体体积物理对象添加到物理世界中。

demo 源码

<html lang="en"><head><title>Ammo.js软体体积演示</title> <!-- 设置页面标题 --><meta charset="utf-8"><meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"><link type="text/css" rel="stylesheet" href="main.css"><style>body {color: #333;}</style></head><body><div id="info">Ammo.js物理软体体积演示<br/> <!-- 页面顶部信息 -->点击以抛出一个球 <!-- 提示用户点击以抛出一个球 --></div><div id="container"></div><script src="jsm/libs/ammo.wasm.js"></script> <!-- 引入Ammo.js库 --><script type="importmap">{"imports": {"three": "../build/three.module.js", <!-- 引入Three.js库 -->"three/addons/": "./jsm/"}}</script><script type="module">import * as THREE from 'three'; <!-- 导入Three.js库 -->import Stats from 'three/addons/libs/stats.module.js'; <!-- 导入性能统计库Stats.js -->import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; <!-- 导入OrbitControls控制器 -->import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; <!-- 导入BufferGeometryUtils工具库 -->// 图形变量let container, stats; <!-- 定义容器和性能统计变量 -->let camera, controls, scene, renderer; <!-- 定义相机、控制器、场景和渲染器变量 -->let textureLoader; <!-- 纹理加载器变量 -->const clock = new THREE.Clock(); <!-- 时钟变量 -->let clickRequest = false; <!-- 点击请求标志 -->const mouseCoords = new THREE.Vector2(); <!-- 鼠标坐标变量 -->const raycaster = new THREE.Raycaster(); <!-- 射线投射器变量 -->const ballMaterial = new THREE.MeshPhongMaterial( { color: 0x202020 } ); <!-- 球体材质 -->const pos = new THREE.Vector3(); <!-- 位置向量 -->const quat = new THREE.Quaternion(); <!-- 四元数变量 -->// 物理变量const gravityConstant = - 9.8; <!-- 重力常数 -->let physicsWorld; <!-- 物理世界变量 -->const rigidBodies = []; <!-- 刚体数组 -->const softBodies = []; <!-- 软体数组 -->const margin = 0.05; <!-- 边缘间距 -->let transformAux1; <!-- 辅助变换对象 -->let softBodyHelpers; <!-- 软体帮助对象 -->Ammo().then( function ( AmmoLib ) { <!-- 异步加载Ammo.js库 -->Ammo = AmmoLib;init(); <!-- 初始化 -->animate(); <!-- 动画循环 -->} );function init() { <!-- 初始化函数 -->initGraphics(); <!-- 初始化图形部分 -->initPhysics(); <!-- 初始化物理部分 -->createObjects(); <!-- 创建物体 -->initInput(); <!-- 初始化输入事件 -->}function initGraphics() { <!-- 初始化图形函数 -->container = document.getElementById( 'container' ); <!-- 获取容器元素 -->camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.2, 2000 ); <!-- 创建透视相机 -->scene = new THREE.Scene(); <!-- 创建场景 -->scene.background = new THREE.Color( 0xbfd1e5 ); <!-- 设置场景背景色 -->camera.position.set( - 7, 5, 8 ); <!-- 设置相机位置 -->renderer = new THREE.WebGLRenderer( { antialias: true } ); <!-- 创建WebGL渲染器 -->renderer.setPixelRatio( window.devicePixelRatio ); <!-- 设置像素比 -->renderer.setSize( window.innerWidth, window.innerHeight ); <!-- 设置渲染器大小 -->renderer.shadowMap.enabled = true; <!-- 开启阴影映射 -->container.appendChild( renderer.domElement ); <!-- 将渲染器添加到容器中 -->controls = new OrbitControls( camera, renderer.domElement ); <!-- 创建轨道控制器 -->controls.target.set( 0, 2, 0 ); <!-- 设置控制器目标 -->controls.update(); <!-- 更新控制器状态 -->textureLoader = new THREE.TextureLoader(); <!-- 创建纹理加载器对象 -->const ambientLight = new THREE.AmbientLight( 0xbbbbbb ); <!-- 创建环境光 -->scene.add( ambientLight ); <!-- 将环境光添加到场景中 -->const light = new THREE.DirectionalLight( 0xffffff, 3 ); <!-- 创建方向光 -->light.position.set( - 10, 10, 5 ); <!-- 设置光源位置 -->light.castShadow = true; <!-- 开启阴影 -->const d = 20;light.shadow.camera.left = - d; <!-- 设置阴影相机左边界 -->light.shadow.camera.right = d; <!-- 设置阴影相机右边界 -->light.shadow.camera.top = d; <!-- 设置阴影相机上边界 -->light.shadow.camera.bottom = - d; <!-- 设置阴影相机下边界 -->light.shadow.camera.near = 2; <!-- 设置阴影相机近裁剪面 -->light.shadow.camera.far = 50; <!-- 设置阴影相机远裁剪面 -->light.shadow.mapSize.x = 1024; <!-- 设置阴影贴图大小 -->light.shadow.mapSize.y = 1024; <!-- 设置阴影贴图大小 -->scene.add( light ); <!-- 将光源添加到场景中 -->stats = new Stats(); <!-- 创建性能统计对象 -->stats.domElement.style.position = 'absolute'; <!-- 设置性能统计元素位置 -->stats.domElement.style.top = '0px'; <!-- 设置性能统计元素位置 -->container.appendChild( stats.domElement ); <!-- 将性能统计元素添加到容器中 -->window.addEventListener( 'resize', onWindowResize ); <!-- 监听窗口大小变化事件 -->}function initPhysics() { <!-- 初始化物理函数 -->// 物理配置const collisionConfiguration = new Ammo.btSoftBodyRigidBodyCollisionConfiguration(); <!-- 创建碰撞配置对象 -->const dispatcher = new Ammo.btCollisionDispatcher( collisionConfiguration ); <!-- 创建碰撞分发器对象 -->const broadphase = new Ammo.btDbvtBroadphase(); <!-- 创建Broadphase对象 -->const solver = new Ammo.btSequentialImpulseConstraintSolver(); <!-- 创建约束求解器对象 -->const softBodySolver = new Ammo.btDefaultSoftBodySolver(); <!-- 创建软体求解器对象 -->physicsWorld = new Ammo.btSoftRigidDynamicsWorld( dispatcher, broadphase, solver, collisionConfiguration, softBodySolver ); <!-- 创建软硬体动力学世界对象 -->physicsWorld.setGravity( new Ammo.btVector3( 0, gravityConstant, 0 ) ); <!-- 设置重力 -->physicsWorld.getWorldInfo().set_m_gravity( new Ammo.btVector3( 0, gravityConstant, 0 ) ); <!-- 设置世界重力 -->transformAux1 = new Ammo.btTransform(); <!-- 创建辅助变换对象 -->softBodyHelpers = new Ammo.btSoftBodyHelpers(); <!-- 创建软体帮助对象 -->}function createObjects() { <!-- 创建物体函数 -->// 地面pos.set( 0, - 0.5, 0 );quat.set( 0, 0, 0, 1 );const ground = createParalellepiped( 40, 1, 40, 0, pos, quat, new THREE.MeshPhongMaterial( { color: 0xFFFFFF } ) ); <!-- 创建地面 -->ground.castShadow = true; <!-- 设置地面投射阴影 -->ground.receiveShadow = true; <!-- 设置地面接收阴影 -->textureLoader.load( 'textures/grid.png', function ( texture ) { <!-- 加载地面纹理 -->texture.colorSpace = THREE.SRGBColorSpace; <!-- 设置纹理色彩空间 -->texture.wrapS = THREE.RepeatWrapping; <!-- 设置纹理水平重复方式 -->texture.wrapT = THREE.RepeatWrapping; <!-- 设置纹理垂直重复方式 -->texture.repeat.set( 40, 40 ); <!-- 设置纹理重复次数 -->ground.material.map = texture; <!-- 设置地面材质纹理 -->ground.material.needsUpdate = true; <!-- 更新材质 -->} );// 创建软体体积const volumeMass = 15; <!-- 设置体积质量 -->const sphereGeometry = new THREE.SphereGeometry( 1.5, 40, 25 ); <!-- 创建球体几何体 -->sphereGeometry.translate( 5, 5, 0 ); <!-- 设置球体位置 -->createSoftVolume( sphereGeometry, volumeMass, 250 ); <!-- 创建球体软体体积 -->const boxGeometry = new THREE.BoxGeometry( 1, 1, 5, 4, 4, 20 ); <!-- 创建盒体几何体 -->boxGeometry.translate( - 2, 5, 0 ); <!-- 设置盒体位置 -->createSoftVolume( boxGeometry, volumeMass, 120 ); <!-- 创建盒体软体体积 -->// 斜坡pos.set( 3, 1, 0 );quat.setFromAxisAngle( new THREE.Vector3( 0, 0, 1 ), 30 * Math.PI / 180 );const obstacle = createParalellepiped( 10, 1, 4, 0, pos, quat, new THREE.MeshPhongMaterial( { color: 0x606060 } ) ); <!-- 创建斜坡 -->obstacle.castShadow = true; <!-- 设置斜坡投射阴影 -->obstacle.receiveShadow = true; <!-- 设置斜坡接收阴影 -->}function processGeometry( bufGeometry ) {// 只考虑位置值来合并顶点const posOnlyBufGeometry = new THREE.BufferGeometry();posOnlyBufGeometry.setAttribute( 'position', bufGeometry.getAttribute( 'position' ) );posOnlyBufGeometry.setIndex( bufGeometry.getIndex() );// 合并顶点以将三角形网格转换为索引三角形const indexedBufferGeom = BufferGeometryUtils.mergeVertices( posOnlyBufGeometry );// 创建索引数组,将索引顶点映射到bufGeometry顶点mapIndices( bufGeometry, indexedBufferGeom );}function isEqual( x1, y1, z1, x2, y2, z2 ) {const delta = 0.000001;return Math.abs( x2 - x1 ) < delta &&Math.abs( y2 - y1 ) < delta &&Math.abs( z2 - z1 ) < delta;}function mapIndices( bufGeometry, indexedBufferGeom ) {// 创建ammoVertices、ammoIndices和ammoIndexAssociation在bufGeometry中const vertices = bufGeometry.attributes.position.array;const idxVertices = indexedBufferGeom.attributes.position.array;const indices = indexedBufferGeom.index.array;const numIdxVertices = idxVertices.length / 3;const numVertices = vertices.length / 3;bufGeometry.ammoVertices = idxVertices;bufGeometry.ammoIndices = indices;bufGeometry.ammoIndexAssociation = [];for ( let i = 0; i < numIdxVertices; i ++ ) {const association = [];bufGeometry.ammoIndexAssociation.push( association );const i3 = i * 3;for ( let j = 0; j <numVertices; j ++ ) {const j3 = j * 3;if ( isEqual( idxVertices[ i3 ], idxVertices[ i3 + 1 ], idxVertices[ i3 + 2 ],vertices[ j3 ], vertices[ j3 + 1 ], vertices[ j3 + 2 ] ) ) {association.push( j3 );}}}}function createSoftVolume( bufferGeom, mass, pressure ) {processGeometry( bufferGeom );const volume = new THREE.Mesh( bufferGeom, new THREE.MeshPhongMaterial( { color: 0xFFFFFF } ) );volume.castShadow = true;volume.receiveShadow = true;volume.frustumCulled = false;scene.add( volume );textureLoader.load( 'textures/colors.png', function ( texture ) {volume.material.map = texture;volume.material.needsUpdate = true;} );// 体积物理对象const volumeSoftBody = softBodyHelpers.CreateFromTriMesh(physicsWorld.getWorldInfo(),bufferGeom.ammoVertices,bufferGeom.ammoIndices,bufferGeom.ammoIndices.length / 3,true );const sbConfig = volumeSoftBody.get_m_cfg();sbConfig.set_viterations( 40 );sbConfig.set_piterations( 40 );// 软-软体和软-刚体碰撞sbConfig.set_collisions( 0x11 );// 摩擦sbConfig.set_kDF( 0.1 );// 阻尼sbConfig.set_kDP( 0.01 );// 压力sbConfig.set_kPR( pressure );// 刚度volumeSoftBody.get_m_materials().at( 0 ).set_m_kLST( 0.9 );volumeSoftBody.get_m_materials().at( 0 ).set_m_kAST( 0.9 );volumeSoftBody.setTotalMass( mass, false );Ammo.castObject( volumeSoftBody, Ammo.btCollisionObject ).getCollisionShape().setMargin( margin );physicsWorld.addSoftBody( volumeSoftBody, 1, - 1 );volume.userData.physicsBody = volumeSoftBody;// 禁用去激活volumeSoftBody.setActivationState( 4 );softBodies.push( volume );}function createParalellepiped( sx, sy, sz, mass, pos, quat, material ) {const threeObject = new THREE.Mesh( new THREE.BoxGeometry( sx, sy, sz, 1, 1, 1 ), material );const shape = new Ammo.btBoxShape( new Ammo.btVector3( sx * 0.5, sy * 0.5, sz * 0.5 ) );shape.setMargin( margin );createRigidBody( threeObject, shape, mass, pos, quat );return threeObject;}function createRigidBody( threeObject, physicsShape, mass, pos, quat ) {threeObject.position.copy( pos );threeObject.quaternion.copy( quat );const transform = new Ammo.btTransform();transform.setIdentity();transform.setOrigin( new Ammo.btVector3( pos.x, pos.y, pos.z ) );transform.setRotation( new Ammo.btQuaternion( quat.x, quat.y, quat.z, quat.w ) );const motionState = new Ammo.btDefaultMotionState( transform );const localInertia = new Ammo.btVector3( 0, 0, 0 );physicsShape.calculateLocalInertia( mass, localInertia );const rbInfo = new Ammo.btRigidBodyConstructionInfo( mass, motionState, physicsShape, localInertia );const body = new Ammo.btRigidBody( rbInfo );threeObject.userData.physicsBody = body;scene.add( threeObject );if ( mass > 0 ) {rigidBodies.push( threeObject );// 禁用去激活body.setActivationState( 4 );}physicsWorld.addRigidBody( body );return body;}function initInput() {window.addEventListener( 'pointerdown', function ( event ) {if ( ! clickRequest ) {mouseCoords.set(( event.clientX / window.innerWidth ) * 2 - 1,- ( event.clientY / window.innerHeight ) * 2 + 1);clickRequest = true;}} );}function processClick() {if ( clickRequest ) {raycaster.setFromCamera( mouseCoords, camera );// 创建球体const ballMass = 3;const ballRadius = 0.4;const ball = new THREE.Mesh( new THREE.SphereGeometry( ballRadius, 18, 16 ), ballMaterial );ball.castShadow = true;ball.receiveShadow = true;const ballShape = new Ammo.btSphereShape( ballRadius );ballShape.setMargin( margin );pos.copy( raycaster.ray.direction );pos.add( raycaster.ray.origin );quat.set( 0, 0, 0, 1 );const ballBody = createRigidBody( ball, ballShape, ballMass, pos, quat );ballBody.setFriction( 0.5 );pos.copy( raycaster.ray.direction );pos.multiplyScalar( 14 );ballBody.setLinearVelocity( new Ammo.btVector3( pos.x, pos.y, pos.z ) );clickRequest = false;}}function onWindowResize() {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize( window.innerWidth, window.innerHeight );}function animate() {requestAnimationFrame( animate );render();stats.update();}function render() {const deltaTime = clock.getDelta();updatePhysics( deltaTime );processClick();renderer.render( scene, camera );}function updatePhysics( deltaTime ) {// 步进世界physicsWorld.stepSimulation( deltaTime, 10 );// 更新软体体积for ( let i = 0, il = softBodies.length; i < il; i ++ ) {const volume = softBodies[ i ];const geometry = volume.geometry;const softBody = volume.userData.physicsBody;const volumePositions = geometry.attributes.position.array;const volumeNormals = geometry.attributes.normal.array;const association = geometry.ammoIndexAssociation;const numVerts = association.length;const nodes = softBody.get_m_nodes();for ( let j = 0; j < numVerts; j ++ ) {const node = nodes.at( j );const nodePos = node.get_m_x();const x =nodePos.x();const y = nodePos.y();const z = nodePos.z();const nodeNormal = node.get_m_n();const normal = association[ j ];for ( let k = 0, kl = normal.length; k < kl; k ++ ) {const indexVertex = normal[ k ];volumePositions[ indexVertex ] = x;volumePositions[ indexVertex + 1 ] = y;volumePositions[ indexVertex + 2 ] = z;volumeNormals[ indexVertex ] = - nodeNormal.x();volumeNormals[ indexVertex + 1 ] = - nodeNormal.y();volumeNormals[ indexVertex + 2 ] = - nodeNormal.z();}}geometry.attributes.position.needsUpdate = true;geometry.attributes.normal.needsUpdate = true;}// 更新物体位置for ( let i = 0, il = rigidBodies.length; i < il; i ++ ) {const objThree = rigidBodies[ i ];const objPhys = objThree.userData.physicsBody;const ms = objPhys.getMotionState();if ( ms ) {ms.getWorldTransform( transformAux1 );const p = transformAux1.getOrigin();const q = transformAux1.getRotation();objThree.position.set( p.x(), p.y(), p.z() );objThree.quaternion.set( q.x(), q.y(), q.z(), q.w() );}}}</script></body>
</html>

本内容来源于小豆包,想要更多内容请跳转小豆包 》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/620333.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SENet模型原理及代码介绍

一.模型简介&#xff1a; SENet的全称叫Squeeze-and-Excitation Networks&#xff08;挤压-激励网络&#xff0c;简称SENet&#xff09;&#xff0c;于2017年提出&#xff0c;并拿下了当年的ImageNet分类比赛的冠军。ResNet是2015年ImageNet的冠军&#xff0c;2016年ResNeXt&am…

护眼台灯怎么选看哪些指标?细数五款性价比最高的护眼灯

在日常生活中&#xff0c;越来越多的人开始重视眼部保护。除了日常用眼要合理、阅读写作姿势要正确外&#xff0c;良好的用眼环境同样重要。很多人在写作、学习时都会开启台灯来补充光源&#xff0c;优化用眼环境。但如果台灯不护眼&#xff0c;反而可能加剧眼部疲劳、近视等问…

【服务器部署篇】Linux下Jenkins安装和配置

作者介绍&#xff1a;本人笔名姑苏老陈&#xff0c;从事JAVA开发工作十多年了&#xff0c;带过刚毕业的实习生&#xff0c;也带过技术团队。最近有个朋友的表弟&#xff0c;马上要大学毕业了&#xff0c;想从事JAVA开发工作&#xff0c;但不知道从何处入手。于是&#xff0c;产…

Java反序列化Commons-Collections-CC1链

环境搭建 JDK8u71以下&#xff0c;这个漏洞已经被修复了&#xff0c;这个JDK的以上版本都修复了漏洞 JDK8u65 下载地址 https://www.oracle.com/cn/java/technologies/javase/javase8-archive-downloads.html这个时候来到 pom.xml 配置Maven依赖下载CommonsCollections3.2.…

【HTML】制作一个简单的实时字体时钟

目录 前言 HTML部分 CSS部分 JS部分 效果图 总结 前言 无需多言&#xff0c;本文将详细介绍一段HTML代码&#xff0c;具体内容如下&#xff1a; 开始 首先新建文件夹&#xff0c;创建一个文本文档&#xff0c;两个文件夹&#xff0c;其中HTML的文件名改为[index.html]&am…

SpringSecurity源码分析3--UserDetail部分

UserDetailsService.class DaoAuthenticationProvider.class AbstractUserDetailsAuthenticationProvider.class 一个允许子类重写和处理UserDetails对象的基AuthenticationProvider。该类旨在响应UsernamePasswordAuthenticationToken身份验证请求。 AuthenticationProvider…

树莓派安装Nginx服务结合内网穿透实现无公网IP远程访问

文章目录 1. Nginx安装2. 安装cpolar3.配置域名访问Nginx4. 固定域名访问5. 配置静态站点 安装 Nginx&#xff08;发音为“engine-x”&#xff09;可以将您的树莓派变成一个强大的 Web 服务器&#xff0c;可以用于托管网站或 Web 应用程序。相比其他 Web 服务器&#xff0c;Ngi…

负载均衡(理解/解析)

目录 什么是负载均衡 应用场景 网络服务和应用&#xff1a; 云计算和虚拟化&#xff1a; 负载均衡分类 硬件负载均衡器 软件负载均衡器 部署方式 硬件部署&#xff1a; 软件部署&#xff1a; 云部署&#xff1a; 路由模式&#xff1a; 算法实现 轮询法&#xff08;Round R…

【详细介绍下火绒安全】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

如何做信创测试

信创测试是一种系统化的方法&#xff0c;旨在评估和验证创意和创新项目的潜力和可行性。进行信创测试可以帮助企业在投入大量资源之前&#xff0c;对创意进行客观、科学的评估&#xff0c;以减少失败的风险并最大化成功的可能性。以下是一般性的信创测试步骤&#xff1a; 确定…

Web前端 JavaScript笔记4

1、元素内容 属性名称说明元素名.innerText输出一个字符串&#xff0c;设置或返回元素中的内容&#xff0c;不识别html标签元素名.innerHTML输出一个字符串&#xff0c;设置或返回元素中的内容&#xff0c;识别html标签元素名.textContent设置或返回指定节点的文本内容&#x…