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