Guest User

Untitled

a guest
May 15th, 2023
69
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import {
  2.     Scene,
  3.     Engine,
  4.     Vector3,
  5.     Mesh,
  6.     Plane,
  7.     PBRMaterial,
  8.     MeshBuilder,
  9.     Matrix,
  10.     Quaternion,
  11.     KeyboardEventTypes,
  12.     Observer,
  13.     KeyboardInfo,
  14.     Nullable,
  15.     FluidRenderer,
  16.     IFluidRenderingRenderObject,
  17.     VertexBuffer,
  18.     TmpVectors,
  19.     Color4,
  20. } from "@babylonjs/core";
  21. import "@babylonjs/core/Rendering/fluidRenderer/fluidRenderer"
  22. import "@babylonjs/core/Rendering/fluidRenderer/fluidRenderingObjectCustomParticles"
  23. import RenderScene from "./RenderScene";
  24. import {
  25.     DEFAULT_BOX_OPACITY,
  26.     DEFAULT_DENSITY_REFERENCE,
  27.     DEFAULT_FLUID_COLOR,
  28.     DEFAULT_FLUID_COLOR_DENSITY,
  29.     DEFAULT_FLUID_VELOCITY,
  30.     DEFAULT_PARTICLES_COUNT,
  31.     DEFAULT_PARTICLE_SIZE,
  32.     DEFAULT_PRESSURE_CONSTANT,
  33.     DEFAULT_SMOOTHING_RADIUS,
  34.     MAX_ACCELERATION,
  35.     MAX_FLUID_COLOR_DENSITY,
  36.     PARTICLE_RADIUS,
  37.     SHAPE_COLLISION_RESTITUTION,
  38.     VISCOSITY,
  39.     changableFluidParams,
  40. } from "@/constants";
  41. import { SDFHelper } from "./SDFHelper";
  42. import { ParticleGenerator } from "./ParticleGenerator";
  43. import { FluidSimulator } from "./FluidSimulator";
  44.  
  45. export class FluidVisualisation {
  46.     // Rendering
  47.     private renderScene: RenderScene
  48.     private scene: Scene
  49.     private engine: Engine
  50.     private sceneRenderObserver: Nullable<Observer<Scene>>
  51.     private sceneKeyboardObserver: Nullable<Observer<KeyboardInfo>>
  52.     private sceneObserver: Nullable<Observer<Scene>>
  53.     private fluidRenderer: Nullable<FluidRenderer>
  54.     private numParticles: number
  55.     private shapeCollisionRestitution: number
  56.     private particleGenerator: Nullable<ParticleGenerator>
  57.     private fluidRenderObject: IFluidRenderingRenderObject
  58.     private fluidSimulation: FluidSimulator
  59.  
  60.     // Collision objects
  61.     private collisionObjectPromises: any[]
  62.     private collisionObjects: any[]
  63.  
  64.     // Bounding Box
  65.     private boxMin: Vector3
  66.     private boxMax: Vector3
  67.     private boxMesh: Mesh
  68.     private boxMeshFront: Mesh
  69.     private boxMaterial: PBRMaterial
  70.     private boxMaterialFront: PBRMaterial
  71.     private origCollisionPlanes: Plane[]
  72.     private collisionPlanes: any[]
  73.  
  74.     // Box rotation
  75.     private angleX: number
  76.     private angleY: number
  77.     private autoRotateBox: boolean
  78.     private prevTransform: Matrix
  79.  
  80.     private isPaused: boolean
  81.  
  82.     constructor(renderScene: RenderScene) {
  83.         this.renderScene = renderScene
  84.         this.scene = renderScene.scene
  85.         this.engine = renderScene.engine
  86.         this.fluidRenderer = this.scene.enableFluidRenderer()
  87.         this.numParticles = DEFAULT_PARTICLES_COUNT
  88.  
  89.         this.sceneRenderObserver = null as any
  90.         this.sceneKeyboardObserver = null as any
  91.         this.sceneObserver = null as any
  92.         this.shapeCollisionRestitution = SHAPE_COLLISION_RESTITUTION
  93.         this.particleGenerator = null
  94.         const particleRadius = PARTICLE_RADIUS
  95.         const camera = this.scene.activeCameras?.[0] ?? this.scene.activeCamera
  96.  
  97.         this.fluidRenderObject = this.fluidRenderer!.addCustomParticles({}, 0, false, undefined, camera!)
  98.         this.fluidRenderObject.targetRenderer.enableBlurDepth = true;
  99.         this.fluidRenderObject.targetRenderer.blurDepthFilterSize = 20;
  100.         this.fluidRenderObject.targetRenderer.blurDepthNumIterations = 5;
  101.         this.fluidRenderObject.targetRenderer.blurDepthDepthScale = 10;
  102.         this.fluidRenderObject.targetRenderer.fluidColor = DEFAULT_FLUID_COLOR.clone()
  103.         this.fluidRenderObject.targetRenderer.density = DEFAULT_FLUID_COLOR_DENSITY;
  104.         this.fluidRenderObject.targetRenderer.refractionStrength = 0.02;
  105.         this.fluidRenderObject.targetRenderer.specularPower = 150;
  106.         this.fluidRenderObject.targetRenderer.blurThicknessFilterSize = 10;
  107.         this.fluidRenderObject.targetRenderer.blurThicknessNumIterations = 2;
  108.         this.fluidRenderObject.targetRenderer.dirLight = new Vector3(2, -1, 1);
  109.         this.fluidRenderObject.object.particleSize = particleRadius * 2 * 2;
  110.         this.fluidRenderObject.object.particleThicknessAlpha =
  111.             this.fluidRenderObject.object.particleSize;
  112.         this.fluidRenderObject.object.useVelocity =
  113.             this.fluidRenderObject.targetRenderer.useVelocity;
  114.         this.fluidRenderObject.targetRenderer.minimumThickness =
  115.             this.fluidRenderObject.object.particleThicknessAlpha / 2;
  116.  
  117.         this.fluidSimulation = new FluidSimulator()
  118.         this.fluidSimulation.smoothingRadius = particleRadius * 2
  119.         this.fluidSimulation.maxVelocity = 3
  120.         this.particleGenerator = new ParticleGenerator(this.scene)
  121.         this.particleGenerator.particleRadius = particleRadius
  122.  
  123.         this.boxMax = new Vector3(1, 1, 1)
  124.         this.boxMin = new Vector3(-1, -1, -1)
  125.         this.particleGenerator.position.y = (this.boxMin.y + this.boxMax.y) / 2
  126.  
  127.         this.isPaused = false
  128.  
  129.         this.collisionObjectPromises = []
  130.         this.collisionObjects = []
  131.  
  132.         this.boxMesh = null as any
  133.         this.boxMeshFront = null as any
  134.         this.boxMaterial = null as any
  135.         this.boxMaterialFront = null as any
  136.         this.origCollisionPlanes = [
  137.             new Plane(0, 0, -1, Math.abs(this.boxMax.z)),
  138.             new Plane(0, 0, 1, Math.abs(this.boxMin.z)),
  139.             new Plane(1, 0, 0, Math.abs(this.boxMin.x)),
  140.             new Plane(-1, 0, 0, Math.abs(this.boxMax.x)),
  141.             new Plane(0, -1, 0, Math.abs(this.boxMax.y)),
  142.             new Plane(0, 1, 0, Math.abs(this.boxMin.y)),
  143.             new Plane(0, 1, 0, Math.abs(this.boxMin.y)),
  144.         ]
  145.         this.collisionPlanes = []
  146.         for (let i = 0; i < this.origCollisionPlanes.length; ++i) {
  147.             const plane = this.origCollisionPlanes[i]
  148.             this.addCollisionPlane(plane.normal, plane.d, i === this.origCollisionPlanes.length - 1 ? 0.98 : undefined)
  149.         }
  150.  
  151.         this.angleX = 0
  152.         this.angleY = 0
  153.         this.autoRotateBox = false
  154.         this.prevTransform = Matrix.Identity()
  155.     }
  156.  
  157.     set boxOpacity(value: number) {
  158.         this.boxMaterial.alpha = value
  159.     }
  160.  
  161.     async run() {
  162.         this.collisionObjects = await Promise.all(this.collisionObjectPromises);
  163.  
  164.         // Get collision meshes
  165.         for (let i = 0; i < this.origCollisionPlanes.length; ++i) {
  166.             this.collisionPlanes.push(this.collisionObjects[i]);
  167.         }
  168.         this.collisionPlanes[this.collisionPlanes.length - 1][1].disabled = true;
  169.  
  170.         // Box mesh
  171.         this.boxMaterial = new PBRMaterial('boxMeshMat', this.scene)
  172.         this.boxMaterial.metallic = 0.3
  173.         this.boxMaterial.roughness = 0
  174.         this.boxMaterial.alpha = DEFAULT_BOX_OPACITY
  175.         this.boxMaterial.backFaceCulling = false
  176.         this.boxMaterial.cullBackFaces = false
  177.         this.boxMaterialFront = this.boxMaterial.clone('boxMeshFrontMat')
  178.         this.boxMaterialFront.cullBackFaces = true
  179.  
  180.         this.boxMesh = MeshBuilder.CreateBox('boxMesh', {
  181.             width: this.boxMax.x - this.boxMin.x,
  182.             height: this.boxMax.y - this.boxMin.y,
  183.             depth: this.boxMax.z - this.boxMin.z,
  184.         })
  185.         this.boxMesh.material = this.boxMaterial
  186.         this.boxMesh.position.x = (this.boxMax.x + this.boxMin.x) / 2
  187.         this.boxMesh.position.y = (this.boxMax.y + this.boxMin.y) / 2
  188.         this.boxMesh.position.z = (this.boxMax.z + this.boxMin.z) / 2
  189.         this.boxMesh.isPickable = false
  190.  
  191.         this.boxMeshFront = this.boxMesh.clone('boxMeshFront')
  192.         this.boxMeshFront.material = this.boxMaterialFront
  193.         this.boxMeshFront.layerMask = 0x10000000
  194.  
  195.         // Keyboard handling
  196.         let arrowLeftDown = false
  197.         let arrowRightDown = false
  198.         let arrowUpDown = false
  199.         let arrowDownDown = false
  200.         this.sceneKeyboardObserver = this.scene.onKeyboardObservable.add(keyboardInfo => {
  201.             switch (keyboardInfo.type) {
  202.                 case KeyboardEventTypes.KEYDOWN:
  203.                     if (keyboardInfo.event.code === 'ArrowLeft') {
  204.                         arrowLeftDown = true
  205.                     }
  206.                     if (keyboardInfo.event.code === 'ArrowRight') {
  207.                         arrowRightDown = true
  208.                     }
  209.                     if (keyboardInfo.event.code === 'ArrowUp') {
  210.                         arrowUpDown = true
  211.                     }
  212.                     if (keyboardInfo.event.code === 'ArrowDown') {
  213.                         arrowDownDown = true
  214.                     }
  215.                     break
  216.                 case KeyboardEventTypes.KEYUP:
  217.                     if (keyboardInfo.event.code === 'ArrowLeft') {
  218.                         arrowLeftDown = false
  219.                     }
  220.                     if (keyboardInfo.event.code === 'ArrowRight') {
  221.                         arrowRightDown = false
  222.                     }
  223.                     if (keyboardInfo.event.code === 'ArrowUp') {
  224.                         arrowUpDown = false
  225.                     }
  226.                     if (keyboardInfo.event.code === 'ArrowDown') {
  227.                         arrowDownDown = false
  228.                     }
  229.                     break
  230.             }
  231.         })
  232.  
  233.         this.sceneRenderObserver = this.scene.onBeforeRenderObservable.add(() => {
  234.             if (this.isPaused) {
  235.                 return
  236.             }
  237.  
  238.             if (arrowLeftDown) {
  239.                 this.angleX += (2 * 30) / 60
  240.                 this.rotateMeshes(this.angleX, this.angleY)
  241.             }
  242.  
  243.             if (arrowRightDown) {
  244.                 this.angleX -= (2 * 30) / 60
  245.                 this.rotateMeshes(this.angleX, this.angleY)
  246.             }
  247.  
  248.             if (arrowUpDown) {
  249.                 this.angleY -= (2 * 30) / 60
  250.                 this.rotateMeshes(this.angleX, this.angleY)
  251.             }
  252.  
  253.             if (arrowDownDown) {
  254.                 this.angleY += (2 * 30) / 60
  255.                 this.rotateMeshes(this.angleX, this.angleY)
  256.             }
  257.  
  258.             if (this.autoRotateBox) {
  259.                 const fps = this.engine.getFps()
  260.                 this.angleX += 20 / fps
  261.                 this.angleY += 30 / fps
  262.                 this.rotateMeshes(this.angleX, this.angleY)
  263.             }
  264.         })
  265.  
  266.         this.fluidRenderObject.object.particleSize = DEFAULT_PARTICLE_SIZE
  267.         this.fluidSimulation.smoothingRadius = DEFAULT_SMOOTHING_RADIUS
  268.         this.fluidSimulation.densityReference = DEFAULT_DENSITY_REFERENCE
  269.         this.fluidSimulation.pressureConstant = DEFAULT_PRESSURE_CONSTANT
  270.         this.fluidSimulation.viscosity = VISCOSITY * 2
  271.         this.fluidSimulation.maxVelocity = DEFAULT_FLUID_VELOCITY
  272.         this.fluidSimulation.maxAcceleration = MAX_ACCELERATION
  273.  
  274.         await this.generateParticles()
  275.  
  276.         this.sceneObserver = this.scene.onBeforeRenderObservable.add(() => {
  277.             this.fluidSimulation.currentNumParticles = Math.min(this.numParticles, this.particleGenerator!.currNumParticles)
  278.             this.fluidRenderObject.object.setNumParticles(this.fluidSimulation.currentNumParticles)
  279.  
  280.             if (!this.isPaused) {
  281.                 this.fluidSimulation.update(1 / 100)
  282.                 this.checkCollisions(this.fluidRenderObject.object.particleSize / 2)
  283.             }
  284.  
  285.             if (this.fluidRenderObject &&
  286.                 this.fluidRenderObject.object.vertexBuffers['position']) {
  287.                 this.fluidRenderObject.object.vertexBuffers['position'].updateDirectly(this.fluidSimulation.positions!, 0)
  288.                 this.fluidRenderObject.object.vertexBuffers['velocity'].updateDirectly(this.fluidSimulation.velocities!, 0)
  289.             }
  290.         })
  291.     }
  292.  
  293.     public addCollisionPlane(normal: Vector3, d: number, collisionRestitution: number | undefined) {
  294.         const collisionShape = {
  295.             params: [normal.clone(), d],
  296.             sdEvaluate: SDFHelper.SDPlane,
  297.             computeNormal: SDFHelper.ComputeSDFNormal,
  298.             mesh: null,
  299.             position: new Vector3(0, 0, 0),
  300.             rotation: new Vector3(0, 0, 0),
  301.             transf: Matrix.Identity(),
  302.             scale: 1,
  303.             invTransf: Matrix.Identity(),
  304.             dragPlane: null,
  305.             collisionRestitution,
  306.         }
  307.  
  308.         const promise = Promise.resolve([null, collisionShape])
  309.         this.collisionObjectPromises.push(promise)
  310.         return promise
  311.     }
  312.  
  313.     public rotateMeshes(angleX: number, angleY: number) {
  314.         const transform = Matrix.RotationYawPitchRoll(0, angleX * Math.PI / 180, angleY * Math.PI / 180)
  315.         const boxVertices = [
  316.             new Vector3(this.boxMin.x, this.boxMin.y, this.boxMin.z),
  317.             new Vector3(this.boxMin.x, this.boxMax.y, this.boxMin.z),
  318.             new Vector3(this.boxMin.x, this.boxMax.y, this.boxMax.z),
  319.             new Vector3(this.boxMin.x, this.boxMin.y, this.boxMax.z),
  320.             new Vector3(this.boxMax.x, this.boxMin.y, this.boxMin.z),
  321.             new Vector3(this.boxMax.x, this.boxMax.y, this.boxMin.z),
  322.             new Vector3(this.boxMax.x, this.boxMax.y, this.boxMax.z),
  323.             new Vector3(this.boxMax.x, this.boxMin.y, this.boxMax.z),
  324.         ]
  325.  
  326.         let yMin = Number.MAX_VALUE
  327.         for (const boxVertex of boxVertices) {
  328.             const v = Vector3.TransformCoordinates(boxVertex, transform)
  329.             yMin = Math.min(yMin, v.y)
  330.         }
  331.  
  332.         this.collisionPlanes[this.origCollisionPlanes.length - 1][1].params[1] = Math.abs(yMin) + 0.02
  333.         for (let i = 0; i < this.origCollisionPlanes.length - 1; ++i) {
  334.             const plane = this.origCollisionPlanes[i].transform(transform)
  335.             this.collisionPlanes[i][1].params = [plane.normal, plane.d]
  336.         }
  337.  
  338.         // TODO: Add rotation to all items?
  339.  
  340.         const quat = Quaternion.FromRotationMatrix(transform)
  341.         if (this.boxMesh && this.boxMeshFront) {
  342.             this.boxMesh.rotationQuaternion = quat
  343.             this.boxMeshFront.rotationQuaternion = quat
  344.             this.boxMesh.position.x = (this.boxMin.x + this.boxMax.x) / 2
  345.             this.boxMesh.position.y = (this.boxMin.y + this.boxMax.y) / 2
  346.             this.boxMesh.position.z = (this.boxMin.z + this.boxMax.z) / 2
  347.             this.boxMesh.position = Vector3.TransformCoordinates(this.boxMesh.position, transform)
  348.             this.boxMeshFront.position = this.boxMesh.position
  349.         }
  350.         this.prevTransform.copyFrom(transform)
  351.     }
  352.  
  353.     public onPaused(value: boolean) {
  354.         this.isPaused = value
  355.         if (value) {
  356.             this.autoRotateBox = false
  357.         }
  358.     }
  359.  
  360.     public restart() {
  361.         this.angleX = 0
  362.         this.angleY = 0
  363.         this.autoRotateBox = false
  364.         this.rotateMeshes(0, 0)
  365.         this.generateParticles()
  366.     }
  367.  
  368.     public onAutoRotate(value: boolean) {
  369.         this.autoRotateBox = value
  370.     }
  371.  
  372.     public onCheckBounds(value: boolean) {
  373.         this.boxMesh?.setEnabled(value)
  374.         this.boxMeshFront?.setEnabled(value)
  375.  
  376.         for (let i = 0; i < this.collisionPlanes.length; ++i) {
  377.             this.collisionPlanes[i][1].disabled =
  378.                 (!value && i < this.collisionPlanes.length - 1) ||
  379.                 (value && i === this.collisionPlanes.length - 1)
  380.         }
  381.  
  382.         if (!value) {
  383.             this.autoRotateBox = false
  384.         }
  385.     }
  386.  
  387.     public changeColor(newColor: Color4) {
  388.         const fluidRenderer = this.fluidRenderer
  389.         if (fluidRenderer && fluidRenderer.targetRenderers[0]) {
  390.             fluidRenderer.targetRenderers[0].fluidColor.copyFromFloats(newColor.r, newColor.g, newColor.b)
  391.  
  392.             const newFluidColorDensity = newColor.a * MAX_FLUID_COLOR_DENSITY
  393.             fluidRenderer.targetRenderers[0].density = newFluidColorDensity
  394.         }
  395.     }
  396.  
  397.     public changeParticlesCount(value: number) {
  398.         this.numParticles = value
  399.         this.generateParticles(false)
  400.     }
  401.  
  402.     public changeFluidParam(param: changableFluidParams, value: number) {
  403.         switch (param) {
  404.             case changableFluidParams.particleSize:
  405.                 if (this.fluidRenderer && this.fluidRenderer.renderObjects[0].object) {
  406.                     this.fluidRenderer.renderObjects[0].object.particleSize = value
  407.                 }
  408.                 break;
  409.             case changableFluidParams.smoothingRadius:
  410.                 if (this.particleGenerator) {
  411.                     this.fluidSimulation.smoothingRadius = value
  412.                     this.particleGenerator.particleRadius = value / 2
  413.                 }
  414.                 break;
  415.             case changableFluidParams.densityReference:
  416.                 this.fluidSimulation.densityReference = value
  417.                 break;
  418.             case changableFluidParams.pressureConstant:
  419.                 this.fluidSimulation.pressureConstant = value
  420.                 break;
  421.             case changableFluidParams.maxVelocity:
  422.                 this.fluidSimulation.maxVelocity = value
  423.                 break;
  424.             default:
  425.                 break;
  426.         }
  427.     }
  428.  
  429.     public dispose() {
  430.         while (this.collisionObjects.length > 1) {
  431.             this.disposeCollisionObject(0)
  432.         }
  433.         this.scene.onBeforeRenderObservable.remove(this.sceneRenderObserver)
  434.         this.scene.onBeforeRenderObservable.remove(this.sceneObserver)
  435.         this.scene.onKeyboardObservable.remove(this.sceneKeyboardObserver)
  436.         this.boxMesh?.dispose()
  437.         this.boxMeshFront?.dispose()
  438.         this.boxMaterial?.dispose()
  439.         this.boxMaterialFront?.dispose()
  440.     }
  441.  
  442.     public disposeCollisionObject(index: number) {
  443.         const shape = this.collisionObjects[index][1]
  444.         shape?.mesh?.material?.dispose()
  445.         shape?.mesh?.dispose()
  446.         this.collisionObjects.splice(index, 1)
  447.         this.collisionObjectPromises.splice(index, 1)
  448.     }
  449.  
  450.     private async generateParticles(regenerateAll: boolean = true) {
  451.         await this.particleGenerator?.generateParticles(this.numParticles, regenerateAll)
  452.  
  453.         if (this.fluidSimulation &&
  454.             this.particleGenerator &&
  455.             this.fluidSimulation.positions !== this.particleGenerator.positions) {
  456.             this.fluidSimulation.setParticleData(this.particleGenerator.positions, this.particleGenerator.velocities)
  457.  
  458.             this.fluidRenderObject.object.vertexBuffers['position']?.dispose()
  459.             this.fluidRenderObject.object.vertexBuffers['velocity']?.dispose()
  460.  
  461.             this.fluidRenderObject.object.vertexBuffers['position'] =
  462.                 new VertexBuffer(this.engine, this.fluidSimulation.positions!, VertexBuffer.PositionKind, true, false, 3, true)
  463.  
  464.             this.fluidRenderObject.object.vertexBuffers['velocity'] =
  465.                 new VertexBuffer(this.engine, this.fluidSimulation.velocities!, 'velocity', true, false, 3, true)
  466.         }
  467.     }
  468.  
  469.     private checkCollisions(particleRadius: number) {
  470.         if (this.collisionObjects.length === 0) {
  471.             return
  472.         }
  473.  
  474.         const positions = this.fluidSimulation.positions!
  475.         const velocities = this.fluidSimulation.velocities!
  476.         const tmpQuat = TmpVectors.Quaternion[0]
  477.         const tmpScale = TmpVectors.Vector3[0]
  478.         tmpScale.copyFromFloats(1, 1, 1)
  479.  
  480.         for (let i = 0; i < this.collisionObjects.length; ++i) {
  481.             const shape = this.collisionObjects[i][1]
  482.             const quat = shape.mesh?.rotationQuaternion ??
  483.                 shape.rotationQuaternion ??
  484.                 Quaternion.FromEulerAnglesToRef(
  485.                     shape.mesh?.rotation.x ?? shape.rotation.x,
  486.                     shape.mesh?.rotation.y ?? shape.rotation.y,
  487.                     shape.mesh?.rotation.z ?? shape.rotation.z,
  488.                     tmpQuat
  489.                 )
  490.  
  491.             Matrix.ComposeToRef(tmpScale, quat, shape.mesh?.position ?? shape.position, shape.transf)
  492.             shape.transf.invertToRef(shape.invTransf)
  493.         }
  494.  
  495.         const pos = TmpVectors.Vector3[4]
  496.         const normal = TmpVectors.Vector3[7]
  497.         for (let a = 0; a < this.fluidSimulation.currentNumParticles; ++a) {
  498.             const px = positions[a * 3 + 0]
  499.             const py = positions[a * 3 + 1]
  500.             const pz = positions[a * 3 + 2]
  501.             for (let i = 0; i < this.collisionObjects.length; ++i) {
  502.                 const shape = this.collisionObjects[i][1]
  503.                 if (shape.disabled) {
  504.                     continue
  505.                 }
  506.  
  507.                 pos.copyFromFloats(px, py, pz)
  508.                 Vector3.TransformCoordinatesToRef(pos, shape.invTransf, pos)
  509.                 pos.scaleInPlace(1 / shape.scale)
  510.                 const dist = shape.scale * shape.sdEvaluate(pos, ...shape.params) - particleRadius
  511.  
  512.                 if (dist < 0) {
  513.                     shape.computeNormal(pos, shape, normal)
  514.                     const restitution = shape.collisionRestitution ?? this.shapeCollisionRestitution
  515.                     const dotvn =
  516.                         velocities[a * 3 + 0] * normal.x +
  517.                         velocities[a * 3 + 1] * normal.y +
  518.                         velocities[a * 3 + 2] * normal.z
  519.  
  520.                     velocities[a * 3 + 0] = (velocities[a * 3 + 0] - 2 * dotvn * normal.x) * restitution
  521.                     velocities[a * 3 + 1] = (velocities[a * 3 + 1] - 2 * dotvn * normal.y) * restitution
  522.                     velocities[a * 3 + 2] = (velocities[a * 3 + 2] - 2 * dotvn * normal.z) * restitution
  523.  
  524.                     positions[a * 3 + 0] -= normal.x * dist
  525.                     positions[a * 3 + 1] -= normal.y * dist
  526.                     positions[a * 3 + 2] -= normal.z * dist
  527.                 }
  528.             }
  529.         }
  530.  
  531.     }
  532. }
Add Comment
Please, Sign In to add comment