rmath3d 1.2.3 → 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e8d8b8a38ad55ec12170a103c39607b841855790e279ae4c003e394900f3391
4
- data.tar.gz: 8d74d4f0917015c74accd26293cb4036d9befa0bbe0d562893a324881a1b005f
3
+ metadata.gz: 5dc23938dfb4e458f92a723ca9340b88c8cd9745b2b332c81abf8aef4981e46c
4
+ data.tar.gz: b23cdf387d8def83bd5310a6666ca83c57b898ee740dee861c804799935d1407
5
5
  SHA512:
6
- metadata.gz: c6ea5c48fba49380581ae07cef869767a73ab1e3f2d8bda7481b352241bf3bd82197a188d529bf230ec786dedb35bb9a49145d430b54f298729598f7b3ba6702
7
- data.tar.gz: b02fb89b9fbb8fe9bc1dd3456ef99507d4d1d1e659b3a2884243ea5342100bca7bee219550e6764e15e43c352cf4561bea5615db56827c2d9365596e9e098802
6
+ metadata.gz: 78dbf7e6ac5f2b5be92247a2ac26100b47df994cd646f25c638e8fc7486f2dbc195a452b88cc28035cc611d87de4778f93ab64a9f94205ff2405005ada383168
7
+ data.tar.gz: 401b5ab4bb610ea41689276cc96d05bb0c1f4a5b90d579d51781fffb08bde75d8da7140b88a2b8bac8ea223ed64a3cef2f7e1a5d6c667761a096dd6552721eab
data/ChangeLog CHANGED
@@ -1,3 +1,7 @@
1
+ 2020-07-23 vaiorabbit <http://twitter.com/vaiorabbit>
2
+
3
+ * rmath3d.c, rmath3d_plain.rb (RMtx4): Added lookAtLH, perspectiveLH, etc.
4
+
1
5
  2020-06-21 vaiorabbit <http://twitter.com/vaiorabbit>
2
6
 
3
7
  * rmath3d.c, rmath3d_plain.rb (RMtx4): Added argument 'ndc_homogeneous' for projection matrix APIs.
File without changes
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  rmath3d is a math module for 3D game programming and computer graphics.
6
6
 
7
- * Last Update: Jun 21, 2020
7
+ * Last Update: Jul 23, 2020
8
8
  * Since: Jul 20, 2008
9
9
 
10
10
  * rmath3d (C Extension Library Implementation) [![Gem Version](https://badge.fury.io/rb/rmath3d.svg)](https://badge.fury.io/rb/rmath3d) [![Gem](https://img.shields.io/gem/dt/rmath3d.svg)](https://rubygems.org/gems/rmath3d)
@@ -33,14 +33,8 @@ rmath3d is a math module for 3D game programming and computer graphics.
33
33
  Notice: This library provides native extension. You must setup develop environment (or DevKit) before installation.
34
34
 
35
35
  * Ruby
36
- * ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.4.0]
37
- * ruby 2.0.0p247 (2013-06-27) [i386-mingw32] With Development Kit installed.
38
- * I used: DevKit-mingw64-32-4.7.2-20130224-1151-sfx.exe
39
- * Unpack the archive -> "> ruby dk.rb init" -> edit config.yml (just add your ruby foldier) -> "> ruby dk.rb install"
40
- * Ref.: http://blog.mattwynne.net/2010/10/12/installing-ruby-gems-with-native-extensions-on-windows/
41
- * ruby 2.2.2p95 (2015-04-13 revision 50295) [x86_64-darwin14]
42
- * Ruby 1.9.3 and prior versions are no longer supported.
43
- * Ref.: https://www.ruby-lang.org/en/news/2015/02/23/support-for-ruby-1-9-3-has-ended/
36
+ * ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x64-mingw32]
37
+ * Ruby 2.3 and prior versions are no longer supported.
44
38
 
45
39
  ## Building rmath3d.{so|bundle} ##
46
40
 
File without changes
@@ -436,6 +436,104 @@ RMtx4Scale( RMtx4* out, const RMtx4* m, rmReal f )
436
436
  GET_ELEMENT( m, row, col ) * f );
437
437
  }
438
438
 
