oopsie
This commit is contained in:
parent
37d053d9c2
commit
069705a31e
76
anchor.js
Normal file
76
anchor.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
class Anchor{
|
||||||
|
constructor(opt={}){
|
||||||
|
this.p=opt.p||[0,0,0]
|
||||||
|
this.a=opt.a||[[1,0,0],[0,1,0]]
|
||||||
|
this.r=opt.r||[[0,0,0],[0,0,0]]
|
||||||
|
this.v=opt.v||[0,0,0]
|
||||||
|
this.forces=[[0,0,0],[0,0,0],[0,0,0]]
|
||||||
|
this.pr={p:[...this.p],a:[[...this.a[0]],[...this.a[1]],vcross(...this.a)]}
|
||||||
|
}
|
||||||
|
update(dt=1){
|
||||||
|
this.pr={p:[...this.p],a:[[...this.a[0]],[...this.a[1]],vcross(...this.a)]}
|
||||||
|
for(let i=0;i<2;i++){for(let j=0;j<3;j++){this.r[i][j]+=this.forces[i][j]*dt}}
|
||||||
|
for(let z=0;z<3;z++){this.v[z]+=this.forces[2][z]*dt}
|
||||||
|
this.forces=[[0,0,0],[0,0,0],[0,0,0]]
|
||||||
|
for(let i=0;i<2;i++){for(let j=0;j<3;j++){this.r[i][j]*=cnst.drag.rot;if(i)this.v[j]*=cnst.drag.mov}}
|
||||||
|
for(let z=0;z<3;z++){this.p[z]+=this.v[z]*dt}
|
||||||
|
let b=[[...this.a[0]],[...this.a[1]],vcross(...this.a)]
|
||||||
|
for(let i=0;i<2;i++){for(let j=0;j<3;j++){for(let z=0;z<3;z++){this.a[i][z]+=this.r[i][j]*b[j][z]*dt}}}
|
||||||
|
|
||||||
|
this.a[1]=vnorm(vmultf(vcross(this.a[0],vcross(...this.a)),-1))
|
||||||
|
this.a[0]=vnorm(this.a[0])
|
||||||
|
}
|
||||||
|
applyForce(p,d){
|
||||||
|
this.forces[0][1]-=cnst.inertia.rot*p[1]*d[0]
|
||||||
|
this.forces[0][1]+=cnst.inertia.rot*p[0]*d[1]
|
||||||
|
this.forces[0][2]-=cnst.inertia.rot*p[2]*d[0]
|
||||||
|
this.forces[0][2]+=cnst.inertia.rot*p[0]*d[2]
|
||||||
|
this.forces[1][0]-=cnst.inertia.rot*p[1]*d[0]
|
||||||
|
this.forces[1][0]+=cnst.inertia.rot*p[0]*d[1]
|
||||||
|
this.forces[1][2]-=cnst.inertia.rot*p[2]*d[1]
|
||||||
|
this.forces[1][2]+=cnst.inertia.rot*p[1]*d[2]
|
||||||
|
let a=[...this.a,vcross(...this.a)]
|
||||||
|
for(let i=0;i<3;i++){for(let z=0;z<3;z++){this.forces[2][i]+=cnst.inertia.mov*d[z]*a[z][i]}}
|
||||||
|
}
|
||||||
|
applyWorldForce(p,d){
|
||||||
|
this.applyForce(toGrid(p),absolNormal(d))
|
||||||
|
}
|
||||||
|
//clarify: toGrid() is used to convert from world-space to internal grid space, fromGrid() is used to convert from internal grid space back to world space
|
||||||
|
toGrid(p){
|
||||||
|
let a=[p[0]-this.p[0],p[1]-this.p[1],p[2]-this.p[2]]
|
||||||
|
return [vdot(a,this.a[0]),vdot(a,this.a[1]),vdot(a,vcross(...this.a))]
|
||||||
|
}
|
||||||
|
fromGrid(p){
|
||||||
|
let a=[...this.p],b=[...this.a,vcross(...this.a)]
|
||||||
|
for(let z=0;z<3;z++){for(let i=0;i<3;i++){a[i]+=b[z][i]*p[z]}}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
//clarify: absolNormal() converts a world-space vector to a grid-space vector, for example you can use to apply a constant upwards force independent of rotation
|
||||||
|
//gridNormal() can be used to display a grid-space vector in world-space
|
||||||
|
absolNormal(p){
|
||||||
|
return [vdot(p,this.a[0]),vdot(p,this.a[1]),vdot(p,vcross(...this.a))]
|
||||||
|
}
|
||||||
|
gridNormal(p){
|
||||||
|
let a=[0,0,0],b=[...this.a,vcross(...this.a)]
|
||||||
|
for(let z=0;z<3;z++){for(let i=0;i<3;i++){a[i]+=b[z][i]*p[z]}}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
pr_toGrid(p){
|
||||||
|
let a=[p[0]-this.pr.p[0],p[1]-this.pr.p[1],p[2]-this.pr.p[2]]
|
||||||
|
return [vdot(a,this.pr.a[0]),vdot(a,this.pr.a[1]),vdot(a,vcross(...this.pr.a))]
|
||||||
|
}
|
||||||
|
pr_fromGrid(p){
|
||||||
|
let a=[...this.pr.p],b=[...this.pr.a,vcross(...this.pr.a)]
|
||||||
|
for(let z=0;z<3;z++){for(let i=0;i<3;i++){a[i]+=b[z][i]*p[z]}}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
pr_absolNormal(p){
|
||||||
|
return [vdot(p,this.pr.a[0]),vdot(p,this.pr.a[1]),vdot(p,vcross(...this.pr.a))]
|
||||||
|
}
|
||||||
|
pr_gridNormal(p){
|
||||||
|
let a=[0,0,0],b=[...this.pr.a,vcross(...this.pr.a)]
|
||||||
|
for(let z=0;z<3;z++){for(let i=0;i<3;i++){a[i]+=b[z][i]*p[z]}}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
}
|
455
craft.js
Normal file
455
craft.js
Normal file
@ -0,0 +1,455 @@
|
|||||||
|
class Craft{
|
||||||
|
constructor(opt={}){
|
||||||
|
this.fix=opt.fix||[]
|
||||||
|
this.edges=opt.edges||[]
|
||||||
|
this.faces=opt.faces||[]
|
||||||
|
this.joints=opt.joints||[]
|
||||||
|
this.complexEdges=[]
|
||||||
|
this.complexFaces=[]
|
||||||
|
this.p_jt=[[],[],[]]
|
||||||
|
this.o_jt=[[],[],[]]
|
||||||
|
this.fc=[]
|
||||||
|
this.weight=0;this.m_center=[0,0,0]
|
||||||
|
this.reactive=false
|
||||||
|
this.reactSetup=opt.reactive||{}
|
||||||
|
this.reactSetup.generateFriction=this.reactSetup.generateFriction||'vmultf(vadd(this.anchor.pr_fromGrid(this.p_fix[psz[i][2]]),vmultf(this.anchor.fromGrid(psz[i][0]),-1)),1)'
|
||||||
|
}
|
||||||
|
addFixture(p,c={},joint=-1){
|
||||||
|
if(!(this.joints[joint]||joint<0))return -1
|
||||||
|
let y=p,jt=joint,t=0,x=this.joints.length
|
||||||
|
while(t<x){
|
||||||
|
t++
|
||||||
|
y=vadd(y,jt<0?[0,0,0]:vmultf(this.joints[jt].offset,-1))
|
||||||
|
if(jt<0)break
|
||||||
|
else jt=this.joints[jt].joint
|
||||||
|
}
|
||||||
|
this.fix.push({joint:joint,grip:c.grip||cnst.grip,rebound:c.rebound||cnst.rebound,slide:c.slide||cnst.slide,offset:y,ptCol:['#FF0',-1]})
|
||||||
|
return this.fix.length-1
|
||||||
|
}
|
||||||
|
addJoint(p,axis=[0,1,0],joint=-1,opt={}){
|
||||||
|
if(!(this.joints[joint]||joint<0))return -1
|
||||||
|
let y=p,jt=joint,t=0,x=this.joints.length
|
||||||
|
while(t<x){
|
||||||
|
t++
|
||||||
|
y=vadd(y,jt<0?[0,0,0]:vmultf(this.joints[jt].offset,-1))
|
||||||
|
if(jt<0)break
|
||||||
|
else jt=this.joints[jt].joint
|
||||||
|
}
|
||||||
|
this.joints.push({t:0,joint:joint,axis:axis,offset:y,friction:opt.friction||10,stiff:opt.stiff||0.7,a:new Anchor(),weight:0,m_center:[0,0,0],chain:[]})
|
||||||
|
return this.joints.length-1
|
||||||
|
}
|
||||||
|
addEdge(a,b,w=1,c='#FF0'){
|
||||||
|
this.edges.push({p:[a,b],w:w,c:c})
|
||||||
|
if(this.fix[a].ptCol[1]<w)this.fix[a].ptCol=[c,w]
|
||||||
|
if(this.fix[b].ptCol[1]<w)this.fix[b].ptCol=[c,w]
|
||||||
|
return this.edges.length-1
|
||||||
|
}
|
||||||
|
addFace(a,b,c,w=1,n=0,s="#BBB"){
|
||||||
|
this.faces.push({p:[a,b,c],w:w,n:n,c:s,offset:[0,0,0],norm:[0,0,0],force:0})
|
||||||
|
return this.faces.length-1
|
||||||
|
}
|
||||||
|
setup(){
|
||||||
|
this.reactive=new Reactive(this.reactSetup)
|
||||||
|
this.reactive.returnCollides=1
|
||||||
|
let x=this.edges.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
if(this.fix[this.edges[i].p[0]].joint==this.fix[this.edges[i].p[1]].joint){
|
||||||
|
if(this.fix[this.edges[i].p[0]].joint<0){
|
||||||
|
let a=vmag(vadd(this.fix[this.edges[i].p[0]].offset,vmultf(this.fix[this.edges[i].p[1]].offset,-1)))*this.edges[i].w
|
||||||
|
this.weight+=a
|
||||||
|
this.m_center=vadd(this.m_center,vmultf(vadd(this.fix[this.edges[i].p[0]].offset,this.fix[this.edges[i].p[1]].offset),a/2))
|
||||||
|
}else{
|
||||||
|
let a=vmag(vadd(this.fix[this.edges[i].p[0]].offset,vmultf(this.fix[this.edges[i].p[1]].offset,-1)))*this.edges[i].w
|
||||||
|
this.joints[this.fix[this.edges[i].p[0]].joint].weight+=a
|
||||||
|
this.joints[this.fix[this.edges[i].p[0]].joint].m_center=vadd(this.joints[this.fix[this.edges[i].p[0]].joint].m_center,
|
||||||
|
vmultf(vadd(this.fix[this.edges[i].p[0]].offset,this.fix[this.edges[i].p[1]].offset),a/2))
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
this.complexEdges.push(this.edges[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x=this.faces.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
if(this.fix[this.faces[i].p[0]].joint==this.fix[this.faces[i].p[1]].joint&&this.fix[this.faces[i].p[2]].joint==this.fix[this.faces[i].p[1]].joint){
|
||||||
|
if(this.fix[this.faces[i].p[0]].joint<0){
|
||||||
|
let a=(
|
||||||
|
vmag(vadd(this.fix[this.faces[i].p[0]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1)))*
|
||||||
|
vmag(vadd(this.fix[this.faces[i].p[2]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1)))*
|
||||||
|
Math.sqrt(1-sqrx(vdot(
|
||||||
|
vnorm(vadd(this.fix[this.faces[i].p[0]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1))),
|
||||||
|
vnorm(vadd(this.fix[this.faces[i].p[2]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1)))
|
||||||
|
)))
|
||||||
|
)/8
|
||||||
|
this.faces[i].force=a*this.faces[i].n
|
||||||
|
this.faces[i].norm=vnorm(vcross(vadd(this.fix[this.faces[i].p[0]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1)),vadd(this.fix[this.faces[i].p[2]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1))))
|
||||||
|
this.faces[i].offset=vmultf(vadd(
|
||||||
|
this.fix[this.faces[i].p[0]].offset,vadd(this.fix[this.faces[i].p[1]].offset,this.fix[this.faces[i].p[2]].offset)
|
||||||
|
),1/3)
|
||||||
|
this.weight+=a
|
||||||
|
this.m_center=vadd(this.m_center,vmultf(vadd(
|
||||||
|
this.fix[this.faces[i].p[0]].offset,vadd(this.fix[this.faces[i].p[1]].offset,this.fix[this.faces[i].p[2]].offset)
|
||||||
|
),a*this.faces[i].w/3))
|
||||||
|
}else{
|
||||||
|
let a=(
|
||||||
|
vmag(vadd(this.fix[this.faces[i].p[0]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1)))*
|
||||||
|
vmag(vadd(this.fix[this.faces[i].p[2]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1)))*
|
||||||
|
Math.sqrt(1-sqrx(vdot(
|
||||||
|
vnorm(vadd(this.fix[this.faces[i].p[0]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1))),
|
||||||
|
vnorm(vadd(this.fix[this.faces[i].p[2]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1)))
|
||||||
|
)))
|
||||||
|
)/8
|
||||||
|
this.faces[i].force=a*this.faces[i].n
|
||||||
|
this.faces[i].norm=vnorm(vcross(vadd(this.fix[this.faces[i].p[0]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1)),vadd(this.fix[this.faces[i].p[2]].offset,vmultf(this.fix[this.faces[i].p[1]].offset,-1))))
|
||||||
|
this.faces[i].offset=vmultf(vadd(
|
||||||
|
this.fix[this.faces[i].p[0]].offset,vadd(this.fix[this.faces[i].p[1]].offset,this.fix[this.faces[i].p[2]].offset)
|
||||||
|
),1/3)
|
||||||
|
this.m_center=vadd(this.m_center,vmultf(vadd(
|
||||||
|
this.fix[this.faces[i].p[0]].offset,vadd(this.fix[this.faces[i].p[1]].offset,this.fix[this.faces[i].p[2]].offset)
|
||||||
|
),a*this.faces[i].w/3))
|
||||||
|
this.joints[this.fix[this.faces[i].p[0]].joint].weight+=a
|
||||||
|
this.joints[this.fix[this.faces[i].p[0]].joint].m_center=vadd(this.joints[this.fix[this.faces[i].p[0]].joint].m_center,vmultf(vadd(
|
||||||
|
this.fix[this.faces[i].p[0]].offset,vadd(this.fix[this.faces[i].p[1]].offset,this.fix[this.faces[i].p[2]].offset)
|
||||||
|
),a/3))
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
this.complexFaces.push(this.faces[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x=this.joints.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
if(this.joints[i].weight)this.joints[i].m_center=vmultf(this.joints[i].m_center,1/this.joints[i].weight)
|
||||||
|
let c=0,z=this.joints[i].joint;this.joints[i].chain=[]
|
||||||
|
while(z>-1||c>x){
|
||||||
|
c++
|
||||||
|
this.joints[i].chain.push(z)
|
||||||
|
z=this.joints[z].joint
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.m_center=this.weight?vmultf(this.m_center,1/this.weight):[0,0,0]
|
||||||
|
this.weld()
|
||||||
|
this.weld()
|
||||||
|
this.reactive.p_fix=[]
|
||||||
|
x=this.reactive.fix.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
this.fc.push(this.fix[i].ptCol[0])
|
||||||
|
this.reactive.p_fix.push(this.reactive.fix[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
weld(){
|
||||||
|
this.reactive.p_fix=[]
|
||||||
|
let x=this.reactive.fix.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
this.reactive.p_fix.push(this.reactive.fix[i])
|
||||||
|
}
|
||||||
|
this.reactive.fix=[]
|
||||||
|
this.reactive.edges=[...this.edges]
|
||||||
|
let jp=[],jr=[],offset=[0,0,0],axes=[[1,0,0],[0,1,0]],c,t
|
||||||
|
x=this.joints.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
this.joints[i].a.p=[0,0,0]
|
||||||
|
this.joints[i].a.v=[0,0,0]
|
||||||
|
let z=this.joints[i].joint
|
||||||
|
offset=[...this.joints[i].offset]
|
||||||
|
axes=this.joints[i].a.a
|
||||||
|
c=0
|
||||||
|
while(z>-1&&c<x){
|
||||||
|
c++
|
||||||
|
if(jp[z]){
|
||||||
|
offset=vadd(jp[z],vtransform(jr[z],[0,0,0],offset))
|
||||||
|
axes=[vnorm(vtransform(jr[z],[0,0,0],axes[0])),vnorm(vtransform(jr[z],[0,0,0],axes[1]))]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
offset=vadd(this.joints[z].offset,this.joints[z].a.gridNormal(offset))
|
||||||
|
axes=[this.joints[z].a.gridNormal(axes[0]),this.joints[z].a.gridNormal(axes[1])]
|
||||||
|
z=this.joints[z].joint
|
||||||
|
}
|
||||||
|
jp.push(offset)
|
||||||
|
jr.push(axes)
|
||||||
|
}
|
||||||
|
this.o_jt=[[],[],[...this.p_jt[2]]]
|
||||||
|
for(let i=0;i<this.p_jt[0].length;i++){
|
||||||
|
this.o_jt[0].push([...this.p_jt[0][i]])
|
||||||
|
}
|
||||||
|
for(let i=0;i<this.p_jt[1].length;i++){
|
||||||
|
this.o_jt[1].push([...this.p_jt[1][i]])
|
||||||
|
}
|
||||||
|
this.p_jt=[jp,jr]
|
||||||
|
x=this.fix.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
if(this.fix[i].joint<0){
|
||||||
|
this.reactive.fix.push(this.fix[i].offset)
|
||||||
|
}else{
|
||||||
|
this.reactive.fix.push(vtransform(jr[this.fix[i].joint],jp[this.fix[i].joint],this.fix[i].offset))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offset=[0,0,0];c=0
|
||||||
|
x=this.joints.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
c+=this.joints[i].weight
|
||||||
|
offset=vadd(offset,vmultf(vadd(jp[i],vtransform(jr[i],[0,0,0],this.joints[i].m_center)),this.joints[i].weight))
|
||||||
|
}
|
||||||
|
c+=this.weight
|
||||||
|
offset=vadd(offset,vmultf(this.m_center,this.weight))
|
||||||
|
offset=vmultf(offset,-1/c)
|
||||||
|
this.p_jt.push(offset)
|
||||||
|
x=this.reactive.fix.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
this.reactive.fix[i]=vadd(this.reactive.fix[i],offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
center(){
|
||||||
|
let offset=[0,0,0],c=0,x=this.joints.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
c+=this.joints[i].weight
|
||||||
|
offset=vadd(offset,vmultf(vadd(this.p_jt[0][i],vtransform(this.p_jt[1][i],[0,0,0],this.joints[i].m_center)),this.joints[i].weight))
|
||||||
|
}
|
||||||
|
c+=this.weight
|
||||||
|
offset=vadd(offset,vmultf(this.m_center,this.weight))
|
||||||
|
offset=vmultf(offset,-1/c)
|
||||||
|
this.m_center=vadd(this.m_center,offset)
|
||||||
|
x=this.fix.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
if(this.fix[i].joint<0)this.fix[i].offset=vadd(this.fix[i].offset,offset)
|
||||||
|
}
|
||||||
|
x=this.joints.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
this.joints[i].offset=vadd(this.joints[i].offset,offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update(dt=1){
|
||||||
|
let t_weight=this.weight
|
||||||
|
for(let i=0;i<this.joints.length;i++){
|
||||||
|
t_weight+=this.joints[i].weight
|
||||||
|
}
|
||||||
|
for(let i=0;i<this.faces.length;i++){
|
||||||
|
if(this.faces[i].force){
|
||||||
|
let p=[0,0,0],op=[0,0,0],d=[0,0,0]
|
||||||
|
if(this.fix[this.faces[i].p[0]].joint<0){
|
||||||
|
p=this.faces[i].offset
|
||||||
|
op=this.faces[i].offset
|
||||||
|
d=this.faces[i].norm
|
||||||
|
}else{
|
||||||
|
p=vadd(this.p_jt[0][this.fix[this.faces[i].p[0]].joint],vtransform(this.p_jt[1][this.fix[this.faces[i].p[0]].joint],[0,0,0],this.faces[i].offset))
|
||||||
|
op=vadd(this.o_jt[0][this.fix[this.faces[i].p[0]].joint],vtransform(this.o_jt[1][this.fix[this.faces[i].p[0]].joint],[0,0,0],this.faces[i].offset))
|
||||||
|
d=vtransform(this.p_jt[1][this.fix[this.faces[i].p[0]].joint],[0,0,0],this.faces[i].norm)
|
||||||
|
op=vadd(p,vmultf(vadd(op,vmultf(p,-1)),20))
|
||||||
|
}
|
||||||
|
this.applyGlobForce(
|
||||||
|
this.fix[this.faces[i].p[0]].joint,
|
||||||
|
vadd(p,vmultf(this.p_jt[2],1)),
|
||||||
|
vmultf(d,vdot(
|
||||||
|
vadd(this.reactive.anchor.pr_fromGrid(vadd(op,vmultf(this.p_jt[2],-1))),vmultf(this.reactive.anchor.fromGrid(vadd(p,vmultf(this.p_jt[2],-1))),-1)),
|
||||||
|
this.reactive.anchor.gridNormal(d)
|
||||||
|
)*this.faces[i].force/t_weight*20)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.weld()
|
||||||
|
if(this.reactive){
|
||||||
|
this.reactive.anchor.update(dt)
|
||||||
|
for(let i=0;i<this.joints.length;i++){
|
||||||
|
this.joints[i].a.update(dt)
|
||||||
|
if(this.joints[i].axis[0]!=0){
|
||||||
|
this.joints[i].a.a[0]=this.joints[i].axis
|
||||||
|
this.joints[i].a.a[1]=vsnap(this.joints[i].a.a[1],this.joints[i].axis)
|
||||||
|
}
|
||||||
|
if(this.joints[i].axis[1]!=0){
|
||||||
|
this.joints[i].a.a[1]=this.joints[i].axis
|
||||||
|
this.joints[i].a.a[0]=vsnap(this.joints[i].a.a[0],this.joints[i].axis)
|
||||||
|
}
|
||||||
|
if(this.joints[i].axis[2]!=0){
|
||||||
|
this.joints[i].a.a[0]=vsnap(this.joints[i].a.a[0],this.joints[i].axis)
|
||||||
|
this.joints[i].a.a[1]=vsnap(this.joints[i].a.a[1],this.joints[i].axis)
|
||||||
|
if(vmag(vadd(vcross(...this.joints[i].a.a),this.joints[i].axis))<1)this.joints[i].a.a[1]=vmultf(this.joints[i].a.a[1],-1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
applyJointForce(j,p2,d2){
|
||||||
|
let p=[...p2],d=[...d2]
|
||||||
|
if(this.joints[j]){
|
||||||
|
let axes=this.p_jt[1][j]
|
||||||
|
p=vtransform(axes,[0,0,0],p);d=vtransform(axes,[0,0,0],d)
|
||||||
|
let weightSum=this.weight,weightJoint=0,x=this.joints.length
|
||||||
|
for(let i=0;i<x;i++){
|
||||||
|
weightSum+=this.joints[i].weight
|
||||||
|
if(i==j||this.joints[i].chain.includes(j))weightJoint+=this.joints[i].weight
|
||||||
|
}
|
||||||
|
this.joints[j].a.applyForce(p2,vmultf(d2,weightJoint/weightSum/2-1/2))
|
||||||
|
this.joints[j].a.applyForce(vmultf(p2,-1),vmultf(d2,1/2-weightJoint/weightSum/2))
|
||||||
|
this.reactive.applyForce(p,vmultf(d,weightJoint/weightSum/2))
|
||||||
|
this.reactive.applyForce(vmultf(p,-1),vmultf(d,-weightJoint/weightSum/2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
applyAbsolJointForce(j,p,d2){
|
||||||
|
let d=vsnap(vdetransform(
|
||||||
|
this.p_jt[1][j],
|
||||||
|
[0,0,0],
|
||||||
|
d2
|
||||||
|
),this.joints[j].axis)
|
||||||
|
this.applyJointForce(j,p,d)
|
||||||
|
}
|
||||||
|
applyWorldJointForce(j,p,d2){
|
||||||
|
let np=vsnap(vdetransform(
|
||||||
|
this.p_jt[1][j],
|
||||||
|
[0,0,0],
|
||||||
|
vadd(p,vadd(vmultf(this.p_jt[0][j],-1),vmultf(this.p_jt[2],-1)))
|
||||||
|
),this.joints[j].axis),
|
||||||
|
d=vsnap(vdetransform(
|
||||||
|
this.p_jt[1][j],
|
||||||
|
[0,0,0],
|
||||||
|
d2
|
||||||
|
),this.joints[j].axis)
|
||||||
|
this.applyJointForce(j,np,d)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
turnJoint(j,target2,reference2,force,damping){
|
||||||
|
if(!this.joints[j])return
|
||||||
|
if(this.joints[j].t==0){
|
||||||
|
let target=vmultf(vnorm(target2),-1),reference=vnorm(reference2)
|
||||||
|
this.applyJointForce(j,vsnap(reference,this.joints[j].axis),vmultf(vsnap(this.joints[j].a.absolNormal(target),this.joints[j].axis),force))
|
||||||
|
this.applyJointForce(j,this.joints[j].axis[0]?[0,1,0]:[1,0,0],vmultf(this.joints[j].a.r[this.joints[j].axis[0]?1:0],damping))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
applyGlobForce(j,p,d){
|
||||||
|
let jt=j,c=0
|
||||||
|
while(jt>-1&&c<this.joints.length){
|
||||||
|
this.applyJointForce(
|
||||||
|
jt,
|
||||||
|
vsnap(vdetransform(
|
||||||
|
this.p_jt[1][jt],
|
||||||
|
[0,0,0],
|
||||||
|
vadd(p,vadd(vmultf(this.p_jt[0][jt],-1),vmultf(this.p_jt[2],-1)))
|
||||||
|
),this.joints[jt].axis),
|
||||||
|
vmultf(
|
||||||
|
vsnap(vdetransform(
|
||||||
|
this.p_jt[1][jt],
|
||||||
|
[0,0,0],
|
||||||
|
d
|
||||||
|
),this.joints[jt].axis),
|
||||||
|
-this.joints[jt].stiff
|
||||||
|
)
|
||||||
|
)
|
||||||
|
jt=this.joints[jt].joint
|
||||||
|
c++
|
||||||
|
}
|
||||||
|
this.reactive.anchor.applyForce(p,d)
|
||||||
|
}
|
||||||
|
collide(dt,p,d){
|
||||||
|
let dt2=1//(1+(dt-1)*3)
|
||||||
|
if(this.reactive){
|
||||||
|
let collides=this.reactive.collide(p,d)
|
||||||
|
if(!collides.length)return
|
||||||
|
let z=collides.length,n=[0]
|
||||||
|
for(let i=0;i<this.joints.length;i++){
|
||||||
|
n.push(0)
|
||||||
|
}
|
||||||
|
for(let i=0;i<z;i++){
|
||||||
|
n[this.fix[collides[i][0][2]].joint+1]++
|
||||||
|
}
|
||||||
|
for(let i=0;i<z;i++){
|
||||||
|
let rebound=this.fix[collides[i][0][2]].rebound,grip=this.fix[collides[i][0][2]].grip/dt,jt=this.fix[collides[i][0][2]].joint,c=0
|
||||||
|
while(jt>-1&&c<this.joints.length){
|
||||||
|
let np=vsnap(vdetransform(
|
||||||
|
this.p_jt[1][jt],
|
||||||
|
[0,0,0],
|
||||||
|
vadd(collides[i][0][0],vadd(vmultf(this.p_jt[0][jt],-1),vmultf(this.p_jt[2],-1)))
|
||||||
|
),this.joints[jt].axis)
|
||||||
|
let fc=[
|
||||||
|
this.reactive.anchor.absolNormal(vmultf(collides[i][0][3],-collides[i][0][1][1]/z*rebound/cnst.inertia.mov)),
|
||||||
|
this.reactive.anchor.absolNormal(vmultf(collides[i][1],1/2/n[this.fix[collides[i][0][2]].joint+1]*grip/cnst.inertia.mov))
|
||||||
|
]
|
||||||
|
fc[0]=vsnap(vdetransform(
|
||||||
|
this.p_jt[1][jt],
|
||||||
|
[0,0,0],
|
||||||
|
fc[0]
|
||||||
|
),this.joints[jt].axis)
|
||||||
|
fc[1]=vsnap(vdetransform(
|
||||||
|
this.p_jt[1][jt],
|
||||||
|
[0,0,0],
|
||||||
|
fc[1]
|
||||||
|
),this.joints[jt].axis)
|
||||||
|
this.applyJointForce(jt,vnorm(np),vmultf(fc[0],-dt2*this.joints[jt].stiff))
|
||||||
|
this.applyJointForce(jt,vnorm(np),vmultf(fc[1],-dt2*dt2*this.joints[jt].stiff))
|
||||||
|
jt=this.joints[jt].joint
|
||||||
|
c++
|
||||||
|
}
|
||||||
|
this.reactive.anchor.applyForce(vnorm(collides[i][0][0]),this.reactive.anchor.absolNormal(vmultf(collides[i][0][3],-dt2*collides[i][0][1][1]/z*rebound/cnst.inertia.mov)))
|
||||||
|
this.reactive.anchor.applyForce(vnorm(collides[i][0][0]),this.reactive.anchor.absolNormal(vmultf(collides[i][1],dt2*dt2/2/n[this.fix[collides[i][0][2]].joint+1]*grip/cnst.inertia.mov)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
collidef(dt,g){
|
||||||
|
let dt2=1//(1+(dt-1)*3)
|
||||||
|
if(this.reactive){
|
||||||
|
let collides=this.reactive.collidef(g)
|
||||||
|
if(!collides.length)return
|
||||||
|
let z=collides.length,n=[0]
|
||||||
|
for(let i=0;i<this.joints.length;i++){
|
||||||
|
n.push(0)
|
||||||
|
}
|
||||||
|
for(let i=0;i<z;i++){
|
||||||
|
n[this.fix[collides[i][0][2]].joint+1]++
|
||||||
|
}
|
||||||
|
for(let i=0;i<z;i++){
|
||||||
|
let rebound=this.fix[collides[i][0][2]].rebound,grip=this.fix[collides[i][0][2]].grip,slide=this.fix[collides[i][0][2]].slide,jt=this.fix[collides[i][0][2]].joint,c=0
|
||||||
|
while(jt>-1&&c<this.joints.length){
|
||||||
|
let np=vsnap(vdetransform(
|
||||||
|
this.p_jt[1][jt],
|
||||||
|
[0,0,0],
|
||||||
|
vadd(collides[i][0][0],vadd(vmultf(this.p_jt[0][jt],-1),vmultf(this.p_jt[2],-1)))
|
||||||
|
),this.joints[jt].axis)
|
||||||
|
let fc=[
|
||||||
|
this.reactive.anchor.absolNormal(vmultf(collides[i][0][3],-collides[i][0][1][1]/z*rebound/cnst.inertia.mov)),
|
||||||
|
this.reactive.anchor.absolNormal(vmultf(collides[i][1],1/2/n[this.fix[collides[i][0][2]].joint+1]*grip/cnst.inertia.mov))
|
||||||
|
]
|
||||||
|
fc[0]=vsnap(vdetransform(
|
||||||
|
this.p_jt[1][jt],
|
||||||
|
[0,0,0],
|
||||||
|
fc[0]
|
||||||
|
),this.joints[jt].axis)
|
||||||
|
fc[1]=vsnap(vdetransform(
|
||||||
|
this.p_jt[1][jt],
|
||||||
|
[0,0,0],
|
||||||
|
fc[1]
|
||||||
|
),this.joints[jt].axis)
|
||||||
|
this.applyJointForce(jt,vnorm(np),vmultf(fc[0],-dt2*this.joints[jt].stiff))
|
||||||
|
this.applyJointForce(jt,vnorm(np),vmultf(fc[1],-dt2*dt2*this.joints[jt].stiff))
|
||||||
|
jt=this.joints[jt].joint
|
||||||
|
c++
|
||||||
|
}
|
||||||
|
this.reactive.anchor.applyForce(vnorm(collides[i][0][0]),this.reactive.anchor.absolNormal(vmultf(collides[i][0][3],-dt2*collides[i][0][1][1]/z*rebound/cnst.inertia.mov)))
|
||||||
|
this.reactive.anchor.applyForce(vnorm(collides[i][0][0]),this.reactive.anchor.absolNormal(vmultf(collides[i][0][3],vdot(collides[i][1],collides[i][0][3])/2/n[this.fix[collides[i][0][2]].joint+1]*grip/cnst.inertia.mov)))
|
||||||
|
this.reactive.anchor.applyForce(vnorm(collides[i][0][0]),this.reactive.anchor.absolNormal(vmultf(vsnap(collides[i][1],collides[i][0][3]),slide/2/n[this.fix[collides[i][0][2]].joint+1]*grip/cnst.inertia.mov)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
applyForce(p,d){
|
||||||
|
if(this.reactive)this.reactive.applyForce(p,d)
|
||||||
|
}
|
||||||
|
toGrid(p){
|
||||||
|
if(this.reactive)return this.reactive.toGrid(p)
|
||||||
|
}
|
||||||
|
fromGrid(p){
|
||||||
|
if(this.reactive)return this.reactive.fromGrid(p)
|
||||||
|
}
|
||||||
|
absolNormal(p){
|
||||||
|
if(this.reactive)return this.reactive.absolNormal(p)
|
||||||
|
}
|
||||||
|
gridNormal(p){
|
||||||
|
if(this.reactive)return this.reactive.gridNormal(p)
|
||||||
|
}
|
||||||
|
pr_toGrid(p){
|
||||||
|
if(this.reactive)return this.reactive.pr_toGrid(p)
|
||||||
|
}
|
||||||
|
pr_fromGrid(p){
|
||||||
|
if(this.reactive)return this.reactive.pr_fromGrid(p)
|
||||||
|
}
|
||||||
|
pr_absolNormal(p){
|
||||||
|
if(this.reactive)return this.reactive.pr_absolNormal(p)
|
||||||
|
}
|
||||||
|
pr_gridNormal(p){
|
||||||
|
if(this.reactive)return this.reactive.pr_gridNormal(p)
|
||||||
|
}
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
../phys/craft_models.js
|
|
73
craft_models.js
Normal file
73
craft_models.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
let sqr3 = Math.sqrt(3)
|
||||||
|
|
||||||
|
genCraftModels=craft=>{
|
||||||
|
let uid=newUID(),models=[[]]
|
||||||
|
models[0].push(new p5.Geometry(
|
||||||
|
1,1,
|
||||||
|
function createGeometry(){
|
||||||
|
for(let x=0;x<craft.faces.length;x++){
|
||||||
|
if(craft.fix[craft.faces[x].p[0]].joint==-1){
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.faces[x].p[0]].offset))
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.faces[x].p[1]].offset))
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.faces[x].p[2]].offset))
|
||||||
|
this.uvs.push([0,0])
|
||||||
|
this.uvs.push([1,0])
|
||||||
|
this.uvs.push([1/2,1/2*sqr3])
|
||||||
|
this.faces.push([this.vertices.length-1,this.vertices.length-2,this.vertices.length-3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.computeNormals()
|
||||||
|
this.gid='craft-geometry-faces-'+uid
|
||||||
|
}
|
||||||
|
))
|
||||||
|
models[0].push(new p5.Geometry(
|
||||||
|
1,1,
|
||||||
|
function createGeometry(){
|
||||||
|
for(let x=0;x<craft.edges.length;x++){
|
||||||
|
if(craft.fix[craft.edges[x].p[0]].joint==-1){
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.edges[x].p[0]].offset))
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.edges[x].p[1]].offset))
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.edges[x].p[1]].offset))
|
||||||
|
this.faces.push([this.vertices.length-1,this.vertices.length-2,this.vertices.length-3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.gid='craft-geometry-edges-'+uid
|
||||||
|
}
|
||||||
|
))
|
||||||
|
for(let i=0;i<craft.joints.length;i++){
|
||||||
|
models.push([])
|
||||||
|
models[i+1].push(new p5.Geometry(
|
||||||
|
1,1,
|
||||||
|
function createGeometry(){
|
||||||
|
for(let x=0;x<craft.faces.length;x++){
|
||||||
|
if(craft.fix[craft.faces[x].p[0]].joint==i){
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.faces[x].p[0]].offset))
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.faces[x].p[1]].offset))
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.faces[x].p[2]].offset))
|
||||||
|
this.uvs.push([0,0])
|
||||||
|
this.uvs.push([1,0])
|
||||||
|
this.uvs.push([1/2,1/2*sqr3])
|
||||||
|
this.faces.push([this.vertices.length-1,this.vertices.length-2,this.vertices.length-3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.computeNormals()
|
||||||
|
this.gid='craft-geometry-joint-faces-'+i.toString()+uid
|
||||||
|
}
|
||||||
|
))
|
||||||
|
models[i+1].push(new p5.Geometry(
|
||||||
|
1,1,
|
||||||
|
function createGeometry(){
|
||||||
|
for(let x=0;x<craft.edges.length;x++){
|
||||||
|
if(craft.fix[craft.edges[x].p[0]].joint==i){
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.edges[x].p[0]].offset))
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.edges[x].p[1]].offset))
|
||||||
|
this.vertices.push(new p5.Vector(...craft.fix[craft.edges[x].p[1]].offset))
|
||||||
|
this.faces.push([this.vertices.length-1,this.vertices.length-2,this.vertices.length-3])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.gid='craft-geometry-joint-edges-'+i.toString()+uid
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return models
|
||||||
|
}
|
@ -1 +0,0 @@
|
|||||||
../phys/index.html
|
|
14
index.html
Normal file
14
index.html
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/p5@1.9.3/lib/p5.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<script src="utils.js"></script>
|
||||||
|
<script src="anchor.js"></script>
|
||||||
|
<script src="reactive.js"></script>
|
||||||
|
<script src="craft.js"></script>
|
||||||
|
<script src="craft_models.js"></script>
|
||||||
|
<script src="main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
118
main.js
Normal file
118
main.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
let reacts = [], dt = 1, paused = 1;
|
||||||
|
|
||||||
|
function setup(){
|
||||||
|
let craftdata = {
|
||||||
|
fix: [
|
||||||
|
[1, 1, 1], // 0
|
||||||
|
[1, 1, -1], // 1
|
||||||
|
[1, -1, 1], // 2
|
||||||
|
[1, -1, -1], // 3
|
||||||
|
[-1, 1, 1], // 4
|
||||||
|
[-1, 1, -1], // 5
|
||||||
|
[-1, -1, 1], // 6
|
||||||
|
[-1, -1, -1] // 7
|
||||||
|
],
|
||||||
|
edges: [
|
||||||
|
[0, 1],
|
||||||
|
[0, 2],
|
||||||
|
[0, 4],
|
||||||
|
[1, 3],
|
||||||
|
[1, 5],
|
||||||
|
[2, 3],
|
||||||
|
[2, 6],
|
||||||
|
[3, 7],
|
||||||
|
[4, 5],
|
||||||
|
[4, 6],
|
||||||
|
[5, 7],
|
||||||
|
[6, 7]
|
||||||
|
],
|
||||||
|
faces: [
|
||||||
|
[0, 1, 2],
|
||||||
|
[4, 6, 7],
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
for(let i=0; i<4; ++i){
|
||||||
|
reacts.push(new Craft());
|
||||||
|
for(let fix of craftdata.fix) reacts[reacts.length-1].addFixture(fix);
|
||||||
|
for(let edge of craftdata.edges) reacts[reacts.length-1].addEdge(...edge);
|
||||||
|
for(let face of craftdata.faces) reacts[reacts.length-1].addFace(...face);
|
||||||
|
reacts[reacts.length-1].setup();
|
||||||
|
reacts[reacts.length-1].reactive.anchor.p[1] = -5
|
||||||
|
reacts[reacts.length-1].applyForce([Math.random()*10-5, 0, Math.random()*10-5],
|
||||||
|
reacts[reacts.length-1].reactive.absolNormal([0, -Math.random()*10-20, 0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
createCanvas(400, 400, WEBGL);
|
||||||
|
|
||||||
|
lt = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw(){
|
||||||
|
background(200);
|
||||||
|
scale(10);
|
||||||
|
|
||||||
|
for(let i=0; i<10; ++i)
|
||||||
|
point(Math.cos(TWO_PI/10*i)*10, 4, Math.sin(TWO_PI/10*i)*10);
|
||||||
|
|
||||||
|
for(let react of reacts){
|
||||||
|
if(!paused){
|
||||||
|
react.applyForce([0, 0, 0], react.reactive.absolNormal([0, 8, 0]));
|
||||||
|
react.collide(1/dt, [0, 4, 0], [[0, 0, 1], [0, 1, 0]]);
|
||||||
|
react.update(1/dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
push();
|
||||||
|
applyMatrix(mlookAt(react.reactive.anchor.p,react.reactive.anchor.a));
|
||||||
|
if(!react.models||!react.models.length)
|
||||||
|
react.models=genCraftModels(react)
|
||||||
|
strokeWeight(5);
|
||||||
|
push();
|
||||||
|
translate(...react.p_jt[2]);
|
||||||
|
fill(100, 100, 100); noStroke();
|
||||||
|
model(react.models[0][0]);
|
||||||
|
noFill(); stroke(255, 255, 0); strokeWeight(1);
|
||||||
|
model(react.models[0][1]);
|
||||||
|
pop();
|
||||||
|
for(let f=0; f<react.joints.length; ++f){
|
||||||
|
push();
|
||||||
|
applyMatrix(mlookAt(vadd(react.p_jt[0][f],react.p_jt[2]),react.p_jt[1][f]))
|
||||||
|
fill(100); noStroke();
|
||||||
|
model(react.models[f+1][0]);
|
||||||
|
noFill(); stroke(255, 255, 0); strokeWeight(1);
|
||||||
|
model(react.models[f+1][1]);
|
||||||
|
pop();
|
||||||
|
strokeWeight(1.5);
|
||||||
|
stroke(255, 0, 0);
|
||||||
|
point(...vadd(react.p_jt[0][f], react.p_jt[2]));
|
||||||
|
}
|
||||||
|
pop();
|
||||||
|
push();
|
||||||
|
push();
|
||||||
|
applyMatrix(mlookAt(react.reactive.anchor.p,react.reactive.anchor.a));
|
||||||
|
translate(react.p_jt[2][0], 4, react.p_jt[2][2]);
|
||||||
|
pop();
|
||||||
|
translate(-4.1*.3, 4.1, -4.1*.3);
|
||||||
|
applyMatrix([
|
||||||
|
1, 0, 0, 0,
|
||||||
|
.3, 0, .3, 0,
|
||||||
|
0, 0, 1, 0,
|
||||||
|
0, 0, 0, 1
|
||||||
|
]);
|
||||||
|
applyMatrix(mlookAt(react.reactive.anchor.p,react.reactive.anchor.a));
|
||||||
|
fill(150, 150, 150); noStroke();
|
||||||
|
model(react.models[0][0]);
|
||||||
|
noFill(); stroke(150, 150, 150); strokeWeight(1);
|
||||||
|
model(react.models[0][1]);
|
||||||
|
pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
orbitControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyReleased(){
|
||||||
|
if(key == 'a') paused = !paused;
|
||||||
|
if(key == 's'){
|
||||||
|
paused = false; dt = 6 - dt;
|
||||||
|
}
|
||||||
|
}
|
2
mirror.sh
Executable file
2
mirror.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
cp ~/misc/phys/*.js ./
|
||||||
|
cp ~/misc/phys/index.html ./
|
@ -1 +0,0 @@
|
|||||||
../phys/reactive.js
|
|
92
reactive.js
Normal file
92
reactive.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
class Reactive{
|
||||||
|
constructor(opt={}){
|
||||||
|
this.anchor=new Anchor(opt.anchor||{})
|
||||||
|
this.fix=opt.fix||[]
|
||||||
|
this.edges=opt.edges||[]
|
||||||
|
this.returnCollides=opt.returnCollides||0
|
||||||
|
this.generateFriction=opt.generateFriction||'vadd(this.anchor.pr_fromGrid(psz[i][0]),vmultf(this.anchor.fromGrid(psz[i][0]),-1))'
|
||||||
|
}
|
||||||
|
collide(p,d2){
|
||||||
|
let collides=[],d=[vnorm(d2[0]),vnorm(d2[1])],psz=[],x,tc=0,getOrient=i=>{let x=vadd(i,vmultf(p,-1));return [vdot(x,d[0]),vdot(x,d[1]),vdot(x,vcross(...d))]}
|
||||||
|
for(let i=0;i<this.fix.length;i++){
|
||||||
|
x=getOrient(this.anchor.fromGrid(this.fix[i]))
|
||||||
|
let r=vmag(this.fix[i])
|
||||||
|
if(x[1]>0)psz.push([this.fix[i],vmultf(x,1/r),i,d[1],r])
|
||||||
|
}
|
||||||
|
for(let i=0;i<psz.length;i++){
|
||||||
|
let z=vmultf(eval(this.generateFriction),1/psz[i][4])
|
||||||
|
if(this.returnCollides){
|
||||||
|
collides.push([psz[i],z])
|
||||||
|
}else{
|
||||||
|
this.anchor.applyForce(vnorm(psz[i][0]),this.anchor.absolNormal(vmultf(d[1],-psz[i][1][1]/psz.length*cnst.rebound/cnst.inertia.mov)))
|
||||||
|
this.anchor.applyForce(vnorm(psz[i][0]),this.anchor.absolNormal(vmultf(z,1/psz.length*cnst.grip/cnst.inertia.mov)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(psz.length==0){
|
||||||
|
x=getOrient(this.anchor.p)
|
||||||
|
if(x[1]>0){
|
||||||
|
this.anchor.applyForce([0,0,0],this.anchor.absolNormal(vmultf([0,-x[1],0],cnst.rebound/cnst.inertia.mov)))
|
||||||
|
this.anchor.applyForce([0,0,0],this.anchor.absolNormal(vmultf(this.anchor.v,cnst.grip/cnst.inertia.mov)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collides
|
||||||
|
}
|
||||||
|
collidef(g/*generation function for input p, returns {p[3] position d[2][3] anchors}*/){
|
||||||
|
let collides=[],psz=[],x,tc=0,getOrient=i=>{let y=g(i);y.d=[vnorm(y.d[0]),vnorm(y.d[1])];x=vadd(i,vmultf(y.p,-1));return [vdot(x,y.d[0]),vdot(x,y.d[1]),vdot(x,vcross(...y.d))]}
|
||||||
|
for(let i=0;i<this.fix.length;i++){
|
||||||
|
x=getOrient(this.anchor.fromGrid(this.fix[i]))
|
||||||
|
let r=vmag(this.fix[i])
|
||||||
|
if(x[1]>0)psz.push([this.fix[i],vmultf(x,1/r),i,g(this.anchor.fromGrid(this.fix[i])).d[1],r])
|
||||||
|
}
|
||||||
|
for(let i=0;i<psz.length;i++){
|
||||||
|
let z=vmultf(eval(this.generateFriction),1/psz[i][4])
|
||||||
|
if(this.returnCollides){
|
||||||
|
collides.push([psz[i],z])
|
||||||
|
}else{
|
||||||
|
this.anchor.applyForce(vnorm(psz[i][0]),this.anchor.absolNormal(vmultf(psz[i][3],-psz[i][1][1]/psz.length*cnst.rebound/cnst.inertia.mov)))
|
||||||
|
this.anchor.applyForce(vnorm(psz[i][0]),this.anchor.absolNormal(vmultf(z,1/psz.length*cnst.grip/cnst.inertia.mov)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(psz.length==0){
|
||||||
|
x=getOrient(this.anchor.p)
|
||||||
|
if(x[1]>0){
|
||||||
|
this.anchor.applyForce([0,0,0],this.anchor.absolNormal(vmultf([0,-x[1],0],cnst.rebound/cnst.inertia.mov)))
|
||||||
|
this.anchor.applyForce([0,0,0],this.anchor.absolNormal(vmultf(this.anchor.v,cnst.grip/cnst.inertia.mov)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return collides
|
||||||
|
}
|
||||||
|
update(dt=1){
|
||||||
|
this.anchor.update(dt)
|
||||||
|
}
|
||||||
|
applyForce(p,d){
|
||||||
|
this.anchor.applyForce(p,d)
|
||||||
|
}
|
||||||
|
applyWorldForce(p,d){
|
||||||
|
this.anchor.applyWorldForce(p,d)
|
||||||
|
}
|
||||||
|
toGrid(p){
|
||||||
|
return this.anchor.toGrid(p)
|
||||||
|
}
|
||||||
|
fromGrid(p){
|
||||||
|
return this.anchor.fromGrid(p)
|
||||||
|
}
|
||||||
|
absolNormal(p){
|
||||||
|
return this.anchor.absolNormal(p)
|
||||||
|
}
|
||||||
|
gridNormal(p){
|
||||||
|
return this.anchor.gridNormal(p)
|
||||||
|
}
|
||||||
|
pr_toGrid(p){
|
||||||
|
return this.anchor.pr_toGrid(p)
|
||||||
|
}
|
||||||
|
pr_fromGrid(p){
|
||||||
|
return this.anchor.pr_fromGrid(p)
|
||||||
|
}
|
||||||
|
pr_absolNormal(p){
|
||||||
|
return this.anchor.pr_absolNormal(p)
|
||||||
|
}
|
||||||
|
pr_gridNormal(p){
|
||||||
|
return this.anchor.pr_gridNormal(p)
|
||||||
|
}
|
||||||
|
}
|
77
utils.js
Normal file
77
utils.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
const cnst={
|
||||||
|
inertia:{
|
||||||
|
rot:1/1000,
|
||||||
|
mov:1/1000
|
||||||
|
},
|
||||||
|
drag:{
|
||||||
|
rot:1,
|
||||||
|
mov:1
|
||||||
|
},
|
||||||
|
grip:0.7,
|
||||||
|
rebound:0.7,
|
||||||
|
slide:0.7
|
||||||
|
}
|
||||||
|
vdot=(a,b)=>a.map((x,i)=>a[i]*b[i]).reduce((m,n)=>m+n)
|
||||||
|
vcross=(a,b)=>[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]
|
||||||
|
vnorm=a=>{let b=Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);if(b==0)return [0,0,0];return [a[0]/b,a[1]/b,a[2]/b]}
|
||||||
|
vadd=(a,b)=>[a[0]+b[0],a[1]+b[1],a[2]+b[2]]
|
||||||
|
vmult=(a,b)=>[a[0]*b[0],a[1]*b[1],a[2]*b[2]]
|
||||||
|
vmultf=(a,b)=>[a[0]*b,a[1]*b,a[2]*b]
|
||||||
|
vmag=a=>Math.sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2])
|
||||||
|
vsnap=(a,b)=>vadd(a,vmultf(b,-vdot(b,a)))
|
||||||
|
vtransform=(a,p,v)=>{
|
||||||
|
let x=[...p],b=[...a,vcross(...a)]
|
||||||
|
for(let z=0;z<3;z++){for(let i=0;i<3;i++){x[i]+=b[z][i]*v[z]}}
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
vdetransform=(a,p,v)=>{
|
||||||
|
let x=[v[0]-p[0],v[1]-p[1],v[2]-p[2]]
|
||||||
|
return [vdot(x,a[0]),vdot(x,a[1]),vdot(x,vcross(...a))]
|
||||||
|
}
|
||||||
|
pointAt=(p,c)=>{
|
||||||
|
rnd.rotateY(-Math.atan2(p[2]-c[2],p[0]-c[0]))
|
||||||
|
rnd.rotateZ(Math.atan2(p[1]-c[1],Math.sqrt((p[0]-c[0])*(p[0]-c[0])+(p[2]-c[2])*(p[2]-c[2]))))
|
||||||
|
}
|
||||||
|
drawScreenAt=(p,c)=>{
|
||||||
|
rnd.translate(...p)
|
||||||
|
pointAt(p,c)
|
||||||
|
}
|
||||||
|
build_pointAt=(p,c)=>{
|
||||||
|
build_rnd.rotateY(-Math.atan2(p[2]-c[2],p[0]-c[0]))
|
||||||
|
build_rnd.rotateZ(Math.atan2(p[1]-c[1],Math.sqrt((p[0]-c[0])*(p[0]-c[0])+(p[2]-c[2])*(p[2]-c[2]))))
|
||||||
|
}
|
||||||
|
build_drawScreenAt=(p,c)=>{
|
||||||
|
build_rnd.translate(...p)
|
||||||
|
build_pointAt(p,c)
|
||||||
|
}
|
||||||
|
let currUID=0
|
||||||
|
newUID=_=>{
|
||||||
|
currUID++
|
||||||
|
return 'UID_'+currUID.toString()
|
||||||
|
}
|
||||||
|
keyToCode=(dir,n)=>{
|
||||||
|
let mapTable=(`RIGHT 39_LEFT 37_DOWN 40_UP 38_SHIFT 16_SPACE 32_0 48_1 49_2 50_3 51_4 52_5 53_6 54_7 55_8 56_9 57_a 65_b 66_c 67_d 68_e 69_f 70_g 71_h 72_i 73_j 74_k 75_l 76_m 77_n 78_o 79_p 80_q 81_r 82_s 83_t 84_u 85_v 86_w 87_x 88_y 89_z 90`).split('_')
|
||||||
|
if(dir=='key'){for(let i=0;i<mapTable.length;i++){if(mapTable[i].endsWith(n.toString()))return mapTable[i].split(' ')[0]}}
|
||||||
|
else if(dir=='code'){for(let i=0;i<mapTable.length;i++){if(mapTable[i].startsWith(n))return parseInt(mapTable[i].slice(mapTable[i].length-2,mapTable[i].length))}}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
mlookAt=(p2,a2)=>{
|
||||||
|
let a=[],p=[...p2]
|
||||||
|
a.push([...a2[0]],[...a2[1]])
|
||||||
|
a.push(vcross(...a))
|
||||||
|
a[0]=vnorm(a[0])
|
||||||
|
a[1]=vnorm(a[1])
|
||||||
|
return [...a[0],0,...a[1],0,...a[2],0,...p,1]
|
||||||
|
}
|
||||||
|
line3d=(r,a,b,w=0.03)=>{
|
||||||
|
r.push()
|
||||||
|
let x=[vnorm(vadd(a,vmultf(b,-1)))],c=vmultf(vadd(a,b),1/2)
|
||||||
|
if(x[0][0]>0.9)x.push([0,1,0])
|
||||||
|
else x.push([1,0,0])
|
||||||
|
x[1]=vnorm(vcross(...x))
|
||||||
|
x.push(vnorm(vcross(...x)))
|
||||||
|
r.applyMatrix([...x[0],0,...x[1],0,...x[2],0,...c,1])
|
||||||
|
r.box(vmag(vadd(a,vmultf(b,-1))),w,w)
|
||||||
|
r.pop()
|
||||||
|
}
|
||||||
|
sqrx=a=>a*a
|
Loading…
Reference in New Issue
Block a user