-
Notifications
You must be signed in to change notification settings - Fork 10
/
min-rt.c
2300 lines (1937 loc) · 70.3 KB
/
min-rt.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/****************************************************************/
/* */
/* Ray Tracing Program for C */
/* */
/* Original Program by Ryoji Kawamichi */
/* Arranged for Chez Scheme by Motohico Nanano */
/* Arranged for Objective Caml by Y. Oiwa and E. Sumii */
/* Added diffuse ray tracer by Y.Ssugawara */
/* Arranged for C by K.Watanabe and H. Kobayashi */
/* */
/****************************************************************/
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
typedef struct {
double x, y, z;
} vec_t;
typedef struct {
double x, y, z, w;
} vec4_t;
typedef struct {
int tex, shape, surface;
bool isrot;
vec_t abc, xyz;
bool invert;
double surfparams[2];
vec_t color, rot123;
vec4_t ctbl;
} obj_t;
typedef struct {
vec_t rgb;
vec_t *isect_ps;
int *sids;
int *cdif;
vec_t *engy;
vec_t *r20p;
int gid;
vec_t *nvectors;
} pixel_t;
typedef struct {
vec_t vec;
double *cnst[120]; /* cnstの各要素は定数の配列(長さ4~6でオブジェクトの形による) */
} dvec_t;
typedef struct {
int sid;
dvec_t dv;
double br;
} refl_t;
/**************** グローバル変数の宣言 ****************/
/* オブジェクトの個数 */
int n_objects = 0;
/* オブジェクトのデータを入れるベクトル(最大60個)*/
obj_t objects[60];
/* Screen の中心座標 */
vec_t screen;
/* 視点の座標 */
vec_t viewpoint;
/* 光源方向ベクトル (単位ベクトル) */
vec_t light;
/* 鏡面ハイライト強度 (標準=255) */
double beam = 255.0;
/* AND ネットワークを保持 */
int *and_net[50];
/* OR ネットワークを保持 */
int **or_net;
/* 以下、交差判定ルーチンの返り値格納用 */
/* solver の交点 の t の値 */
double solver_dist = 0.0;
/* 交点の直方体表面での方向 */
int intsec_rectside = 0;
/* 発見した交点の最小の t */
double tmin = 1000000000.0;
/* 交点の座標 */
vec_t intersection_point;
/* 衝突したオブジェクト番号 */
int intersected_object_id = 0;
/* 法線ベクトル */
vec_t nvector;
/* 交点の色 */
vec_t texture_color;
/* 計算中の間接受光強度を保持 */
vec_t diffuse_ray;
/* スクリーン上の点の明るさ */
vec_t rgb;
/* 画像サイズ */
int image_size[2];
/* 画像の中心 = 画像サイズの半分 */
int image_center[2];
/* 3次元上のピクセル間隔 */
double scan_pitch;
/* judge_intersectionに与える光線始点 */
vec_t startp;
/* judge_intersection_fastに与える光線始点 */
vec_t startp_fast;
/* 画面上のx,y,z軸の3次元空間上の方向 */
vec_t screenx_dir;
vec_t screeny_dir;
vec_t screenz_dir;
/* 直接光追跡で使う光方向ベクトル */
vec_t ptrace_dirvec;
/* 間接光サンプリングに使う方向ベクトル */
dvec_t *dirvecs[5];
/* 光源光の前処理済み方向ベクトル */
dvec_t light_dirvec;
/* 鏡平面の反射情報 */
refl_t reflections[180];
/* reflectionsの有効な要素数 */
int n_reflections;
/******************************************************************************
Runtime
*****************************************************************************/
#define fneg(x) (-(x))
#define fispos(x) ((x) > 0.0)
#define fisneg(x) ((x) < 0.0)
#define fiszero(x) ((x) == 0.0)
#define fhalf(x) ((x) * 0.5)
#define fsqr(x) ((x) * (x))
#define int_of_double(f) ((int)(f))
#define float_of_int(i) ((double)(i))
int read_int() {
unsigned n = 0;
n += getchar();
n += getchar() << 8;
n += getchar() << 16;
n += getchar() << 24;
return n;
}
double read_float() {
union {unsigned i; float f;} u;
u.i = read_int();
return u.f;
}
void print_char(char c) {
printf("%c", c);
}
void print_int(int i) {
printf("%d", i);
}
/******************************************************************************
ユーティリティー
*****************************************************************************/
/* 符号 */
double sgn (double x) {
if (fiszero(x)) {
return 0.0;
} else if (fispos(x)) {
return 1.0;
} else {
return -1.0;
}
}
/* 条件付き符号反転 */
#define fneg_cond(cond, x) ((cond) ? (x) : fneg(x))
/******************************************************************************
ベクトル操作のためのプリミティブ
*****************************************************************************/
/* 値代入 */
#define vecset(v, a, b, c) \
do { \
(v)->x = a; \
(v)->y = b; \
(v)->z = c; \
} while(0)
/* 零初期化 */
#define vecbzero(v) \
((v)->x = (v)->y = (v)->z = 0.0)
/* 符号付正規化 ゼロ割チェック*/
void vecunit_sgn (vec_t *v, int inv) {
double l = sqrt (fsqr(v->x) + fsqr(v->y) + fsqr(v->z));
double il;
if (fiszero(l)) {
il = 1.0;
} else if (inv) {
il = -1.0 / l;
} else {
il = 1.0 / l;
}
v->x = v->x * il;
v->y = v->y * il;
v->z = v->z * il;
}
/* 内積 */
#define veciprod(v, w) \
((v)->x * (w)->x + (v)->y * (w)->y + (v)->z * (w)->z)
/* 内積 */
#define veciprod_d(v, w) \
((v)->vec.x * (w)->x + (v)->vec.y * (w)->y + (v)->vec.z * (w)->z)
/* 内積 引数形式が異なる版 */
#define veciprod2(v, w0, w1, w2) \
((v)->x * (w0) + (v)->y * (w1) + (v)->z * (w2))
/* 別なベクトルの定数倍を加算 */
#define vecaccum(dest, scale, v) \
do { \
(dest)->x += (scale) * (v)->x; \
(dest)->y += (scale) * (v)->y; \
(dest)->z += (scale) * (v)->z; \
} while(0)
/* ベクトルの和 */
#define vecadd(dest, v) \
do { \
(dest)->x += (v)->x; \
(dest)->y += (v)->y; \
(dest)->z += (v)->z; \
} while(0)
/* ベクトルを定数倍 */
#define vecscale(dest, scale) \
do { \
(dest)->x *= (scale); \
(dest)->y *= (scale); \
(dest)->z *= (scale); \
} while(0)
/* 他の2ベクトルの要素同士の積を計算し加算 */
#define vecaccumv(dest, v, w) \
do { \
(dest)->x += (v)->x * (w)->x; \
(dest)->y += (v)->y * (w)->y; \
(dest)->z += (v)->z * (w)->z; \
} while(0)
/******************************************************************************
オブジェクトデータ構造へのアクセス関数
*****************************************************************************/
/* テクスチャ種 0:無し 1:市松模様 2:縞模様 3:同心円模様 4:斑点*/
#define o_texturetype(m) ((m)->tex)
/* 物体の形状 0:直方体 1:平面 2:二次曲面 3:円錐 */
#define o_form(m) ((m)->shape)
/* 反射特性 0:拡散反射のみ 1:拡散+非完全鏡面反射 2:拡散+完全鏡面反射 */
#define o_reflectiontype(m) ((m)->surface)
/* 曲面の外側が真かどうかのフラグ true:外側が真 false:内側が真 */
#define o_isinvert(m) ((m)->invert)
/* 回転の有無 true:回転あり false:回転無し 2次曲面と円錐のみ有効 */
#define o_isrot(m) ((m)->isrot)
/* 物体形状の aパラメータ */
#define o_param_a(m) ((m)->abc.x)
/* 物体形状の bパラメータ */
#define o_param_b(m) ((m)->abc.y)
/* 物体形状の cパラメータ */
#define o_param_c(m) ((m)->abc.z)
/* 物体形状の abcパラメータ */
#define o_param_abc(m) (&(m)->abc)
/* 物体の中心x座標 */
#define o_param_x(m) ((m)->xyz.x)
/* 物体の中心y座標 */
#define o_param_y(m) ((m)->xyz.y)
/* 物体の中心z座標 */
#define o_param_z(m) ((m)->xyz.z)
/* 物体の拡散反射率 0.0 -- 1.0 */
#define o_diffuse(m) ((m)->surfparams[0])
/* 物体の不完全鏡面反射率 0.0 -- 1.0 */
#define o_hilight(m) ((m)->surfparams[1])
/* 物体色の R成分 */
#define o_color_red(m) ((m)->color.x)
/* 物体色の G成分 */
#define o_color_green(m) ((m)->color.y)
/* 物体色の B成分 */
#define o_color_blue(m) ((m)->color.z)
/* 物体の曲面方程式の y*z項の係数 2次曲面と円錐で、回転がある場合のみ */
#define o_param_r1(m) ((m)->rot123.x)
/* 物体の曲面方程式の x*z項の係数 2次曲面と円錐で、回転がある場合のみ */
#define o_param_r2(m) ((m)->rot123.y)
/* 物体の曲面方程式の x*y項の係数 2次曲面と円錐で、回転がある場合のみ */
#define o_param_r3(m) ((m)->rot123.z)
/* 光線の発射点をあらかじめ計算した場合の定数テーブル */
/*
0 -- 2 番目の要素: 物体の固有座標系に平行移動した光線始点
3番目の要素:
直方体→無効
平面→ abcベクトルとの内積
二次曲面、円錐→二次方程式の定数項
*/
#define o_param_ctbl(m) (&(m)->ctbl)
/******************************************************************************
Pixelデータのメンバアクセス関数群
*****************************************************************************/
/* 直接光追跡で得られたピクセルのRGB値 */
#define p_rgb(p) (&(p)->rgb)
/* 飛ばした光が物体と衝突した点の配列 */
#define p_intersection_points(p) ((p)->isect_ps)
/* 飛ばした光が衝突した物体面番号の配列 */
/* 物体面番号は オブジェクト番号 * 4 + (solverの返り値) */
#define p_surface_ids(p) ((p)->sids)
/* 間接受光を計算するか否かのフラグ */
#define p_calc_diffuse(p) ((p)->cdif)
/* 衝突点の間接受光エネルギーがピクセル輝度に与える寄与の大きさ */
#define p_energy(p) ((p)->engy)
/* 衝突点の間接受光エネルギーを光線本数を1/5に間引きして計算した値 */
#define p_received_ray_20percent(p) ((p)->r20p)
/* このピクセルのグループ ID */
/*
スクリーン座標 (x,y)の点のグループIDを (x+2*y) mod 5 と定める
結果、下図のような分け方になり、各点は上下左右4点と別なグループになる
0 1 2 3 4 0 1 2 3 4
2 3 4 0 1 2 3 4 0 1
4 0 1 2 3 4 0 1 2 3
1 2 3 4 0 1 2 3 4 0
*/
#define p_group_id(p) ((p)->gid)
/* グループIDをセットするアクセス関数 */
#define p_set_group_id(p, id) ((p)->gid = (id))
/* 各衝突点における法線ベクトル */
#define p_nvectors(p) ((p)->nvectors)
/******************************************************************************
前処理済み方向ベクトルのメンバアクセス関数
*****************************************************************************/
/* ベクトル */
#define d_vec(d) (&(d)->vec)
/* 各オブジェクトに対して作った solver 高速化用定数テーブル */
#define d_const(d) ((d)->cnst)
/******************************************************************************
平面鏡面体の反射情報
*****************************************************************************/
/* 面番号 オブジェクト番号*4 + (solverの返り値) */
#define r_surface_id(r) ((r)->sid)
/* 光源光の反射方向ベクトル(光と逆向き) */
#define r_dvec(r) &((r)->dv)
/* 物体の反射率 */
#define r_bright(r) ((r)->br)
/******************************************************************************
データ読み込みの関数群
*****************************************************************************/
/* ラジアン */
double rad (double x) {
return x * 0.017453293;
}
/**** 環境データの読み込み ****/
void read_screen_settings (void) {
double v1, cos_v1, sin_v1;
double v2, cos_v2, sin_v2;
screen.x = read_float();
screen.y = read_float();
screen.z = read_float();
v1 = rad(read_float());
v2 = rad(read_float());
cos_v1 = cos(v1);
sin_v1 = sin(v1);
cos_v2 = cos(v2);
sin_v2 = sin(v2);
screenz_dir.x = cos_v1 * sin_v2 * 200.0;
screenz_dir.y = sin_v1 * (-200.0);
screenz_dir.z = cos_v1 * cos_v2 * 200.0;
screenx_dir.x = cos_v2;
screenx_dir.y = 0.0;
screenx_dir.z = - sin_v2;
screeny_dir.x = - sin_v1 * sin_v2;
screeny_dir.y = - cos_v1;
screeny_dir.z = - sin_v1 * cos_v2;
viewpoint.x = screen.x - screenz_dir.x;
viewpoint.y = screen.y - screenz_dir.y;
viewpoint.z = screen.z - screenz_dir.z;
}
void read_light(void) {
int nl = read_int();
double l1 = rad(read_float());
double sl1 = sin(l1);
double l2 = rad(read_float());
double cl1 = cos(l1);
double sl2 = sin(l2);
double cl2 = cos(l2);
light.y = - sl1;
light.x = cl1 * sl2;
light.z = cl1 * cl2;
beam = read_float();
}
void rotate_quadratic_matrix(vec_t *abc, vec_t *rot) {
/* 回転行列の積 R(z)R(y)R(x) を計算する */
double cos_x = cos(rot->x);
double sin_x = sin(rot->x);
double cos_y = cos(rot->y);
double sin_y = sin(rot->y);
double cos_z = cos(rot->z);
double sin_z = sin(rot->z);
double m00 = cos_y * cos_z;
double m01 = sin_x * sin_y * cos_z - cos_x * sin_z;
double m02 = cos_x * sin_y * cos_z + sin_x * sin_z;
double m10 = cos_y * sin_z;
double m11 = sin_x * sin_y * sin_z + cos_x * cos_z;
double m12 = cos_x * sin_y * sin_z - sin_x * cos_z;
double m20 = - sin_y;
double m21 = sin_x * cos_y;
double m22 = cos_x * cos_y;
/* a, b, cの元の値をバックアップ */
double ao = abc->x;
double bo = abc->y;
double co = abc->z;
/* R^t * A * R を計算 */
/* X^2, Y^2, Z^2成分 */
abc->x = ao * fsqr(m00) + bo * fsqr(m10) + co * fsqr(m20);
abc->y = ao * fsqr(m01) + bo * fsqr(m11) + co * fsqr(m21);
abc->z = ao * fsqr(m02) + bo * fsqr(m12) + co * fsqr(m22);
/* 回転によって生じた XY, YZ, ZX成分 */
rot->x = 2.0 * (ao * m01 * m02 + bo * m11 * m12 + co * m21 * m22);
rot->y = 2.0 * (ao * m00 * m02 + bo * m10 * m12 + co * m20 * m22);
rot->z = 2.0 * (ao * m00 * m01 + bo * m10 * m11 + co * m20 * m21);
}
/**** オブジェクト1つのデータの読み込み ****/
bool read_nth_object(int n) {
int texture = read_int();
if (texture != -1) {
int form;
int refltype;
int isrot_p;
vec_t abc;
vec_t xyz;
int m_invert;
double reflparam[2];
vec_t color;
vec_t rotation;
bool m_invert2;
vec4_t ctbl;
form = read_int();
refltype = read_int();
isrot_p = read_int();
abc.x = read_float();
abc.y = read_float();
abc.z = read_float();
xyz.x = read_float();
xyz.y = read_float();
xyz.z = read_float();
m_invert = fisneg (read_float());
reflparam[0] = read_float(); /* diffuse */
reflparam[1] = read_float(); /* hilight */
color.x = read_float();
color.y = read_float();
color.z = read_float(); /* 15 */
if (isrot_p != 0) {
rotation.x = rad (read_float());
rotation.y = rad (read_float());
rotation.z = rad (read_float());
}
/* パラメータの正規化 */
/* 注: 下記正規化 (form = 2) 参照 */
m_invert2 = form == 2 ? true : m_invert;
if (form == 3) {
/* 2次曲面: X,Y,Z サイズから2次形式行列の対角成分へ */
double a = abc.x;
double b = abc.y;
double c = abc.z;
abc.x = (a == 0.0) ? 0.0 : (sgn(a) / fsqr(a)); /* X^2 成分 */
abc.y = (b == 0.0) ? 0.0 : (sgn(b) / fsqr(b)); /* Y^2 成分 */
abc.z = (c == 0.0) ? 0.0 : (sgn(c) / fsqr(c)); /* Z^2 成分 */
} else if (form == 2) {
/* 平面: 法線ベクトルを正規化, 極性を負に統一 */
vecunit_sgn(&abc, !m_invert);
}
/* 2次形式行列に回転変換を施す */
if (isrot_p != 0) {
rotate_quadratic_matrix(&abc, &rotation);
}
{
/* ここからあとは abc と rotation しか操作しない。*/
objects[n].tex = texture;
objects[n].shape = form;
objects[n].surface = refltype;
objects[n].isrot = isrot_p;
objects[n].abc = abc;
objects[n].xyz = xyz;
objects[n].invert = m_invert2;
/* reflection paramater */
objects[n].surfparams[0] = reflparam[0];
objects[n].surfparams[1] = reflparam[1];
objects[n].color = color;
objects[n].rot123 = rotation;
objects[n].ctbl = ctbl;
}
return true;
} else {
return false; /* データの終了 */
}
}
/**** 物体データ全体の読み込み ****/
void read_all_object() {
int i;
for(i = 0; i < 60; ++i) {
if(!read_nth_object(i)) {
n_objects = i;
return;
}
}
assert(false); /* failwith "too many objects" */
}
/**** AND, OR ネットワークの読み込み ****/
/* ネットワーク1つを読み込みベクトルにして返す */
int *read_net_item(int length) {
int item = read_int();
if (item == -1) {
int *ary = (int *) malloc(sizeof(int) * (length + 1));
memset(ary, -1, sizeof(int) * (length + 1));
return ary;
}else {
int *v = read_net_item(length + 1);
v[length] = item;
return v;
}
}
int **read_or_network(int length) {
int *net = read_net_item(0);
if (net[0] == -1) {
int **ary = (int **) malloc(sizeof(int*) * (length + 1));
int i;
for (i = 0; i < length + 1; ++i) {
ary[i] = net;
}
return ary;
} else {
int **v = read_or_network (length + 1);
v[length] = net;
return v;
}
}
void read_and_network (int n) {
int *net = read_net_item(0);
if (net[0] != -1) {
free(and_net[n]);
and_net[n] = net;
read_and_network(n + 1);
}
}
void read_parameter() {
read_screen_settings();
read_light();
read_all_object();
read_and_network(0);
or_net = read_or_network(0);
}
/******************************************************************************
直線とオブジェクトの交点を求める関数群
*****************************************************************************/
/* solver :
オブジェクト (の index) と、ベクトル L, P を受けとり、
直線 Lt + P と、オブジェクトとの交点を求める。
交点がない場合は 0 を、交点がある場合はそれ以外を返す。
この返り値は nvector で交点の法線ベクトルを求める際に必要。
(直方体の場合)
交点の座標は t の値として solver_dist に格納される。
*/
/* 直方体の指定された面に衝突するかどうか判定する */
/* i0 : 面に垂直な軸のindex X:0, Y:1, Z:2 i2,i3は他の2軸のindex */
bool solver_rect_surface(obj_t *m, vec_t *dirvec, double b0, double b1, double b2, int i0, int i1, int i2) {
double *dirvec_arr = (double *) dirvec;
if (dirvec_arr[i0] == 0.0) {
return false;
} else {
vec_t *abc = o_param_abc(m);
double *abc_arr = (double *) abc;
double d = fneg_cond(o_isinvert(m) ^ fisneg(dirvec_arr[i0]), abc_arr[i0]);
double d2 = (d - b0) / dirvec_arr[i0];
if ((fabs(d2 * dirvec_arr[i1] + b1)) < abc_arr[i1]) {
if ((fabs(d2 * dirvec_arr[i2] + b2)) < abc_arr[i2]) {
solver_dist = d2;
return true;
}else {
return false;
}
}
else {
return false;
}
}
}
/***** 直方体オブジェクトの場合 ****/
int solver_rect (obj_t *m, vec_t *dirvec, double b0, double b1, double b2) {
if (solver_rect_surface(m, dirvec, b0, b1, b2, 0, 1, 2)) {
return 1; /* YZ 平面 */
} else if (solver_rect_surface(m, dirvec, b1, b2, b0, 1, 2, 0)) {
return 2; /* ZX 平面 */
} else if (solver_rect_surface(m, dirvec, b2, b0, b1, 2, 0, 1)) {
return 3; /* XY 平面 */
} else {
return 0;
}
}
/* 平面オブジェクトの場合 */
int solver_surface(obj_t *m, vec_t *dirvec, double b0, double b1, double b2) {
/* 点と平面の符号つき距離 */
/* 平面は極性が負に統一されている */
vec_t *abc = o_param_abc(m);
double d = veciprod(dirvec, abc);
if (d > 0.0) {
solver_dist = fneg(veciprod2(abc, b0, b1, b2)) / d;
return 1;
} else {
return 0;
}
}
/* 3変数2次形式 v^t A v を計算 */
/* 回転が無い場合は対角部分のみ計算すれば良い */
double quadratic(obj_t *m, double v0, double v1, double v2) {
double diag_part =
fsqr(v0) * o_param_a(m) + fsqr(v1) * o_param_b(m) + fsqr(v2) * o_param_c(m);
if (o_isrot(m) == 0) {
return diag_part;
} else {
return diag_part
+ v1 * v2 * o_param_r1(m)
+ v2 * v0 * o_param_r2(m)
+ v0 * v1 * o_param_r3(m);
}
}
/* 3変数双1次形式 v^t A w を計算 */
/* 回転が無い場合は A の対角部分のみ計算すれば良い */
double bilinear(obj_t *m, double v0, double v1, double v2, double w0, double w1, double w2) {
double diag_part =
v0 * w0 * o_param_a(m)
+ v1 * w1 * o_param_b(m)
+ v2 * w2 * o_param_c(m);
if (o_isrot(m) == 0) {
return diag_part;
} else {
return diag_part + fhalf
((v2 * w1 + v1 * w2) * o_param_r1(m)
+ (v0 * w2 + v2 * w0) * o_param_r2(m)
+ (v0 * w1 + v1 * w0) * o_param_r3(m));
}
}
/* 2次曲面または円錐の場合 */
/* 2次形式で表現された曲面 x^t A x - (0 か 1) = 0 と 直線 base + dirvec*t の
交点を求める。曲線の方程式に x = base + dirvec*t を代入してtを求める。
つまり (base + dirvec*t)^t A (base + dirvec*t) - (0 か 1) = 0、
展開すると (dirvec^t A dirvec)*t^2 + 2*(dirvec^t A base)*t +
(base^t A base) - (0か1) = 0 、よってtに関する2次方程式を解けば良い。*/
int solver_second(obj_t *m, vec_t *dirvec, double b0, double b1, double b2) {
/* 解の公式 (-b' ± sqrt(b'^2 - a*c)) / a を使用(b' = b/2) */
/* a = dirvec^t A dirvec */
double aa = quadratic(m, dirvec->x, dirvec->y, dirvec->z);
if (aa == 0.0) {
return 0; /* 正確にはこの場合も1次方程式の解があるが、無視しても通常は大丈夫 */
} else {
/* b' = b/2 = dirvec^t A base */
double bb = bilinear(m, dirvec->x, dirvec->y, dirvec->z, b0, b1, b2);
/* c = base^t A base - (0か1) */
double cc0 = quadratic(m, b0, b1, b2);
double cc = o_form(m) == 3 ? cc0 - 1.0 : cc0;
/* 判別式 */
double d = bb * bb - aa * cc;
if (d > 0.0) {
double sd = sqrt(d);
double t1 = o_isinvert(m) ? sd : - sd;
solver_dist = (t1 - bb) / aa;
return 1;
} else {
return 0;
}
}
}
/**** solver のメインルーチン ****/
int solver(int index, vec_t *dirvec, vec_t *org) {
obj_t *m = &objects[index];
/* 直線の始点を物体の基準位置に合わせて平行移動 */
double b0 = org->x - o_param_x(m);
double b1 = org->y - o_param_y(m);
double b2 = org->z - o_param_z(m);
int m_shape = o_form(m);
/* 物体の種類に応じた補助関数を呼ぶ */
int ret;
if (m_shape == 1) {
ret = solver_rect(m, dirvec, b0, b1, b2); /* 直方体 */
} else if (m_shape == 2) {
ret = solver_surface(m, dirvec, b0, b1, b2); /* 平面 */
} else {
ret = solver_second(m, dirvec, b0, b1, b2); /* 2次曲面/円錐 */
}
return ret;
}
/******************************************************************************
solverのテーブル使用高速版
*****************************************************************************/
/*
通常版solver と同様、直線 start + t * dirvec と物体の交点を t の値として返す
t の値は solver_distに格納
solver_fast は、直線の方向ベクトル dirvec について作ったテーブルを使用
内部的に solver_rect_fast, solver_surface_fast, solver_second_fastを呼ぶ
solver_fast2 は、dirvecと直線の始点 start それぞれに作ったテーブルを使用
直方体についてはstartのテーブルによる高速化はできないので、solver_fastと
同じく solver_rect_fastを内部的に呼ぶ。それ以外の物体については
solver_surface_fast2またはsolver_second_fast2を内部的に呼ぶ
変数dconstは方向ベクトル、sconstは始点に関するテーブル
*/
/***** solver_rectのdirvecテーブル使用高速版 ******/
int solver_rect_fast(obj_t *m, vec_t *v, double *dconst, double b0, double b1, double b2) {
double d0 = (dconst[0] - b0) * dconst[1];
bool tmp0;
double d1 = (dconst[2] - b1) * dconst[3];
bool tmp_zx;
double d2 = (dconst[4] - b2) * dconst[5];
bool tmp_xy;
/* YZ平面との衝突判定 */
if (fabs (d0 * v->y + b1) < o_param_b(m)) {
if (fabs (d0 * v->z + b2) < o_param_c(m)) {
tmp0 = dconst[1] != 0.0;
}
else {
tmp0 = false;
}
}
else tmp0 = false;
if (tmp0 != false) {
solver_dist = d0;
return 1;
}
/* ZX平面との衝突判定 */
if (fabs (d1 * v->x + b0) < o_param_a(m)) {
if (fabs (d1 * v->z + b2) < o_param_c(m)) {
tmp_zx = dconst[3] != 0.0;
} else {
tmp_zx = false;
}
}
else tmp_zx = false;
if (tmp_zx != false) {
solver_dist = d1;
return 2;
}
/* XY平面との衝突判定 */
if (fabs (d2 * v->x + b0) < o_param_a(m)) {
if (fabs (d2 * v->y + b1) < o_param_b(m)) {
tmp_xy = dconst[5] != 0.0;
}
else tmp_xy = false;
}
else tmp_xy = false;
if (tmp_xy != false) {
solver_dist = d2;
return 3;
}
return 0;
}
/**** solver_surfaceのdirvecテーブル使用高速版 ******/
int solver_surface_fast(obj_t *m, double *dconst, double b0, double b1, double b2) {
if (fisneg(dconst[0])) {
solver_dist = dconst[1] * b0 + dconst[2] * b1 + dconst[3] * b2;
return 1;
} else {
return 0;
}
}
/**** solver_second のdirvecテーブル使用高速版 ******/
int solver_second_fast(obj_t *m, double *dconst, double b0, double b1, double b2) {
double aa = dconst[0];
if (fiszero(aa)) {
return 0;
} else {
double neg_bb = dconst[1] * b0 + dconst[2] * b1 + dconst[3] * b2;
double cc0 = quadratic(m, b0, b1, b2);
double cc = o_form(m) == 3 ? cc0 - 1.0 : cc0;
double d = fsqr(neg_bb) - aa * cc;
if (fispos(d)) {
if (o_isinvert(m)) {
solver_dist = (neg_bb + sqrt(d)) * dconst[4];
} else {
solver_dist = (neg_bb - sqrt(d)) * dconst[4];
}
return 1;
} else {
return 0;
}
}
}
/**** solver のdirvecテーブル使用高速版 *******/
int solver_fast(int index, dvec_t *dirvec, vec_t *org) {
obj_t *m = &objects[index];
double b0 = org->x - o_param_x(m);
double b1 = org->y - o_param_y(m);
double b2 = org->z - o_param_z(m);
double **dconsts = d_const(dirvec);
double *dconst = dconsts[index];
int m_shape = o_form(m);
int ret;
if (m_shape == 1) {
ret = solver_rect_fast(m, d_vec(dirvec), dconst, b0, b1, b2);
} else if (m_shape == 2) {
ret = solver_surface_fast(m, dconst, b0, b1, b2);
} else {
ret = solver_second_fast(m, dconst, b0, b1, b2);
}
return ret;
}
/* solver_surfaceのdirvec+startテーブル使用高速版 */
int solver_surface_fast2(obj_t *m, double *dconst, vec4_t *sconst, double b0, double b1, double b2) {
if (fisneg(dconst[0])) {
solver_dist = dconst[0] * sconst->w;
return 1;
} else {
return 0;
}
}
/* solver_secondのdirvec+startテーブル使用高速版 */
int solver_second_fast2(obj_t *m, double *dconst, vec4_t *sconst, double b0, double b1, double b2) {
double aa = dconst[0];
if (fiszero(aa)) {
return 0;
} else {
double neg_bb = dconst[1] * b0 + dconst[2] * b1 + dconst[3] * b2;
double cc = sconst->w;
double d = fsqr(neg_bb) - aa * cc;
if (fispos(d)) {
if (o_isinvert(m)) {
solver_dist = (neg_bb + sqrt(d)) * dconst[4];
} else {
solver_dist = (neg_bb - sqrt(d)) * dconst[4];
}
return 1;
} else {
return 0;
}
}
}
/* solverの、dirvec+startテーブル使用高速版 */
int solver_fast2(int index, dvec_t *dirvec) {
obj_t *m = &objects[index];
vec4_t *sconst = o_param_ctbl(m);
double b0 = sconst->x;