mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 23:58:20 +00:00
Change the llRotBetween algorithm.
The former ones don't match LSL's behaviour, in particular llRotBetween(<1,0,0>,<-1,0,0>) should return <0,0,1,0> but it didn't. Fix by using an algorithm that is closer to the one used by the sim.
This commit is contained in:
parent
48e1035ac3
commit
37a4c86516
1 changed files with 31 additions and 44 deletions
|
@ -1650,50 +1650,37 @@ def llRotBetween(v1, v2):
|
||||||
assert isvector(v1)
|
assert isvector(v1)
|
||||||
assert isvector(v2)
|
assert isvector(v2)
|
||||||
|
|
||||||
aabb = math.sqrt(mul(v1, v1, f32=False) * mul(v2, v2, f32=False)) # product of the lengths of the arguments
|
# Loosely based on the "Bad" reference implementation and
|
||||||
if aabb == 0.:
|
# on SL source code (pre Moon Metty's changes).
|
||||||
return ZERO_ROTATION # the arguments are too small, return zero rotation
|
# See <https://bitbucket.org/lindenlab/viewer-release/src/015080d8/indra/llmath/llquaternion.cpp#llquaternion.cpp-425>
|
||||||
ab = mul(v1, v2, f32=False) / aabb # normalized dotproduct of the arguments (cosine)
|
v1 = llVecNorm(v1)
|
||||||
c = Vector(((v1[1] * v2[2] - v1[2] * v2[1]) / aabb, # normalized crossproduct of the arguments
|
v2 = llVecNorm(v2)
|
||||||
(v1[2] * v2[0] - v1[0] * v2[2]) / aabb,
|
dot = mul(v1, v2)
|
||||||
(v1[0] * v2[1] - v1[1] * v2[0]) / aabb))
|
axis = mod(v1, v2)
|
||||||
cc = mul(c, c, f32=False) # squared length of the normalized crossproduct (sine)
|
threshold = float.fromhex('0x1.fffffcp-1')
|
||||||
if cc != 0.: # test if the arguments are (anti)parallel
|
if -threshold <= dot <= threshold:
|
||||||
if ab > -0.7071067811865476: # test if the angle is smaller than 3/4 PI
|
# non-aligned - their cross product is a good axis
|
||||||
s = 1. + ab # use the cosine to adjust the s-element
|
m = math.sqrt(mul(axis, axis) + (dot + 1.) * (dot + 1.))
|
||||||
else:
|
return Quaternion(F32((axis[0] / m, axis[1] / m, axis[2] / m,
|
||||||
s = cc / (1. + math.sqrt(1. - cc)); # use the sine to adjust the s-element
|
(dot + 1.) / m)))
|
||||||
m = math.sqrt(cc + s * s) # the magnitude of the quaternion
|
# about aligned - two cases to deal with
|
||||||
return Quaternion(F32((c[0] / m, c[1] / m, c[2] / m, s / m))) # return the normalized quaternion
|
if dot > 0.:
|
||||||
if ab > 0.: # test if the angle is smaller than PI/2
|
# same signs
|
||||||
return ZERO_ROTATION # the arguments are parallel
|
return Quaternion((0., 0., 0., 1.))
|
||||||
m = math.sqrt(v1[0] * v1[0] + v1[1] * v1[1]) # the length of one argument projected on the XY-plane
|
# opposite signs - find one vector in the plane perpendicular to
|
||||||
if m != 0.:
|
# either vector, to use as axis. We do this by choosing an arbitrary
|
||||||
return Quaternion(F32((v1[1] / m, -v1[0] / m, 0., 0.))) # return rotation with the axis in the XY-plane
|
# vector (<1,0,0> in our case), and calculating the cross product with it,
|
||||||
return Quaternion((0., 0., 1., 0.)) # rotate around the Z-axis
|
# which will be perpendicular to both. But matching the SL results requires
|
||||||
|
# another cross product of the input with the result, so we do that.
|
||||||
# Algorithm by Moon Metty (for reference)
|
ortho = mod(mod(v1, Vector((1., 0., 0.))), v1)
|
||||||
# dot = mul(v1, v2, f32=False)
|
ortho = Vector((0. if f == 0. else f for f in ortho)) # remove minus zero
|
||||||
# cross = mod(v1, v2, f32=False)
|
m = mul(ortho, ortho)
|
||||||
# csq = mul(cross, cross, f32=False)
|
if m < float.fromhex('0x1.b7cdfep-34'):
|
||||||
#
|
# The input vectors were aligned with <1,0,0>, so this was not a
|
||||||
# ddc2 = dot*dot + csq
|
# good choice. Return 180 deg. rotation over Z instead.
|
||||||
#
|
return Quaternion((0., 0., 1., 0.))
|
||||||
# DenormalStart = float.fromhex('0x1p-149')
|
m = math.sqrt(m)
|
||||||
# if ddc2 >= DenormalStart:
|
return Quaternion(F32((ortho[0] / m, ortho[1] / m, ortho[2] / m, 0.)))
|
||||||
# if csq >= DenormalStart:
|
|
||||||
# s = math.sqrt(ddc2) + dot;
|
|
||||||
# m = math.sqrt(csq + s*s);
|
|
||||||
# return Quaternion(F32((cross[0]/m, cross[1]/m, cross[2]/m, s/m)))
|
|
||||||
#
|
|
||||||
# # Deal with degenerate cases here
|
|
||||||
# if dot > 0:
|
|
||||||
# return ZERO_ROTATION
|
|
||||||
# m = math.sqrt(v1[0]*v1[0] + v1[1]*v1[1])
|
|
||||||
# if m >= DenormalStart:
|
|
||||||
# return Quaternion(F32((v1[1]/m, -v1[0]/m, 0., 0.)))
|
|
||||||
# return Quaternion((1., 0., 0., 0.))
|
|
||||||
# return ZERO_ROTATION
|
|
||||||
|
|
||||||
def llRound(f):
|
def llRound(f):
|
||||||
assert isfloat(f)
|
assert isfloat(f)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue