danaugrs 7 лет назад
Родитель
Сommit
68fc78f144
5 измененных файлов с 237 добавлено и 71 удалено
  1. 21 0
      physics/collision.go
  2. 52 43
      physics/forcefield.go
  3. 18 4
      physics/particle.go
  4. 18 8
      physics/rigidbody.go
  5. 128 16
      physics/simulation.go

+ 21 - 0
physics/collision.go

@@ -0,0 +1,21 @@
+// Copyright 2016 The G3N Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package physics
+
+import (
+	"github.com/g3n/engine/core"
+)
+
+// Particle represents a physics-driven particle.
+type Collision struct {
+	// TODO
+}
+
+// NewCollision creates and returns a pointer to a new Collision.
+func  NewCollision(inode core.INode) *Collision {
+
+	c := new(Collision)
+	return c
+}

+ 52 - 43
physics/forcefield.go

@@ -8,148 +8,157 @@ import "github.com/g3n/engine/math32"
 
 // ForceField represents a force field. A force is defined for every point.
 type ForceField interface {
-	ForceAt(pos *math32.Vector3) *math32.Vector3
+	ForceAt(pos *math32.Vector3) math32.Vector3
 }
 
 //
-// Constant is a constant force field.
+// ConstantForceField is a constant force field.
 // It can be used to simulate surface gravity.
 //
