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
|
#include "UnityPrefix.h"
#include "CubemapProcessor.h"
//--------------------------------------------------------------------------------------
//Based on CCubeMapProcessor from CubeMapGen v1.4
// Class for filtering and processing cubemaps
//
//
//--------------------------------------------------------------------------------------
// (C) 2005 ATI Research, Inc., All rights reserved.
//--------------------------------------------------------------------------------------
//used to index cube faces
#define CP_FACE_X_POS 0
#define CP_FACE_X_NEG 1
#define CP_FACE_Y_POS 2
#define CP_FACE_Y_NEG 3
#define CP_FACE_Z_POS 4
#define CP_FACE_Z_NEG 5
//used to index image edges
// NOTE.. the actual number corresponding to the edge is important
// do not change these, or the code will break
//
// CP_EDGE_LEFT is u = 0
// CP_EDGE_RIGHT is u = width-1
// CP_EDGE_TOP is v = 0
// CP_EDGE_BOTTOM is v = height-1
#define CP_EDGE_LEFT 0
#define CP_EDGE_RIGHT 1
#define CP_EDGE_TOP 2
#define CP_EDGE_BOTTOM 3
//corners of CUBE map (P or N specifys if it corresponds to the
// positive or negative direction each of X, Y, and Z
#define CP_CORNER_NNN 0
#define CP_CORNER_NNP 1
#define CP_CORNER_NPN 2
#define CP_CORNER_NPP 3
#define CP_CORNER_PNN 4
#define CP_CORNER_PNP 5
#define CP_CORNER_PPN 6
#define CP_CORNER_PPP 7
//information about cube maps neighboring face after traversing
// across an edge
struct CPCubeMapNeighbor
{
UInt8 m_Face; //index of neighboring face
UInt8 m_Edge; //edge in neighboring face that abuts this face
};
//------------------------------------------------------------------------------
// D3D cube map face specification
// mapping from 3D x,y,z cube map lookup coordinates
// to 2D within face u,v coordinates
//
// --------------------> U direction
// | (within-face texture space)
// | _____
// | | |
// | | +Y |
// | _____|_____|_____ _____
// | | | | | |
// | | -X | +Z | +X | -Z |
// | |_____|_____|_____|_____|
// | | |
// | | -Y |
// | |_____|
// |
// v V direction
// (within-face texture space)
//------------------------------------------------------------------------------
//Information about neighbors and how texture coorrdinates change across faces
// in ORDER of left, right, top, bottom (e.g. edges corresponding to u=0,
// u=1, v=0, v=1 in the 2D coordinate system of the particular face.
//Note this currently assumes the D3D cube face ordering and orientation
CPCubeMapNeighbor sg_CubeNgh[6][4] =
{
//XPOS face
{{CP_FACE_Z_POS, CP_EDGE_RIGHT },
{CP_FACE_Z_NEG, CP_EDGE_LEFT },
{CP_FACE_Y_POS, CP_EDGE_RIGHT },
{CP_FACE_Y_NEG, CP_EDGE_RIGHT }},
//XNEG face
{{CP_FACE_Z_NEG, CP_EDGE_RIGHT },
{CP_FACE_Z_POS, CP_EDGE_LEFT },
{CP_FACE_Y_POS, CP_EDGE_LEFT },
{CP_FACE_Y_NEG, CP_EDGE_LEFT }},
//YPOS face
{{CP_FACE_X_NEG, CP_EDGE_TOP },
{CP_FACE_X_POS, CP_EDGE_TOP },
{CP_FACE_Z_NEG, CP_EDGE_TOP },
{CP_FACE_Z_POS, CP_EDGE_TOP }},
//YNEG face
{{CP_FACE_X_NEG, CP_EDGE_BOTTOM},
{CP_FACE_X_POS, CP_EDGE_BOTTOM},
{CP_FACE_Z_POS, CP_EDGE_BOTTOM},
{CP_FACE_Z_NEG, CP_EDGE_BOTTOM}},
//ZPOS face
{{CP_FACE_X_NEG, CP_EDGE_RIGHT },
{CP_FACE_X_POS, CP_EDGE_LEFT },
{CP_FACE_Y_POS, CP_EDGE_BOTTOM },
{CP_FACE_Y_NEG, CP_EDGE_TOP }},
//ZNEG face
{{CP_FACE_X_POS, CP_EDGE_RIGHT },
{CP_FACE_X_NEG, CP_EDGE_LEFT },
{CP_FACE_Y_POS, CP_EDGE_TOP },
{CP_FACE_Y_NEG, CP_EDGE_BOTTOM }}
};
//The 12 edges of the cubemap, (entries are used to index into the neighbor table)
// this table is used to average over the edges.
int sg_CubeEdgeList[12][2] = {
{CP_FACE_X_POS, CP_EDGE_LEFT},
{CP_FACE_X_POS, CP_EDGE_RIGHT},
{CP_FACE_X_POS, CP_EDGE_TOP},
{CP_FACE_X_POS, CP_EDGE_BOTTOM},
{CP_FACE_X_NEG, CP_EDGE_LEFT},
{CP_FACE_X_NEG, CP_EDGE_RIGHT},
{CP_FACE_X_NEG, CP_EDGE_TOP},
{CP_FACE_X_NEG, CP_EDGE_BOTTOM},
{CP_FACE_Z_POS, CP_EDGE_TOP},
{CP_FACE_Z_POS, CP_EDGE_BOTTOM},
{CP_FACE_Z_NEG, CP_EDGE_TOP},
{CP_FACE_Z_NEG, CP_EDGE_BOTTOM}
};
//Information about which of the 8 cube corners are correspond to the
// the 4 corners in each cube face
// the order is upper left, upper right, lower left, lower right
int sg_CubeCornerList[6][4] = {
{ CP_CORNER_PPP, CP_CORNER_PPN, CP_CORNER_PNP, CP_CORNER_PNN }, // XPOS face
{ CP_CORNER_NPN, CP_CORNER_NPP, CP_CORNER_NNN, CP_CORNER_NNP }, // XNEG face
{ CP_CORNER_NPN, CP_CORNER_PPN, CP_CORNER_NPP, CP_CORNER_PPP }, // YPOS face
{ CP_CORNER_NNP, CP_CORNER_PNP, CP_CORNER_NNN, CP_CORNER_PNN }, // YNEG face
{ CP_CORNER_NPP, CP_CORNER_PPP, CP_CORNER_NNP, CP_CORNER_PNP }, // ZPOS face
{ CP_CORNER_PPN, CP_CORNER_NPN, CP_CORNER_PNN, CP_CORNER_NNN } // ZNEG face
};
//==========================================================================================================
//void FixupCubeEdges(CImageSurface *a_CubeMap, int a_FixupType, int a_FixupWidth);
//
//Apply edge fixup to a cubemap mip level.
//
//a_CubeMap [in/out] Array of 6 images comprising cubemap miplevel to apply edge fixup to.
//a_FixupType [in] Specifies the technique used for edge fixup. Choose one of the following,
// CP_FIXUP_NONE, CP_FIXUP_PULL_LINEAR, CP_FIXUP_PULL_HERMITE, CP_FIXUP_AVERAGE_LINEAR,
// CP_FIXUP_AVERAGE_HERMITE
//a_FixupWidth [in] Fixup width in texels
//
//==========================================================================================================
//--------------------------------------------------------------------------------------
// Fixup cube edges
//
// average texels on cube map faces across the edges
//--------------------------------------------------------------------------------------
void FixupCubeEdges(CImageSurface *a_CubeMap, int a_FixupType, int a_FixupWidth)
{
int i, j, k;
int face;
int edge;
int neighborFace;
int neighborEdge;
int nChannels = a_CubeMap[0].m_NumChannels;
int size = a_CubeMap[0].m_Width;
CPCubeMapNeighbor neighborInfo;
CP_ITYPE* edgeStartPtr;
CP_ITYPE* neighborEdgeStartPtr;
int edgeWalk;
int neighborEdgeWalk;
//pointer walk to walk one texel away from edge in perpendicular direction
int edgePerpWalk;
int neighborEdgePerpWalk;
//number of texels inward towards cubeface center to apply fixup to
int fixupDist;
int iFixup;
// note that if functionality to filter across the three texels for each corner, then
CP_ITYPE *cornerPtr[8][3]; //indexed by corner and face idx
CP_ITYPE *faceCornerPtrs[4]; //corner pointers for face
int cornerNumPtrs[8]; //indexed by corner and face idx
int iCorner; //corner iterator
int iFace; //iterator for faces
int corner;
//if there is no fixup, or fixup width = 0, do nothing
if((a_FixupType == CP_FIXUP_NONE) ||
(a_FixupWidth == 0) )
{
return;
}
//special case 1x1 cubemap, average face colors
if( a_CubeMap[0].m_Width == 1 )
{
//iterate over channels
for(k=0; k<nChannels; k++)
{
CP_ITYPE accum = 0.0f;
//iterate over faces to accumulate face colors
for(iFace=0; iFace<6; iFace++)
{
accum += *(a_CubeMap[iFace].m_ImgData + k);
}
//compute average over 6 face colors
accum /= 6.0f;
//iterate over faces to distribute face colors
for(iFace=0; iFace<6; iFace++)
{
*(a_CubeMap[iFace].m_ImgData + k) = accum;
}
}
return;
}
//iterate over corners
for(iCorner = 0; iCorner < 8; iCorner++ )
{
cornerNumPtrs[iCorner] = 0;
}
//iterate over faces to collect list of corner texel pointers
for(iFace=0; iFace<6; iFace++ )
{
//the 4 corner pointers for this face
faceCornerPtrs[0] = a_CubeMap[iFace].m_ImgData;
faceCornerPtrs[1] = a_CubeMap[iFace].m_ImgData + ( (size - 1) * nChannels );
faceCornerPtrs[2] = a_CubeMap[iFace].m_ImgData + ( (size) * (size - 1) * nChannels );
faceCornerPtrs[3] = a_CubeMap[iFace].m_ImgData + ( (((size) * (size - 1)) + (size - 1)) * nChannels );
//iterate over face corners to collect cube corner pointers
for(i=0; i<4; i++ )
{
corner = sg_CubeCornerList[iFace][i];
cornerPtr[corner][ cornerNumPtrs[corner] ] = faceCornerPtrs[i];
cornerNumPtrs[corner]++;
}
}
//iterate over corners to average across corner tap values
for(iCorner = 0; iCorner < 8; iCorner++ )
{
for(k=0; k<nChannels; k++)
{
CP_ITYPE cornerTapAccum;
cornerTapAccum = 0.0f;
//iterate over corner texels and average results
for(i=0; i<3; i++ )
{
cornerTapAccum += *(cornerPtr[iCorner][i] + k);
}
//divide by 3 to compute average of corner tap values
cornerTapAccum *= (1.0f / 3.0f);
//iterate over corner texels and average results
for(i=0; i<3; i++ )
{
*(cornerPtr[iCorner][i] + k) = cornerTapAccum;
}
}
}
//maximum width of fixup region is one half of the cube face size
fixupDist = std::min( a_FixupWidth, size / 2);
//iterate over the twelve edges of the cube to average across edges
for(i=0; i<12; i++)
{
face = sg_CubeEdgeList[i][0];
edge = sg_CubeEdgeList[i][1];
neighborInfo = sg_CubeNgh[face][edge];
neighborFace = neighborInfo.m_Face;
neighborEdge = neighborInfo.m_Edge;
edgeStartPtr = a_CubeMap[face].m_ImgData;
neighborEdgeStartPtr = a_CubeMap[neighborFace].m_ImgData;
edgeWalk = 0;
neighborEdgeWalk = 0;
//amount to pointer to sample taps away from cube face
edgePerpWalk = 0;
neighborEdgePerpWalk = 0;
//Determine walking pointers based on edge type
// e.g. CP_EDGE_LEFT, CP_EDGE_RIGHT, CP_EDGE_TOP, CP_EDGE_BOTTOM
switch(edge)
{
case CP_EDGE_LEFT:
// no change to faceEdgeStartPtr
edgeWalk = nChannels * size;
edgePerpWalk = nChannels;
break;
case CP_EDGE_RIGHT:
edgeStartPtr += (size - 1) * nChannels;
edgeWalk = nChannels * size;
edgePerpWalk = -nChannels;
break;
case CP_EDGE_TOP:
// no change to faceEdgeStartPtr
edgeWalk = nChannels;
edgePerpWalk = nChannels * size;
break;
case CP_EDGE_BOTTOM:
edgeStartPtr += (size) * (size - 1) * nChannels;
edgeWalk = nChannels;
edgePerpWalk = -(nChannels * size);
break;
}
//For certain types of edge abutments, the neighbor edge walk needs to
// be flipped: the cases are
// if a left edge mates with a left or bottom edge on the neighbor
// if a top edge mates with a top or right edge on the neighbor
// if a right edge mates with a right or top edge on the neighbor
// if a bottom edge mates with a bottom or left edge on the neighbor
//Seeing as the edges are enumerated as follows
// left =0
// right =1
// top =2
// bottom =3
//
//If the edge enums are the same, or the sum of the enums == 3,
// the neighbor edge walk needs to be flipped
if( (edge == neighborEdge) || ((edge + neighborEdge) == 3) )
{ //swapped direction neighbor edge walk
switch(neighborEdge)
{
case CP_EDGE_LEFT: //start at lower left and walk up
neighborEdgeStartPtr += (size - 1) * (size) * nChannels;
neighborEdgeWalk = -(nChannels * size);
neighborEdgePerpWalk = nChannels;
break;
case CP_EDGE_RIGHT: //start at lower right and walk up
neighborEdgeStartPtr += ((size - 1)*(size) + (size - 1)) * nChannels;
neighborEdgeWalk = -(nChannels * size);
neighborEdgePerpWalk = -nChannels;
break;
case CP_EDGE_TOP: //start at upper right and walk left
neighborEdgeStartPtr += (size - 1) * nChannels;
neighborEdgeWalk = -nChannels;
neighborEdgePerpWalk = (nChannels * size);
break;
case CP_EDGE_BOTTOM: //start at lower right and walk left
neighborEdgeStartPtr += ((size - 1)*(size) + (size - 1)) * nChannels;
neighborEdgeWalk = -nChannels;
neighborEdgePerpWalk = -(nChannels * size);
break;
}
}
else
{ //swapped direction neighbor edge walk
switch(neighborEdge)
{
case CP_EDGE_LEFT: //start at upper left and walk down
//no change to neighborEdgeStartPtr for this case since it points
// to the upper left corner already
neighborEdgeWalk = nChannels * size;
neighborEdgePerpWalk = nChannels;
break;
case CP_EDGE_RIGHT: //start at upper right and walk down
neighborEdgeStartPtr += (size - 1) * nChannels;
neighborEdgeWalk = nChannels * size;
neighborEdgePerpWalk = -nChannels;
break;
case CP_EDGE_TOP: //start at upper left and walk left
//no change to neighborEdgeStartPtr for this case since it points
// to the upper left corner already
neighborEdgeWalk = nChannels;
neighborEdgePerpWalk = (nChannels * size);
break;
case CP_EDGE_BOTTOM: //start at lower left and walk left
neighborEdgeStartPtr += (size) * (size - 1) * nChannels;
neighborEdgeWalk = nChannels;
neighborEdgePerpWalk = -(nChannels * size);
break;
}
}
//Perform edge walk, to average across the 12 edges and smoothly propagate change to
//nearby neighborhood
//step ahead one texel on edge
edgeStartPtr += edgeWalk;
neighborEdgeStartPtr += neighborEdgeWalk;
// note that this loop does not process the corner texels, since they have already been
// averaged across faces across earlier
for(j=1; j<(size - 1); j++)
{
//for each set of taps along edge, average them
// and rewrite the results into the edges
for(k = 0; k<nChannels; k++)
{
CP_ITYPE edgeTap, neighborEdgeTap, avgTap; //edge tap, neighborEdgeTap and the average of the two
CP_ITYPE edgeTapDev, neighborEdgeTapDev;
edgeTap = *(edgeStartPtr + k);
neighborEdgeTap = *(neighborEdgeStartPtr + k);
//compute average of tap intensity values
avgTap = 0.5f * (edgeTap + neighborEdgeTap);
//propagate average of taps to edge taps
(*(edgeStartPtr + k)) = avgTap;
(*(neighborEdgeStartPtr + k)) = avgTap;
edgeTapDev = edgeTap - avgTap;
neighborEdgeTapDev = neighborEdgeTap - avgTap;
//iterate over taps in direction perpendicular to edge, and
// adjust intensity values gradualy to obscure change in intensity values of
// edge averaging.
for(iFixup = 1; iFixup < fixupDist; iFixup++)
{
//fractional amount to apply change in tap intensity along edge to taps
// in a perpendicular direction to edge
CP_ITYPE fixupFrac = (CP_ITYPE)(fixupDist - iFixup) / (CP_ITYPE)(fixupDist);
CP_ITYPE fixupWeight;
switch(a_FixupType )
{
case CP_FIXUP_PULL_LINEAR:
{
fixupWeight = fixupFrac;
}
break;
case CP_FIXUP_PULL_HERMITE:
{
//hermite spline interpolation between 1 and 0 with both pts derivatives = 0
// e.g. smooth step
// the full formula for hermite interpolation is:
//
// [ 2 -2 1 1 ][ p0 ]
// [t^3 t^2 t 1 ][ -3 3 -2 -1 ][ p1 ]
// [ 0 0 1 0 ][ d0 ]
// [ 1 0 0 0 ][ d1 ]
//
// Where p0 and p1 are the point locations and d0, and d1 are their respective derivatives
// t is the parameteric coordinate used to specify an interpoltion point on the spline
// and ranges from 0 to 1.
// if p0 = 0 and p1 = 1, and d0 and d1 = 0, the interpolation reduces to
//
// p(t) = - 2t^3 + 3t^2
fixupWeight = ((-2.0 * fixupFrac + 3.0) * fixupFrac * fixupFrac);
}
break;
case CP_FIXUP_AVERAGE_LINEAR:
{
fixupWeight = fixupFrac;
//perform weighted average of edge tap value and current tap
// fade off weight linearly as a function of distance from edge
edgeTapDev =
(*(edgeStartPtr + (iFixup * edgePerpWalk) + k)) - avgTap;
neighborEdgeTapDev =
(*(neighborEdgeStartPtr + (iFixup * neighborEdgePerpWalk) + k)) - avgTap;
}
break;
case CP_FIXUP_AVERAGE_HERMITE:
{
fixupWeight = ((-2.0 * fixupFrac + 3.0) * fixupFrac * fixupFrac);
//perform weighted average of edge tap value and current tap
// fade off weight using hermite spline with distance from edge
// as parametric coordinate
edgeTapDev =
(*(edgeStartPtr + (iFixup * edgePerpWalk) + k)) - avgTap;
neighborEdgeTapDev =
(*(neighborEdgeStartPtr + (iFixup * neighborEdgePerpWalk) + k)) - avgTap;
}
break;
}
// vary intensity of taps within fixup region toward edge values to hide changes made to edge taps
*(edgeStartPtr + (iFixup * edgePerpWalk) + k) -= (fixupWeight * edgeTapDev);
*(neighborEdgeStartPtr + (iFixup * neighborEdgePerpWalk) + k) -= (fixupWeight * neighborEdgeTapDev);
}
}
edgeStartPtr += edgeWalk;
neighborEdgeStartPtr += neighborEdgeWalk;
}
}
}
|