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

学习threejs,使用Physijs物理引擎,各种constraint约束限制

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • 1.1 ☘️Physijs 物理引擎
      • 1.1.1 ☘️代码示例
      • 1.1.2 ☘️核心方法/属性
      • 1.1.3 ☘️网格对象
      • 1.1.4 ☘️约束
      • 1.1.4 ☘️约束、材质Materials、暂停/恢复模拟、场景配置、更新对象的位置和旋转使用样例
        • 1.1.4.1 ☘️约束使用样例
        • 1.1.4.2 ☘️材质Materials使用样例
        • 1.1.4.3 ☘️暂停/恢复模拟使用样例
        • 1.1.4.4 ☘️场景配置使用样例
        • 1.1.4.5 ☘️更新对象的位置和旋转使用样例
  • 二、🍀使用Physijs物理引擎,各种constraint约束限制
    • 1. ☘️实现思路
    • 2. ☘️代码样例


一、🍀前言

本文详细介绍如何基于threejs在三维场景中使用Physijs物理引擎,各种constraint约束限制,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️Physijs 物理引擎

Three.js 的 Physi.js 是一个基于 Physijs 的物理引擎插件,用于为 Three.js 场景添加物理模拟(如碰撞检测、重力、刚体动力学等)。

1.1.1 ☘️代码示例

// 初始化 Physi.js 场景
const scene = new Physijs.Scene();// 创建带有物理效果的立方体
const box = new Physijs.BoxMesh(new THREE.BoxGeometry(1, 1, 1),new THREE.MeshBasicMaterial({ color: 0xff0000 })
);
scene.add(box);// 监听碰撞事件
box.addEventListener('collision', (otherObject) => {console.log('发生碰撞!', otherObject);
});// 在动画循环中更新物理
function animate() {requestAnimationFrame(animate);scene.simulate(); // 更新物理模拟renderer.render(scene, camera);
}
animate();

1.1.2 ☘️核心方法/属性

Physijs.Scene
创建支持物理的 Three.js 场景。

mesh.setLinearVelocity()
设置物体的线性速度(移动速度)。

mesh.setAngularVelocity()
设置物体的角速度(旋转速度)。

mesh.addEventListener()
监听碰撞事件(如 ‘collision’)。

new Physijs.BoxMesh()
创建带有长方体碰撞体的物体。

new Physijs.SphereMesh()
创建带有球体碰撞体的物体。

scene.simulate()
在渲染循环中调用,更新物理模拟。

Physijs.createMaterial(material, friction, restitution)
创建物理材质,影响摩擦力和弹性。
参数:
material:Three.js 材质(如 THREE.MeshPhongMaterial)。
friction:摩擦系数(默认 0.8)。
restitution:弹性系数(默认 0)。

1.1.3 ☘️网格对象

Physijs.PlaneMesh // 这个网格可以用来创建一个厚度为0的平面。这样的平面也可以用BoxMesh对象包装一个高度很低的THREE.CubeGeometry来表示Physijs.BoxMesh // 如果是类似方块的几何体,你可以使用这个网格。例如,它的属性跟THREE.CubeGeometry的属性很相配Physijs.SphereMesh // 对于球形可以使用这个网格。它跟THREE.SphereGeometry的属性很相配Physijs.CylinderMesh // 通过设置THREE.Cylinder的属性你可以创建出各种柱状图形。Physijs为各种柱性提供了不同网格。Physijs.CylinderMesh可以用于一般的、上下一致的圆柱形Physijs.ConeMesh // 如果顶部的半径为0,底部的半径值大于0,那么你可以用THREE.Cylinder创建一个圆锥体。如果你想在这样一个对象上应用物理效果,那么可以使用的、最相匹配的网格类就是ConeMeshPhysijs.CapsuleMesh(胶囊网格) // 跟THREE.Cylinder属性很相似,但其底部和底部是圆的Physijs.ConvexMesh(凸包网格) // Physijs.ConvexMesh是一种比较粗略的图形,可用于多数复杂退行。它可以创建一个模拟复杂图形的凸包Physijs.ConcaveMesh // ConvexMesh是一个比较粗略的图形,而ConcaveMesh则可以对负责图形进行比较细致的表现。需要注意的是使用ConcaveMesh对效率的影响比较大Physijs.HeightfieldMesh(高度场网格) // 这是一种非常特别的网格。通过该网格你可以从一个THREE.PlaneGeometry对象创建出一个高度场。