-type Constant struct {
+type ConstantForceField struct {
 	force math32.Vector3
 }
 
-// NewConstant creates and returns a pointer to a new Constant force field.
-func NewConstant(acceleration float32) *Constant {
+// NewConstantForceField creates and returns a pointer to a new ConstantForceField.
+func NewConstantForceField(force *math32.Vector3) *ConstantForceField {
 
-	g := new(Constant)
-	g.force = math32.Vector3{0,0,-acceleration}
+	g := new(ConstantForceField)
+	g.force = *force
 	return g
 }
 
 // SetForce sets the force of the force field.
-func (g *Constant) SetForce(newDirection *math32.Vector3) {
+func (g *ConstantForceField) SetForce(newDirection *math32.Vector3) {
 
 	g.force = *newDirection
 }
 
 // Force returns the force of the force field.
-func (g *Constant) Force() *math32.Vector3 {
+func (g *ConstantForceField) Force() *math32.Vector3 {
 
 	return &g.force
 }
 
 // ForceAt satisfies the ForceField interface and returns the force at the specified position.
-func (g *Constant) ForceAt(pos *math32.Vector3) *math32.Vector3 {
+func (g *ConstantForceField) ForceAt(pos *math32.Vector3) math32.Vector3 {
 
-	return &g.force
+	return g.force
 }
 
 //
-// PointAttractor is a force field where all forces point to a single point.
+// AttractorForceField is a force field where all forces point to a single point.
 // The force strength changes with the inverse distance squared.
 // This can be used to model planetary attractions.
 //
-type PointAttractor struct {
+type AttractorForceField struct {
 	position math32.Vector3
 	mass     float32
 }
 
-// NewPointAttractor creates and returns a pointer to a new PointAttractor force field.
-func NewPointAttractor(position *math32.Vector3, mass float32) *PointAttractor {
+// NewAttractorForceField creates and returns a pointer to a new AttractorForceField.
+func NewAttractorForceField(position *math32.Vector3, mass float32) *AttractorForceField {
 
-	pa := new(PointAttractor)
+	pa := new(AttractorForceField)
 	pa.position = *position
 	pa.mass = mass
 	return pa
 }
 
-// SetPosition sets the position of the PointAttractor.
-func (pa *PointAttractor) SetPosition(newPosition *math32.Vector3) {
+// SetPosition sets the position of the AttractorForceField.
+func (pa *AttractorForceField) SetPosition(newPosition *math32.Vector3) {
 
 	pa.position = *newPosition
 }
 
-// Position returns the position of the PointAttractor.
-func (pa *PointAttractor) Position() *math32.Vector3 {
+// Position returns the position of the AttractorForceField.
+func (pa *AttractorForceField) Position() *math32.Vector3 {
 
 	return &pa.position
 }
 
-// SetMass sets the mass of the PointAttractor.
-func (pa *PointAttractor) SetMass(newMass float32) {
+// SetMass sets the mass of the AttractorForceField.
+func (pa *AttractorForceField) SetMass(newMass float32) {
 
 	pa.mass = newMass
 }
 
-// Mass returns the mass of the PointAttractor.
-func (pa *PointAttractor) Mass() float32 {
+// Mass returns the mass of the AttractorForceField.
+func (pa *AttractorForceField) Mass() float32 {
 
 	return pa.mass
 }
 
 // ForceAt satisfies the ForceField interface and returns the force at the specified position.
-func (pa *PointAttractor) ForceAt(pos *math32.Vector3) *math32.Vector3 {
+func (pa *AttractorForceField) ForceAt(pos *math32.Vector3) math32.Vector3 {
 
 	dir := pos
 	dir.Negate()
 	dir.Add(&pa.position)
 	dist := dir.Length()
 	dir.Normalize()
-	dir.MultiplyScalar(pa.mass/(dist*dist))
-	return dir
+	var val float32
+	log.Error("dist %v", dist)
+	if dist > 0 {
+		val = pa.mass/(dist*dist)
+	} else {
+		val = 0
+	}
+	val = math32.Min(val, 100) // TODO deal with instability
+	log.Error("%v", val)
+	dir.MultiplyScalar(val) // TODO multiply by gravitational constant: 6.673×10−11 (N–m2)/kg2
+	return *dir
 }
 
 //
-// PointRepeller is a force field where all forces point away from a single point.
+// RepellerForceField is a force field where all forces point away from a single point.
 // The force strength changes with the inverse distance squared.
 //
-type PointRepeller struct {
+type RepellerForceField struct {
 	position math32.Vector3
 	mass     float32
 }
 
-// NewPointRepeller creates and returns a pointer to a new PointRepeller force field.
-func NewPointRepeller(position *math32.Vector3, mass float32) *PointRepeller {
+// NewRepellerForceField creates and returns a pointer to a new RepellerForceField.
+func NewRepellerForceField(position *math32.Vector3, mass float32) *RepellerForceField {
 
-	pr := new(PointRepeller)
+	pr := new(RepellerForceField)
 	pr.position = *position
 	pr.mass = mass
 	return pr
 }
 
-// SetPosition sets the position of the PointRepeller.
-func (pr *PointRepeller) SetPosition(newPosition *math32.Vector3) {
+// SetPosition sets the position of the RepellerForceField.
+func (pr *RepellerForceField) SetPosition(newPosition *math32.Vector3) {
 
 	pr.position = *newPosition
 }
 
-// Position returns the position of the PointRepeller.
-func (pr *PointRepeller) Position() *math32.Vector3 {
+// Position returns the position of the RepellerForceField.
+func (pr *RepellerForceField) Position() *math32.Vector3 {
 
 	return &pr.position
 }
 
-// SetMass sets the mass of the PointRepeller.
-func (pr *PointRepeller) SetMass(newMass float32) {
+// SetMass sets the mass of the RepellerForceField.
+func (pr *RepellerForceField) SetMass(newMass float32) {
 
 	pr.mass = newMass
 }
 
-// Mass returns the mass of the PointRepeller.
-func (pr *PointRepeller) Mass() float32 {
+// Mass returns the mass of the RepellerForceField.
+func (pr *RepellerForceField) Mass() float32 {
 
 	return pr.mass
 }
 
 // ForceAt satisfies the ForceField interface and returns the force at the specified position.
-func (pr *PointRepeller) ForceAt(pos *math32.Vector3) *math32.Vector3 {
+func (pr *RepellerForceField) ForceAt(pos *math32.Vector3) math32.Vector3 {
 
 	dir := pr.position
 	dir.Negate()
 	dir.Add(pos)
 	dist := dir.Length()
 	dir.Normalize()
-	dir.MultiplyScalar(pr.mass/(dist*dist))
-	return &dir
+	dir.MultiplyScalar(pr.mass/(dist*dist)) // TODO multiply by gravitational constant: 6.673×10−11 (N–m2)/kg2
+	return dir
 }

+ 18 - 4
physics/particle.go

@@ -4,14 +4,28 @@
 
 package physics
 
+import (
+	"github.com/g3n/engine/math32"
+	"github.com/g3n/engine/core"
+)
+
 // Particle represents a physics-driven particle.
 type Particle struct {
-	// TODO :)
+	core.INode
+	mass      float32
+	radius    float32
+	position  math32.Vector3
+	velocity  math32.Vector3
+	//netForce  math32.Vector3
+	colliding bool
 }
 
 // NewParticle creates and returns a pointer to a new Particle.
-func NewParticle() *Particle {
+func  NewParticle(inode core.INode) *Particle {
 
-	b := new(Particle)
-	return b
+	p := new(Particle)
+	p.INode = inode
+	p.mass = 1
+	p.radius = 1
+	return p
 }

+ 18 - 8
physics/rigidbody.go

@@ -4,17 +4,27 @@
 
 package physics
 
-import "github.com/g3n/engine/math32"
+import (
+	"github.com/g3n/engine/math32"
+	"github.com/g3n/engine/core"
+)
 
-// RigidBody represents a physics-driven solid body.
-type RigidBody struct {
-	// TODO :)
-	position math32.Vector3 // World position of the center of gravity
+// Body represents a physics-driven solid body.
+type Body struct {
+	core.INode
+	mass            float32        // Total mass
+	velocity        math32.Vector3 // Linear velocity
+	angularMass     math32.Matrix3 // Angular mass i.e. moment of inertia
+	angularVelocity math32.Vector3 // Angular velocity
+	position        math32.Vector3 // World position of the center of gravity
+	static          bool // If true - the rigidBody does not move or rotate
 }
 
-// NewRigidBody creates and returns a pointer to a new RigidBody.
-func NewRigidBody() *RigidBody {
+// NewBody creates and returns a pointer to a new RigidBody.
+func NewBody(inode core.INode) *Body {
 
-	b := new(RigidBody)
+	b := new(Body)
+	b.INode = inode
+	b.mass = 1
 	return b
 }

+ 128 - 16
physics/simulation.go

@@ -4,16 +4,29 @@
 
 package physics
 
+import (
+	"time"
+)
+
 type ICollidable interface {
+	Collided() bool
+	Static() bool
+	//GetCollisions() []*Collision
+}
 
+type CollisionGroup struct {
+	// TODO future
 }
 
 // Simulation represents a physics simulation.
 type Simulation struct {
-	forceFields []*ForceField
-	rigidBodies []*RigidBody
+	forceFields []ForceField
+	bodies      []*Body
 	particles   []*Particle
 
+	//dynamical   []int // non collidable but still affected by force fields
+	//collidables []ICollidable
+
 }
 
 // NewSimulation creates and returns a pointer to a new physics simulation.
@@ -24,14 +37,14 @@ func NewSimulation() *Simulation {
 }
 
 // AddForceField adds a force field to the simulation.
-func (s *Simulation) AddForceField(ff *ForceField) {
+func (s *Simulation) AddForceField(ff ForceField) {
 
 	s.forceFields = append(s.forceFields, ff)
 }
 
 // RemoveForceField removes the specified force field from the simulation.
-// Returns true if found or false otherwise.
-func (s *Simulation) RemoveForceField(ff *ForceField) bool {
+// Returns true if found, false otherwise.
+func (s *Simulation) RemoveForceField(ff ForceField) bool {
 
 	for pos, current := range s.forceFields {
 		if current == ff {
@@ -44,26 +57,125 @@ func (s *Simulation) RemoveForceField(ff *ForceField) bool {
 	return false
 }
 
-func (s *Simulation) CollisionBroadphase() {
+// AddBody adds a body to the simulation.
+func (s *Simulation) AddBody(rb *Body) {
 
+	s.bodies = append(s.bodies, rb)
 }
 
-func (s *Simulation) CheckCollisions(collidables []ICollidable) {
+// RemoveBody removes the specified body from the simulation.
+// Returns true if found, false otherwise.
+func (s *Simulation) RemoveBody(rb *Body) bool {
 
+	for pos, current := range s.bodies {
+		if current == rb {
+			copy(s.bodies[pos:], s.bodies[pos+1:])
+			s.bodies[len(s.bodies)-1] = nil
+			s.bodies = s.bodies[:len(s.bodies)-1]
+			return true
+		}
+	}
+	return false
 }
 
-// Step steps the simulation.
-func (s *Simulation) Step() {
+// AddParticle adds a particle to the simulation.
+func (s *Simulation) AddParticle(rb *Particle) {
 
-	// Check for collisions (broad phase)
-	//s.CollisionBroadphase()
+	s.particles = append(s.particles, rb)
+}
 
-	// Check for collisions (narrow phase)
-	//s.CheckCollisions()
+// RemoveParticle removes the specified particle from the simulation.
+// Returns true if found, false otherwise.
+func (s *Simulation) RemoveParticle(rb *Particle) bool {
 
-	// Apply forces/inertia/impulses
+	for pos, current := range s.particles {
+		if current == rb {
+			copy(s.particles[pos:], s.particles[pos+1:])
+			s.particles[len(s.particles)-1] = nil
+			s.particles = s.particles[:len(s.particles)-1]
+			return true
+		}
+	}
+	return false
+}
 
+func (s *Simulation) applyForceFields(frameDelta time.Duration) {
+
+	for _, ff := range s.forceFields {
+		for _, rb := range s.bodies {
+			pos := rb.GetNode().Position()
+			force := ff.ForceAt(&pos)
+			//log.Error("force: %v", force)
+			//log.Error("mass: %v", rb.mass)
+			//log.Error("frameDelta: %v", frameDelta.Seconds())
+			vdiff := force.MultiplyScalar(float32(frameDelta.Seconds())/rb.mass)
+			//log.Error("vdiff: %v", vdiff)
+			rb.velocity.Add(vdiff)
+		}
+	}
 
-	// Update visual representation
+	for _, ff := range s.forceFields {
+		for _, rb := range s.particles {
+			pos := rb.GetNode().Position()
+			force := ff.ForceAt(&pos)
+			//log.Error("force: %v", force)
+			//log.Error("mass: %v", rb.mass)
+			//log.Error("frameDelta: %v", frameDelta.Seconds())
+			vdiff := force.MultiplyScalar(float32(frameDelta.Seconds())/rb.mass)
+			//log.Error("vdiff: %v", vdiff)
+			rb.velocity.Add(vdiff)
+		}
+	}
+}
 
-}
+// updatePositions integrates the velocity of the objects to obtain the position in the next frame.
+func (s *Simulation) updatePositions(frameDelta time.Duration) {
+
+	for _, rb := range s.bodies {
+		pos := rb.GetNode().Position()
+		posDelta := rb.velocity
+		posDelta.MultiplyScalar(float32(frameDelta.Seconds()))
+		pos.Add(&posDelta)
+		rb.GetNode().SetPositionVec(&pos)
+	}
+
+	for _, rb := range s.particles {
+		pos := rb.GetNode().Position()
+		posDelta := rb.velocity
+		posDelta.MultiplyScalar(float32(frameDelta.Seconds()))
+		pos.Add(&posDelta)
+		rb.GetNode().SetPositionVec(&pos)
+	}
+}
+
+//func (s *Simulation) CheckCollisions() []*Collision{//collidables []ICollidable) {
+//
+//	return
+//}
+
+
+func (s *Simulation) Backtrack() {
+
+}
+
+// Step steps the simulation.
+func (s *Simulation) Step(frameDelta time.Duration) {
+
+	// Check for collisions
+	//collisions := s.CheckCollisions()
+	//if len(collisions) > 0 {
+	//	// Backtrack to 0 penetration
+	//	s.Backtrack()
+	//}
+
+	// Apply static forces/inertia/impulses (only to objects that did not collide)
+	s.applyForceFields(frameDelta)
+	// s.applyDrag(frameDelta) // TODO
+
+	// Apply impact forces/inertia/impulses to objects that collided
+	//s.applyImpactForces(frameDelta)
+
+	// Update object positions based on calculated final speeds
+	s.updatePositions(frameDelta)
+
+}