//------------------------------------------------------------- // nmask.C // // Implements functions in the NormalMask class // // Hansong Zhang // Department of Computer Science // UNC-Chapel Hill // 1996 //------------------------------------------------------------- #include #include #include #include "nmask.h" #define DEG_TO_RAD 0.0174532 // nSubdiv is in terms of clusters. So if there're n clusters // along each dimension, there're n+1 grid points along each // dimension. NormalMask::NormalMask(int _nSubdiv) { nSubdiv = _nSubdiv; size = (nSubdiv * nSubdiv * 6 + 7) / 8; mask = new unsigned char [size]; for (int i=0; i (1, 1, 1); float halfNumSubdiv = nSubdiv / 2.; for (face=0; face<6; face++) for (j=0; j<=nSubdiv; j++) for (i=0; i<=nSubdiv; i++) { int offsetOnFace = i+j*(nSubdiv+1); // Form the line segment origin---grid_point. switch (face) { case 0: case 1: Normals[face][offsetOnFace].x = face==0 ? -1 : 1; Normals[face][offsetOnFace].y = i / halfNumSubdiv - 1; Normals[face][offsetOnFace].z = j / halfNumSubdiv - 1; break; case 2: case 3: Normals[face][offsetOnFace].y = face==2 ? -1 : 1; Normals[face][offsetOnFace].z = i / halfNumSubdiv - 1; Normals[face][offsetOnFace].x = j / halfNumSubdiv - 1; break; case 4: case 5: Normals[face][offsetOnFace].z = face==4 ? -1 : 1; Normals[face][offsetOnFace].x = i / halfNumSubdiv - 1; Normals[face][offsetOnFace].y = j / halfNumSubdiv - 1; break; } // Normalize the line segment origin---grid_point Normals[face][offsetOnFace].Normalize(); } } // // This function takes a viewing direction and field of view, and // compute the frontface mask. Note: in the paper I described the // algorithm in terms of the *backface* mask. But here I happened to // implemented it using the *frontface* mask. Of course they're // the bitwise NOT of each other. No big deal just don't get confused. // // Normally this function is called once per frame // or once per bounding volume per frame (if you're forming sub-frusta // towards to bounding volumes). In the latter case, the function can // and need to be better optimized. But now it's written for ease of // understanding. // // FOV is in degrees // void NormalMask::FillBits(Vec3 &_vDir, float FOV) { float theta, cosineTheta; register i, j, face; register nClustersPerFace = nSubdiv*nSubdiv; Vec3 vDir; int frontCount=0, backCount=0; // Half of the field of view theta = (90. - FOV/2) * DEG_TO_RAD; // cos(fov/2) cosineTheta = cos(theta); // Clear the mask memset(mask, 0, size); vDir = _vDir; vDir.Normalize(); for (face=0; face<6; face++) for (j=0; j<=nSubdiv; j++) for (i=0; i<=nSubdiv; i++) { // offset of the normal at (i,j) in Normals[face] int offsetOnFace = i+j*(nSubdiv+1); // Cosine of the angle between the normal and the viewing direction float cosine = vDir * Normals[face][offsetOnFace]; // Because cos is decreasing 0 - PI... if (cosine <= cosineTheta) IsBackfacing[face][offsetOnFace] = 0; else IsBackfacing[face][offsetOnFace] = 1; } for (face=0; face<6; face++) for (j=0; j