9. -
. ,
. ,
.
, ,
. ,
. ( -) , ,
.
.
– , -
, –
. ,
.
.
. ( . . 1.2)
Int Ray ( – ):
Pwri Pwri
Int ( Ray ) = K C ∑ C i dot ( N , L ) + K ∑ C i dot ( R ,V ) P + K r Int ( RayR ) (1.1)
d m 2 i s 2 i
i Ti i Ti
Int (Ray ) - , . Int ( Ray ) ∈ [0..1]
dot ( a, b) -
C - .C ∈ [0..1]
m m
K - . K ∈ [0, ∞)
d d
C - i- . C ∈ [0..1]
i i
Pwr - i- . Pwr ∈ [0, ∞)
i i
T - i-
i
N -
L - , i-
i
K - . K ∈ [0, ∞)
s s
R -
i
V - ,
P - . P ∈ [1, ∞)
K - . K ∈ [0,1]
r r
RayR - , Ray
8
10. ,
, . -
.
. -
.
, RGB. -
: , -
. (1.1)
.
. 1.2: ( ).
Int Int:
d
Pwri
Int =K C ∑ Ci dot ( N , Li ) (1.2)
Ti2
d d m
i
-
π
: K ⋅ I l ⋅ cos α , α ∈ [0, ] -
d 2
Pwri
, Il = Ci -
Ti 2
( . . 1.2).
L, N– . cos α = dot ( L, N ) .
C Int Int :
s
Pwri
Int = K ∑ C dot ( Ri ,V ) P (1.3)
s s 2 i
i Ti
9
11. , .
-
. R - -
, V- , . -
: K ⋅ I l ⋅ cos P y ,
s
γ - R V. P -
« » « » . R V- ,
: K ⋅ I l ⋅ dot ( R , V ) P .
s
V = − Ray.Dir , Ray.Dir -
R = − L + 2 ⋅ dot ( L , N ) ⋅ N
K , K , K - , .
a d s
. ,
, . -
, , -
. . 1.3 -
.
. 1.3: .
- ,
.
-
10
12. . -
,
3D-
[CPC84].
1.3.
.
3D- ,
-
. -
, .
, -
3D-
. ,
. -
3D- ,
. -
. -
SAH (Surface Area
Heuristic [Hav01, GS87]). , -
N, :
SA( N L ) SA( N R )
SAHCost ( N ) = ⋅ Count ( N L ) + ⋅ Count ( N R ) (1.4)
SA( N ) SA( N )
: SA(N) –
AABB(N) N; Count(N) – N; NL NR – N.
(1.4) [Hav01].
, -
. -
.
(1.4). -
.
,
- [Wal07; WBS07] [HMFS07; Gar08]. -
(1.4),
, .
11
31. SIMD- AABB ( RayAABBTest, . 2.1).
// ri – индекс SIMD-луча
// P.Org4[0] = (__m128 *) forg[0]; и т.д. – см. рис. 2.4. P.T4 = (__m128 *) fT;
// iDir4 = 1 / P.Dir4, т.е. обратное значение направления предварительно вычислено
// sse_0 = [0, 0, 0, 0]
// операторы *, -, + выполняют _mm_mul_ps, _mm_sub_ps, _mm_add_ps
void RayAABBTest(unsigned int ri, PACKET P, AABB BV) { // см. Алгоритм 2.1
// эту репликацию можно вынести за скобки (за верхний цикл по лучам)
const __m128 BV4[6] = {_mm_set_ps1(BV[0]),_mm_set_ps1(BV[1]),_mm_set_ps1(BV[2]),
_mm_set_ps1(BV[3]), _mm_set_ps1(BV[4]), _mm_set_ps1(BV[5])};
const __m128 Org[3] = {P.Org4[0][ri], P.Org4[1][ri], P.Org4[2][ri]};
const __m128 iDir[3] = {P.iDir4[0][ri], P.iDir4[1][ri], P.iDir4[1][ri]};
const __m128 T[6] = {(BV4[0] - Org[0]) * iDir[0], (BV4[1] - Org[1]) * iDir[1],
(BV4[2] - Org[2]) * iDir[2], (BV4[3] - Org[0]) * iDir[0],
(BV4[4] - Org[1]) * iDir[1], (BV4[5] - Org[2]) * iDir[2]};
const __m128 taX = _mm_min_ps(T[0], T[3]), tbX = _mm_max_ps(T[0], T[3]);
const __m128 taY = _mm_min_ps(T[1], T[4]), tbY = _mm_max_ps(T[1], T[4]);
const __m128 taZ = _mm_min_ps(T[2], T[5]), tbZ = _mm_max_ps(T[2], T[5]);
const __m128 ta = _mm_max_ps(_mm_max_ps(taX, taY), _mm_max_ps(taZ,sse_0));
const __m128 tb = _mm_min_ps(_mm_min_ps(tbX, tbY), _mm_min_ps(tbZ,P.T4[ri]));
if(_mm_movemask_ps(_mm_cmple_ps(ta, tb))) // если какой-то луч пересекает AABB
return true; // то считается, что SIMD-луч пересекает AABB
return false;
}
SIMD- ( RayTriangleTest, . 2.1).
[Wal04]
( . . 2.5).
X B
Y
B` H
A
ab` C
H`
Z A`
ac`
dir
C` org
. 2.5: [org,dir] 2D- YZ.
u, v t.
, X YZ ( .
. 2.5) 2D- .
: , -
.
Cross( a, b) – , Dot(a, b) – .
[A, B, ] – , [org, dir] – ( ).
ab = B − A , ac = C − A , N = Cross( ab, ac) , N `= N / N . x = [1, N . y / N . x, N . z / N . y ]
-
1
( N`):
30
32. t = ( Dot( A, N `) − Dot(org , N `)) / Dot(dir, N `) = ( DAN − Dot(org , N `)) / Dot( dir, N `)
H = org + t ⋅ dir – .
YZ:
H `= [0, H . y, H . z ] , A`= [0, A. y , A. z ] , ab`= [0, ab. y , ab. z ] , ac`= [0, ac. y , ac. z ] , ah`= H `− A` .
H − A = u ⋅ ab + v ⋅ ac , u, v – H.
ah`= u ⋅ ab`+ v ⋅ ac` , . . u v .
ah`. y = u ⋅ ab`. y + v ⋅ ac`. y ah`. z = u ⋅ ab`. z + v ⋅ ac`. z , :
ah`. y ⋅ ac`.z − ah`.z ⋅ ac`. y ah`. y ⋅ ac`.z − ah`.z ⋅ ac`. y
u= =
ab`. y ⋅ ac`.z − ab`.z ⋅ ac`. y N .x
ab`. y ⋅ ah`.z − ab`.z ⋅ ah`. y ab`. y ⋅ ah`.z − ab`.z ⋅ ah`. y
v= = , :
ab`. y ⋅ ac`.z − ab`.z ⋅ ac`. y N .x
ac`.z − ac`. y A`.z ⋅ ac`. y − A`. y ⋅ ac`.z
u = H `. y ⋅ + H `.z ⋅ + = H `. y ⋅ KUY + H `.z ⋅ KUZ + KUD
N .x N .x N .x
− ab`.z ab`. y A`. y ⋅ ab`.z − A`.z ⋅ ab`. y
v = H `. y ⋅ + H `.z ⋅ + = H `. y ⋅ KVY + H `.z ⋅ KVZ + KVD
N .x N .x N .x
0≤t, , .
0 ≤ u , 0 ≤ v , u + v ≤1, H .
// P.Org4[0] = (__m128 *) forg[0]; и т.д. - см. рис. 2.4
// P.T4 = (__m128 *) fT; P.Tri4 = (__m128i *) ftri;
// sse_0 = [0, 0, 0, 0], sse_1 = [1, 1, 1, 1]
// __m128i NewTri4 = [TriID, TriID, TriID, TriID], где TriID – индекс треугольника A,B,C
// операторы *, -, + выполняют _mm_mul_ps, _mm_sub_ps, _mm_add_ps
// _mm_inverse_ps(a) = 1 / a (быстрое вычисление обратного значения)
void PacketTriangleTest(float3 A, float3 B, float3 C, PACKET P) { // SIMD-тест из [Wal04]
// Определить (X,Y,Z) (проекция вдоль X на плоскость YZ), где тройка может принимать значения:
// (0,1,2), (1,2,0) или (2,1,0), где 0..2 – индексы для выбора значений компонент 3D данных.
// Предварительно здесь вычислить DAN, N`, KUY, KUZ, KUD, KVY, KVZ, KVD
for(int ri = 0; ri < P.N; ri++) {
const __m128 Org[3] = {P.Org4[0][ri], P.Org4[1][ri], P.Org4[2][ri]};
const __m128 Dir[3] = {P.Dir4[0][ri], P.Dir4[1][ri], P.Dir4[2][ri]};
const __m128 Nom = DAN4 - Org[X] – N`[Y] * Org[Y] - N`[Z] * Org[Z]
const __m128 T = Nom * _mm_inverse_ps(Dir[X] + N`[Y] * Dir[Y] + N`[Z] * Dir[Z]);
__m128 mask = _mm_and_ps(_mm_cmplt_ps(sse_0, T), _mm_cmple_ps(T, P.T4[ri]));
if(!_mm_movemask_ps(mask4)) continue; // 0 < t < сохранённый t
const __m128 HY = Org[Y] + T * Dir[Y], HZ = Org[Z] + T * Dir[Z];
const __m128 U = KUY4 * HY + KUZ4 * HZ + KUD4;
mask = _mm_and_ps(mask, _mm_cmple_ps(sse_0, U));
if(!_mm_movemask_ps(mask)) continue;
const __m128 V = KVY4 * HY + KVZ4 * HZ + KVD4;
mask = _mm_and_ps(mask, _mm_and_ps(_mm_cmple_ps(sse_0, V), _mm_cmple_ps(U + V, sse_1)));
if(!_mm_movemask_ps(mask)) continue;
// если есть какое-то пересечение, то обновить t и ссылку на треуг-ник tri для SIMD-луча
// на основе полученной маски
const __m128i imask = _mm_castps_si128(mask);
P.T4[ri] = _mm_or_ps(_mm_and_ps(mask,T),_mm_andnot_ps(mask,P.T4[ri]));
P.Tri4[ri] = _mm_or_si128(_mm_and_si128(imask,NewTri4),_mm_andnot_si128(imask,P.Tri4[ri]));
}
}
31