This repository was archived by the owner on Jan 3, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 74
/
Copy pathTransformedAABBoxScalar.cpp
243 lines (204 loc) · 8.18 KB
/
TransformedAABBoxScalar.cpp
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
////////////////////////////////////////////////////////////////////////////////
// Copyright 2017 Intel Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy
// of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
////////////////////////////////////////////////////////////////////////////////
#include "TransformedAABBoxScalar.h"
static const UINT sBBIndexList[AABB_INDICES] =
{
// index for top
1, 3, 2,
0, 3, 1,
// index for bottom
5, 7, 4,
6, 7, 5,
// index for left
1, 7, 6,
2, 7, 1,
// index for right
3, 5, 4,
0, 5, 3,
// index for back
2, 4, 7,
3, 4, 2,
// index for front
0, 6, 5,
1, 6, 0,
};
// 0 = use min corner, 1 = use max corner
static const UINT sBBxInd[AABB_VERTICES] = { 1, 0, 0, 1, 1, 1, 0, 0 };
static const UINT sBByInd[AABB_VERTICES] = { 1, 1, 1, 1, 0, 0, 0, 0 };
static const UINT sBBzInd[AABB_VERTICES] = { 1, 1, 0, 0, 0, 1, 1, 0 };
//--------------------------------------------------------------------------
// Get the bounding box center and half vector
// Create the vertex and index list for the triangles that make up the bounding box
//--------------------------------------------------------------------------
void TransformedAABBoxScalar::CreateAABBVertexIndexList(CPUTModelDX11 *pModel)
{
mWorldMatrix = *pModel->GetWorldMatrix();
pModel->GetBoundsObjectSpace(&mBBCenter, &mBBHalf);
mRadiusSq = mBBHalf.lengthSq();
pModel->GetBoundsWorldSpace(&mBBCenterWS, &mBBHalfWS);
}
//----------------------------------------------------------------
// Determine is model is inside view frustum
//----------------------------------------------------------------
bool TransformedAABBoxScalar::IsInsideViewFrustum(CPUTCamera *pCamera)
{
return pCamera->mFrustum.IsVisible(mBBCenterWS, mBBHalfWS);
}
//----------------------------------------------------------------------------
// Determine if the occludee size is too small and if so avoid drawing it
//----------------------------------------------------------------------------
bool TransformedAABBoxScalar::IsTooSmall(const BoxTestSetupScalar &setup, float4x4 &cumulativeMatrix)
{
cumulativeMatrix = mWorldMatrix * setup.mViewProjViewport;
float w = mBBCenter.x * cumulativeMatrix.r0.w +
mBBCenter.y * cumulativeMatrix.r1.w +
mBBCenter.z * cumulativeMatrix.r2.w +
cumulativeMatrix.r3.w;
if( w > 1.0f )
{
return mRadiusSq < w * setup.radiusThreshold;
}
return false;
}
//----------------------------------------------------------------
// Trasforms the AABB vertices to screen space once every frame
//----------------------------------------------------------------
bool TransformedAABBoxScalar::TransformAABBox(float4 xformedPos[], const float4x4 &cumulativeMatrix)
{
float4 vCenter = float4(mBBCenter.x, mBBCenter.y, mBBCenter.z, 1.0);
float4 vHalf = float4(mBBHalf.x, mBBHalf.y, mBBHalf.z, 1.0);
float4 vMin = vCenter - vHalf;
float4 vMax = vCenter + vHalf;
// transforms
float4 xRow[2], yRow[2], zRow[2];
xRow[0] = float4(vMin.x, vMin.x, vMin.x, vMin.x) * cumulativeMatrix.r0;
xRow[1] = float4(vMax.x, vMax.x, vMax.x, vMax.x) * cumulativeMatrix.r0;
yRow[0] = float4(vMin.y, vMin.y, vMin.y, vMin.y) * cumulativeMatrix.r1;
yRow[1] = float4(vMax.y, vMax.y, vMax.y, vMax.y) * cumulativeMatrix.r1;
zRow[0] = float4(vMin.z, vMin.z, vMin.z, vMin.z) * cumulativeMatrix.r2;
zRow[1] = float4(vMax.z, vMax.z, vMax.z, vMax.z) * cumulativeMatrix.r2;
bool zAllIn = true;
for(UINT i = 0; i < AABB_VERTICES; i++)
{
float4 vert = cumulativeMatrix.r3;
vert += xRow[sBBxInd[i]];
vert += yRow[sBByInd[i]];
vert += zRow[sBBzInd[i]];
zAllIn = vert.z <= vert.w ? zAllIn & true : zAllIn & false;
xformedPos[i] = vert/ vert.w;
}
return zAllIn;
}
void TransformedAABBoxScalar::Gather(float4 pOut[3], UINT triId, const float4 xformedPos[])
{
for(UINT i = 0; i < 3; i++)
{
UINT index = sBBIndexList[(triId * 3) + i];
pOut[i] = xformedPos[index];
}
}
//-----------------------------------------------------------------------------------------
// Rasterize the occludee AABB and depth test it against the CPU rasterized depth buffer
// If any of the rasterized AABB pixels passes the depth test exit early and mark the occludee
// as visible. If all rasterized AABB pixels are occluded then the occludee is culled
//-----------------------------------------------------------------------------------------
bool TransformedAABBoxScalar::RasterizeAndDepthTestAABBox(UINT *pRenderTargetPixels, const float4 pXformedPos[], UINT idx)
{
float* pDepthBuffer = (float*)pRenderTargetPixels;
// Rasterize the AABB triangles
for(UINT i = 0; i < AABB_TRIANGLES; i++)
{
float4 xformedPos[3];
Gather(xformedPos, i, pXformedPos);
int fxPtX[3], fxPtY[3];
float Z[3];
for(UINT j = 0; j < 3; j++)
{
fxPtX[j] = (int)(xformedPos[j].x + 0.5);
fxPtY[j] = (int)(xformedPos[j].y + 0.5);
Z[j] = xformedPos[j].z;
}
// Fab(x, y) = Ax + By + C = 0
// Fab(x, y) = (ya - yb)x + (xb - xa)y + (xa * yb - xb * ya) = 0
// Compute A = (ya - yb) for the 3 line segments that make up each triangle
int A0 = fxPtY[1] - fxPtY[2];
int A1 = fxPtY[2] - fxPtY[0];
int A2 = fxPtY[0] - fxPtY[1];
// Compute B = (xb - xa) for the 3 line segments that make up each triangle
int B0 = fxPtX[2] - fxPtX[1];
int B1 = fxPtX[0] - fxPtX[2];
int B2 = fxPtX[1] - fxPtX[0];
// Compute C = (xa * yb - xb * ya) for the 3 line segments that make up each triangle
int C0 = fxPtX[1] * fxPtY[2] - fxPtX[2] * fxPtY[1];
int C1 = fxPtX[2] * fxPtY[0] - fxPtX[0] * fxPtY[2];
int C2 = fxPtX[0] * fxPtY[1] - fxPtX[1] * fxPtY[0];
// Compute triangle area
int triArea = (fxPtX[1] - fxPtX[0]) * (fxPtY[2] - fxPtY[0]) - (fxPtX[0] - fxPtX[2]) * (fxPtY[0] - fxPtY[1]);
float oneOverTriArea = (1.0f/float(triArea));
Z[1] = (Z[1] - Z[0]) * oneOverTriArea;
Z[2] = (Z[2] - Z[0]) * oneOverTriArea;
// Use bounding box traversal strategy to determine which pixels to rasterize
int startX = max(min(min(fxPtX[0], fxPtX[1]), fxPtX[2]), 0) & int(0xFFFFFFFE);
int endX = min(max(max(fxPtX[0], fxPtX[1]), fxPtX[2]), SCREENW-1);
int startY = max(min(min(fxPtY[0], fxPtY[1]), fxPtY[2]), 0) & int(0xFFFFFFFE);
int endY = min(max(max(fxPtY[0], fxPtY[1]), fxPtY[2]), SCREENH-1);
//Skip triangle if area is zero
if(triArea <= 0)
{
continue;
}
int rowIdx = (startY * SCREENW + startX);
int col = startX;
int row = startY;
int alpha0 = (A0 * col) + (B0 * row) + C0;
int beta0 = (A1 * col) + (B1 * row) + C1;
int gama0 = (A2 * col) + (B2 * row) + C2;
float zx = A1 * Z[1] + A2 * Z[2];
// Incrementally compute Fab(x, y) for all the pixels inside the bounding box formed by (startX, endX) and (startY, endY)
for(int r = startY; r < endY; r++,
row++,
rowIdx = rowIdx + SCREENW,
alpha0 += B0,
beta0 += B1,
gama0 += B2)
{
// Compute barycentric coordinates
int index = rowIdx;
int alpha = alpha0;
int beta = beta0;
int gama = gama0;
float depth = Z[0] + Z[1] * beta + Z[2] * gama;
bool anyOut = false;
for(int c = startX; c < endX; c++,
index++,
alpha = alpha + A0,
beta = beta + A1,
gama = gama + A2,
depth += zx)
{
//Test Pixel inside triangle
int mask = alpha | beta | gama;
float previousDepthValue = pDepthBuffer[index];
anyOut = (mask > 0 && depth >= previousDepthValue) ? anyOut | true : anyOut | false;
}//for each column
if(anyOut)
{
return true;
}
}// for each row
}// for each triangle
return false;
}