Ptex
PtexTriangleFilter.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 <math.h>
38 #include <assert.h>
39 
40 #include "PtexTriangleFilter.h"
41 #include "PtexTriangleKernel.h"
42 #include "PtexUtils.h"
43 
44 namespace {
45  inline float squared(float x) { return x*x; }
46 }
47 
48 void PtexTriangleFilter::eval(float* result, int firstChan, int nChannels,
49  int faceid, float u, float v,
50  float uw1, float vw1, float uw2, float vw2,
51  float width, float blur)
52 {
53  // init
54  if (!_tx || nChannels <= 0) return;
55  if (faceid < 0 || faceid >= _tx->numFaces()) return;
57  _dt = _tx->dataType();
58  _firstChanOffset = firstChan*DataSize(_dt);
59  _nchan = PtexUtils::min(nChannels, _ntxchan-firstChan);
60 
61  // get face info
62  const FaceInfo& f = _tx->getFaceInfo(faceid);
63 
64  // if neighborhood is constant, just return constant value of face
65  if (f.isNeighborhoodConstant()) {
66  PtexPtr<PtexFaceData> data ( _tx->getData(faceid, 0) );
67  if (data) {
68  char* d = (char*) data->getData() + _firstChanOffset;
69  Ptex::ConvertToFloat(result, d, _dt, _nchan);
70  }
71  return;
72  }
73 
74  // clamp u and v
75  u = PtexUtils::clamp(u, 0.0f, 1.0f);
76  v = PtexUtils::clamp(v, 0.0f, 1.0f);
77 
78  // build kernel
80  buildKernel(k, u, v, uw1, vw1, uw2, vw2, width, blur, f.res);
81 
82  // accumulate the weight as we apply
83  _weight = 0;
84 
85  // allocate temporary result
86  _result = (float*) alloca(sizeof(float)*_nchan);
87  memset(_result, 0, sizeof(float)*_nchan);
88 
89  // apply to faces
90  splitAndApply(k, faceid, f);
91 
92  // normalize (both for data type and cumulative kernel weight applied)
93  // and output result
94  float scale = 1.0f / (_weight * OneValue(_dt));
95  for (int i = 0; i < _nchan; i++) result[i] = float(_result[i] * scale);
96 
97  // clear temp result
98  _result = 0;
99 }
100 
101 
102 
104  float uw1, float vw1, float uw2, float vw2,
105  float width, float blur, Res faceRes)
106 {
107  const float sqrt3 = 1.7320508075688772f;
108 
109  // compute ellipse coefficients, A*u^2 + B*u*v + C*v^2 == AC - B^2/4
110  float scaleAC = 0.25f * width*width;
111  float scaleB = -2.0f * scaleAC;
112  float A = (vw1*vw1 + vw2*vw2) * scaleAC;
113  float B = (uw1*vw1 + uw2*vw2) * scaleB;
114  float C = (uw1*uw1 + uw2*uw2) * scaleAC;
115 
116  // convert to cartesian domain
117  float Ac = 0.75f * A;
118  float Bc = float(sqrt3/2) * (B-A);
119  float Cc = 0.25f * A - 0.5f * B + C;
120 
121  // compute min blur for eccentricity clamping
122  const float maxEcc = 15.0f; // max eccentricity
123  const float eccRatio = (maxEcc*maxEcc + 1.0f) / (maxEcc*maxEcc - 1.0f);
124  float X = sqrtf(squared(Ac - Cc) + squared(Bc));
125  float b_e = 0.5f * (eccRatio * X - (Ac + Cc));
126 
127  // compute min blur for texel clamping
128  // (ensure that ellipse is no smaller than a texel)
129  float b_t = squared(0.5f / (float)faceRes.u());
130 
131  // add blur
132  float b_b = 0.25f * blur * blur;
133  float b = PtexUtils::max(b_b, PtexUtils::max(b_e, b_t));
134  Ac += b;
135  Cc += b;
136 
137  // compute minor radius
138  float m = sqrtf(2.0f*(Ac*Cc - 0.25f*Bc*Bc) / (Ac + Cc + X));
139 
140  // choose desired resolution
141  int reslog2 = PtexUtils::max(0, PtexUtils::calcResFromWidth(2.0f*m));
142 
143  // convert back to triangular domain
144  A = float(4/3.0) * Ac;
145  B = float(2/sqrt3) * Bc + A;
146  C = -0.25f * A + 0.5f * B + Cc;
147 
148  // scale by kernel width
150  A *= scale;
151  B *= scale;
152  C *= scale;
153 
154  // find u,v,w extents
155  float uw = PtexUtils::min(sqrtf(C), 1.0f);
156  float vw = PtexUtils::min(sqrtf(A), 1.0f);
157  float ww = PtexUtils::min(sqrtf(A-B+C), 1.0f);
158 
159  // init kernel
160  float w = 1.0f - u - v;
161  k.set(Res((int8_t)reslog2, (int8_t)reslog2), u, v, u-uw, v-vw, w-ww, u+uw, v+vw, w+ww, A, B, C);
162 }
163 
164 
166 {
167  // do we need to split? if so, split kernel and apply across edge(s)
168  if (k.u1 < 0 && f.adjface(2) >= 0) {
170  k.splitU(ka);
171  applyAcrossEdge(ka, f, 2);
172  }
173  if (k.v1 < 0 && f.adjface(0) >= 0) {
175  k.splitV(ka);
176  applyAcrossEdge(ka, f, 0);
177  }
178  if (k.w1 < 0 && f.adjface(1) >= 0) {
180  k.splitW(ka);
181  applyAcrossEdge(ka, f, 1);
182  }
183  // apply to local face
184  apply(k, faceid, f);
185 }
186 
187 
189  const Ptex::FaceInfo& f, int eid)
190 {
191  int afid = f.adjface(eid), aeid = f.adjedge(eid);
192  const Ptex::FaceInfo& af = _tx->getFaceInfo(afid);
193  k.reorient(eid, aeid);
194  splitAndApply(k, afid, af);
195 }
196 
197 
199 {
200  // clamp kernel face (resolution and extent)
201  k.clampRes(f.res);
202  k.clampExtent();
203 
204  // build kernel iterators
205  PtexTriangleKernelIter keven, kodd;
206  k.getIterators(keven, kodd);
207  if (!keven.valid && !kodd.valid) return;
208 
209  // get face data, and apply
210  PtexPtr<PtexFaceData> dh ( _tx->getData(faceid, k.res) );
211  if (!dh) return;
212 
213  if (keven.valid) applyIter(keven, dh);
214  if (kodd.valid) applyIter(kodd, dh);
215 }
216 
217 
219 {
220  if (dh->isConstant()) {
222  _weight += k.weight;
223  }
224  else if (dh->isTiled()) {
225  Ptex::Res tileres = dh->tileRes();
226  PtexTriangleKernelIter kt = k;
227  int tileresu = tileres.u();
228  int tileresv = tileres.v();
229  kt.rowlen = tileresu;
230  int ntilesu = k.rowlen / kt.rowlen;
231  int wOffsetBase = k.rowlen - tileresu;
232  for (int tilev = k.v1 / tileresv, tilevEnd = (k.v2-1) / tileresv; tilev <= tilevEnd; tilev++) {
233  int vOffset = tilev * tileresv;
234  kt.v = k.v - (float)vOffset;
235  kt.v1 = PtexUtils::max(0, k.v1 - vOffset);
236  kt.v2 = PtexUtils::min(k.v2 - vOffset, tileresv);
237  for (int tileu = k.u1 / tileresu, tileuEnd = (k.u2-1) / tileresu; tileu <= tileuEnd; tileu++) {
238  int uOffset = tileu * tileresu;
239  int wOffset = wOffsetBase - uOffset - vOffset;
240  kt.u = k.u - (float)uOffset;
241  kt.u1 = PtexUtils::max(0, k.u1 - uOffset);
242  kt.u2 = PtexUtils::min(k.u2 - uOffset, tileresu);
243  kt.w1 = k.w1 - wOffset;
244  kt.w2 = k.w2 - wOffset;
245  PtexPtr<PtexFaceData> th ( dh->getTile(tilev * ntilesu + tileu) );
246  if (th) {
247  kt.weight = 0;
248  if (th->isConstant())
249  kt.applyConst(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan);
250  else
251  kt.apply(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan, _ntxchan);
252  _weight += kt.weight;
253  }
254  }
255  }
256  }
257  else {
259  _weight += k.weight;
260  }
261 }
void apply(PtexTriangleKernel &k, int faceid, const Ptex::FaceInfo &f)
int adjface(int eid) const
Access an adjacent face id. The eid value must be 0..3.
Definition: Ptexture.h:267
virtual int numChannels()=0
Number of channels stored in file.
void applyConst(float *dst, void *data, DataType dt, int nChan)
void splitU(PtexTriangleKernel &ka)
static int DataSize(DataType dt)
Look up size of given data type (in bytes).
Definition: Ptexture.h:132
void apply(float *dst, void *data, DataType dt, int nChan, int nTxChan)
void splitV(PtexTriangleKernel &ka)
void buildKernel(PtexTriangleKernel &k, float u, float v, float uw1, float vw1, float uw2, float vw2, float width, float blur, Res faceRes)
void reorient(int eid, int aeid)
static T min(T a, T b)
Definition: PtexUtils.h:116
Triangle filter kernel iterator (in texel coords)
bool isNeighborhoodConstant() const
Determine if neighborhood of face is constant (by checking a flag).
Definition: Ptexture.h:273
void splitAndApply(PtexTriangleKernel &k, int faceid, const Ptex::FaceInfo &f)
Platform-specific classes, functions, and includes.
int v() const
V resolution in texels.
Definition: Ptexture.h:181
static float OneValue(DataType dt)
Look up value of given data type that corresponds to the normalized value of 1.0. ...
Definition: Ptexture.h:138
#define C(eid, aeid)
Per-face texture data accessor.
Definition: Ptexture.h:388
int u() const
U resolution in texels.
Definition: Ptexture.h:178
virtual void * getData()=0
Access the data from this data block.
static T clamp(T x, T lo, T hi)
Definition: PtexUtils.h:122
virtual PtexFaceData * getTile(int tile)=0
Access a tile from the data block.
virtual void getData(int faceid, void *buffer, int stride)=0
Access texture data for a face at highest-resolution.
static int calcResFromWidth(float w)
Definition: PtexUtils.h:82
virtual int numFaces()=0
Number of faces stored in file.
Triangle filter kernel (in normalized triangle coords)
void set(Res resVal, float uVal, float vVal, float u1Val, float v1Val, float w1Val, float u2Val, float v2Val, float w2Val, float AVal, float BVal, float CVal)
EdgeId adjedge(int eid) const
Access an adjacent edge id. The eid value must be 0..3.
Definition: Ptexture.h:264
virtual Ptex::DataType dataType()=0
Type of data stored in file.
void getIterators(PtexTriangleKernelIter &ke, PtexTriangleKernelIter &ko)
Smart-pointer for acquiring and releasing API objects.
Definition: Ptexture.h:955
virtual bool isTiled()=0
True if this data block is tiled.
virtual bool isConstant()=0
True if this data block is constant.
Pixel resolution of a given texture.
Definition: Ptexture.h:161
void applyAcrossEdge(PtexTriangleKernel &k, const Ptex::FaceInfo &f, int eid)
Res res
Resolution of face.
Definition: Ptexture.h:238
static const float PtexTriangleKernelWidth
Information about a face, as stored in the Ptex file header.
Definition: Ptexture.h:237
virtual void eval(float *result, int firstchan, int nchannels, int faceid, float u, float v, float uw1, float vw1, float uw2, float vw2, float width, float blur)
Apply filter to a ptex data file.
static void ConvertToFloat(float *dst, const void *src, Ptex::DataType dt, int numChannels)
Convert a number of data values from the given data type to float.
Definition: PtexUtils.cpp:107
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)=0
Access resolution and adjacency information about a face.
void clampRes(Res fres)
void applyIter(PtexTriangleKernelIter &k, PtexFaceData *dh)
void splitW(PtexTriangleKernel &ka)
virtual Ptex::Res tileRes()=0
Resolution of each tile in this data block.
static T max(T a, T b)
Definition: PtexUtils.h:119