439
+ /* http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/lookat.html
440
+ http://msdn.microsoft.com/en-us/library/bb205343.aspx
441
+ */
442
+ void
443
+ RMtx4LookAtLH( RMtx4* out, const RVec3* eye, const RVec3* at, const RVec3* up )
444
+ {
445
+ #define AX(i) RVec3GetElement( &axis_x, i )
446
+ #define AY(i) RVec3GetElement( &axis_y, i )
447
+ #define AZ(i) RVec3GetElement( &axis_z, i )
448
+
449
+ RVec3 axis_x, axis_y, axis_z;
450
+
451
+ RMtx4Identity( out );
452
+
453
+ RVec3Sub( &axis_z, at, eye );
454
+ RVec3Normalize( &axis_z, &axis_z );
455
+
456
+ RVec3Cross( &axis_x, up, &axis_z );
457
+ RVec3Normalize( &axis_x, &axis_x );
458
+
459
+ RVec3Cross( &axis_y, &axis_z, &axis_x );
460
+
461
+ SET_ELEMENT( out, 0, 0, AX(0) );
462
+ SET_ELEMENT( out, 0, 1, AX(1) );
463
+ SET_ELEMENT( out, 0, 2, AX(2) );
464
+ SET_ELEMENT( out, 0, 3, -RVec3Dot(&axis_x, eye) );
465
+
466
+ SET_ELEMENT( out, 1, 0, AY(0) );
467
+ SET_ELEMENT( out, 1, 1, AY(1) );
468
+ SET_ELEMENT( out, 1, 2, AY(2) );
469
+ SET_ELEMENT( out, 1, 3, -RVec3Dot(&axis_y, eye) );
470
+
471
+ SET_ELEMENT( out, 2, 0, AZ(0) );
472
+ SET_ELEMENT( out, 2, 1, AZ(1) );
473
+ SET_ELEMENT( out, 2, 2, AZ(2) );
474
+ SET_ELEMENT( out, 2, 3, -RVec3Dot(&axis_z, eye) );
475
+
476
+ #undef AX
477
+ #undef AY
478
+ #undef AZ
479
+ }
480
+
481
+ void
482
+ RMtx4PerspectiveLH( RMtx4* out, rmReal width, rmReal height, rmReal znear, rmReal zfar, bool ndc_homogeneous )
483
+ {
484
+ RMtx4PerspectiveOffCenterLH( out, -width/2.0f, width/2.0f, -height/2.0f, height/2.0f, znear, zfar, ndc_homogeneous );
485
+ }
486
+
487
+ void
488
+ RMtx4PerspectiveFovLH( RMtx4* out, rmReal fovy_radian, rmReal aspect, rmReal znear, rmReal zfar, bool ndc_homogeneous )
489
+ {
490
+ rmReal top = rmTan(fovy_radian / 2.0f) * znear;
491
+ rmReal bottom = -top;
492
+ rmReal right = top * aspect;
493
+ rmReal left = -right;
494
+ RMtx4PerspectiveOffCenterLH(out, left, right, bottom, top, znear, zfar, ndc_homogeneous);
495
+ }
496
+
497
+ void
498
+ RMtx4PerspectiveOffCenterLH( RMtx4* out, rmReal left, rmReal right, rmReal bottom, rmReal top, rmReal znear, rmReal zfar, bool ndc_homogeneous )
499
+ {
500
+ rmReal A = (right+left) / (right-left);
501
+ rmReal B = (top+bottom) / (top-bottom);
502
+ rmReal C = ndc_homogeneous ? -(zfar+znear) / (zfar-znear) : -zfar / (zfar-znear);
503
+ rmReal D = ndc_homogeneous ? -(2*znear*zfar) / (zfar-znear) : -(znear*zfar) / (zfar-znear);
504
+
505
+ RMtx4Zero( out );
506
+ SET_ELEMENT( out, 0, 0, 2*znear/(right-left) );
507
+ SET_ELEMENT( out, 0, 2, -A );
508
+ SET_ELEMENT( out, 1, 1, 2*znear/(top-bottom) );
509
+ SET_ELEMENT( out, 1, 2, -B );
510
+ SET_ELEMENT( out, 2, 2, -C );
511
+ SET_ELEMENT( out, 2, 3, D );
512
+ SET_ELEMENT( out, 3, 2, 1.0f );
513
+ }
514
+
515
+ void
516
+ RMtx4OrthoLH( RMtx4* out, rmReal width, rmReal height, rmReal znear, rmReal zfar, bool ndc_homogeneous )
517
+ {
518
+ RMtx4OrthoOffCenterLH( out, -width/2.0f, width/2.0f, -height/2.0f, height/2.0f, znear, zfar, ndc_homogeneous );
519
+ }
520
+
521
+ void
522
+ RMtx4OrthoOffCenterLH( RMtx4* out, rmReal left, rmReal right, rmReal bottom, rmReal top, rmReal znear, rmReal zfar, bool ndc_homogeneous )
523
+ {
524
+ rmReal tx = -(right+left) / (right-left);
525
+ rmReal ty = -(top+bottom) / (top-bottom);
526
+ rmReal tz = ndc_homogeneous ? -(zfar+znear) / (zfar-znear) : -znear / (zfar-znear);
527
+
528
+ RMtx4Identity( out );
529
+ SET_ELEMENT( out, 0, 0, 2.0f/(right-left) );
530
+ SET_ELEMENT( out, 0, 3, tx );
531
+ SET_ELEMENT( out, 1, 1, 2.0f/(top-bottom) );
532
+ SET_ELEMENT( out, 1, 3, ty );
533
+ SET_ELEMENT( out, 2, 2, (ndc_homogeneous ? 2.0f : 1.0f)/(zfar-znear) );
534
+ SET_ELEMENT( out, 2, 3, tz );
535
+ }
536
+
439
537
  /* http://www.opengl.org/documentation/specs/man_pages/hardcopy/GL/html/glu/lookat.html
440
538
  http://msdn.microsoft.com/en-us/library/bb205343.aspx
441
539
  */
@@ -484,25 +582,16 @@ RMtx4PerspectiveRH( RMtx4* out, rmReal width, rmReal height, rmReal znear, rmRea
484
582
  RMtx4PerspectiveOffCenterRH( out, -width/2.0f, width/2.0f, -height/2.0f, height/2.0f, znear, zfar, ndc_homogeneous );
485
583
  }
486
584
 
487
- /* https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
488
- Game Programming in C++ (2018) https://www.oreilly.com/library/view/game-programming-in/9780134598185/
585
+ /* https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/opengl-perspective-projection-matrix
489
586
  */
490
587
  void
491
588
  RMtx4PerspectiveFovRH( RMtx4* out, rmReal fovy_radian, rmReal aspect, rmReal znear, rmReal zfar, bool ndc_homogeneous )
