rmath3d 1.2.3 → 1.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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).