1 /** 2 3D Transformation. 3x4 matrix. 3 4 Copyright: 5 Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. 6 Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) 7 Copyright (c) 2017-2018 Godot-D contributors 8 9 License: $(LINK2 https://opensource.org/licenses/MIT, MIT License) 10 11 12 */ 13 module godot.core.transform; 14 15 import godot.core.defs; 16 import godot.core.vector3; 17 import godot.core.quat; 18 import godot.core.basis; 19 import godot.core.aabb; 20 import godot.core.plane; 21 22 /** 23 Represents one or many transformations in 3D space such as translation, rotation, or scaling. It is similar to a 3x4 matrix. 24 */ 25 struct Transform 26 { 27 @nogc nothrow: 28 29 Basis basis; /// 30 Vector3 origin; /// 31 32 this(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, 33 real_t zx, real_t zy, real_t zz,real_t tx, real_t ty, real_t tz) { 34 set(xx, xy, xz, yx, yy, yz, zx, zy, zz,tx, ty, tz); 35 } 36 37 this(in Basis basis, in Vector3 origin) { this.basis = basis; this.origin = origin; } 38 39 40 Transform inverseXform(in Transform t) const 41 { 42 Vector3 v = t.origin - origin; 43 return Transform(basis.transposeXform(t.basis), 44 basis.xform(v)); 45 } 46 47 void set(real_t xx, real_t xy, real_t xz, real_t yx, real_t yy, real_t yz, real_t zx, real_t zy, real_t zz,real_t tx, real_t ty, real_t tz) 48 { 49 basis.elements[0][0]=xx; 50 basis.elements[0][1]=xy; 51 basis.elements[0][2]=xz; 52 basis.elements[1][0]=yx; 53 basis.elements[1][1]=yy; 54 basis.elements[1][2]=yz; 55 basis.elements[2][0]=zx; 56 basis.elements[2][1]=zy; 57 basis.elements[2][2]=zz; 58 origin.x=tx; 59 origin.y=ty; 60 origin.z=tz; 61 } 62 63 64 65 Vector3 xform(in Vector3 p_vector) const 66 { 67 return Vector3( 68 basis[0].dot(p_vector)+origin.x, 69 basis[1].dot(p_vector)+origin.y, 70 basis[2].dot(p_vector)+origin.z 71 ); 72 } 73 Vector3 xformInv(in Vector3 p_vector) const 74 { 75 Vector3 v = p_vector - origin; 76 77 return Vector3( 78 (basis.elements[0][0]*v.x ) + ( basis.elements[1][0]*v.y ) + ( basis.elements[2][0]*v.z ), 79 (basis.elements[0][1]*v.x ) + ( basis.elements[1][1]*v.y ) + ( basis.elements[2][1]*v.z ), 80 (basis.elements[0][2]*v.x ) + ( basis.elements[1][2]*v.y ) + ( basis.elements[2][2]*v.z ) 81 ); 82 } 83 84 Plane xform(in Plane p_plane) const 85 { 86 Vector3 point=p_plane.normal*p_plane.d; 87 Vector3 point_dir=point+p_plane.normal; 88 point=xform(point); 89 point_dir=xform(point_dir); 90 91 Vector3 normal=point_dir-point; 92 normal.normalize(); 93 real_t d=normal.dot(point); 94 95 return Plane(normal,d); 96 97 } 98 Plane xformInv(in Plane p_plane) const 99 { 100 Vector3 point=p_plane.normal*p_plane.d; 101 Vector3 point_dir=point+p_plane.normal; 102 point = xformInv(point); 103 point_dir = xformInv(point_dir); 104 105 Vector3 normal=point_dir-point; 106 normal.normalize(); 107 real_t d=normal.dot(point); 108 109 return Plane(normal,d); 110 111 } 112 113 AABB xform(in AABB p_aabb) const 114 { 115 /* define vertices */ 116 Vector3 x=basis.getAxis(0)*p_aabb.size.x; 117 Vector3 y=basis.getAxis(1)*p_aabb.size.y; 118 Vector3 z=basis.getAxis(2)*p_aabb.size.z; 119 Vector3 pos = xform( p_aabb.pos ); 120 //could be even further optimized 121 AABB new_aabb; 122 new_aabb.pos=pos; 123 new_aabb.expandTo( pos+x ); 124 new_aabb.expandTo( pos+y ); 125 new_aabb.expandTo( pos+z ); 126 new_aabb.expandTo( pos+x+y ); 127 new_aabb.expandTo( pos+x+z ); 128 new_aabb.expandTo( pos+y+z ); 129 new_aabb.expandTo( pos+x+y+z ); 130 return new_aabb; 131 } 132 AABB xformInv(in AABB p_aabb) const 133 { 134 /* define vertices */ 135 Vector3[8] vertices=[ 136 Vector3(p_aabb.pos.x+p_aabb.size.x, p_aabb.pos.y+p_aabb.size.y, p_aabb.pos.z+p_aabb.size.z), 137 Vector3(p_aabb.pos.x+p_aabb.size.x, p_aabb.pos.y+p_aabb.size.y, p_aabb.pos.z), 138 Vector3(p_aabb.pos.x+p_aabb.size.x, p_aabb.pos.y, p_aabb.pos.z+p_aabb.size.z), 139 Vector3(p_aabb.pos.x+p_aabb.size.x, p_aabb.pos.y, p_aabb.pos.z), 140 Vector3(p_aabb.pos.x, p_aabb.pos.y+p_aabb.size.y, p_aabb.pos.z+p_aabb.size.z), 141 Vector3(p_aabb.pos.x, p_aabb.pos.y+p_aabb.size.y, p_aabb.pos.z), 142 Vector3(p_aabb.pos.x, p_aabb.pos.y, p_aabb.pos.z+p_aabb.size.z), 143 Vector3(p_aabb.pos.x, p_aabb.pos.y, p_aabb.pos.z) 144 ]; 145 AABB ret; 146 ret.pos=xformInv(vertices[0]); 147 for(int i=1;i<8;i++) 148 { 149 ret.expandTo( xformInv(vertices[i]) ); 150 } 151 return ret; 152 153 } 154 155 void affineInvert() 156 { 157 basis.invert(); 158 origin = basis.xform(-origin); 159 } 160 161 Transform affineInverse() const 162 { 163 Transform ret=this; 164 ret.affineInvert(); 165 return ret; 166 167 } 168 169 170 void invert() 171 { 172 basis.transpose(); 173 origin = basis.xform(-origin); 174 } 175 176 Transform inverse() const 177 { 178 // FIXME: this function assumes the basis is a rotation matrix, with no scaling. 179 // affine_inverse can handle matrices with scaling, so GDScript should eventually use that. 180 Transform ret=this; 181 ret.invert(); 182 return ret; 183 } 184 185 186 void rotate(in Vector3 p_axis,real_t p_phi) 187 { 188 this = rotated(p_axis, p_phi); 189 } 190 191 Transform rotated(in Vector3 p_axis,real_t p_phi) const 192 { 193 return Transform(Basis( p_axis, p_phi ), Vector3()) * (this); 194 } 195 196 void rotateBasis(in Vector3 p_axis,real_t p_phi) 197 { 198 basis.rotate(p_axis,p_phi); 199 } 200 201 Transform lookingAt( in Vector3 p_target, in Vector3 p_up ) const 202 { 203 Transform t = this; 204 t.setLookAt(origin,p_target,p_up); 205 return t; 206 } 207 208 void setLookAt( in Vector3 p_eye, in Vector3 p_target, in Vector3 p_up ) 209 { 210 // Reference: MESA source code 211 Vector3 v_x, v_y, v_z; 212 /* Make rotation matrix */ 213 214 /* Z vector */ 215 v_z = p_eye - p_target; 216 217 v_z.normalize(); 218 219 v_y = p_up; 220 221 222 v_x=v_y.cross(v_z); 223 224 /* Recompute Y = Z cross X */ 225 v_y=v_z.cross(v_x); 226 227 v_x.normalize(); 228 v_y.normalize(); 229 230 basis.setAxis(0,v_x); 231 basis.setAxis(1,v_y); 232 basis.setAxis(2,v_z); 233 origin=p_eye; 234 } 235 236 Transform interpolateWith(in Transform p_transform, real_t p_c) const 237 { 238 /* not sure if very "efficient" but good enough? */ 239 Vector3 src_scale = basis.getScale(); 240 Quat src_rot = basis.quat; 241 Vector3 src_loc = origin; 242 243 Vector3 dst_scale = p_transform.basis.getScale(); 244 Quat dst_rot = p_transform.basis.quat; 245 Vector3 dst_loc = p_transform.origin; 246 247 Transform dst; 248 dst.basis = Basis(src_rot.slerp(dst_rot,p_c)); 249 dst.basis.scale(src_scale.linearInterpolate(dst_scale,p_c)); 250 dst.origin=src_loc.linearInterpolate(dst_loc,p_c); 251 252 return dst; 253 } 254 255 void scale(in Vector3 p_scale) 256 { 257 basis.scale(p_scale); 258 origin*=p_scale; 259 } 260 261 Transform scaled(in Vector3 p_scale) const 262 { 263 Transform t = this; 264 t.scale(p_scale); 265 return t; 266 } 267 268 void scaleBasis(in Vector3 p_scale) 269 { 270 basis.scale(p_scale); 271 } 272 273 void translate(real_t p_tx, real_t p_ty, real_t p_tz) 274 { 275 translate( Vector3(p_tx,p_ty,p_tz) ); 276 } 277 void translate(in Vector3 p_translation) 278 { 279 for( int i = 0; i < 3; i++ ) 280 { 281 origin[i] += basis[i].dot(p_translation); 282 } 283 } 284 285 Transform translated(in Vector3 p_translation) const 286 { 287 Transform t=this; 288 t.translate(p_translation); 289 return t; 290 } 291 292 void orthonormalize() 293 { 294 basis.orthonormalize(); 295 } 296 297 Transform orthonormalized() const 298 { 299 Transform _copy = this; 300 _copy.orthonormalize(); 301 return _copy; 302 } 303 304 void opOpAssign(string op : "*")(in Transform p_transform) 305 { 306 origin=xform(p_transform.origin); 307 basis*=p_transform.basis; 308 } 309 310 Transform opBinary(string op : "*")(in Transform p_transform) const 311 { 312 Transform t=this; 313 t*=p_transform; 314 return t; 315 } 316 } 317