📄 normalmapper.cpp
字号:
//////////////////////////////////////////////////////////////////////////
void
ComputePlaneEqn (float v0[3], float v1[3], float norm[3], double plane[4])
{
// Find A, B, C - normal to plane
double v[3];
VEC_Subtract (v1, v0, v);
VEC_Cross (v, norm, plane);
double tmp = sqrt (plane[0]*plane[0] + plane[1]*plane[1]+plane[2]*plane[2]);
if (tmp < EPSILON)
{
plane[0] = 0;
plane[1] = 0;
plane[2] = 1;
}
else
{
plane[0] = plane[0]/tmp;
plane[1] = plane[1]/tmp;
plane[2] = plane[2]/tmp;
}
// Find D (A*x + B*y + C*z = D)
plane[3] = VEC_DotProduct (plane, v0);
}
//////////////////////////////////////////////////////////////////////////
// Is the triangle "inside" the plane - if any of the three points lie on
// or above the given plane then the triangle is "inside". Given the
// plane equation above if the dot product with ABC is >= D it's in!
//////////////////////////////////////////////////////////////////////////
inline bool
IsInside (NmRawTriangle* tri, double plane[4])
{
if (VEC_DotProduct (tri->vert[0].v, plane) >= plane[3])
{
return true;
}
if (VEC_DotProduct (tri->vert[1].v, plane) >= plane[3])
{
return true;
}
if (VEC_DotProduct (tri->vert[2].v, plane) >= plane[3])
{
return true;
}
return false;
}
//////////////////////////////////////////////////////////////////////////
// Convert to John style experimental pixel format
//////////////////////////////////////////////////////////////////////////
void
ConvertToJohn (double x, double y, double z, JohnPixel* jp)
{
// Compute one minus z
double omz = 1.0 - z;
double ax = fabs (x);
double ay = fabs (y);
double aomz = fabs (omz);
// Find max.
double max;
if (ax > ay)
{
if (ax > aomz)
{
max = ax;
}
else
{
max = aomz;
}
}
else
{
if (ay > aomz)
{
max = ay;
}
else
{
max = aomz;
}
}
// Now compute values.
jp->r = PACKINTOBYTE_MINUS1TO1(x/max);
jp->g = PACKINTOBYTE_MINUS1TO1(y/max);
jp->b = PACKINTOBYTE_MINUS1TO1(omz/max);
jp->a = PACKINTOBYTE_0TO1(max);
}
//////////////////////////////////////////////////////////////////////////
// Fetch from the normal map given the uv.
//////////////////////////////////////////////////////////////////////////
void
Fetch (float* map, int width, int height, double u, double v, double bumpN[3])
{
// Get coordinates in 0-1 range
if ((u < 0.0) || (u > 1.0))
{
u -= floor(u);
}
if ((v < 0.0) || (v > 1.0))
{
v -= floor(v);
}
// Now figure out the texel information for u coordinate
double up = (double)(width-1) * u;
double umin = floor (up);
double umax = ceil (up);
double ufrac = up - umin;
// Now figure out the texel information for v coordinate
double vp = (double)(height-1) * v;
double vmin = floor (vp);
double vmax = ceil (vp);
double vfrac = vp - vmin;
// First term umin/vmin
int idx = (int)(vmin)*width*3 + (int)(umin)*3;
bumpN[0] = ((1.0-ufrac)*(1.0-vfrac)*(double)(map[idx]));
bumpN[1] = ((1.0-ufrac)*(1.0-vfrac)*(double)(map[idx+1]));
bumpN[2] = ((1.0-ufrac)*(1.0-vfrac)*(double)(map[idx+2]));
// Second term umax/vmin
idx = (int)(vmin)*width*3 + (int)(umax)*3;
bumpN[0] += (ufrac*(1.0-vfrac)*(double)(map[idx]));
bumpN[1] += (ufrac*(1.0-vfrac)*(double)(map[idx+1]));
bumpN[2] += (ufrac*(1.0-vfrac)*(double)(map[idx+2]));
// Third term umin/vmax
idx = (int)(vmax)*width*3 + (int)(umin)*3;
bumpN[0] += ((1.0-ufrac)*vfrac*(double)(map[idx]));
bumpN[1] += ((1.0-ufrac)*vfrac*(double)(map[idx+1]));
bumpN[2] += ((1.0-ufrac)*vfrac*(double)(map[idx+2]));
// Fourth term umax/vmax
idx = (int)(vmax)*width*3 + (int)(umax)*3;
bumpN[0] += (ufrac*vfrac*(double)(map[idx]));
bumpN[1] += (ufrac*vfrac*(double)(map[idx+1]));
bumpN[2] += (ufrac*vfrac*(double)(map[idx+2]));
}
//////////////////////////////////////////////////////////////////////////
// Get a pixel from the image.
//////////////////////////////////////////////////////////////////////////
inline void
ReadPixel (BYTE* image, int width, int off, pixel* pix, int x, int y)
{
int idx = y*width*off + x*off;
if (off > 0)
{
pix->red = image[idx];
}
if (off > 1)
{
pix->blue = image[idx + 1];
}
if (off > 2)
{
pix->green = image[idx + 2];
}
}
//////////////////////////////////////////////////////////////////////////
// Reads a height field file from disk and converts it into a normal for
// use in perturbing the normals generated from the high res model
//////////////////////////////////////////////////////////////////////////
void
GetBumpMapFromHeightMap (char* bumpName, int* bumpWidth, int* bumpHeight,
float** bumpMap, float scale)
{
// No height field
if (bumpName == NULL)
{
(*bumpWidth) = 0;
(*bumpHeight) = 0;
(*bumpMap) = NULL;
return;
}
// First read in the heightmap.
FILE* fp = fopen (bumpName, "rb");
if (fp == NULL)
{
NmPrint ("ERROR: Unable to open %s\n", bumpName);
exit (-1);
}
BYTE* image;
int bpp;
if (!TGAReadImage (fp, bumpWidth, bumpHeight, &bpp, &image))
{
NmPrint ("ERROR: Unable to read %s\n", bumpName);
exit (-1);
}
fclose (fp);
// Allocate normal image.
(*bumpMap) = new float [(*bumpWidth)*(*bumpHeight)*3];
if ((*bumpMap) == NULL)
{
NmPrint ("ERROR: Unable to allocate normal map memory!");
exit (-1);
}
// Get offset
int off = 0;
switch (bpp)
{
case 8:
off = 1;
break;
case 16:
off = 2;
break;
case 24:
off = 3;
break;
case 32:
off = 4;
break;
default:
NmPrint ("ERROR: Unhandled bit depth for bump map!\n");
exit (-1);
}
// Sobel the image to get normals.
float dX, dY, nX, nY, nZ, oolen;
pixel pix;
for (int y = 0; y < (*bumpHeight); y++)
{
for (int x = 0; x < (*bumpWidth); x++)
{
// Do Y Sobel filter
ReadPixel (image, (*bumpWidth), off,
&pix, (x-1+(*bumpWidth)) % (*bumpWidth), (y+1) % (*bumpHeight));
dY = ((((float) pix.red) / 255.0f)*scale) * -1.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, x % (*bumpWidth), (y+1) % (*bumpHeight));
dY += ((((float) pix.red) / 255.0f)*scale) * -2.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, (x+1) % (*bumpWidth), (y+1) % (*bumpHeight));
dY += ((((float) pix.red) / 255.0f)*scale) * -1.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, (x-1+(*bumpWidth)) % (*bumpWidth), (y-1+(*bumpHeight)) % (*bumpHeight));
dY += ((((float) pix.red) / 255.0f)*scale) * 1.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, x % (*bumpWidth), (y-1+(*bumpHeight)) % (*bumpHeight));
dY += ((((float) pix.red) / 255.0f)*scale) * 2.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, (x+1) % (*bumpWidth), (y-1+(*bumpHeight)) % (*bumpHeight));
dY += ((((float) pix.red) / 255.0f)*scale) * 1.0f;
// Do X Sobel filter
ReadPixel(image, (*bumpWidth), off,
&pix, (x-1+(*bumpWidth)) % (*bumpWidth), (y-1+(*bumpHeight)) % (*bumpHeight));
dX = ((((float) pix.red) / 255.0f)*scale) * -1.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, (x-1+(*bumpWidth)) % (*bumpWidth), y % (*bumpHeight));
dX += ((((float) pix.red) / 255.0f)*scale) * -2.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, (x-1+(*bumpWidth)) % (*bumpWidth), (y+1) % (*bumpHeight));
dX += ((((float) pix.red) / 255.0f)*scale) * -1.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, (x+1) % (*bumpWidth), (y-1+(*bumpHeight)) % (*bumpHeight));
dX += ((((float) pix.red) / 255.0f)*scale) * 1.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, (x+1) % (*bumpWidth), y % (*bumpHeight));
dX += ((((float) pix.red) / 255.0f)*scale) * 2.0f;
ReadPixel(image, (*bumpWidth), off,
&pix, (x+1) % (*bumpWidth), (y+1) % (*bumpHeight));
dX += ((((float) pix.red) / 255.0f)*scale) * 1.0f;
// Cross Product of components of gradient reduces to
nX = -dX;
nY = -dY;
nZ = 1;
// Normalize
oolen = 1.0f/((float) sqrt(nX*nX + nY*nY + nZ*nZ));
nX *= oolen;
nY *= oolen;
nZ *= oolen;
int idx = y*(*bumpWidth)*3 + x*3;
(*bumpMap)[idx] = nX;
(*bumpMap)[idx+1] = nY;
(*bumpMap)[idx+2] = nZ;
}
}
}
//////////////////////////////////////////////////////////////////////////
// Check argument flags and set the appropriate values.
//////////////////////////////////////////////////////////////////////////
void
TestArgs (char* args)
{
// Print out flags
NmPrint ("Flags: %s\n", args);
// Super-sample number
if (strstr (args, "1") != NULL)
{
gNumSamples = 1;
}
if (strstr (args, "2") != NULL)
{
gNumSamples = 2;
}
if (strstr (args, "3") != NULL)
{
gNumSamples = 3;
}
if (strstr (args, "4") != NULL)
{
gNumSamples = 4;
}
if (strstr (args, "5") != NULL)
{
gNumSamples = 5;
}
if (strstr (args, "6") != NULL)
{
gNumSamples = 9;
}
if (strstr (args, "7") != NULL)
{
gNumSamples = 13;
}
if (strstr (args, "8") != NULL)
{
gNumSamples = 21;
}
if (strstr (args, "9") != NULL)
{
gNumSamples = 37;
}
if (strstr (args, "0") != NULL)
{
gNumSamples = 57;
}
// Rulesets for determining best normals
if (strstr (args, "c") != NULL)
{
gNormalRules = NORM_RULE_CLOSEST;
if (strstr (args, "X") != NULL)
{
gNormalRules = NORM_RULE_FRONT_CLOSEST;
}
}
if (strstr (args, "C") != NULL)
{
gNormalRules = NORM_RULE_BEST_CLOSEST;
if (strstr (args, "X") != NULL)
{
gNormalRules = NORM_RULE_FRONT_BEST_CLOSEST;
}
}
if (strstr (args, "f") != NULL)
{
gNormalRules = NORM_RULE_FARTHEST;
if (strstr (args, "X") != NULL)
{
gNormalRules = NORM_RULE_FRONT_FURTHEST;
}
}
if (strstr (args, "F") != NULL)
{
gNormalRules = NORM_RULE_BEST_FARTHEST;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -