// compute pixel's NCC score float DepthEstimator::ScorePixel(Depth depth, const Normal& normal) { ASSERT(normal.z < 0); FOREACH(idx, images) { // center a patch of given size on the segment and fetch the pixel values in the target image const ViewData& image1 = images[idx]; float& score = scores[idx]; const Matrix3x3f H(ComputeHomographyMatrix(image1, depth, normal)); Point2f pt; int n = 0; for (int i=0; i<nSizeWindow; ++i) { for (int j=0; j<nSizeWindow; ++j) { ProjectVertex_3x3_2_2(H.val, Point2f((float)(lt0.x+j), (float)(lt0.y+i)).ptr(), pt.ptr()); if (!image1.view.image.isInsideWithBorder<float,1>(pt)) { score = 2.f; goto NEXT_IMAGE; } texels1(n++) = image1.view.image.sample(pt); } } { ASSERT(n == nTexels); // score similarity of the reference and target texture patches const float normSq1(normSqZeroMean<float,float,nTexels>(texels1.data())); const float nrm(normSq0*normSq1); if (nrm == 0.f) { score = 1.f; continue; } const float ncc(texels0.dot(texels1)/SQRT(nrm)); score = 1.f - CLAMP(ncc, -1.f, 1.f); // encourage smoothness FOREACHPTR(pNbr, neighborsData) { score *= 1.f - (1.f - smoothBonusDepth) * EXP(SQUARE(DepthSimilarity(depth, pNbr->depth)) * smoothSigmaDepth); score *= 1.f - (1.f - smoothBonusNormal) * EXP(SQUARE(ACOS(ComputeAngle<float,float>(normal.ptr(), pNbr->normal.ptr()))) * smoothSigmaNormal); } } NEXT_IMAGE:; }
void Mesh ::getDifferentialGeometry(const Triangle &tri, const Point &p, const float b1, const float b2, DifferentialGeometry &dg) const { // shorthand const Point &p1 = mPoints[tri[0]]; const Point &p2 = mPoints[tri[1]]; const Point &p3 = mPoints[tri[2]]; // compute the last barycentric coordinate float b0 = 1.0f - b1 - b2; // XXX why do we do this here and not getDifferentialGeometry()? // interpolate normal? Normal ng; if(mInterpolateNormals) { // get each vertex's Normals const Mesh::NormalList &norms = getNormals(); const Normal &n1 = norms[tri[0]]; const Normal &n2 = norms[tri[1]]; const Normal &n3 = norms[tri[2]]; ng = b0 * n1 + b1 * n2 + b2 * n3; // no need to normalize this if they are // unit-length to begin with //ng = ng.normalize(); } // end else else { // XXX just look up from mNormals ng = (p2 - p1).cross(p3 - p1).normalize(); } // end else ParametricCoordinates uv0; ParametricCoordinates uv1; ParametricCoordinates uv2; getParametricCoordinates(tri, uv0, uv1, uv2); // compute deltas for partial derivatives float du1 = uv0[0] - uv2[0]; float du2 = uv1[0] - uv2[0]; float dv1 = uv0[1] - uv2[1]; float dv2 = uv1[1] - uv2[1]; Vector dp1 = p1 - p3, dp2 = p2 - p3; float determinant = du1 * dv2 - dv1 * du2; Vector dpdu, dpdv; if(determinant == 0.0) { // handle zero determinant case dpdu = ng.orthogonalVector(); dpdv = ng.cross(dpdu).normalize(); } // end if else { float invDet = 1.0f / determinant; dpdu = ( dv2*dp1 - dv1*dp2) * invDet; dpdv = (-du2*dp1 + du1*dp2) * invDet; } // end else dg.setPointPartials(dpdu,dpdv); // interpolate uv using barycentric coordinates ParametricCoordinates uv; uv[0] = b0*uv0[0] + b1*uv1[0] + b2*uv2[0]; uv[1] = b0*uv0[1] + b1*uv1[1] + b2*uv2[1]; dg.setPoint(p); dg.setNormal(ng); dg.setParametricCoordinates(uv); dg.setTangent(dpdu.normalize()); // force an orthonormal basis dg.setBinormal(ng.cross(dg.getTangent())); // set the inverse surface area dg.setInverseSurfaceArea(getInverseSurfaceArea()); } // end Mesh::getDifferentialGeometry()
int main(int arg, char** argv) { if(arg != 2) { cerr << "[INFO] Please input a filename!" << endl; return -1; } string inputfile = argv[1]; ifstream infile; infile.open(inputfile.c_str(), ios::in); if(!infile) { cerr << "[ERROR] Fail to open filename!" << endl; return -1; } string line; char dest[4096]; Normal norm; norm.Init(); int32_t num = 0; SEGMENT_1* seg = SEGMENT_1::getInstance(); seg->Init(); while(getline(infile, line)) { spaceGary::StringTrim(line); vector<string> seg_parts; spaceGary::StringSplit(line, seg_parts, "##_##"); string key = seg_parts[0]; string ans = seg_parts[1]; /* if(key.length() < 1 || key.length() > 200 || ans.length() < 1 || ans.length() > 200) { cerr << "[note] length of key or ans is illegual!" << endl; cerr << "line = " << line << endl; cerr << "key = " << key << endl; cerr << "ans = " << ans << endl; continue; } */ string key_norm; string seg_norm; num ++; if(key.length() > 100) { cerr << "[INFO] key is too long, line number "<< num<< endl; continue; } if(norm.Normalize_(key, seg_norm, key_norm, seg) == -1) { cerr << "[ERROR]: Fail to get Normalize_() outcome." << endl; continue; } //cout << key_norm; //cout << "##_##"; // ans /* * seg_parts.clear(); memset(dest,0x00,4096); EncodingConvertor::getInstance()->dbc2gchar( ans.c_str(), (gchar_t*)dest, 4096/2, true); Segment_(graph,string(dest),seg_parts); for(int i = 0; i < seg_parts.size(); i++) { cout << seg_parts[i]; } */ //cout << ans; //cout << endl; // cout << seg_norm << "##_##"<< ans << endl; } return 0; }
const Matrix<T,Dynamic,Dynamic>& Sigma() const {return normal_.Sigma();};
void test1(int n) { Normal nn; Uniform uniform; cout << "Print 20 N(0,1) random numbers - should be the same as in sample output" << endl; { Format F; F.FormatType(Format::DEC_FIGS); F.Precision(12); F.Width(15); for (int i=0; i<20; i++) cout << F << nn.Next() << endl; } cout << endl; cout << "Print histograms of data from a variety distributions" << endl; cout << "Histograms should be close to those in sample output" << endl; cout << "s. mean and s. var should be close to p. mean and s. mean" << endl << endl; { Constant c(5.0); Histogram(&c, n); } { Uniform u; Histogram(&u, n); } { SumRandom sr=uniform(3)-1.5; Histogram(&sr, n); } { SumRandom sr=uniform-uniform; Histogram(&sr, n); } { Normal normal; Histogram(&normal, n); } { Cauchy cauchy; Histogram(&cauchy, n); } { AsymGenX normal10(NORMAL10, 10.0); Histogram(&normal10, n); } cout << "Mean and variance should be 10.0 and 4.0" << endl; { AsymGenX uniform2(UNIF,0.5); Histogram(&uniform2, n); } cout << "Mean and variance should be 0.5 and 0.083333" << endl; { SymGenX triang(TRIANG); Histogram(&triang, n); } cout << "Mean and variance should be 0 and 0.16667" << endl; { Poisson p(0.25); Histogram(&p, n); } { Poisson p(10.0); Histogram(&p, n); } { Poisson p(16.0); Histogram(&p, n); } { Binomial b(18,0.3); Histogram(&b, n); } { Binomial b(19,0.3); Histogram(&b, n); } { Binomial b(20,0.3); Histogram(&b, n); } { Binomial b(58,0.3); Histogram(&b, n); } { Binomial b(59,0.3); Histogram(&b, n); } { Binomial b(60,0.3); Histogram(&b, n); } { Binomial b(18,0.05); Histogram(&b, n); } { Binomial b(19,0.05); Histogram(&b, n); } { Binomial b(20,0.05); Histogram(&b, n); } { Binomial b(98,0.01); Histogram(&b, n); } { Binomial b(99,0.01); Histogram(&b, n); } { Binomial b(100,0.01); Histogram(&b, n); } { Binomial b(18,0.95); Histogram(&b, n); } { Binomial b(19,0.95); Histogram(&b, n); } { Binomial b(20,0.95); Histogram(&b, n); } { Binomial b(98,0.99); Histogram(&b, n); } { Binomial b(99,0.99); Histogram(&b, n); } { Binomial b(100,0.99); Histogram(&b, n); } { NegativeBinomial nb(100,6.0); Histogram(&nb, n); } { NegativeBinomial nb(11,9.0); Histogram(&nb, n); } { NegativeBinomial nb(11,1.9); Histogram(&nb, n); } { NegativeBinomial nb(11,0.10); Histogram(&nb, n); } { NegativeBinomial nb(1.5,1.9); Histogram(&nb, n); } { NegativeBinomial nb(1.0,1.9); Histogram(&nb, n); } { NegativeBinomial nb(0.3,19); Histogram(&nb, n); } { NegativeBinomial nb(0.3,1.9); Histogram(&nb, n); } { NegativeBinomial nb(0.3,0.05); Histogram(&nb, n); } { NegativeBinomial nb(100.8,0.18); Histogram(&nb, n); } { ChiSq c(1,2.0); Histogram(&c, n); } { ChiSq c(2,2.0); Histogram(&c, n); } { ChiSq c(3,2.0); Histogram(&c, n); } { ChiSq c(4,2.0); Histogram(&c, n); } { ChiSq c(1 ); Histogram(&c, n); } { ChiSq c(2 ); Histogram(&c, n); } { ChiSq c(3 ); Histogram(&c, n); } { ChiSq c(4 ); Histogram(&c, n); } { Gamma g1(1.0); Histogram(&g1, n); } { Gamma g2(0.5); Histogram(&g2, n); } { Gamma g3(1.01); Histogram(&g3, n); } { Gamma g4(2.0); Histogram(&g4, n); } { Pareto p1(0.5); Histogram(&p1, n); } { Pareto p2(1.5); Histogram(&p2, n); } { Pareto p3(2.5); Histogram(&p3, n); } { Pareto p4(4.5); Histogram(&p4, n); } Real probs[]={.1,.3,.05,.11,.05,.04,.05,.05,.1,.15}; Real val[]={2,3,4,6,8,12,16,24,32,48}; { DiscreteGen discrete(10,probs); Histogram(&discrete, n); } { DiscreteGen discrete(10,probs,val); Histogram(&discrete, n); } }
bool TriMesh::computeTangentSpaceBasis() { int zeroArea = 0, zeroNormals = 0; if (!m_texcoords) { bool anisotropic = hasBSDF() && m_bsdf->getType() & BSDF::EAnisotropic; if (anisotropic) Log(EError, "\"%s\": computeTangentSpace(): texture coordinates " "are required to generate tangent vectors. If you want to render with an anisotropic " "material, please make sure that all associated shapes have valid texture coordinates.", getName().c_str()); return false; } if (m_tangents) Log(EError, "Tangent space vectors have already been generated!"); if (!m_normals) { Log(EWarn, "Vertex normals are required to compute a tangent space basis!"); return false; } m_tangents = new TangentSpace[m_vertexCount]; memset(m_tangents, 0, sizeof(TangentSpace)); /* No. of triangles sharing a vertex */ uint32_t *sharers = new uint32_t[m_vertexCount]; for (size_t i=0; i<m_vertexCount; i++) { m_tangents[i].dpdu = Vector(0.0f); m_tangents[i].dpdv = Vector(0.0f); if (m_normals[i].isZero()) { zeroNormals++; m_normals[i] = Normal(1.0f, 0.0f, 0.0f); } sharers[i] = 0; } for (size_t i=0; i<m_triangleCount; i++) { uint32_t idx0 = m_triangles[i].idx[0], idx1 = m_triangles[i].idx[1], idx2 = m_triangles[i].idx[2]; const Point &v0 = m_positions[idx0]; const Point &v1 = m_positions[idx1]; const Point &v2 = m_positions[idx2]; const Point2 &uv0 = m_texcoords[idx0]; const Point2 &uv1 = m_texcoords[idx1]; const Point2 &uv2 = m_texcoords[idx2]; Vector dP1 = v1 - v0, dP2 = v2 - v0; Vector2 dUV1 = uv1 - uv0, dUV2 = uv2 - uv0; Float invDet = 1.0f, determinant = dUV1.x * dUV2.y - dUV1.y * dUV2.x; if (determinant != 0) invDet = 1.0f / determinant; Vector dpdu = ( dUV2.y * dP1 - dUV1.y * dP2) * invDet; Vector dpdv = (-dUV2.x * dP1 + dUV1.x * dP2) * invDet; if (dpdu.length() == 0.0f) { /* Recovery - required to recover from invalid geometry */ Normal n = Normal(cross(v1 - v0, v2 - v0)); Float length = n.length(); if (length != 0) { n /= length; dpdu = cross(n, dpdv); if (dpdu.length() == 0.0f) { /* At least create some kind of tangent space basis (fair enough for isotropic BxDFs) */ coordinateSystem(n, dpdu, dpdv); } } else { zeroArea++; } } if (dpdv.length() == 0.0f) { Normal n = Normal(cross(v1 - v0, v2 - v0)); Float length = n.length(); if (length != 0) { n /= length; dpdv = cross(dpdu, n); if (dpdv.length() == 0.0f) { /* At least create some kind of tangent space basis (fair enough for isotropic BxDFs) */ coordinateSystem(n, dpdu, dpdv); } } else { zeroArea++; } } m_tangents[idx0].dpdu += dpdu; m_tangents[idx1].dpdu += dpdu; m_tangents[idx2].dpdu += dpdu; m_tangents[idx0].dpdv += dpdv; m_tangents[idx1].dpdv += dpdv; m_tangents[idx2].dpdv += dpdv; sharers[idx0]++; sharers[idx1]++; sharers[idx2]++; } /* Orthogonalization + Normalization pass */ for (size_t i=0; i<m_vertexCount; i++) { Vector &dpdu = m_tangents[i].dpdu; Vector &dpdv = m_tangents[i].dpdv; if (dpdu.lengthSquared() == 0.0f || dpdv.lengthSquared() == 0.0f) { /* At least create some kind of tangent space basis (fair enough for isotropic BxDFs) */ coordinateSystem(m_normals[i], dpdu, dpdv); } else { if (sharers[i] > 0) { dpdu /= (Float) sharers[i]; dpdv /= (Float) sharers[i]; } } } delete[] sharers; if (zeroArea > 0 || zeroNormals > 0) Log(EWarn, "\"%s\": computeTangentSpace(): Mesh contains invalid " "geometry: %i zero area triangles and %i zero normals found!", m_name.c_str(), zeroArea, zeroNormals); return true; }
/* Calculate the face or vertex normals of the current vertex data. */ void VertexData::_calculateNormals( const bool vertexNormals ) { if(_normals.valid()) return; #ifndef NDEBUG int wrongNormals = 0; #endif if(!_normals.valid()) { _normals = new osg::Vec3Array; } //normals.clear(); if( vertexNormals ) { // initialize all normals to zero for( size_t i = 0; i < _vertices->size(); ++i ) { _normals->push_back( osg::Vec3( 0, 0, 0 ) ); } } for( size_t i = 0; i < ((_triangles->size())); i += 3 ) { // iterate over all triangles and add their normals to adjacent vertices Normal triangleNormal; unsigned int i0, i1, i2; i0 = (*_triangles)[i+0]; i1 = (*_triangles)[i+1]; i2 = (*_triangles)[i+2]; triangleNormal.normal((*_vertices)[i0], (*_vertices)[i1], (*_vertices)[i2] ); // count emtpy normals in debug mode #ifndef NDEBUG if( triangleNormal.triNormal.length() == 0.0f ) ++wrongNormals; #endif if( vertexNormals ) { (*_normals)[i0] += triangleNormal.triNormal; (*_normals)[i1] += triangleNormal.triNormal; (*_normals)[i2] += triangleNormal.triNormal; } else _normals->push_back( triangleNormal.triNormal ); } // normalize all the normals if( vertexNormals ) for( size_t i = 0; i < _normals->size(); ++i ) (*_normals)[i].normalize(); #ifndef NDEBUG if( wrongNormals > 0 ) MESHINFO << wrongNormals << " faces had no valid normal." << endl; #endif }
int main() { const int n_steps = 20000; const int n_burn = 4000; std::cout << "Students, Questions, Errors, Confidence " << std::endl; for (int n_students=10; n_students<11; n_students++) { for (int n_questions=5; n_questions<20; n_questions++) { s.clear(); q.clear(); o.clear(); for (int i=0; i<n_students; i++) { Normal norm; norm.set_params(random_(0, 5), 0.1); s.push_back(norm); } for (int i=0; i<n_questions; i++) { Normal norm; norm.set_params(random_(0, 5), 0.1); q.push_back(norm); } for (int i=0; i<n_students; i++) { for (int j=0; j<n_questions; j++) { Observation obs; if (s[i].last() > q[j].last()) obs.set(i, j, 1); else obs.set(i, j, 0); o.push_back(obs); } } Gibbs h; h.run(n_steps, n_burn); int error_sum = 0; for (int i=0; i<o.size(); i++) { double proficiency = s[o[i].get_sid()].mean(); double hardness = q[o[i].get_qid()].mean(); if (proficiency > hardness && o[i].get_response() == 0) error_sum++; if (proficiency < hardness && o[i].get_response() == 1) error_sum++; } double var = 0; for (int i=0; i<s.size(); i++) { var += (1.0/s[i].mean_variance()); } for (int i=0; i<q.size(); i++) { var += (1.0/q[i].mean_variance()); } var = sqrt(1.0/var); std::cout << n_students << ", "; std::cout << n_questions << ", "; std::cout << error_sum << ", "; std::cout << var << std::endl; } // n_questions } // n_students }
void test3(int n) { cout << endl; // Do chi-squared tests to discrete data cout << "ChiSquared tests for discrete data" << endl; cout << "chisq should be less than 95% point in most cases" << endl; cout << " and 99% point in almost all cases" << endl << endl; { Real p[] = { 0.05, 0.10, 0.05, 0.5, 0.01, 0.01, 0.03, 0.20, 0.05 }; TestDiscreteGen(9, p, n); } { Real p[] = { 0.4, 0.2, 0.1, 0.05, 0.025, 0.0125, 0.00625, 0.00625, 0.2 }; TestDiscreteGen(9, p, n); } TestNegativeBinomial(200.3, 0.05, n); TestNegativeBinomial(150.3, 0.15, n); TestNegativeBinomial(100.8, 0.18, n); TestNegativeBinomial(100.8, 1.22, n); TestNegativeBinomial(100.8, 9.0, n); TestNegativeBinomial(10.5, 0.18, n); TestNegativeBinomial(10.5, 1.22, n); TestNegativeBinomial(10.5, 9.0, n); TestNegativeBinomial(0.35, 0.18, n); TestNegativeBinomial(0.35, 1.22, n); TestNegativeBinomial(0.35, 9.0, n); TestBinomial(100, 0.45, n); TestBinomial(100, 0.25, n); TestBinomial(100, 0.02, n); TestBinomial(100, 0.01, n); TestBinomial(49, 0.60, n); TestBinomial(21, 0.70, n); TestBinomial(10, 0.90, n); TestBinomial(10, 0.25, n); TestBinomial(10, 0.10, n); TestPoisson(0.75, n); TestPoisson(4.3, n); TestPoisson(10, n); TestPoisson(100, n); Real* data = new Real[n]; if (!data) Throw(Bad_alloc()); // Apply KS test to a variety of continuous distributions // - use cdf transform to convert to uniform cout << endl; cout << "Kolmogorov-Smirnoff tests for continuous distributions" << endl; cout << "25%, 5%, 1%, .1% upper points are 1.019, 1.358, 1.628, 1.950" << endl; cout << "5% lower point is 0.520" << endl; cout << "Values should be mostly less than 5% upper point" << endl; cout << " and less than 1% point almost always" << endl << endl; { ChiSq X(1, 1.44); for (int i = 0; i < n; i++) { Real x = sqrt(X.Next()); data[i] = NormalDF(x - 1.2) - NormalDF(-x - 1.2); } cout << X.Name() << ": " << KS(data, n) << endl; } { ChiSq X(4); for (int i = 0; i < n; i++) { Real x = 0.5 * X.Next(); data[i] = (1+x)*exp(-x); } cout << X.Name() << ": " << KS(data, n) << endl; } { ChiSq X(2); for (int i = 0; i < n; i++) data[i] = exp(-0.5 * X.Next()); cout << X.Name() << ": " << KS(data, n) << endl; } { Pareto X(0.5); for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = 1.0 / sqrt(x); } cout << X.Name() << ": " << KS(data, n) << endl; } { Pareto X(1.5); for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = 1.0 / (x * sqrt(x)); } cout << X.Name() << ": " << KS(data, n) << endl; } { Normal X; for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = NormalDF(x); } cout << X.Name() << ": " << KS(data, n) << endl; } { Normal N; SumRandom X = 10 + 5 * N; for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = NormalDF((x-10)/5); } cout << X.Name() << ": " << KS(data, n) << endl; } { Normal N; Cauchy C; MixedRandom X = N(0.9) + C(0.1); for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = 0.9*NormalDF(x)+0.1*(atan(x)/3.141592654 + 0.5); } cout << X.Name() << ": " << KS(data, n) << endl; } { Normal N; MixedRandom X = N(0.9) + (10*N)(0.1); for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = 0.9*NormalDF(x)+0.1*NormalDF(x/10); } cout << X.Name() << ": " << KS(data, n) << endl; } { Normal X0; SumRandom X = X0 * 0.6 + X0 * 0.8; for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = NormalDF(x); } cout << X.Name() << ": " << KS(data, n) << endl; } { Normal X1; MixedRandom X = X1(0.2) + (X1 * 2.5 + 1.1)(0.35) + (X1 + 2.3)(0.45); for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = 0.20 * NormalDF(x) + 0.35 * NormalDF((x - 1.1) / 2.5) + 0.45 * NormalDF(x - 2.3); } cout << X.Name() << ": " << KS(data, n) << endl; } { Gamma X(0.5); for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = 2.0 * NormalDF(-sqrt(2 * x)); } cout << X.Name() << ": " << KS(data, n) << endl; } { Gamma X(3); for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = (1+x+0.5*x*x)*exp(-x); } cout << X.Name() << ": " << KS(data, n) << endl; } { Gamma X1(0.85); Gamma X2(2.15); SumRandom X = X1 + X2; for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = (1+x+0.5*x*x)*exp(-x); } cout << X.Name() << ": " << KS(data, n) << endl; } { Gamma X1(0.75); Gamma X2(0.25); SumRandom X = X1 + X2; for (int i = 0; i < n; i++) data[i] = exp(-X.Next()); cout << X.Name() << ": " << KS(data, n) << endl; } { Gamma X(2); for (int i = 0; i < n; i++) { Real x = X.Next(); data[i] = (1+x)*exp(-x); } cout << X.Name() << ": " << KS(data, n) << endl; } { Exponential X; for (int i = 0; i < n; i++) data[i] = exp(-X.Next()); cout << X.Name() << ": " << KS(data, n) << endl; } { Cauchy X; for (int i = 0; i < n; i++) data[i] = atan(X.Next())/3.141592654 + 0.5; cout << X.Name() << ": " << KS(data, n) << endl; } { Cauchy X0; SumRandom X = X0 * 0.3 + X0 * 0.7; for (int i = 0; i < n; i++) data[i] = atan(X.Next())/3.141592654 + 0.5; cout << X.Name() << ": " << KS(data, n) << endl; } { Uniform X; for (int i = 0; i < n; i++) data[i] = X.Next(); cout << X.Name() << ": " << KS(data, n) << endl; } delete [] data; }
double LogNormal::Draw(RandomGenerator & g) const { double normal = normal_.Draw(g); double value = std::exp(normal); return value; }
double LogNormal::Draw() const { double normal = normal_.Draw(); double value = std::exp(normal); return value; }
void MeshBaryTriangle::GetShadingGeometry(const Transform &obj2world, const DifferentialGeometry &dg, DifferentialGeometry *dgShading) const { if (!mesh->n) { *dgShading = dg; return; } // Use _n_ to compute shading tangents for triangle, _ss_ and _ts_ const Normal nsi = dg.iData.baryTriangle.coords[0] * mesh->n[v[0]] + dg.iData.baryTriangle.coords[1] * mesh->n[v[1]] + dg.iData.baryTriangle.coords[2] * mesh->n[v[2]]; const Normal ns = Normalize(nsi); Vector ss, ts; Vector tangent, bitangent; float btsign; // if we got a generated tangent space, use that if (mesh->t) { // length of these vectors is essential for sampled normal mapping // they should be normalized at vertex level, and NOT normalized after interpolation tangent = dg.iData.baryTriangle.coords[0] * mesh->t[v[0]] + dg.iData.baryTriangle.coords[1] * mesh->t[v[1]] + dg.iData.baryTriangle.coords[2] * mesh->t[v[2]]; // only degenerate triangles will have different vertex signs bitangent = Cross(nsi, tangent); // store sign, and also magnitude of interpolated normal so we can recover it btsign = (mesh->btsign[v[0]] ? 1.f : -1.f) * nsi.Length(); ss = Normalize(tangent); ts = Normalize(bitangent); } else { ts = Normalize(Cross(ns, dg.dpdu)); ss = Cross(ts, ns); ts *= Dot(dg.dpdv, ts) > 0.f ? 1.f : -1.f; tangent = ss; bitangent = ts; btsign = (Dot(ts, ns) > 0.f ? 1.f : -1.f); } // the length of dpdu/dpdv can be important for bumpmapping ss *= dg.dpdu.Length(); ts *= dg.dpdv.Length(); Normal dndu, dndv; // Compute \dndu and \dndv for triangle shading geometry float uvs[3][2]; GetUVs(uvs); // Compute deltas for triangle partial derivatives of normal const float du1 = uvs[0][0] - uvs[2][0]; const float du2 = uvs[1][0] - uvs[2][0]; const float dv1 = uvs[0][1] - uvs[2][1]; const float dv2 = uvs[1][1] - uvs[2][1]; const Normal dn1 = mesh->n[v[0]] - mesh->n[v[2]]; const Normal dn2 = mesh->n[v[1]] - mesh->n[v[2]]; const float determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.f) dndu = dndv = Normal(0, 0, 0); else { const float invdet = 1.f / determinant; dndu = ( dv2 * dn1 - dv1 * dn2) * invdet; dndv = (-du2 * dn1 + du1 * dn2) * invdet; } *dgShading = DifferentialGeometry(dg.p, ns, ss, ts, dndu, dndv, tangent, bitangent, btsign, dg.u, dg.v, this); dgShading->iData = dg.iData; }
int main(int argc, char** argv) { cout << "Welcome to Le Fancy Vase Drawer.\n" << endl; printf("Instructions:\n"\ "r,g,b - Change colour of mesh to red, green, blue\n"\ "k - Colour the mesh black\n"\ "p - RAINBOW.\n"\ "1,3 - Zoom in, zoom out\n"\ "w,s - Move camera up, down\n"\ "a,d - Rotate mesh left, right\n"\ "q,e - Move gaze point up, down\n"\ "z,c - Move camera and gaze point up, down\n"); float viewingAngle = 60.; // degrees float aspectRatio = 1; float N = 5.; // near plane float F = 30.; // far plane float t = N * tan(CV_PI / 360 * viewingAngle); // top float b = -t; // bottom float r = aspectRatio*t; // right float l = -r; // left int w = 512, h = 512; bool camChanged = true; bool rainbow = true; int rotationInc = 5; int roll = 0; namedWindow(wndName, CV_WINDOW_AUTOSIZE); // used as row vectors, so they can be appended to Matrix easily Mat e = (Mat_<float>(1, 3) << 30., 30., 22.); // camera vector. 15, 15, 10 Mat g = (Mat_<float>(1, 3) << 0., 0., 18.); // a point through which the gaze direction unit vector n points to Mat p = (Mat_<float>(1, 3) << 0., 0., 1.); // x, y, z, w Mat n, u, v; Mat screen(w, h, CV_8UC3); int flip = 1; // -1 to flip along X Mat Mv(0, 3, CV_32FC1); Mat S1T1Mp = (Mat_<float>(4, 4) << (2*N)/(r-l), 0, (r+l)/(r-l), 0, 0, (2*N)/(t-b), (t+b)/(t-b), 0, 0, 0, -(F+N)/(F-N), -2*F*N/(F-N), 0, 0, -1, 0 ); Mat WS2T2 = (Mat_<float>(4, 4) << w/2, 0, 0, w/2, 0, flip*h/2, 0, -h/2+h, 0, 0, 1, 0, 0, 0, 0, 1 ); // container for screen coords vector<Point2i> coords; // background colour and line colour Scalar bgColour(255, 255, 255); Scalar lineColour(0); // HSV and BGR matrices for colours of the rainbow int sat = 200, val = 200; Mat hsv(Size(1,1),CV_8UC3, Scalar(10,sat,val)), bgr; // the polygonal mesh object PolygonalMesh poly; poly.readFromFile("PolyVase.xml"); bool normalChanged = true; char c = -1; // input char while (true) { if (camChanged) { if (normalChanged) { // normalize vector from camera to gaze point normalize(e - g, n); // generate vectors describing camera plane //u = (getRotationMatrix(n, rotationInc) * u.t()).t(); //v = (getRotationMatrix(n, rotationInc) * v.t()).t(); // normalize to keep window same size //normalize(u, u); //normalize(v, v); u = p.cross(n); v = u.cross(n); u = (getRotationMatrix(n, roll) * u.t()).t(); v = (getRotationMatrix(n, roll) * v.t()).t(); normalize(u, u); normalize(v, v); normalChanged = false; } // construct matrix for world coords to camera viewing coords Mv = Mat(0, 3, CV_32FC1); Mv.push_back(u); Mv.push_back(v); Mv.push_back(n); Mv = Mv.t(); Mv.push_back(Mat((Mat_<float>(1, 3) << -e.dot(u), -e.dot(v), -e.dot(n)))); Mv = Mv.t(); Mv.push_back(Mat((Mat_<float>(1, 4) << 0, 0, 0, 1))); // works //scale, transformation, and projection matrix S1T1Mp = (Mat_<float>(4, 4) << (2*N)/(r-l), 0, (r+l)/(r-l), 0, 0, (2*N)/(t-b), (t+b)/(t-b), 0, 0, 0, -(F+N)/(F-N), -2*F*N/(F-N), 0, 0, -1, 0 ); // scal, transform from viewing volume to canonical viewing volume. // Flip along X-axis is desired WS2T2 = (Mat_<float>(4, 4) << w/2, 0, 0, w/2, 0, flip*h/2, 0, -h/2+h, 0, 0, 1, 0, 0, 0, 0, 1 ); // colour the background screen.setTo(bgColour); camChanged = false; } coords.clear(); coords.reserve(poly.vertsH.size()); for (int i = 0; i < poly.vertsH.size(); i++) { // Apply transformations to convert from world coordinates to screen coords Mat pt = WS2T2 * (S1T1Mp * (Mv * poly.vertsH[i])); // Perspective divide pt /= pt.at<float>(3, 0); // store generated coordinate in coords container coords.push_back(Point2f((int)pt.at<float>(0), (int)pt.at<float>(1))); } if (rainbow) { hsv = Mat(Size(1, 1), CV_8UC3, Scalar(10, sat, val)); } for (int i = 0; i < poly.faces.size(); i++) { Face& f = poly.faces[i]; Normal faceNormal = poly.norms[f.data[Face::NORM]]; Mat tv = poly.vertsH[f.data[Face::PT0]]; // triangle 1st vertex // generate camera to triangle vector Vec3f camToTri(tv.at<float>(X) - e.at<float>(X), tv.at<float>(Y) - e.at<float>(Y), tv.at<float>(Z) - e.at<float>(Z)); // compute dot product to determine which faces to draw. float b = faceNormal.dot(camToTri); // camToTri.dot(faceNormal); if (rainbow) { // increment hue value, then convert from HSV to BGR Vec3b clr = hsv.at<Vec3b>(0, 0); clr[0]++; hsv.at<Vec3b>(0, 0) = clr; cvtColor(hsv, bgr, CV_HSV2BGR); Vec3b bgr3 = bgr.at<Vec3b>(0, 0); lineColour = Scalar(bgr3[0], bgr3[1], bgr3[2]); } if (b >= 0) { // draw triangle from 3 face coords line(screen, coords[f.data[Face::PT0]], coords[f.data[Face::PT1]], lineColour); line(screen, coords[f.data[Face::PT0]], coords[f.data[Face::PT2]], lineColour); line(screen, coords[f.data[Face::PT1]], coords[f.data[Face::PT2]], lineColour); } } // draw the image to the screen imshow(wndName, screen); c = waitKey(0); switch (c) { case 'w': // move camera up e.at<float>(Z) += 1; camChanged = true; normalChanged = true; break; case 's': // move camera down e.at<float>(Z) -= 1; camChanged = true; normalChanged = true; break; case 'a':{ // rotate by 5 degrees along z axis float a = rotationInc/180.*CV_PI; e = ((Mat_<float>(3, 3) << cos(a), sin(a), 0, -sin(a), cos(a), 0, 0, 0, 1) * e.t()).t(); camChanged = true; normalChanged = true; } break; case 'd':{ // rotate by -5 degrees along z axis float a = -rotationInc/180.*CV_PI; e = ((Mat_<float>(3, 3) << cos(a), sin(a), 0, -sin(a), cos(a), 0, 0, 0, 1) * e.t()).t(); camChanged = true; normalChanged = true; } break; case 'y': { roll += rotationInc; // rotate camera // rotate around unit vector 'n' -- from gaze point to cam //u = (getRotationMatrix(n, rotationInc) * u.t()).t(); //v = (getRotationMatrix(n, rotationInc) * v.t()).t(); // normalize to keep window same size //normalize(u, u); //normalize(v, v); normalChanged = true; camChanged = true; } break; case 'u': roll -= rotationInc; //u = (getRotationMatrix(n, -rotationInc) * u.t()).t(); //v = (getRotationMatrix(n, -rotationInc) * v.t()).t(); //normalize(u, u); //normalize(v, v); normalChanged = true; camChanged = true; break; case 'q': // shift gaze vector down g.at<float>(Z) -= 1; camChanged = true; normalChanged = true; break; case 'e': // shift gaze vector up g.at<float>(Z) += 1; camChanged = true; normalChanged = true; break; case 'c': // move camera and gaze vector up g.at<float>(Z) += 1; e.at<float>(Z) += 1; camChanged = true; break; case 'z': // move camera and gaze vector down g.at<float>(Z) -= 1; e.at<float>(Z) -= 1; camChanged = true; break; case '1': // move camera closer to object by 10% e *= 0.9; camChanged = true; break; case '3': // move cam further from object by 10% e *= 1.1; camChanged = true; break; case 'r': // colour the mesh red, green, blue, black (next 4 cases) lineColour = Scalar(0, 0, 255); rainbow = false; break; case 'g': lineColour = Scalar(0, 150, 0); rainbow = false; break; case 'b': lineColour = Scalar(255, 0, 0); rainbow = false; break; case 'k': lineColour = Scalar(0, 0, 0); rainbow = false; break; case 'p': //set the rainbow flag rainbow = true; break; default: break; } } // chillout until the user has hit a key waitKey(); getchar(); }