diff --git a/docs/content/physics.md b/docs/content/physics.md index 38fa65fc..6afdc2d1 100644 --- a/docs/content/physics.md +++ b/docs/content/physics.md @@ -157,7 +157,7 @@ addSlider(&dampStr, &damp, 1000) This simulation allows interactive control over the parameters of a `Prismatic` joint, which sets the linear position of a body along a given axis, in this case along the horizontal (`X`) axis. -Click the `Step 10000` button and then start moving the sliders to see the effects interactively. Here's what you should observe: +Click the `Run` button and then start moving the sliders to see the effects interactively (press `Stop` to stop when done). Here's what you should observe: * `Stiff` (stiffness) determines how quickly the joint responds to the position changes. You can make this variable even stronger in practice (e.g., 10,000). diff --git a/physics/phyxyz/editor.go b/physics/phyxyz/editor.go index e661e284..1f999260 100644 --- a/physics/phyxyz/editor.go +++ b/physics/phyxyz/editor.go @@ -215,6 +215,41 @@ func (pe *Editor) Step(n int) { pe.AsyncUnlock() } +// Run runs the physics until stopped +func (pe *Editor) Run() { + if pe.isRunning { + return + } + pe.isRunning = true + pe.Model.SetAsCurrent() + pe.toolbar.AsyncLock() + pe.toolbar.UpdateRender() + pe.toolbar.AsyncUnlock() + for { + if pe.ControlFunc != nil { + pe.ControlFunc(physics.StepsToMsec(pe.TimeStep)) + } + pe.Model.Step() + pe.TimeStep++ + pe.Scene.Update() + pe.editor.AsyncLock() + pe.editor.NeedsRender() + pe.editor.AsyncUnlock() + if !pe.Model.GPU { + time.Sleep(time.Nanosecond) // this is essential for web (wasm) running to actually update + // if running in GPU mode, it works, but otherwise the thread never yields and it never updates. + } + if pe.stop { + pe.stop = false + break + } + } + pe.isRunning = false + pe.AsyncLock() + pe.Update() + pe.AsyncUnlock() +} + func (pe *Editor) MakeToolbar(p *tree.Plan) { stepNButton := func(n int) { nm := fmt.Sprintf("Step %d", n) @@ -253,6 +288,14 @@ func (pe *Editor) MakeToolbar(p *tree.Plan) { }) tree.Add(p, func(w *core.Separator) {}) + tree.Add(p, func(w *core.Button) { + w.SetText("Run").SetIcon(icons.PlayArrow). + SetTooltip("Run physics until Stop is pressed."). + OnClick(func(e events.Event) { + go pe.Run() + }) + w.FirstStyler(func(s *styles.Style) { s.SetEnabled(!pe.isRunning) }) + }) stepNButton(1) stepNButton(10) stepNButton(100) diff --git a/physics/step_joint.go b/physics/step_joint.go index 59ed8c50..e989e731 100644 --- a/physics/step_joint.go +++ b/physics/step_joint.go @@ -76,10 +76,14 @@ func StepJointForces(i uint32) { //gosl:kernel // child world transform poseCR := DynamicPos(jCi, params.Cur) poseCQ := DynamicQuat(jCi, params.Cur) - // note: NOT doing this: slmath.MulSpatialTransforms(poseCR, poseCQ, jCR, jCQ, &xwCR, &xwCQ) + jCR := JointCPos(ji) + jCQ := JointCQuat(ji) + xwCR := jCR + xwCQ := jCQ + slmath.MulSpatialTransforms(poseCR, poseCQ, jCR, jCQ, &xwCR, &xwCQ) // https://github.com/newton-physics/newton/issues/1261 comC := BodyCom(jCbi) - dC := poseCR.Sub(slmath.MulSpatialPoint(poseCR, poseCQ, comC)) // child moment arm + dC := xwCR.Sub(slmath.MulSpatialPoint(poseCR, poseCQ, comC)) // child moment arm var f, t math32.Vector3 switch jt { diff --git a/physics/step_joint.goal b/physics/step_joint.goal index 6f404916..12219730 100644 --- a/physics/step_joint.goal +++ b/physics/step_joint.goal @@ -74,12 +74,14 @@ func StepJointForces(i uint32) { //gosl:kernel // child world transform poseCR := DynamicPos(jCi, params.Cur) poseCQ := DynamicQuat(jCi, params.Cur) + jCR := JointCPos(ji) + jCQ := JointCQuat(ji) xwCR := jCR xwCQ := jCQ slmath.MulSpatialTransforms(poseCR, poseCQ, jCR, jCQ, &xwCR, &xwCQ) // https://github.com/newton-physics/newton/issues/1261 comC := BodyCom(jCbi) - dC := poseCR.Sub(slmath.MulSpatialPoint(poseCR, poseCQ, comC)) // child moment arm + dC := xwCR.Sub(slmath.MulSpatialPoint(poseCR, poseCQ, comC)) // child moment arm var f, t math32.Vector3 switch jt {