492
589
  {
493
- rmReal f = rmTan( fovy_radian / 2.0f );
494
- f = 1.0f / f;
495
-
496
- rmReal C = ndc_homogeneous ? -(zfar+znear) / (zfar-znear) : zfar / -(zfar-znear);
497
- rmReal D = ndc_homogeneous ? -(2*znear*zfar) / (zfar-znear) : -(znear*zfar) / (zfar-znear);
498
-
499
- RMtx4Identity( out );
500
- SET_ELEMENT( out, 0, 0, f / aspect );
501
- SET_ELEMENT( out, 1, 1, f );
502
- SET_ELEMENT( out, 2, 2, C );
503
- SET_ELEMENT( out, 2, 3, D );
504
- SET_ELEMENT( out, 3, 2, -1.0f );
505
- SET_ELEMENT( out, 3, 3, 0.0f );
590
+ rmReal top = rmTan(fovy_radian / 2.0f) * znear;
591
+ rmReal bottom = -top;
592
+ rmReal right = top * aspect;
593
+ rmReal left = -right;
594
+ RMtx4PerspectiveOffCenterRH(out, left, right, bottom, top, znear, zfar, ndc_homogeneous);
506
595
  }
507
596
 
508
597
  /* https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glFrustum.xml
@@ -71,6 +71,13 @@ void RMtx4Sub( RMtx4* out, const RMtx4* m1, const RMtx4* m2 );
71
71
  void RMtx4Mul( RMtx4* out, const RMtx4* m1, const RMtx4* m2 );
72
72
  void RMtx4Scale( RMtx4* out, const RMtx4* m, rmReal f );
73
73
 
74
+ void RMtx4LookAtLH( RMtx4* out, const struct RVec3* eye, const struct RVec3* at, const struct RVec3* up );
75
+ void RMtx4PerspectiveLH( RMtx4* out, rmReal width, rmReal height, rmReal znear, rmReal zfar, bool ndc_homogeneous );
76
+ void RMtx4PerspectiveFovLH( RMtx4* out, rmReal fovy_radian, rmReal aspect, rmReal znear, rmReal zfar, bool ndc_homogeneous );
77
+ void RMtx4PerspectiveOffCenterLH( RMtx4* out, rmReal left, rmReal right, rmReal bottom, rmReal top, rmReal znear, rmReal zfar, bool ndc_homogeneous );
78
+ void RMtx4OrthoLH( RMtx4* out, rmReal width, rmReal height, rmReal znear, rmReal zfar, bool ndc_homogeneous );
79
+ void RMtx4OrthoOffCenterLH( RMtx4* out, rmReal left, rmReal right, rmReal bottom, rmReal top, rmReal znear, rmReal zfar, bool ndc_homogeneous );
80
+
74
81
  void RMtx4LookAtRH( RMtx4* out, const struct RVec3* eye, const struct RVec3* at, const struct RVec3* up );
75
82
  void RMtx4PerspectiveRH( RMtx4* out, rmReal width, rmReal height, rmReal znear, rmReal zfar, bool ndc_homogeneous );
76
83
  void RMtx4PerspectiveFovRH( RMtx4* out, rmReal fovy_radian, rmReal aspect, rmReal znear, rmReal zfar, bool ndc_homogeneous );
File without changes
@@ -3221,6 +3221,224 @@ RMtx4_scaling( VALUE self, VALUE x, VALUE y, VALUE z )
3221
3221
  return self;
3222
3222
  }
3223
3223
 
3224
+ /*
3225
+ * call-seq: lookAtLH(eye,at,up) -> self
3226
+ *
3227
+ * Builds a viewing matrix for a left-handed coordinate system from:
3228
+ * * eye position (+eye+: RVec3)
3229
+ * * a point looking at (+at+: RVec3)
3230
+ * * up vector (+up+: RVec3)
3231
+ */
3232
+ static VALUE
3233
+ RMtx4_lookAtLH( VALUE self, VALUE e, VALUE a, VALUE u )
3234
+ {
3235
+ RMtx4* m = NULL;
3236
+ RVec3* eye = NULL;
3237
+ RVec3* at = NULL;
3238
+ RVec3* up = NULL;
3239
+
3240
+ TypedData_Get_Struct( self, RMtx4, &RMtx4_type, m );
3241
+ TypedData_Get_Struct( e, RVec3, &RVec3_type, eye );
3242
+ TypedData_Get_Struct( a, RVec3, &RVec3_type, at );
3243
+ TypedData_Get_Struct( u, RVec3, &RVec3_type, up );
3244
+ RMtx4LookAtLH( m, eye, at, up );
3245
+
3246
+ return self;
3247
+ }
3248
+
3249
+ /*
3250
+ * call-seq: perspectiveLH(width,height,znear,zfar,ndc_homogeneous) -> self
3251
+ *
3252
+ * Builds a perspective projection matrix for a right-handed coordinate system from:
3253
+ * * View volume width (+width+)
3254
+ * * View volume height (+height+)
3255
+ * * Near clip plane distance (+znear+)
3256
+ * * Far clip plane distance (+zfar+)
3257
+ * * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
3258
+ */
3259
+ static VALUE
3260
+ RMtx4_perspectiveLH( int argc, VALUE* argv, VALUE self )
3261
+ {
3262
+ VALUE w, h, zn, zf, ndch;
3263
+ RMtx4* m = NULL;
3264
+ rmReal width, height, znear, zfar;
3265
+ bool ndc_homogeneous;
3266
+
3267
+ if (argc < 4 || argc > 5)
3268
+ {
3269
+ rb_raise(rb_eArgError, "RMtx4_perspectiveLH : wrong # of arguments (%d)", argc );
3270
+ }
3271
+
3272
+ rb_scan_args(argc, argv, "41", &w, &h, &zn, &zf, &ndch);
3273
+
3274
+ TypedData_Get_Struct( self, RMtx4, &RMtx4_type, m );
3275
+ width = NUM2DBL(w);
3276
+ height = NUM2DBL(h);
3277
+ znear = NUM2DBL(zn);
3278
+ zfar = NUM2DBL(zf);
3279
+ ndc_homogeneous = NIL_P(ndch) ? true : ((ndch == Qtrue) ? true : false);
3280
+
3281
+ RMtx4PerspectiveLH( m, width, height, znear, zfar, ndc_homogeneous );
3282
+
3283
+ return self;
3284
+ }
3285
+
3286
+ /*
3287
+ * call-seq: perspectiveFovLH(fovy,aspect,znear,zfar,ndc_homogeneous) -> self
3288
+ *
3289
+ * Builds a perspective projection matrix for a right-handed coordinate system from:
3290
+ * * Field of view in y direction (+fovy+ radian)
3291
+ * * Aspect ratio (+aspect+)
3292
+ * * Near clip plane distance (+znear+)
3293
+ * * Far clip plane distance (+zfar+)
3294
+ * * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
3295
+ */
3296
+ static VALUE
3297
+ RMtx4_perspectiveFovLH( int argc, VALUE* argv, VALUE self )
3298
+ {
3299
+ VALUE fovy, asp, zn, zf, ndch;
3300
+ RMtx4* m = NULL;
3301
+ rmReal fovy_radian, aspect, znear, zfar;
3302
+ bool ndc_homogeneous;
3303
+
3304
+ if (argc < 4 || argc > 5)
3305
+ {
3306
+ rb_raise(rb_eArgError, "RMtx4_perspectiveFovLH : wrong # of arguments (%d)", argc );
3307
+ }
3308
+
3309
+ rb_scan_args(argc, argv, "41", &fovy, &asp, &zn, &zf, &ndch);
3310
+
3311
+ TypedData_Get_Struct( self, RMtx4, &RMtx4_type, m );
3312
+ fovy_radian = NUM2DBL(fovy);
3313
+ aspect = NUM2DBL(asp);
3314
+ znear = NUM2DBL(zn);
3315
+ zfar = NUM2DBL(zf);
3316
+ ndc_homogeneous = NIL_P(ndch) ? true : ((ndch == Qtrue) ? true : false);
3317
+
3318
+ RMtx4PerspectiveFovLH( m, fovy_radian, aspect, znear, zfar, ndc_homogeneous );
3319
+
3320
+ return self;
3321
+ }
3322
+
3323
+ /*
3324
+ * call-seq: perspectiveOffCenterLH(left,right,bottom,top,znear,zfar,ndc_homogeneous) -> self
3325
+ *
3326
+ * Builds a perspective projection matrix for a right-handed coordinate system from:
3327
+ * * Minimum value of the view volume width (+left+)
3328
+ * * Maximum value of the view volume width (+right+)
3329
+ * * Minimum value of the view volume height (+bottom+)
3330
+ * * Maximum value of the view volume height (+top+)
3331
+ * * Near clip plane distance (+znear+)
3332
+ * * Far clip plane distance (+zfar+)
3333
+ * * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
3334
+ */
3335
+ static VALUE
3336
+ RMtx4_perspectiveOffCenterLH( int argc, VALUE* argv, VALUE self )
3337
+ {
3338
+ VALUE l, r, b, t, zn, zf, ndch;
3339
+ RMtx4* m = NULL;
3340
+ rmReal left, right, bottom, top, znear, zfar;
3341
+ bool ndc_homogeneous;
3342
+
3343
+ if (argc < 6 || argc > 7)
3344
+ {
3345
+ rb_raise(rb_eArgError, "RMtx4_perspectiveOffCenterLH : wrong # of arguments (%d)", argc );
3346
+ }
3347
+
3348
+ rb_scan_args(argc, argv, "61", &l, &r, &b, &t, &zn, &zf, &ndch);
3349
+
3350
+ TypedData_Get_Struct( self, RMtx4, &RMtx4_type, m );
3351
+ left = NUM2DBL(l);
3352
+ right = NUM2DBL(r);
3353
+ bottom = NUM2DBL(b);
3354
+ top = NUM2DBL(t);
3355
+ znear = NUM2DBL(zn);
3356
+ zfar = NUM2DBL(zf);
3357
+ ndc_homogeneous = NIL_P(ndch) ? true : ((ndch == Qtrue) ? true : false);
3358
+
3359
+ RMtx4PerspectiveOffCenterLH( m, left, right, bottom, top, znear, zfar, ndc_homogeneous );
3360
+
3361
+ return self;
3362
+ }
3363
+
3364
+ /*
3365
+ * call-seq: orthoLH(width,height,znear,zfar,ndc_homogeneous) -> self
3366
+ *
3367
+ * Builds a orthogonal projection matrix for a right-handed coordinate system from:
3368
+ * * View volume width (+width+)
3369
+ * * View volume height (+height+)
3370
+ * * Near clip plane distance (+znear+)
3371
+ * * Far clip plane distance (+zfar+)
3372
+ * * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
3373
+ */
3374
+ static VALUE
3375
+ RMtx4_orthoLH( int argc, VALUE* argv, VALUE self )
3376
+ {
3377
+ VALUE w, h, zn, zf, ndch;
3378
+ RMtx4* m = NULL;
3379
+ rmReal width, height, znear, zfar;
3380
+ bool ndc_homogeneous;
3381
+
3382
+ if (argc < 4 || argc > 5)
3383
+ {
3384
+ rb_raise(rb_eArgError, "RMtx4_orthoLH : wrong # of arguments (%d)", argc );
3385
+ }
3386
+
3387
+ rb_scan_args(argc, argv, "41", &w, &h, &zn, &zf, &ndch);
3388
+
3389
+ TypedData_Get_Struct( self, RMtx4, &RMtx4_type, m );
3390
+ width = NUM2DBL(w);
3391
+ height = NUM2DBL(h);
3392
+ znear = NUM2DBL(zn);
3393
+ zfar = NUM2DBL(zf);
3394
+ ndc_homogeneous = NIL_P(ndch) ? true : ((ndch == Qtrue) ? true : false);
3395
+
3396
+ RMtx4OrthoLH( m, width, height, znear, zfar, ndc_homogeneous );
3397
+
3398
+ return self;
3399
+ }
3400
+
3401
+ /*
3402
+ * call-seq: orthoOffCenterLH(left,right,bottom,top,znear,zfar,ndc_homogeneous) -> self
3403
+ *
3404
+ * Builds a orthogonal projection matrix for a right-handed coordinate system from:
3405
+ * * Minimum value of the view volume width (+left+)
3406
+ * * Maximum value of the view volume width (+right+)
3407
+ * * Minimum value of the view volume height (+bottom+)
3408
+ * * Maximum value of the view volume height (+top+)
3409
+ * * Near clip plane distance (+znear+)
3410
+ * * Far clip plane distance (+zfar+)
3411
+ * * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
3412
+ */
3413
+ static VALUE
3414
+ RMtx4_orthoOffCenterLH( int argc, VALUE* argv, VALUE self )
3415
+ {
3416
+ VALUE l, r, b, t, zn, zf, ndch;
3417
+ RMtx4* m = NULL;
3418
+ rmReal left, right, bottom, top, znear, zfar;
3419
+ bool ndc_homogeneous;
3420
+
3421
+ if (argc < 6 || argc > 7)
3422
+ {
3423
+ rb_raise(rb_eArgError, "RMtx4_orthoOffCenterLH : wrong # of arguments (%d)", argc );
3424
+ }
3425
+
3426
+ rb_scan_args(argc, argv, "61", &l, &r, &b, &t, &zn, &zf, &ndch);
3427
+
3428
+ TypedData_Get_Struct( self, RMtx4, &RMtx4_type, m );
3429
+ left = NUM2DBL(l);
3430
+ right = NUM2DBL(r);
3431
+ bottom = NUM2DBL(b);
3432
+ top = NUM2DBL(t);
3433
+ znear = NUM2DBL(zn);
3434
+ zfar = NUM2DBL(zf);
3435
+ ndc_homogeneous = NIL_P(ndch) ? true : ((ndch == Qtrue) ? true : false);
3436
+
3437
+ RMtx4OrthoOffCenterLH( m, left, right, bottom, top, znear, zfar, ndc_homogeneous );
3438
+
3439
+ return self;
3440
+ }
3441
+
3224
3442
  /*
3225
3443
  * call-seq: lookAtRH(eye,at,up) -> self
3226
3444
  *
@@ -7380,6 +7598,13 @@ Init_rmath3d()
7380
7598
  rb_define_method( rb_cRMtx4, "rotationQuaternion", RMtx4_rotationQuaternion, 1 );
7381
7599
  rb_define_method( rb_cRMtx4, "scaling", RMtx4_scaling, 3 );
7382
7600
 
7601
+ rb_define_method( rb_cRMtx4, "lookAtLH", RMtx4_lookAtLH, 3 );
7602
+ rb_define_method( rb_cRMtx4, "perspectiveLH", RMtx4_perspectiveLH, -1 );
7603
+ rb_define_method( rb_cRMtx4, "perspectiveFovLH", RMtx4_perspectiveFovLH, -1 );
7604
+ rb_define_method( rb_cRMtx4, "perspectiveOffCenterLH", RMtx4_perspectiveOffCenterLH, -1 );
7605
+ rb_define_method( rb_cRMtx4, "orthoLH", RMtx4_orthoLH, -1 );
7606
+ rb_define_method( rb_cRMtx4, "orthoOffCenterLH", RMtx4_orthoOffCenterLH, -1 );
7607
+
7383
7608
  rb_define_method( rb_cRMtx4, "lookAtRH", RMtx4_lookAtRH, 3 );
7384
7609
  rb_define_method( rb_cRMtx4, "perspectiveRH", RMtx4_perspectiveRH, -1 );
7385
7610
  rb_define_method( rb_cRMtx4, "perspectiveFovRH", RMtx4_perspectiveFovRH, -1 );
@@ -1904,7 +1904,7 @@ module RMath3D
1904
1904
  end
1905
1905
 
1906
1906
  #
1907
- # call-seq: perspectiveRH(width,height,znear,zfar,ndc_convention) -> self
1907
+ # call-seq: perspectiveLH(width,height,znear,zfar,ndc_convention) -> self
1908
1908
  #
1909
1909
  # Builds a perspective projection matrix for a right-handed coordinate system from:
1910
1910
  # * View volume width (+width+)
@@ -1913,13 +1913,12 @@ module RMath3D
1913
1913
  # * Far clip plane distance (+zfar+)
1914
1914
  # * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
1915
1915
  #
1916
- def perspectiveRH( width, height, znear, zfar, ndc_homogeneous = true)
1917
- perspectiveOffCenterRH(-width/2.0, width/2.0, -height/2.0, height/2.0, znear, zfar, ndc_homogeneous )
1918
- return self
1916
+ def perspectiveLH( width, height, znear, zfar, ndc_homogeneous = true)
1917
+ return perspectiveOffCenterLH(-width/2.0, width/2.0, -height/2.0, height/2.0, znear, zfar, ndc_homogeneous )
1919
1918
  end
1920
1919
 
1921
1920
  #
1922
- # call-seq: perspectiveFovRH(fovy,aspect,znear,zfar,ndc_homogeneous) -> self
1921
+ # call-seq: perspectiveFovLH(fovy,aspect,znear,zfar,ndc_homogeneous) -> self
1923
1922
  #
1924
1923
  # Builds a perspective projection matrix for a right-handed coordinate system from:
1925
1924
  # * Field of view in y direction (+fovy+ radian)
@@ -1928,24 +1927,123 @@ module RMath3D
1928
1927
  # * Far clip plane distance (+zfar+)
1929
1928
  # * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
1930
1929
  #
1931
- def perspectiveFovRH( fovy_radian, aspect, znear, zfar, ndc_homogeneous = true)
1932
- f = Math::tan( fovy_radian / 2.0 )
1933
- f = 1.0 / f
1930
+ def perspectiveFovLH( fovy_radian, aspect, znear, zfar, ndc_homogeneous = true)
1931
+ # Ref.: https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/opengl-perspective-projection-matrix
1932
+ top = Math::tan(fovy_radian / 2.0) * znear
1933
+ bottom = -top
1934
+ right = top * aspect
1935
+ left = -right
1936
+ return perspectiveOffCenterLH(left, right, bottom, top, znear, zfar, ndc_homogeneous)
1937
+ end
1934
1938
 
1939
+ #
1940
+ # call-seq: perspectiveOffCenterLH(left,right,bottom,top,znear,zfar) -> self
1941
+ #
1942
+ # Builds a perspective projection matrix for a right-handed coordinate system from:
1943
+ # * Minimum value of the view volume width (+left+)
1944
+ # * Maximum value of the view volume width (+right+)
1945
+ # * Minimum value of the view volume height (+bottom+)
1946
+ # * Maximum value of the view volume height (+top+)
1947
+ # * Near clip plane distance (+znear+)
1948
+ # * Far clip plane distance (+zfar+)
1949
+ # * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
1950
+ #
1951
+ def perspectiveOffCenterLH( left, right, bottom, top, znear, zfar, ndc_homogeneous = true)
1952
+ a = (right+left) / (right-left)
1953
+ b = (top+bottom) / (top-bottom)
1935
1954
  c = ndc_homogeneous ? -(zfar+znear) / (zfar-znear) : -zfar / (zfar-znear)
1936
1955
  d = ndc_homogeneous ? -(2*znear*zfar) / (zfar-znear) : -(znear*zfar) / (zfar-znear)
1937
1956
 
1938
- setIdentity()
1939
- setElement( 0, 0, f / aspect )
1940
- setElement( 1, 1, f )
1941
- setElement( 2, 2, c )
1957
+ setZero()
1958
+
1959
+ setElement( 0, 0, 2*znear/(right-left) )
1960
+ setElement( 0, 2, -a )
1961
+ setElement( 1, 1, 2*znear/(top-bottom) )
1962
+ setElement( 1, 2, -b )
1963
+ setElement( 2, 2, -c )
1942
1964
  setElement( 2, 3, d )
1943
- setElement( 3, 2, -1.0 )
1944
- setElement( 3, 3, 0.0 )
1965
+ setElement( 3, 2, 1.0 )
1966
+
1967
+ return self
1968
+ end
1969
+
1970
+ #
1971
+ # call-seq: orthoLH(width,height,znear,zfar) -> self
1972
+ #
1973
+ # Builds a orthogonal projection matrix for a right-handed coordinate system from:
1974
+ # * View volume width (+width+)
1975
+ # * View volume height (+height+)
1976
+ # * Near clip plane distance (+znear+)
1977
+ # * Far clip plane distance (+zfar+)
1978
+ # * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
1979
+ #
1980
+ def orthoLH( width, height, znear, zfar, ndc_homogeneous = true)
1981
+ orthoOffCenterLH( -width/2.0, width/2.0, -height/2.0, height/2.0, znear, zfar, ndc_homogeneous )
1982
+ return self
1983
+ end
1984
+
1985
+ #
1986
+ # call-seq: orthoOffCenterLH(left,right,bottom,top,znear,zfar) -> self
1987
+ #
1988
+ # Builds a orthogonal projection matrix for a right-handed coordinate system from:
1989
+ # * Minimum value of the view volume width (+left+)
1990
+ # * Maximum value of the view volume width (+right+)
1991
+ # * Minimum value of the view volume height (+bottom+)
1992
+ # * Maximum value of the view volume height (+top+)
1993
+ # * Near clip plane distance (+znear+)
1994
+ # * Far clip plane distance (+zfar+)
1995
+ # * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
1996
+ #
1997
+ def orthoOffCenterLH( left, right, bottom, top, znear, zfar, ndc_homogeneous = true)
1998
+ tx = -(right+left) / (right-left)
1999
+ ty = -(top+bottom) / (top-bottom)
2000
+ tz = ndc_homogeneous ? -(zfar+znear) / (zfar-znear) : -znear / (zfar-znear)
2001
+
2002
+ setIdentity()
2003
+
2004
+ setElement( 0, 0, 2.0/(right-left) )
2005
+ setElement( 0, 3, tx )
2006
+ setElement( 1, 1, 2.0/(top-bottom) )
2007
+ setElement( 1, 3, ty )
2008
+ setElement( 2, 2, (ndc_homogeneous ? 2.0 : 1.0)/(zfar-znear) )
2009
+ setElement( 2, 3, tz )
1945
2010
 
1946
2011
  return self
1947
2012
  end
1948
2013
 
2014
+ #
2015
+ # call-seq: perspectiveRH(width,height,znear,zfar,ndc_convention) -> self
2016
+ #
2017
+ # Builds a perspective projection matrix for a right-handed coordinate system from:
2018
+ # * View volume width (+width+)
2019
+ # * View volume height (+height+)
2020
+ # * Near clip plane distance (+znear+)
2021
+ # * Far clip plane distance (+zfar+)
2022
+ # * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
2023
+ #
2024
+ def perspectiveRH( width, height, znear, zfar, ndc_homogeneous = true)
2025
+ return perspectiveOffCenterRH(-width/2.0, width/2.0, -height/2.0, height/2.0, znear, zfar, ndc_homogeneous )
2026
+ end
2027
+
2028
+ #
2029
+ # call-seq: perspectiveFovRH(fovy,aspect,znear,zfar,ndc_homogeneous) -> self
2030
+ #
2031
+ # Builds a perspective projection matrix for a right-handed coordinate system from:
2032
+ # * Field of view in y direction (+fovy+ radian)
2033
+ # * Aspect ratio (+aspect+)
2034
+ # * Near clip plane distance (+znear+)
2035
+ # * Far clip plane distance (+zfar+)
2036
+ # * Set true for the environment with Z coordinate ranges from -1 to +1 (OpenGL), and false otherwise (Direct3D, Metal) (+ndc_homogeneous+)
2037
+ #
2038
+ def perspectiveFovRH( fovy_radian, aspect, znear, zfar, ndc_homogeneous = true)
2039
+ # Ref.: https://www.scratchapixel.com/lessons/3d-basic-rendering/perspective-and-orthographic-projection-matrix/opengl-perspective-projection-matrix
2040
+ top = Math::tan(fovy_radian / 2.0) * znear
2041
+ bottom = -top
2042
+ right = top * aspect
2043
+ left = -right
2044
+ return perspectiveOffCenterRH(left, right, bottom, top, znear, zfar, ndc_homogeneous)
2045
+ end
2046
+
1949
2047
  #
1950
2048
  # call-seq: perspectiveOffCenterRH(left,right,bottom,top,znear,zfar) -> self
1951
2049
  #
@@ -1964,7 +2062,7 @@ module RMath3D
1964
2062
  c = ndc_homogeneous ? -(zfar+znear) / (zfar-znear) : -zfar / (zfar-znear)
1965
2063
  d = ndc_homogeneous ? -(2*znear*zfar) / (zfar-znear) : -(znear*zfar) / (zfar-znear)
1966
2064
 
1967
- setIdentity()
2065
+ setZero()
1968
2066
 
1969
2067
  setElement( 0, 0, 2*znear/(right-left) )
1970
2068
  setElement( 0, 2, a )
@@ -1973,7 +2071,6 @@ module RMath3D
1973
2071
  setElement( 2, 2, c )
1974
2072
  setElement( 2, 3, d )
1975
2073
  setElement( 3, 2, -1.0 )
1976
- setElement( 3, 3, 0.0 )
1977
2074
 
1978
2075
  return self
1979
2076
  end
@@ -485,6 +485,29 @@ class TC_RMtx4 < Minitest::Test
485
485
  end
486
486
  end
487
487
 
488
+ def test_lookAtLH
489
+ pEye = RVec3.new( 10, 10, 10 )
490
+ vDir = ( RVec3.new(0,0,0) - pEye ).normalize! # staring at (0,0,0)
491
+ vUp = RVec3.new( 0, 1, 0 )
492
+ vRight = RVec3.cross( vUp, vDir ).normalize!
493
+ vUp = RVec3.cross( vDir, vRight ).normalize!
494
+
495
+ m0 = RMtx4.new( vRight.x, vRight.y, vRight.z, -RVec3.dot(pEye,vRight),
496
+ vUp.x, vUp.y, vUp.z, -RVec3.dot(pEye,vUp),
497
+ vDir.x, vDir.y, vDir.z, -RVec3.dot(pEye,vDir),
498
+ 0.0, 0.0, 0.0, 1.0 )
499
+
500
+ m1 = RMtx4.new.lookAtLH( RVec3.new(10,10,10), # posistion
501
+ RVec3.new(0,0,0), # at
502
+ RVec3.new(0,1,0) ) # up
503
+
504
+ for r in 0...4 do
505
+ for c in 0...4 do
506
+ assert_in_delta( m0.getElement(r,c), m1.getElement(r,c), @tolerance )
507
+ end
508
+ end
509
+ end
510
+
488
511
  def test_lookAtRH
489
512
  pEye = RVec3.new( 10, 10, 10 )
490
513
  vDir = ( pEye - RVec3.new(0,0,0) ).normalize! # staring at (0,0,0)
@@ -540,15 +563,15 @@ class TC_RMtx4 < Minitest::Test
540
563
  fovy = 2.0 * Math::atan( (height/2.0) / z_n )
541
564
  f = 1.0/Math::tan( fovy/2.0 )
542
565
 
543
- m2 = RMtx4.new( f/aspect, 0.0, 0.0, 0.0,
544
- 0.0, f, 0.0, 0.0,
545
- 0.0, 0.0, (z_f+z_n)/(z_n-z_f), 2*z_f*z_n/(z_n-z_f),
546
- 0.0, 0.0, -1.0, 0.0 )
566
+ m2 = RMtx4.new( f/aspect, 0.0, 0.0, 0.0,
567
+ 0.0, f, 0.0, 0.0,
568
+ 0.0, 0.0, -(z_f+z_n)/(z_f-z_n), -2*z_f*z_n/(z_f-z_n),
569
+ 0.0, 0.0, -1.0, 0.0 )
547
570
  m3 = RMtx4.new.perspectiveFovRH( fovy, aspect, z_n, z_f, true );
548
571
 
549
572
  for r in 0...4 do
550
573
  for c in 0...4 do
551
- assert_in_delta( m2.getElement(r,c), m2.getElement(r,c), @tolerance )
574
+ assert_in_delta( m2.getElement(r,c), m3.getElement(r,c), @tolerance )
552
575
  end
553
576
  end
554
577
 
@@ -572,6 +595,67 @@ class TC_RMtx4 < Minitest::Test
572
595
  end
573
596
  end
574
597
 
598
+ def test_perspectiveLH
599
+ left = -640.0
600
+ right = 640.0
601
+ bottom = -360.0
602
+ top = 360.0
603
+ z_n = 1.0
604
+ z_f = 1000.0
605
+ width = right - left
606
+ height = top - bottom
607
+ aspect = width/height
608
+
609
+ # RMtx4#perspectiveLH
610
+ m0 = RMtx4.new( 2*z_n/width, 0.0, 0.0, 0.0,
611
+ 0.0, 2*z_n/height, 0.0, 0.0,
612
+ 0.0, 0.0, (z_f+z_n)/(z_f-z_n), -2.0*z_f*z_n / (z_f-z_n),
613
+ 0.0, 0.0, 1.0, 0.0 )
614
+ m1 = RMtx4.new.perspectiveLH( width, height, z_n, z_f, true )
615
+
616
+ for r in 0...4 do
617
+ for c in 0...4 do
618
+ assert_in_delta( m0.getElement(r,c), m1.getElement(r,c), @tolerance )
619
+ end
620
+ end
621
+
622
+ # RMtx4#perspectiveFovLH
623
+
624
+ # [NOTE] tan(fovy/2) == (height/2)/z_n
625
+ fovy = 2.0 * Math::atan( (height/2.0) / z_n )
626
+ f = 1.0/Math::tan( fovy/2.0 )
627
+
628
+ m2 = RMtx4.new( f/aspect, 0.0, 0.0, 0.0,
629
+ 0.0, f, 0.0, 0.0,
630
+ 0.0, 0.0, (z_f+z_n)/(z_f-z_n), -2.0*z_f*z_n/(z_f-z_n),
631
+ 0.0, 0.0, 1.0, 0.0 )
632
+ m3 = RMtx4.new.perspectiveFovLH( fovy, aspect, z_n, z_f, true );
633
+ for r in 0...4 do
634
+ for c in 0...4 do
635
+ assert_in_delta( m2.getElement(r,c), m3.getElement(r,c), @tolerance )
636
+ end
637
+ end
638
+
639
+ # RMtx4#perspectiveOffCenterLH
640
+
641
+ a = (right+left)/(right-left)
642
+ b = (top+bottom)/(top-bottom)
643
+ c = -(z_f+z_n)/(z_f-z_n)
644
+ d = -2.0*z_f*z_n/(z_f-z_n)
645
+ m4 = RMtx4.new( 2*z_n/(right-left), 0.0, -a, 0.0,
646
+ 0.0, 2*z_n/(top-bottom), -b, 0.0,
647
+ 0.0, 0.0, -c, d,
648
+ 0.0, 0.0, 1.0, 0.0 )
649
+
650
+ m5 = RMtx4.new.perspectiveOffCenterLH( left, right, bottom, top, z_n, z_f, true )
651
+
652
+ for r in 0...4 do
653
+ for c in 0...4 do
654
+ assert_in_delta( m4.getElement(r,c), m5.getElement(r,c), @tolerance )
655
+ end
656
+ end
657
+ end
658
+
575
659
  # http://pyopengl.sourceforge.net/documentation/manual/glOrtho.3G.xml
576
660
  def test_orthoRH
577
661
  left = -640.0
@@ -616,6 +700,49 @@ class TC_RMtx4 < Minitest::Test
616
700
  end
617
701
  end
618
702
 
703
+ def test_orthoLH
704
+ left = -640.0
705
+ right = 640.0
706
+ bottom = -360.0
707
+ top = 360.0
708
+ z_n = 1.0
709
+ z_f = 1000.0
710
+ width = right - left
711
+ height = top - bottom
712
+
713
+ # RMtx4#orthoLH
714
+ tx = -(right+left)/width
715
+ ty = -(top+bottom)/height
716
+ tz = -(z_f+z_n)/(z_f-z_n)
717
+ m0 = RMtx4.new( 2.0/width, 0.0, 0.0, tx,
718
+ 0.0, 2.0/height, 0.0, ty,
719
+ 0.0, 0.0, 2.0/(z_f-z_n), tz,
720
+ 0.0, 0.0, 0.0, 1.0 )
721
+ m1 = RMtx4.new.orthoLH( width, height, z_n, z_f, true )
722
+
723
+ for r in 0...4 do
724
+ for c in 0...4 do
725
+ assert_in_delta( m0.getElement(r,c), m1.getElement(r,c), @tolerance )
726
+ end
727
+ end
728
+
729
+ # RMtx4#orthoOffCenterLH
730
+ tx = -(right+left)/(right-left)
731
+ ty = -(top+bottom)/(top-bottom)
732
+ tz = -(z_f+z_n)/(z_f-z_n)
733
+ m2 = RMtx4.new( 2.0/(right-left), 0.0, 0.0, tx,
734
+ 0.0, 2.0/(top-bottom), 0.0, ty,
735
+ 0.0, 0.0, 2.0/(z_f-z_n), tz,
736
+ 0.0, 0.0, 0.0, 1.0 )
737
+ m3 = RMtx4.new.orthoOffCenterLH( left, right, bottom, top, z_n, z_f, true )
738
+
739
+ for r in 0...4 do
740
+ for c in 0...4 do
741
+ assert_in_delta( m2.getElement(r,c), m3.getElement(r,c), @tolerance )
742
+ end
743
+ end
744
+ end
745
+
619
746
  def test_unary_operators
620
747
  # RMtx4#+@
621
748
  m0 = RMtx4.new( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 )
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rmath3d
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.3
4
+ version: 1.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - vaiorabbit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-21 00:00:00.000000000 Z
11
+ date: 2020-07-23 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Provides vector2/3/4, matrix2x2/3x3/4x4 and quaternion in C extension library form (and plain Ruby form with the same interface for debugging use).