treeform/vmath

Additionnal functions and a few remarks

flintforge opened this issue · 1 comments

These are a few personal notes I wrote when I first tried vmath.
I was hoping to get some time to code some nim, unfortunately I don't have that time.
and didn't keep a very closed eye on the project, so it is perfectly possible these remarks fall flat.
(I saw something on the swizzle ops passing by), still, hoping they will be helpful :

#+Date:[2022-06-18 15:25:23]

# additional functions to suiggest in vmath

import vmath

type
  GV2 = Vec2 | array[2,float32] | tuple[x,y:float32]  # a generic vector of size 2
  GV3 = Vec3 | array[3,float32] | tuple[x,y,z:float32]  # a generic vector of size 3
  GV4 = Vec4 | array[4,float32] | tuple[x,y,z,w:float32]  # a generic vector of size 4

  GVec234[T] = GVec2[T] | GVec3[T] | GVec4[T]

  Vec4f* = Vec4 
  Mat4f* = Mat4

template `=`*[T](a: var GVec234[T], b:GV2) = (a[0], a[1])            = (b[0], b[1])
template `=`*[T](a: var GVec234[T], b:GV3) = (a[0], a[1], a[2])      = (b[0], b[1], b[3])
template `=`*[T](a: var GVec234[T], b:GV4) = (a[0], a[1], a[2],a[3]) = (b[0], b[1], b[2], b[3])

template `xy=`*[T](a: var GVec234[T], b: GV2) = (a[0], a[1]) = (b[0], b[1])

# add or mul of a vec with a smaller one is accepted
proc `*=`*(a: var Vec3, b:GV2) = a.x *= b[0]; a.y *= b[1]
proc `+=`*(a: var Vec3, b:GV2) = a.x += b[0]; a.y += b[1]

template `=`*(a: var Vec3, b:Vec2) = (a[0], a[1], a[2]) = (b[0], b[1], 0.0)

# allow int parameter given to vec2f ctor
proc vec2*(x,y:int):Vec2 = return vec2(float(x), float(y))

when isMainModule:
  let a:int=0
  assert vec2(a,1) is GVec2[float32]

# vec2f accept a vec3 as ctor
proc vec2*(v:Vec3):Vec2 = return vec2(v.xy)

when isMainModule:
  assert type(vec2(vec3())) is GVec2[float32]


# the identity. Often requested, must be passed by copy  
const IDT*:Mat4f = gmat4(1.0f, 0.0f, 0.0f, 0.0f,
                         0.0f, 1.0f, 0.0f, 0.0f,
                         0.0f, 0.0f, 1.0f, 0.0f,
                         0.0f, 0.0f, 0.0f, 1.0f  )
# If passed bycopy is the following still necessary ?
# proc Identity(m:var Mat4f)=  m = IDT

const DEGREE_TO_RADIAN* = 0.01745329251994329576  


proc mat4[T](Q:Quat):GMat4[T]=
  # create a matrix from a quaterniop located at origin
  let (w, x, y, z) = Q
    
  result = [[1.f-2.f*(y*y+z*z), 2.f*(x*y+w*z),     2.f*(x*z-w*y),     0.f],
            [2.f*(x*y-w*z),     1.f-2.f*(x*x+z*z), 2.f*(y*z+w*x),     0.f],
            [2.f*(x*z+w*y),     2.f*(y*z-w*x),     1.f-2.f*(x*x+y*y), 0.f],
            [0.f,               0.f,               0.f,               1.f]]

Aren't those naming dubious :
translate, rotate, scale ?

If they aren't performing operations
but returning the corresponing
matrices in canonical base,
then they should be named
translation, rotation, and scaling

while translate would modify the given matrix as parameter

# aren't we missing quaternion templates ?
# proc `*`(p,q:Quat):Quat=
#     let
#       w1 = p[0] # w
#       v1 = vec3(p[1],p[2],p[3])
#       w2 = q[0]
#       v2 = vec3(q[1],q[2], q[3])
#       (x,y,z) = (w1 * v2 + w2 * v1 + cross(v1, v2)).xyz
#     result = quat(w1*w2 - dot(v1, v2), x,y,z )


from math import sqrt
    
proc arcball*(x, y : float32):Quat=
  # TODO 
  let h2 = x*x + y*y
  var v:Vec3
  
  if h2 > 1.0f:
    let h = sqrt(h2)
    v = vec3(x/h, y/h, 0f)
  else:
    v = vec3(x, y, sqrt(1.0f-h2))
    
  return quat(v.x, v.y, v.z, 0.0f)


proc translate*[T](m: var GMat4[T], v:GVec3[T]): GMat4[T] =
  ## Create translation matrix.
  m[0][3] += v[0]
  m[1][3] += v[1]
  m[2][3] += v[2]
  m

I really wish I could do more than that.
Keep up the good work !

Sorry, I am not into the many suggests that are here. This vector stuff hard enough and I just see me making bugs where I pass a vec2 into a vec3 and it just magically works. Some amount of magic is nice, while too much can lead to all kind of confusion its totally personal taste.

Sorry not a fan of array or tuples acting like vectors, I feel like if you have a type it should stay that type. Nim is all about type safety I don't want to throw it a way.

You are probably right about the names: translate, rotate, scale. I don't think they are that bad that it all needs chaining and breaking backward compatibility.

I actually like the idea of "allow int parameter given to vec2f ctor" and maybe I'll do some thing like this. I do feel like vec3 is a typed thing and should except integers etc... up-casting to a higher precession.

When you create a mat4() its already an identity mat, why do you want another one?

And quat to mat4 already exists. It just takes a vec4 which is what GLSL does.

I probably need to add other quat functions though.