1.1.4 ☘️约束

PointConstraint // 通过这个约束,你可以将一个对象与另一个对象之间的位置固定下来。例如一个对象动了,另一个对象也会随着移动,它们之间的距离和方向保持不变HingeConstraint // 通过活页约束,你可以限制一个对象只能像活页一样移动,例如门SliderConstraint // 将对象的移动限制在一个轴上。例如移门ConeTwistConstraint // 通过这个约束,你可以用一个对象限制另一个对象的旋转和移动。这个约束的功能类似于一个球削式关节。例如,胳膊在肩关节中的活动DOFConstraint // 通过自由度约束,你可以限制对象在任意轴上的活动,你可以设置对象活动的额最小、最大角度。这是最灵活的约束方式

1.1.4 ☘️约束、材质Materials、暂停/恢复模拟、场景配置、更新对象的位置和旋转使用样例

1.1.4.1 ☘️约束使用样例

点对点:

var constraint = new Physijs.PointConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // OPTIONAL second object - if omitted then physijs_mesh_1 will be constrained to the scenenew THREE.Vector3( 0, 10, 0 ) // point in the scene to apply the constraint
);
scene.addConstraint( constraint );

铰链约束:

var constraint = new Physijs.HingeConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // OPTIONAL second object - if omitted then physijs_mesh_1 will be constrained to the scenenew THREE.Vector3( 0, 10, 0 ), // point in the scene to apply the constraintnew THREE.Vector3( 1, 0, 0 ) // Axis along which the hinge lies - in this case it is the X axis
);
scene.addConstraint( constraint );
constraint.setLimits(low, // minimum angle of motion, in radianshigh, // maximum angle of motion, in radiansbias_factor, // applied as a factor to constraint errorrelaxation_factor, // controls bounce at limit (0.0 == no bounce)
);
constraint.enableAngularMotor( target_velocity, acceration_force );
constraint.disableMotor();

滑块约束:

var constraint = new Physijs.SliderConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // OPTIONAL second object - if omitted then physijs_mesh_1 will be constrained to the scenenew THREE.Vector3( 0, 10, 0 ), // point in the scene to apply the constraintnew THREE.Vector3( 1, 0, 0 ) // Axis along which the hinge lies - in this case it is the X axis
);
scene.addConstraint( constraint );
constraint.setLimits(linear_lower, // lower limit of linear movement, expressed in world unitslinear_upper, // upper limit of linear movement, expressed in world unitsangular_lower, // lower limit of angular movement, expressed in radiansangular_upper // upper limit of angular movement, expressed in radians
);
constraint.setRestitution(linear, // amount of restitution when reaching the linear limitsangular // amount of restitution when reaching the angular limits
);
constraint.enableLinearMotor( target_velocity, acceration_force );
constraint.disableLinearMotor();
constraint.enableAngularMotor( target_velocity, acceration_force );
constraint.disableAngularMotor();

锥形约束:

var constraint = new Physijs.ConeTwistConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // Second object to be constrainednew THREE.Vector3( 0, 10, 0 ), // point in the scene to apply the constraint
);
scene.addConstraint( constraint );
constraint.setLimit( x, y, z ); // rotational limit, in radians, for each axis
constraint.setMotorMaxImpulse( max_impulse ); // float value of the maximum impulse the motor can apply toward its target
constraint.setMotorTarget( target ); // target is the desired rotation for the constraint and can be expressed by a THREE.Vector3, THREE.Matrix4, or THREE.Quaternion
constraint.enableMotor();
constraint.disableMotor();

