예제 #1
0
void PtexTriangleFilter::applyAcrossEdge(PtexTriangleKernel& k,
                                         const Ptex::FaceInfo& f, int eid)
{
    int afid = f.adjface(eid), aeid = f.adjedge(eid);
    const Ptex::FaceInfo& af = _tx->getFaceInfo(afid);
    k.reorient(eid, aeid);
    splitAndApply(k, afid, af);
}
예제 #2
0
PTEX_NAMESPACE_BEGIN

void PtexTriangleFilter::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)
{
    // init
    if (!_tx || nChannels <= 0) return;
    if (faceid < 0 || faceid >= _tx->numFaces()) return;
    _ntxchan = _tx->numChannels();
    _dt = _tx->dataType();
    _firstChanOffset = firstChan*DataSize(_dt);
    _nchan = PtexUtils::min(nChannels, _ntxchan-firstChan);

    // get face info
    const FaceInfo& f = _tx->getFaceInfo(faceid);

    // if neighborhood is constant, just return constant value of face
    if (f.isNeighborhoodConstant()) {
        PtexPtr<PtexFaceData> data ( _tx->getData(faceid, 0) );
        if (data) {
            char* d = (char*) data->getData() + _firstChanOffset;
            Ptex::ConvertToFloat(result, d, _dt, _nchan);
        }
        return;
    }

    // clamp u and v
    u = PtexUtils::clamp(u, 0.0f, 1.0f);
    v = PtexUtils::clamp(v, 0.0f, 1.0f);

    // build kernel
    PtexTriangleKernel k;
    buildKernel(k, u, v, uw1, vw1, uw2, vw2, width, blur, f.res);

    // accumulate the weight as we apply
    _weight = 0;

    // allocate temporary result
    _result = (float*) alloca(sizeof(float)*_nchan);
    memset(_result, 0, sizeof(float)*_nchan);

    // apply to faces
    splitAndApply(k, faceid, f);

    // normalize (both for data type and cumulative kernel weight applied)
    // and output result
    float scale = 1.0f / (_weight * OneValue(_dt));
    for (int i = 0; i < _nchan; i++) result[i] = float(_result[i] * scale);

    // clear temp result
    _result = 0;
}
void PtexSeparableFilter::applyToCornerFace(PtexSeparableKernel& k, const Ptex::FaceInfo& f, int eid,
					    int cfid, const Ptex::FaceInfo& cf, int ceid)
{
    // adjust uv coord and res for face/subface boundary
    bool fIsSubface = f.isSubface(), cfIsSubface = cf.isSubface();
    if (fIsSubface != cfIsSubface) {
	if (cfIsSubface) k.adjustMainToSubface(eid + 3);
	else k.adjustSubfaceToMain(eid + 3);
    }
    
    // rotate and apply (resplit if going to a subface)
    k.rotate(eid - ceid + 2);
    if (cfIsSubface) splitAndApply(k, cfid, cf);
    else apply(k, cfid, cf);
}
void PtexSeparableFilter::applyAcrossEdge(PtexSeparableKernel& k, 
					  int faceid, const Ptex::FaceInfo& f, int eid)
{
    int afid = f.adjface(eid), aeid = f.adjedge(eid);
    const Ptex::FaceInfo* af = &_tx->getFaceInfo(afid);
    int rot = eid - aeid + 2;

    // adjust uv coord and res for face/subface boundary
    bool fIsSubface = f.isSubface(), afIsSubface = af->isSubface();
    if (fIsSubface != afIsSubface) {
	if (afIsSubface) {
	    // main face to subface transition
	    // adjust res and offset uv coord for primary subface
	    bool primary = k.adjustMainToSubface(eid);
	    if (!primary) {
		// advance ajacent face and edge id to secondary subface
		int neid = (aeid + 3) % 4;
		afid = af->adjface(neid);
		aeid = af->adjedge(neid);
		af = &_tx->getFaceInfo(afid);
		rot += neid - aeid + 2;
	    }
	}
	else {
	    // subface to main face transition
	    // Note: the transform depends on which subface the kernel is
	    // coming from.  The "primary" subface is the one the main
	    // face is pointing at.  The secondary subface adjustment
	    // happens to be the same as for the primary subface for the
	    // next edge, so the cases can be combined.
	    bool primary = (af->adjface(aeid) == faceid);
	    k.adjustSubfaceToMain(eid - primary);
	}
    }

    // rotate and apply (resplit if going to a subface)
    k.rotate(rot);
    if (afIsSubface) splitAndApply(k, afid, *af);
    else apply(k, afid, *af);
}
void PtexSeparableFilter::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)
{
    // init
    if (!_tx || nChannels <= 0) return;
    if (faceid < 0 || faceid >= _tx->numFaces()) return;
    _ntxchan = _tx->numChannels();
    _dt = _tx->dataType();
    _firstChanOffset = firstChan*DataSize(_dt);
    _nchan = PtexUtils::min(nChannels, _ntxchan-firstChan);

    // get face info
    const FaceInfo& f = _tx->getFaceInfo(faceid);

    // if neighborhood is constant, just return constant value of face
    if (f.isNeighborhoodConstant()) {
	PtexPtr<PtexFaceData> data ( _tx->getData(faceid, 0) );
	if (data) {
	    char* d = (char*) data->getData() + _firstChanOffset;
	    Ptex::ConvertToFloat(result, d, _dt, _nchan);
	}
	return;
    }

    // find filter width as bounding box of vectors w1 and w2
    float uw = fabs(uw1) + fabs(uw2), vw = fabs(vw1) + fabs(vw2);

    // handle border modes
    switch (_uMode) {
    case m_clamp: u = PtexUtils::clamp(u, 0.0f, 1.0f); break;
    case m_periodic: u = u-floor(u); break;
    case m_black: break; // do nothing
    }

    switch (_vMode) {
    case m_clamp: v = PtexUtils::clamp(v, 0.0f, 1.0f); break;
    case m_periodic: v = v-floor(v);
    case m_black: break; // do nothing
    }

    // build kernel
    PtexSeparableKernel k;
    if (f.isSubface()) {
	// for a subface, build the kernel as if it were on a main face and then downres
	uw = uw * width + blur * 2;
	vw = vw * width + blur * 2;
	buildKernel(k, u*.5, v*.5, uw*.5, vw*.5, f.res);
	if (k.res.ulog2 == 0) k.upresU();
	if (k.res.vlog2 == 0) k.upresV();
	k.res.ulog2--; k.res.vlog2--;
    }
    else {
	uw = uw * width + blur;
	vw = vw * width + blur;
	buildKernel(k, u, v, uw, vw, f.res);
    }
    k.stripZeros();

    // check kernel (debug only)
    assert(k.uw > 0 && k.vw > 0);
    assert(k.uw <= PtexSeparableKernel::kmax && k.vw <= PtexSeparableKernel::kmax);
    _weight = k.weight();

    // allocate temporary double-precision result
    _result = (double*) alloca(sizeof(double)*_nchan);
    memset(_result, 0, sizeof(double)*_nchan);

    // apply to faces
    splitAndApply(k, faceid, f);

    // normalize (both for data type and cumulative kernel weight applied)
    // and output result
    double scale = 1.0 / (_weight * OneValue(_dt));
    for (int i = 0; i < _nchan; i++) result[i] = float(_result[i] * scale);

    // clear temp result
    _result = 0;
}
void PtexSeparableFilter::applyToCorner(PtexSeparableKernel& k, int faceid, 
					const Ptex::FaceInfo& f, int eid)
{
    // traverse clockwise around corner vertex and gather corner faces
    int afid = faceid, aeid = eid;
    const FaceInfo* af = &f;
    bool prevIsSubface = af->isSubface();

    const int MaxValence = 10;
    int cfaceId[MaxValence];
    int cedgeId[MaxValence];
    const FaceInfo* cface[MaxValence];

    int numCorners = 0;
    for (int i = 0; i < MaxValence; i++) {
	// advance to next face
	int prevFace = afid;
	afid = af->adjface(aeid);
	aeid = (af->adjedge(aeid) + 1) % 4;

	// we hit a boundary or reached starting face
	// note: we need to check edge id too because we might have
	// a periodic texture (w/ toroidal topology) where all 4 corners
	// are from the same face
	if (afid < 0 || (afid == faceid && aeid == eid)) {
	    numCorners = i - 2;
	    break;
	}

	// record face info
	af = &_tx->getFaceInfo(afid);
	cfaceId[i] = afid;
	cedgeId[i] = aeid;
	cface[i] = af;

	// check to see if corner is a subface "tee"
	bool isSubface = af->isSubface();
	if (prevIsSubface && !isSubface && af->adjface((aeid+3)%4) == prevFace) 
	{
	    // adjust the eid depending on whether we started from
	    // the primary or secondary subface.
	    bool primary = (i==1);
	    k.adjustSubfaceToMain(eid + primary * 2);
	    k.rotate(eid - aeid + 3 - primary);
	    splitAndApply(k, afid, *af);
	    return;
	}
	prevIsSubface = isSubface;
    }

    if (numCorners == 1) {
	// regular case (valence 4)
	applyToCornerFace(k, f, eid, cfaceId[1], *cface[1], cedgeId[1]);
    }
    else if (numCorners > 1) {
	// valence 5+, make kernel symmetric and apply equally to each face
	// first, rotate to standard orientation, u=v=0
	k.rotate(eid + 2);
        double initialWeight = k.weight();
        double newWeight = k.makeSymmetric(initialWeight);
	for (int i = 1; i <= numCorners; i++) {
	    PtexSeparableKernel kc = k;
	    applyToCornerFace(kc, f, 2, cfaceId[i], *cface[i], cedgeId[i]);
	}
        // adjust weight for symmetrification and for additional corners
        _weight += newWeight * numCorners - initialWeight;
    }
    else {
	// valence 2 or 3, ignore corner face (just adjust weight)
	_weight -= k.weight();
    }
}