Ptex: PtexFilters.cpp Source File

Ptex

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

PtexFilters.cpp
Go to the documentation of this file.
1 /*
2 PTEX SOFTWARE
3 Copyright 2009 Disney Enterprises, Inc. All rights reserved
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
18 Studios" or the names of its contributors may NOT be used to
19 endorse or promote products derived from this software without
20 specific prior written permission from Walt Disney Pictures.
21
22 Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
23 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
25 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
26 IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
31 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34 */
35
36 #include "PtexPlatform.h"
37 #include "Ptexture.h"
38 #include "PtexSeparableFilter.h"
39 #include "PtexSeparableKernel.h"
40 #include "PtexTriangleFilter.h"
41
42 namespace {
43
45 class PtexPointFilter : public PtexFilter, public Ptex
46 {
47 public:
48 PtexPointFilter(PtexTexture* tx) : _tx(tx) {}
49 virtual void release() { delete this; }
50 virtual void eval(float* result, int firstchan, int nchannels,
51 int faceid, float u, float v,
52 float /*uw1*/, float /*vw1*/, float /*uw2*/, float /*vw2*/,
53 float /*width*/, float /*blur*/)
54 {
55 if (!_tx || nchannels <= 0) return;
56 if (faceid < 0 || faceid >= _tx->numFaces()) return;
57 const FaceInfo& f = _tx->getFaceInfo(faceid);
58 int resu = f.res.u(), resv = f.res.v();
59 int ui = PtexUtils::clamp(int(u*(float)resu), 0, resu-1);
60 int vi = PtexUtils::clamp(int(v*(float)resv), 0, resv-1);
61 _tx->getPixel(faceid, ui, vi, result, firstchan, nchannels);
62 }
63
64 private:
65 PtexTexture* _tx;
66 };
67
68
70 class PtexPointFilterTri : public PtexFilter, public Ptex
71 {
72 public:
73 PtexPointFilterTri(PtexTexture* tx) : _tx(tx) {}
74 virtual void release() { delete this; }
75 virtual void eval(float* result, int firstchan, int nchannels,
76 int faceid, float u, float v,
77 float /*uw1*/, float /*vw1*/, float /*uw2*/, float /*vw2*/,
78 float /*width*/, float /*blur*/)
79 {
80 if (!_tx || nchannels <= 0) return;
81 if (faceid < 0 || faceid >= _tx->numFaces()) return;
82 const FaceInfo& f = _tx->getFaceInfo(faceid);
83 int res = f.res.u();
84 int resm1 = res - 1;
85 float ut = u * (float)res, vt = v * (float)res;
86 int ui = PtexUtils::clamp(int(ut), 0, resm1);
87 int vi = PtexUtils::clamp(int(vt), 0, resm1);
88 float uf = ut - (float)ui, vf = vt - (float)vi;
89
90 if (uf + vf <= 1.0f) {
91 // "even" triangles are stored in lower-left half-texture
92 _tx->getPixel(faceid, ui, vi, result, firstchan, nchannels);
93 }
94 else {
95 // "odd" triangles are stored in upper-right half-texture
96 _tx->getPixel(faceid, resm1-vi, resm1-ui, result, firstchan, nchannels);
97 }
98 }
99
100 private:
101 PtexTexture* _tx;
102 };
103
104
116 class PtexWidth4Filter : public PtexSeparableFilter
117 {
118 public:
119 typedef float KernelFn(float x, const float* c);
120
121 PtexWidth4Filter(PtexTexture* tx, const PtexFilter::Options& opts, KernelFn k, const float* c = 0)
122 : PtexSeparableFilter(tx, opts), _k(k), _c(c) {}
123
124 virtual void buildKernel(PtexSeparableKernel& k, float u, float v, float uw, float vw,
125 Res faceRes)
126 {
127 buildKernelAxis(k.res.ulog2, k.u, k.uw, k.ku, u, uw, faceRes.ulog2);
128 buildKernelAxis(k.res.vlog2, k.v, k.vw, k.kv, v, vw, faceRes.vlog2);
129 }
130
131 private:
132
133 float blur(float x)
134 {
135 // 2-unit (x in -1..1) cubic hermite kernel
136 // this produces a blur roughly 1.5 times that of the 4-unit b-spline kernel
137 x = fabsf(x);
138 return x < 1.0f ? (2.0f*x-3.0f)*x*x+1.0f : 0.0f;
139 }
140
141 void buildKernelAxis(int8_t& k_ureslog2, int& k_u, int& k_uw, float* ku,
142 float u, float uw, int f_ureslog2)
143 {
144 // build 1 axis (note: "u" labels may repesent either u or v axis)
145
146 // clamp filter width to no smaller than a texel
147 uw = PtexUtils::max(uw, 1.0f/(float)(1<<f_ureslog2));
148
149 // compute desired texture res based on filter width
150 k_ureslog2 = (int8_t)PtexUtils::calcResFromWidth(uw);
151 int resu = 1 << k_ureslog2;
152 float uwlo = 1.0f/(float)resu; // smallest filter width for this res
153
154 // compute lerp weights (amount to blend towards next-lower res)
155 float lerp2 = _options.lerp ? (uw-uwlo)/uwlo : 0;
156 float lerp1 = 1.0f-lerp2;
157
158 // adjust for large filter widths
159 if (uw >= .25f) {
160 if (uw < .5f) {
161 k_ureslog2 = 2;
162 float upix = u * 4.0f - 0.5f;
163 int u1 = int(ceilf(upix - 2)), u2 = int(ceilf(upix + 2));
164 u1 = u1 & ~1; // round down to even pair
165 u2 = (u2 + 1) & ~1; // round up to even pair
166 k_u = u1;
167 k_uw = u2-u1;
168 float x1 = (float)u1-upix;
169 for (int i = 0; i < k_uw; i+=2) {
170 float xa = x1 + (float)i, xb = xa + 1.0f, xc = (xa+xb)*0.25f;
171 // spread the filter gradually to approach the next-lower-res width
172 // at uw = .5, s = 1.0; at uw = 1, s = 0.8
173 float s = 1.0f/(uw + .75f);
174 float ka = _k(xa, _c), kb = _k(xb, _c), kc = blur(xc*s);
175 ku[i] = ka * lerp1 + kc * lerp2;
176 ku[i+1] = kb * lerp1 + kc * lerp2;
177 }
178 return;
179 }
180 else if (uw < 1) {
181 k_ureslog2 = 1;
182 float upix = u * 2.0f - 0.5f;
183 k_u = int(floorf(u - .5f))*2;
184 k_uw = 4;
185 float x1 = (float)k_u-upix;
186 for (int i = 0; i < k_uw; i+=2) {
187 float xa = x1 + (float)i, xb = xa + 1.0f, xc = (xa+xb)*0.5f;
188 // spread the filter gradually to approach the next-lower-res width
189 // at uw = .5, s = .8; at uw = 1, s = 0.5
190 float s = 1.0f/(uw*1.5f + .5f);
191 float ka = blur(xa*s), kb = blur(xb*s), kc = blur(xc*s);
192 ku[i] = ka * lerp1 + kc * lerp2;
193 ku[i+1] = kb * lerp1 + kc * lerp2;
194 }
195 return;
196 }
197 else {
198 // use res 0 (1 texel per face) w/ no lerping
199 // (future: use face-blended values for filter > 2)
200 k_ureslog2 = 0;
201 float upix = u - .5f;
202 k_uw = 2;
203 float ui = floorf(upix);
204 k_u = int(ui);
205 ku[0] = blur(upix-ui);
206 ku[1] = 1-ku[0];
207 return;
208 }
209 }
210
211 // convert from normalized coords to pixel coords
212 float upix = u * (float)resu - 0.5f;
213 float uwpix = uw * (float)resu;
214
215 // find integer pixel extent: [u,v] +/- [2*uw,2*vw]
216 // (kernel width is 4 times filter width)
217 float dupix = 2.0f*uwpix;
218 int u1 = int(ceilf(upix - dupix)), u2 = int(ceilf(upix + dupix));
219
220 if (lerp2) {
221 // lerp kernel weights towards next-lower res
222 // extend kernel width to cover even pairs
223 u1 = u1 & ~1;
224 u2 = (u2 + 1) & ~1;
225 k_u = u1;
226 k_uw = u2-u1;
227
228 // compute kernel weights
229 float step = 1.0f/uwpix, x1 = ((float)u1-upix)*(float)step;
230 for (int i = 0; i < k_uw; i+=2) {
231 float xa = x1 + (float)i*step, xb = xa + step, xc = (xa+xb)*0.5f;
232 float ka = _k(xa, _c), kb = _k(xb, _c), kc = _k(xc, _c);
233 ku[i] = ka * lerp1 + kc * lerp2;
234 ku[i+1] = kb * lerp1 + kc * lerp2;
235 }
236 }
237 else {
238 k_u = u1;
239 k_uw = u2-u1;
240 // compute kernel weights
241 float x1 = ((float)u1-upix)/uwpix, step = 1.0f/uwpix;
242 for (int i = 0; i < k_uw; i++) ku[i] = _k(x1 + (float)i*step, _c);
243 }
244 }
245
246 KernelFn* _k; // kernel function
247 const float* _c; // kernel coefficients (if any)
248 };
249
250
252 class PtexBicubicFilter : public PtexWidth4Filter
253 {
254 public:
255 PtexBicubicFilter(PtexTexture* tx, const PtexFilter::Options& opts, float sharpness)
256 : PtexWidth4Filter(tx, opts, kernelFn, _coeffs)
257 {
258 // compute Cubic filter coefficients:
259 // abs(x) < 1:
260 // 1/6 * ((12 - 9*B - 6*C)*x^3 + (-18 + 12*B + 6*C)*x^2 + (6 - 2*B))
261 // == c[0]*x^3 + c[1]*x^2 + c[2]
262 // abs(x) < 2:
263 // 1/6 * ((-B - 6*C)*x^3 + (6*B + 30*C)*x^2 + (-12*B - 48*C)*x + (8*B + 24*C))
264 // == c[3]*x^3 + c[4]*x^2 + c[5]*x + c[6]
265 // else: 0
266
267 float B = 1.0f - sharpness; // choose C = (1-B)/2
268 _coeffs[0] = 1.5f - B;
269 _coeffs[1] = 1.5f * B - 2.5f;
270 _coeffs[2] = 1.0f - float(1.0/3.0) * B;
271 _coeffs[3] = float(1.0/3.0) * B - 0.5f;
272 _coeffs[4] = 2.5f - 1.5f * B;
273 _coeffs[5] = 2.0f * B - 4.0f;
274 _coeffs[6] = 2.0f - float(2.0/3.0) * B;
275 }
276
277 private:
278 static float kernelFn(float x, const float* c)
279 {
280 x = fabsf(x);
281 if (x < 1.0f) return (c[0]*x + c[1])*x*x + c[2];
282 else if (x < 2.0f) return ((c[3]*x + c[4])*x + c[5])*x + c[6];
283 else return 0.0f;
284 }
285
286 float _coeffs[7]; // filter coefficients for current sharpness
287 };
288
289
290
292 class PtexGaussianFilter : public PtexWidth4Filter
293 {
294 public:
295 PtexGaussianFilter(PtexTexture* tx, const PtexFilter::Options& opts)
296 : PtexWidth4Filter(tx, opts, kernelFn) {}
297
298 private:
299 static float kernelFn(float x, const float*)
300 {
301 return (float)exp(-2.0f*x*x);
302 }
303 };
304
305
306
311 class PtexBoxFilter : public PtexSeparableFilter
312 {
313 public:
314 PtexBoxFilter(PtexTexture* tx, const PtexFilter::Options& opts)
315 : PtexSeparableFilter(tx, opts) {}
316
317 protected:
318 virtual void buildKernel(PtexSeparableKernel& k, float u, float v, float uw, float vw,
319 Res faceRes)
320 {
321 // clamp filter width to no larger than 1.0
322 uw = PtexUtils::min(uw, 1.0f);
323 vw = PtexUtils::min(vw, 1.0f);
324
325 // clamp filter width to no smaller than a texel
326 uw = PtexUtils::max(uw, 1.0f/((float)faceRes.u()));
327 vw = PtexUtils::max(vw, 1.0f/((float)faceRes.v()));
328
329 // compute desired texture res based on filter width
330 uint8_t ureslog2 = (uint8_t)PtexUtils::calcResFromWidth(uw);
331 uint8_t vreslog2 = (uint8_t)PtexUtils::calcResFromWidth(vw);
332 Res res(ureslog2, vreslog2);
333 k.res = res;
334
335 // convert from normalized coords to pixel coords
336 u = u * (float)k.res.u();
337 v = v * (float)k.res.v();
338 uw *= (float)k.res.u();
339 vw *= (float)k.res.v();
340
341 // find integer pixel extent: [u,v] +/- [uw/2,vw/2]
342 // (box is 1 unit wide for a 1 unit filter period)
343 float u1 = u - 0.5f*uw, u2 = u + 0.5f*uw;
344 float v1 = v - 0.5f*vw, v2 = v + 0.5f*vw;
345 float u1floor = floorf(u1), u2ceil = ceilf(u2);
346 float v1floor = floorf(v1), v2ceil = ceilf(v2);
347 k.u = int(u1floor);
348 k.v = int(v1floor);
349 k.uw = int(u2ceil)-k.u;
350 k.vw = int(v2ceil)-k.v;
351
352 // compute kernel weights along u and v directions
353 computeWeights(k.ku, k.uw, 1.0f-(u1-u1floor), 1.0f-(u2ceil-u2));
354 computeWeights(k.kv, k.vw, 1.0f-(v1-v1floor), 1.0f-(v2ceil-v2));
355 }
356
357 private:
358 void computeWeights(float* kernel, int size, float f1, float f2)
359 {
360 assert(size >= 1 && size <= 3);
361
362 if (size == 1) {
363 kernel[0] = f1 + f2 - 1.0f;
364 }
365 else {
366 kernel[0] = f1;
367 for (int i = 1; i < size-1; i++) kernel[i] = 1.0f;
368 kernel[size-1] = f2;
369 }
370 }
371 };
372
373
375 class PtexBilinearFilter : public PtexSeparableFilter
376 {
377 public:
378 PtexBilinearFilter(PtexTexture* tx, const PtexFilter::Options& opts)
379 : PtexSeparableFilter(tx, opts) {}
380
381 protected:
382 virtual void buildKernel(PtexSeparableKernel& k, float u, float v, float uw, float vw,
383 Res faceRes)
384 {
385 // clamp filter width to no larger than 1.0
386 uw = PtexUtils::min(uw, 1.0f);
387 vw = PtexUtils::min(vw, 1.0f);
388
389 // clamp filter width to no smaller than a texel
390 uw = PtexUtils::max(uw, 1.0f/((float)faceRes.u()));
391 vw = PtexUtils::max(vw, 1.0f/((float)faceRes.v()));
392
393 uint8_t ureslog2 = (uint8_t)PtexUtils::calcResFromWidth(uw);
394 uint8_t vreslog2 = (uint8_t)PtexUtils::calcResFromWidth(vw);
395 Res res(ureslog2, vreslog2);
396 k.res = res;
397
398 // convert from normalized coords to pixel coords
399 float upix = u * (float)k.res.u() - 0.5f;
400 float vpix = v * (float)k.res.v() - 0.5f;
401
402 float ufloor = floorf(upix);
403 float vfloor = floorf(vpix);
404 k.u = int(ufloor);
405 k.v = int(vfloor);
406 k.uw = 2;
407 k.vw = 2;
408
409 // compute kernel weights
410 float ufrac = upix-ufloor, vfrac = vpix-vfloor;
411 k.ku[0] = 1.0f - ufrac;
412 k.ku[1] = ufrac;
413 k.kv[0] = 1.0f - vfrac;
414 k.kv[1] = vfrac;
415 }
416 };
417
418 } // end local namespace
419
420
421 PtexFilter* PtexFilter::getFilter(PtexTexture* tex, const PtexFilter::Options& opts)
422 {
423 switch (tex->meshType()) {
424 case Ptex::mt_quad:
425 switch (opts.filter) {
426 case f_point: return new PtexPointFilter(tex);
427 case f_bilinear: return new PtexBilinearFilter(tex, opts);
428 default:
429 case f_box: return new PtexBoxFilter(tex, opts);
430 case f_gaussian: return new PtexGaussianFilter(tex, opts);
431 case f_bicubic: return new PtexBicubicFilter(tex, opts, opts.sharpness);
432 case f_bspline: return new PtexBicubicFilter(tex, opts, 0.f);
433 case f_catmullrom: return new PtexBicubicFilter(tex, opts, 1.f);
434 case f_mitchell: return new PtexBicubicFilter(tex, opts, 2.f/3.f);
435 }
436 break;
437
438 case Ptex::mt_triangle:
439 switch (opts.filter) {
440 case f_point: return new PtexPointFilterTri(tex);
441 default: return new PtexTriangleFilter(tex, opts);
442 }
443 break;
444 }
445 return 0;
446 }
PtexSeparableKernel::v
int v
Definition: PtexSeparableKernel.h:49
Ptex::mt_quad
Mesh is quad-based.
Definition: Ptexture.h:79
Ptex
Common data structures and enums used throughout the API.
Definition: Ptexture.h:73
PtexFilter::f_box
Box filter.
Definition: Ptexture.h:871
PtexSeparableKernel::kv
float * kv
Definition: PtexSeparableKernel.h:52
PtexSeparableKernel
Definition: PtexSeparableKernel.h:46
PtexUtils::min
static T min(T a, T b)
Definition: PtexUtils.h:116
PtexFilter::getFilter
static PtexFilter * getFilter(PtexTexture *tx, const Options &opts)
Definition: PtexFilters.cpp:421
Ptex::mt_triangle
Mesh is triangle-based.
Definition: Ptexture.h:78
PtexSeparableFilter
Definition: PtexSeparableFilter.h:43
PtexTriangleFilter.h
Res
Pixel resolution of a given texture.
Definition: Ptexture.h:274
PtexSeparableKernel::ku
float * ku
Definition: PtexSeparableKernel.h:51
PtexFilter::f_bilinear
Bi-linear interpolation.
Definition: Ptexture.h:870
PtexPlatform.h
Platform-specific classes, functions, and includes.
Ptex::Res::v
int v() const
V resolution in texels.
Definition: Ptexture.h:181
PtexSeparableFilter.h
Res::vlog2
int8_t vlog2
log base 2 of v resolution, in texels
Definition: Ptexture.h:276
PtexTexture::meshType
virtual Ptex::MeshType meshType()=0
Type of mesh for which texture data is defined.
Ptex::Res::u
int u() const
U resolution in texels.
Definition: Ptexture.h:178
Ptex::Res::vlog2
int8_t vlog2
log base 2 of v resolution, in texels
Definition: Ptexture.h:163
PtexUtils::clamp
static T clamp(T x, T lo, T hi)
Definition: PtexUtils.h:122
PtexSeparableKernel::uw
int uw
Definition: PtexSeparableKernel.h:50
PtexSeparableKernel::res
Res res
Definition: PtexSeparableKernel.h:48
Res::ulog2
int8_t ulog2
log base 2 of u resolution, in texels
Definition: Ptexture.h:275
if
if(WIN32) add_definitions(/DPTEX_EXPORTS) endif(WIN32) set(SRCS PtexCache.cpp PtexFilters.cpp PtexHalf.cpp PtexReader.cpp PtexSeparableFilter.cpp PtexSeparableKernel.cpp PtexTriangleFilter.cpp PtexTriangleKernel.cpp PtexUtils.cpp PtexWriter.cpp) add_library(Ptex_static STATIC $
Definition: ptex/CMakeLists.txt:1
FaceInfo
Information about a face, as stored in the Ptex file header.
Definition: Ptexture.h:350
PtexUtils::calcResFromWidth
static int calcResFromWidth(float w)
Definition: PtexUtils.h:82
PtexSeparableKernel.h
PtexSeparableKernel::u
int u
Definition: PtexSeparableKernel.h:49
PtexFilter::f_mitchell
Mitchell (equivalent to bi-cubic w/ sharpness=2/3)
Definition: Ptexture.h:876
PtexFilter::f_point
Point-sampled (no filtering)
Definition: Ptexture.h:869
PtexFilter::Options::filter
FilterType filter
Filter type.
Definition: Ptexture.h:882
Res::u
int u() const
U resolution in texels.
Definition: Ptexture.h:291
PtexFilter::f_catmullrom
Catmull-Rom (equivalent to bi-cubic w/ sharpness=1)
Definition: Ptexture.h:875
PtexFilter::f_bspline
BSpline (equivalent to bi-cubic w/ sharpness=0)
Definition: Ptexture.h:874
PtexSeparableKernel::vw
int vw
Definition: PtexSeparableKernel.h:50
Ptex::Res::ulog2
int8_t ulog2
log base 2 of u resolution, in texels
Definition: Ptexture.h:162
PtexFilter::Options::sharpness
float sharpness
Filter sharpness, 0..1 (for general bi-cubic filter only).
Definition: Ptexture.h:884
PtexTexture
Interface for reading data from a ptex file.
Definition: Ptexture.h:439
PtexFilter::f_gaussian
Gaussian filter.
Definition: Ptexture.h:872
PtexUtils
Definition: PtexUtils.h:41
PtexTriangleFilter
Definition: PtexTriangleFilter.h:43
Res::v
int v() const
V resolution in texels.
Definition: Ptexture.h:294
PtexFilter::Options
Choose filter options.
Definition: Ptexture.h:880
FaceInfo::res
Res res
Resolution of face.
Definition: Ptexture.h:351
Ptexture.h
Public API classes for reading, writing, caching, and filtering Ptex files.
PtexFilter::f_bicubic
General bi-cubic filter (uses sharpness option)
Definition: Ptexture.h:873
PtexFilter
Interface for filtered sampling of ptex data files.
Definition: Ptexture.h:861
PtexUtils::max
static T max(T a, T b)
Definition: PtexUtils.h:119