自由度约束:

var constraint = new Physijs.DOFConstraint(physijs_mesh_a, // First object to be constrainedphysijs_mesh_b, // OPTIONAL second object - if omitted then physijs_mesh_1 will be constrained to the scenenew THREE.Vector3( 0, 10, 0 ), // point in the scene to apply the constraint
);
scene.addConstraint( constraint );
constraint.setLinearLowerLimit( new THREE.Vector3( -10, -5, 0 ) ); // sets the lower end of the linear movement along the x, y, and z axes.
constraint.setLinearUpperLimit( new THREE.Vector3( 10, 5, 0 ) ); // sets the upper end of the linear movement along the x, y, and z axes.
constraint.setAngularLowerLimit( new THREE.Vector3( 0, -Math.PI, 0 ) ); // sets the lower end of the angular movement, in radians, along the x, y, and z axes.
constraint.setAngularUpperLimit( new THREE.Vector3( 0, Math.PI, 0 ) ); // sets the upper end of the angular movement, in radians, along the x, y, and z axes.
constraint.configureAngularMotor(which, // which angular motor to configure - 0,1,2 match x,y,zlow_limit, // lower limit of the motorhigh_limit, // upper limit of the motorvelocity, // target velocitymax_force // maximum force the motor can apply
);
constraint.enableAngularMotor( which ); // which angular motor to configure - 0,1,2 match x,y,z
constraint.disableAngularMotor( which ); // which angular motor to configure - 0,1,2 match x,y,z

冻结一个对象:
如果对象始终是静态的,例如地面,则可以0使用第三个参数创建网格时将其设置为质量:new Physijs.BoxMesh( geometry, material, 0)。任何具有质量的对象0将永远是静态的。

1.1.4.2 ☘️材质Materials使用样例

在THREE材质基础上增加了摩擦度和恢复度

var friction = 0.8; // 摩擦度
var restitution = 0.3; // 恢复度
var material = Physijs.createMaterial(new THREE.MeshBasicMaterial({ color: 0x888888 }),friction,restitution
);
var mesh = new Physijs.BoxMesh(new THREE.CubeGeometry( 5, 5, 5 ),material
);
1.1.4.3 ☘️暂停/恢复模拟使用样例
var render = function() {if (!isPaused) {scene.simulate();}renderer.render();
};
var unpauseSimulation = function() {isPaused = false;scene.onSimulationResume();
};

恢复模拟需要调用场景的onSimulationResume方法.

1.1.4.4 ☘️场景配置使用样例
  • fixedTimeStep default=1/60 此数字确定模拟步骤的模拟时间。数字越小,模拟越准确。
  • broadphase 指定将使用哪个宽带,选择是dynamic和sweepprune。
  • reportsize default 50 作为优化,包含对象位置的世界报告基于此数字预先初始化。最好将其设置为您的场景将具有的对象数量。
  • setGravity方法 default ( 0, -10, 0 ) 设定重力的数量和方向
  • setFixedTimeStep 在构造函数中default 1 / 60 重置fixedTimeStep给定的值
var scene = new Physijs.Scene({ reportsize: 50, fixedTimeStep: 1 / 60 });
1.1.4.5 ☘️更新对象的位置和旋转使用样例

有一个方面,无法与three.js进行无缝集成:更改对象的位置和/或旋转。如果这样做,您必须将该对象__dirtyPosition或__dirtyRotation标志设置为true,否则将从模拟中的最后一个已知值覆盖

var mesh = new Physijs.BoxMesh( geometry, material );
scene.add( mesh );var render = function() {// Change the object's positionmesh.position.set( 0, 0, 0 );mesh.__dirtyPosition = true;// Change the object's rotationmesh.rotation.set(0, 90, 180);mesh.__dirtyRotation = true;// You may also want to cancel the object's velocitymesh.setLinearVelocity(new THREE.Vector3(0, 0, 0));mesh.setAngularVelocity(new THREE.Vector3(0, 0, 0));scene.simulate();renderer.render();
};

二、🍀使用Physijs物理引擎,各种constraint约束限制

1. ☘️实现思路

  • 1、引入‘physi.js’,创建Physijs物理引擎三维场景scene,设置scene场景重力信息。
  • 2、初始化camera相机,定义相机位置 camera.position.set,设置相机方向camera.lookAt,场景scene添加camera。
  • 3、创建THREE.SpotLight聚光灯光源light,设置light位置,scene场景加入light。
  • 4、加载几何模型:定义createGround方法,使用‘floor-wood.jpg’木纹贴图创建地面网格对象ground以及四周突出边框网格对象borderLeft、borderRight、borderTop、borderBottom,ground添加borderLeft、borderRight、borderTop、borderBottom。定义createLeftFlipper、createRightFlipper方法,用于创建立方体物理网格对象,并设置活页约束,调用这两个方法。定义createSliderBottom、createSliderTop方法,用于创建立方体物理网格对象,并设置单轴线约束,调用这两个方法。定义createConeTwist方法,创建1个球体物理网格对象、一个立方体物理网格对象,并设置球削式关节约束,调用该个方法。定义createPointToPoint方法,创建2个球体物理网格对象,并设置点到点位置和方向固定约束,调用该个方法。定义controls方法,用于控制上面创建的PointConstraint、HingeConstraint、SliderConstraint和ConeTwistConstraint约束,定义添加、移除物理球体网格对象方法。调用createGround方法。定义render方法,进行三维场景的渲染。具体代码参考下面代码样例。
  • 5、加入gui控制。加入stats监控器,监控帧数信息。

2. ☘️代码样例

<!DOCTYPE html>
<html>
<head><style>body {margin: 0;overflow: hidden;background-color: #000000;}</style><title>学习threejs,使用Physijs物理引擎,各种constraint约束限制</title><script type="text/javascript" src="../libs/three.js"></script><script type="text/javascript" src="../libs/stats.js"></script><script type="text/javascript" src="../libs/physi.js"></script><script type="text/javascript" src="../libs/dat.gui.js"></script><script type="text/javascript" src="../libs/chroma.js"></script><script type="text/javascript">'use strict';Physijs.scripts.worker = '../libs/physijs_worker.js';Physijs.scripts.ammo = '../libs/ammo.js';var scale = chroma.scale(['white', 'blue', 'red', 'yellow']);var initScene, render, applyForce, setMousePosition, mouse_position,ground_material, box_material,projector, renderer, render_stats, physics_stats, scene, ground, light, camera, box, boxes = [];initScene = function () {projector = new THREE.Projector;renderer = new THREE.WebGLRenderer({antialias: true});renderer.setSize(window.innerWidth, window.innerHeight);renderer.setClearColor(new THREE.Color(0x000000));renderer.shadowMapEnabled = true;document.getElementById('viewport').appendChild(renderer.domElement);render_stats = new Stats();render_stats.domElement.style.position = 'absolute';render_stats.domElement.style.top = '1px';render_stats.domElement.style.right = '1px';render_stats.domElement.style.zIndex = 100;document.getElementById('viewport').appendChild(render_stats.domElement);scene = new Physijs.Scene({reportSize: 10, fixedTimeStep: 1 / 60});scene.setGravity(new THREE.Vector3(0, -10, 0));camera = new THREE.PerspectiveCamera(35,window.innerWidth / window.innerHeight,1,1000);camera.position.set(85, 65, 65);camera.lookAt(new THREE.Vector3(0, 0, 0));scene.add(camera);// 创建THREE.SpotLight聚光灯光源light,设置light的位置和投影light = new THREE.SpotLight(0xFFFFFF);light.position.set(20, 50, 50);light.castShadow = true;light.shadowMapDebug = true;light.shadowCameraNear = 10;light.shadowCameraFar = 100;// scene添加lightscene.add(light);var meshes = [];createGround();// 创建立方体物理网格对象,并设置活页约束var flipperLeftConstraint = createLeftFlipper();var flipperRightConstraint = createRightFlipper();//  创建立方体物理网格对象,并设置单轴线约束var sliderBottomConstraint = createSliderBottom();var sliderTopConstraint = createSliderTop();//  创建1个球体物理网格对象、一个立方体物理网格对象,并设置球削式关节约束var coneTwistConstraint = createConeTwist();// 创建2个球体物理网格对象,并设置点到点位置和方向固定约束var point2point = createPointToPoint(true);var controls = new function () {this.enableMotor = false;this.acceleration = 2;this.velocity = -10;this.enableConeTwistMotor = false;this.motorTargetX = 0;this.motorTargetY = 0;this.motorTargetZ = 0;this.updateCone = function () {if (controls.enableConeTwistMotor) {coneTwistConstraint.enableMotor();coneTwistConstraint.setMotorTarget(new THREE.Vector3(controls.motorTargetX, controls.motorTargetY, controls.motorTargetZ));} else {coneTwistConstraint.disableMotor();}};this.updateMotor = function () {if (controls.enableMotor) {// 启用重力flipperLeftConstraint.disableMotor();flipperLeftConstraint.enableAngularMotor(controls.velocity, controls.acceleration);flipperRightConstraint.disableMotor();flipperRightConstraint.enableAngularMotor(-1 * controls.velocity, controls.acceleration);} else {flipperLeftConstraint.disableMotor();flipperRightConstraint.disableMotor();}};this.sliderLeft = function () {sliderBottomConstraint.disableLinearMotor();sliderBottomConstraint.enableLinearMotor(controls.velocity, controls.acceleration);sliderTopConstraint.disableLinearMotor();sliderTopConstraint.enableLinearMotor(controls.velocity, controls.acceleration);};this.sliderRight = function () {sliderBottomConstraint.disableLinearMotor();sliderBottomConstraint.enableLinearMotor(-1 * controls.velocity, controls.acceleration);sliderTopConstraint.disableLinearMotor();sliderTopConstraint.enableLinearMotor(-1 * controls.velocity, controls.acceleration);};this.clearMeshes = function () {meshes.forEach(function (e) {scene.remove(e);});meshes = [];};this.addSpheres = function () {var colorSphere = scale(Math.random()).hex();for (var i = 0; i < 5; i++) {box = new Physijs.SphereMesh(new THREE.SphereGeometry(2, 20),Physijs.createMaterial(new THREE.MeshPhongMaterial({color: colorSphere,opacity: 0.8,transparent: truecontrols.sphereFriction,controls.sphereRestitution), 0.1);box.castShadow = true;box.receiveShadow = true;box.position.set(Math.random() * 50 - 25,20 + Math.random() * 5,Math.random() * 5);meshes.push(box);scene.add(box);}};};controls.updateMotor();var gui = new dat.GUI();gui.domElement.style.position = 'absolute';gui.domElement.style.top = '20px';gui.domElement.style.left = '20px';var generalFolder = gui.addFolder('general');generalFolder.add(controls, "acceleration", 0, 15).onChange(controls.updateMotor);generalFolder.add(controls, "velocity", -10, 10).onChange(controls.updateMotor);var hingeFolder = gui.addFolder('hinge');hingeFolder.add(controls, "enableMotor").onChange(controls.updateMotor);var sliderFolder = gui.addFolder('sliders');sliderFolder.add(controls, "sliderLeft").onChange(controls.sliderLeft);sliderFolder.add(controls, "sliderRight").onChange(controls.sliderRight);var coneTwistFolder = gui.addFolder('coneTwist');coneTwistFolder.add(controls, "enableConeTwistMotor").onChange(controls.updateCone);coneTwistFolder.add(controls, "motorTargetX", -Math.PI / 2, Math.PI / 2).onChange(controls.updateCone);coneTwistFolder.add(controls, "motorTargetY", -Math.PI / 2, Math.PI / 2).onChange(controls.updateCone);coneTwistFolder.add(controls, "motorTargetZ", -Math.PI / 2, Math.PI / 2).onChange(controls.updateCone);var spheresFolder = gui.addFolder('spheres');spheresFolder.add(controls, "clearMeshes").onChange(controls.updateMotor);spheresFolder.add(controls, "addSpheres").onChange(controls.updateMotor);requestAnimationFrame(render);scene.simulate();};function createGround() {// Materialsground_material = Physijs.createMaterial(new THREE.MeshPhongMaterial({
//                                color: 0xaaaaaa,map: THREE.ImageUtils.loadTexture('../assets/textures/general/floor-wood.jpg')}),.9, // high friction.7 // low restitution);// Groundground = new Physijs.BoxMesh(new THREE.BoxGeometry(60, 1, 65),ground_material,0);ground.receiveShadow = true;var borderLeft = new Physijs.BoxMesh(new THREE.BoxGeometry(2, 6, 65),ground_material,0);borderLeft.position.x = -31;borderLeft.position.y = 2;borderLeft.receiveShadow = true;ground.add(borderLeft);var borderRight = new Physijs.BoxMesh(new THREE.BoxGeometry(2, 6, 65),ground_material,0);borderRight.position.x = 31;borderRight.position.y = 2;borderRight.receiveShadow = true;ground.add(borderRight);var borderBottom = new Physijs.BoxMesh(new THREE.BoxGeometry(64, 6, 2),ground_material,0);borderBottom.position.z = 32;borderBottom.position.y = 1.5;borderBottom.receiveShadow = true;ground.add(borderBottom);var borderTop = new Physijs.BoxMesh(new THREE.BoxGeometry(64, 6, 2),ground_material,0);borderTop.position.z = -32;borderTop.position.y = 2;borderTop.receiveShadow = true;ground.add(borderTop);ground.receiveShadow = true;scene.add(ground);}function createConeTwist() {var baseMesh = new THREE.SphereGeometry(1);var armMesh = new THREE.BoxGeometry(2, 12, 3);var objectOne = new Physijs.BoxMesh(baseMesh, Physijs.createMaterial(new THREE.MeshPhongMaterial({color: 0x4444ff, transparent: true, opacity: 0.7}), 0, 0), 0);objectOne.position.z = 0;objectOne.position.x = 20;objectOne.position.y = 15.5;objectOne.castShadow = true;scene.add(objectOne);var objectTwo = new Physijs.SphereMesh(armMesh, Physijs.createMaterial(new THREE.MeshPhongMaterial({color: 0x4444ff, transparent: true, opacity: 0.7}), 0, 0), 10);objectTwo.position.z = 0;objectTwo.position.x = 20;objectTwo.position.y = 7.5;scene.add(objectTwo);objectTwo.castShadow = true;//position is the position of the axis, relative to the ref, based on the current positionvar constraint = new Physijs.ConeTwistConstraint(objectOne, objectTwo, objectOne.position);scene.addConstraint(constraint);// set limit to quarter circle for each axisconstraint.setLimit(0.5 * Math.PI, 0.5 * Math.PI, 0.5 * Math.PI);constraint.setMaxMotorImpulse(1);constraint.setMotorTarget(new THREE.Vector3(0, 0, 0)); // desired rotationreturn constraint;}function createPointToPoint() {var obj1 = new THREE.SphereGeometry(2);var obj2 = new THREE.SphereGeometry(2);var objectOne = new Physijs.SphereMesh(obj1, Physijs.createMaterial(new THREE.MeshPhongMaterial({color: 0xff4444, transparent: true, opacity: 0.7}), 0, 0));objectOne.position.z = -18;objectOne.position.x = -10;objectOne.position.y = 2;objectOne.castShadow = true;scene.add(objectOne);var objectTwo = new Physijs.SphereMesh(obj2, Physijs.createMaterial(new THREE.MeshPhongMaterial({color: 0xff4444, transparent: true, opacity: 0.7}), 0, 0));objectTwo.position.z = -5;objectTwo.position.x = -20;objectTwo.position.y = 2;objectTwo.castShadow = true;scene.add(objectTwo);// if no position two, its fixed to a position. Else fixed to objectTwo and both will movevar constraint = new Physijs.PointConstraint(objectOne, objectTwo, objectTwo.position);scene.addConstraint(constraint);}function createSliderBottom() {var sliderCube = new THREE.BoxGeometry(12, 2, 2);var sliderMesh = new Physijs.BoxMesh(sliderCube, Physijs.createMaterial(new THREE.MeshPhongMaterial({color: 0x44ff44, opacity: 0.6, transparent: true}), 0, 0), 0.01);sliderMesh.position.z = 20;sliderMesh.position.x = 6;sliderMesh.position.y = 1.5;sliderMesh.castShadow = true;scene.add(sliderMesh);var constraint = new Physijs.SliderConstraint(sliderMesh, new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 1, 0));scene.addConstraint(constraint);constraint.setLimits(-10, 10, 0, 0);constraint.setRestitution(0.1, 0.1);return constraint;}function createSliderTop() {var sliderSphere = new THREE.BoxGeometry(7, 2, 7);var sliderMesh = new Physijs.BoxMesh(sliderSphere, Physijs.createMaterial(new THREE.MeshPhongMaterial({color: 0x44ff44, transparent: true, opacity: 0.5}), 0, 0), 10);sliderMesh.position.z = -15;sliderMesh.position.x = -20;sliderMesh.position.y = 1.5;scene.add(sliderMesh);sliderMesh.castShadow = true;//position is the position of the axis, relative to the ref, based on the current positionvar constraint = new Physijs.SliderConstraint(sliderMesh, new THREE.Vector3(-10, 0, 20), new THREE.Vector3(Math.PI / 2, 0, 0));scene.addConstraint(constraint);constraint.setLimits(-20, 10, 0.5, -0, 5);constraint.setRestitution(0.2, 0.1);return constraint;}function createLeftFlipper() {var flipperLeft = new Physijs.BoxMesh(new THREE.BoxGeometry(12, 2, 2), Physijs.createMaterial(new THREE.MeshPhongMaterial({opacity: 0.6, transparent: true})), 0.3);flipperLeft.position.x = -6;flipperLeft.position.y = 2;flipperLeft.position.z = 0;flipperLeft.castShadow = true;scene.add(flipperLeft);var flipperLeftPivot = new Physijs.SphereMesh(new THREE.BoxGeometry(1, 1, 1), ground_material, 0);flipperLeftPivot.position.y = 1;flipperLeftPivot.position.x = -15;flipperLeftPivot.position.z = 0;flipperLeftPivot.rotation.y = 1.4;flipperLeftPivot.castShadow = true;scene.add(flipperLeftPivot);// 当观察轴时,使用的是物体二的轴。// 只要物体二的轴与场景的轴一致,就不会有问题。// 旋转和轴是相对于物体二的。如果位置等于立方体二的位置,那么效果就会如预期一样var constraint = new Physijs.HingeConstraint(flipperLeft, flipperLeftPivot, flipperLeftPivot.position, new THREE.Vector3(0, 1, 0));scene.addConstraint(constraint);constraint.setLimits(-2.2,-0.6,0.1,0);return constraint;}function createRightFlipper() {var flipperright = new Physijs.BoxMesh(new THREE.BoxGeometry(12, 2, 2), Physijs.createMaterial(new THREE.MeshPhongMaterial({opacity: 0.6, transparent: true})), 0.3);flipperright.position.x = 8;flipperright.position.y = 2;flipperright.position.z = 0;flipperright.castShadow = true;scene.add(flipperright);var flipperLeftPivot = new Physijs.SphereMesh(new THREE.BoxGeometry(1, 1, 1), ground_material, 0);flipperLeftPivot.position.y = 2;flipperLeftPivot.position.x = 15;flipperLeftPivot.position.z = 0;flipperLeftPivot.rotation.y = 1.4;flipperLeftPivot.castShadow = true;scene.add(flipperLeftPivot);// 当观察轴时,使用的是物体二的轴。// 只要物体二的轴与场景的轴一致,就不会有问题。// 旋转和轴是相对于物体二的。如果位置等于立方体二的位置,那么效果就会如预期一样var constraint = new Physijs.HingeConstraint(flipperright, flipperLeftPivot, flipperLeftPivot.position, new THREE.Vector3(0, 1, 0));
//            var constraint = new Physijs.HingeConstraint(cube1, new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0));scene.addConstraint(constraint);constraint.setLimits(-2.2, // 从点对象1开始(向后)的最小运动角度(以弧度为单位)-0.6, // 从点对象1开始(向前)的最大运动角度(以弧度为单位)0.1, // 作为约束错误的一个因素应用,当约束被触发时,kantelpunt被移动的程度有多大0 // 控制在极限时的弹跳(0.0表示无弹跳));return constraint;}var direction = 1;render = function () {requestAnimationFrame(render);renderer.render(scene, camera);render_stats.update();ground.__dirtyRotation = true;scene.simulate(undefined, 2);};window.onload = initScene;</script>
</head>
<body>
<div id="viewport"></div>
</body>
</html>

效果如下:
在这里插入图片描述

http://www.xdnf.cn/news/474625.html

相关文章:

  • 分布式锁: Redisson 实现分布式锁的原理与技术细节
  • 前端下载ZIP包方法总结
  • 前端取经路——量子UI:响应式交互新范式
  • 第二天的尝试
  • Java + 鸿蒙双引擎:ZKmall开源商城如何定义下一代B2C商城技术标准?
  • 临床决策支持系统的提示工程优化路径深度解析
  • 【SpringBoot】从零开始全面解析SpringMVC (二)
  • TensorFlow/Keras实现知识蒸馏案例
  • Pyhton训练营打卡Day27
  • virtualbox虚拟机中的ubuntu 20.04.6安装新的linux内核5.4.293 | 并增加一个系统调用 | 证书问题如何解决
  • 初识——QT
  • 【Qt】PyQt5 为什么Qt中的字体显示会模糊或呈现像素化
  • Playwright vs Selenium:2025 年 Web 自动化终极对比指南
  • OptiStruct实例:3D实体转子分析
  • 搭建运行若依微服务版本ruoyi-cloud最新教程
  • NLP双雄争霸:GPT与BERT的生成-理解博弈——从技术分野到产业融合的深度解码
  • 《数据结构初阶》【二叉树 精选9道OJ练习】
  • Python机器学习笔记(二十五、算法链与管道)
  • 龙芯新一代国产服务器CPU及产品闪耀信创大会,助力信创与智算新突破
  • docker(四)使用篇二:docker 镜像
  • Cherry Studio上使用MindCraft API
  • 操作系统之进程和线程听课笔记
  • 【MySQL】数据库三大范式
  • 【Java微服务组件】分布式协调P1-数据共享中心简单设计与实现
  • 【开源Agent框架】CAMEL:角色扮演+任务分解
  • QT6 源(101)篇一:阅读与注释 QPlainTextEdit,其继承于QAbstractScrollArea,属性学习与测试
  • AI Agent开发第67课-彻底消除RAG知识库幻觉(1)-文档分块全技巧
  • 2025ICPC陕西省赛题解
  • 以项目的方式学QT开发C++(一)——超详细讲解(120000多字详细讲解,涵盖qt大量知识)逐步更新!
  • 表记录的检索