📄 normalmapper.cpp
字号:
{
loBbox[k] = lowTris[i].vert[j].v[k];
}
if (lowTris[i].vert[j].v[k] > loBbox[k + 3])
{
loBbox[k + 3] = lowTris[i].vert[j].v[k];
}
}
// Check texture coordinates
if ((lowTris[i].texCoord[j].u < 0.0) ||
(lowTris[i].texCoord[j].u > 1.0))
{
if (fabs(lowTris[i].texCoord[j].u) > EPSILON)
{
NmPrint ("ERROR: Texture coordinates must lie in the 0.0 - 1.0 range for the low res model (u: %f)!\n", lowTris[i].texCoord[j].u);
exit (-1);
}
else
{
lowTris[i].texCoord[j].u = 0.0;
}
}
if ((lowTris[i].texCoord[j].v < 0.0) ||
(lowTris[i].texCoord[j].v > 1.0))
{
if (fabs(lowTris[i].texCoord[j].v) > EPSILON)
{
NmPrint ("ERROR: Texture coordinates must lie in the 0.0 - 1.0 range for the low res model! (v %f)\n", lowTris[i].texCoord[j].v);
exit (-1);
}
else
{
lowTris[i].texCoord[j].v = 0.0;
}
}
}
}
NmPrint ("Low poly bounding box: (%10.3f %10.3f %10.3f)\n", loBbox[0],
loBbox[1], loBbox[2]);
NmPrint (" (%10.3f %10.3f %10.3f)\n", loBbox[3],
loBbox[4], loBbox[5]);
// If the flag is set compute tangent space for all the low res triangles.
NmTangentMatrix* tangentSpace = NULL;
if (gInTangentSpace == true)
{
// Get tangent space.
NmPrint ("Computing tangents\n");
NmRawTangentSpaceD* tan = NULL;
if (NmComputeTangentsD (lowNumTris, lowTris, &tan) == false)
{
NmPrint ("ERROR: Unable to compute tangent space!\n");
exit (-1);
}
// Create tangent matrices
tangentSpace = new NmTangentMatrix [lowNumTris];
for (int j = 0; j < lowNumTris; j++)
{
for (int k = 0; k < 3; k++)
{
tangentSpace[j].m[k][0] = tan[j].tangent[k].x;
tangentSpace[j].m[k][3] = tan[j].tangent[k].y;
tangentSpace[j].m[k][6] = tan[j].tangent[k].z;
tangentSpace[j].m[k][1] = tan[j].binormal[k].x;
tangentSpace[j].m[k][4] = tan[j].binormal[k].y;
tangentSpace[j].m[k][7] = tan[j].binormal[k].z;
tangentSpace[j].m[k][2] = lowTris[j].norm[k].x;
tangentSpace[j].m[k][5] = lowTris[j].norm[k].y;
tangentSpace[j].m[k][8] = lowTris[j].norm[k].z;
}
}
delete [] tan;
} // end if we need to deal with tangent space
// Read in the high res model
// fp = fopen (highName, "rb");
fp = fopen (highName, "r");
if (fp == NULL)
{
NmPrint ("ERROR: Unable to open %s\n", highName);
exit (-1);
}
int highNumTris;
NmRawTriangle* highTris;
// if (NmReadTriangles (fp, &highNumTris, &highTris) == false)
if (SMDReadTriangles (fp, &highNumTris, &highTris) == false)
{
NmPrint ("ERROR: Unable to read %s\n", highName);
fclose (fp);
exit (-1);
}
fclose (fp);
NmPrint ("Found %d triangles in high res model\n", highNumTris);
// Get high res bounding box.
double hiBbox[6];
hiBbox[0] = FLT_MAX; // X min
hiBbox[1] = FLT_MAX; // Y min
hiBbox[2] = FLT_MAX; // Z min
hiBbox[3] = -FLT_MAX; // X max
hiBbox[4] = -FLT_MAX; // Y max
hiBbox[5] = -FLT_MAX; // Z max
for (int h = 0; h < highNumTris; h++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 3; k++)
{
if (highTris[h].vert[j].v[k] < hiBbox[k])
{
hiBbox[k] = highTris[h].vert[j].v[k];
}
if (highTris[h].vert[j].v[k] > hiBbox[k + 3])
{
hiBbox[k + 3] = highTris[h].vert[j].v[k];
}
}
}
}
NmPrint ("High poly bounding box: (%10.3f %10.3f %10.3f)\n", hiBbox[0],
hiBbox[1], hiBbox[2]);
NmPrint (" (%10.3f %10.3f %10.3f)\n", hiBbox[3],
hiBbox[4], hiBbox[5]);
// Tangents for high res if we need them.
NmTangentMatrix* hTangentSpace = NULL;
if (bumpName != NULL)
{
// Get tangent space.
NmPrint ("Computing tangents\n");
NmRawTangentSpaceD* tan = NULL;
if (NmComputeTangentsD (highNumTris, highTris, &tan) == false)
{
NmPrint ("ERROR: Unable to compute tangent space!\n");
exit (-1);
}
// Create tangent matrices
hTangentSpace = new NmTangentMatrix [highNumTris];
for (int j = 0; j < highNumTris; j++)
{
for (int k = 0; k < 3; k++)
{
hTangentSpace[j].m[k][0] = tan[j].tangent[k].x;
hTangentSpace[j].m[k][3] = tan[j].tangent[k].y;
hTangentSpace[j].m[k][6] = tan[j].tangent[k].z;
hTangentSpace[j].m[k][1] = tan[j].binormal[k].x;
hTangentSpace[j].m[k][4] = tan[j].binormal[k].y;
hTangentSpace[j].m[k][7] = tan[j].binormal[k].z;
hTangentSpace[j].m[k][2] = highTris[j].norm[k].x;
hTangentSpace[j].m[k][5] = highTris[j].norm[k].y;
hTangentSpace[j].m[k][8] = highTris[j].norm[k].z;
}
}
delete [] tan;
}
// Loop over low res triangles and figure out which triangles in the
// high res model are relevant for normal finding.
NmVisible* visible = new NmVisible [lowNumTris];
if (visible == NULL)
{
NmPrint ("ERROR: Unable to allocate visibility sets\n");
exit (-1);
}
NmPrint ("Finding visible triangle sets\n");
printf (" 0%%");
for (int t = 0; t < lowNumTris; t++)
{
// Show some progress
int progress = (int)(((float)(t)/(float)(lowNumTris))*100.0);
char prog[24];
sprintf (prog, "%3d%% ", progress);
printf ("\r%s", prog);
// Save off a pointer to the triangle and create
NmRawTriangle* lTri = &lowTris[t];
// Clear out the counts and allocate a new index
visible[t].numTris = 0;
visible[t].index = new unsigned int [highNumTris];
if (visible[t].index == NULL)
{
NmPrint ("ERROR: Unable to allocate visibilty index.\n");
exit (-1);
}
// Plane equation constants
double plane[6][4];
ComputePlaneEqn (lTri->vert[1].v, lTri->vert[0].v, lTri->norm[0].v,
plane[0]);
ComputePlaneEqn (lTri->vert[1].v, lTri->vert[0].v, lTri->norm[1].v,
plane[1]);
ComputePlaneEqn (lTri->vert[2].v, lTri->vert[1].v, lTri->norm[1].v,
plane[2]);
ComputePlaneEqn (lTri->vert[2].v, lTri->vert[1].v, lTri->norm[2].v,
plane[3]);
ComputePlaneEqn (lTri->vert[0].v, lTri->vert[2].v, lTri->norm[2].v,
plane[4]);
ComputePlaneEqn (lTri->vert[0].v, lTri->vert[2].v, lTri->norm[0].v,
plane[5]);
// Loop through the high res triangles to see if they are "visible"
for (int h = 0; h < highNumTris; h++)
{
// Save off triangle pointer
NmRawTriangle* hTri = &highTris[h];
// Check to see if this triangle is in the planes defined by the
// planes computed for the low res triangle
if ( (IsInside (hTri, plane[0]) || IsInside (hTri, plane[1])) &&
(IsInside (hTri, plane[2]) || IsInside (hTri, plane[3])) &&
(IsInside (hTri, plane[4]) || IsInside (hTri, plane[5])) )
{
visible[t].index[visible[t].numTris] = (unsigned)h;
visible[t].numTris++;
}
} // end for high res triangles
} // end for low res triangles
printf ("\r100%%\r");
// Print some stats
float sum = 0;
for (int lt = 0; lt < lowNumTris; lt++)
{
sum += (float)(visible[lt].numTris);
}
if ((int)sum < 1)
{
NmPrint ("ERROR: No visible triangles found!\n");
exit (-1);
}
NmPrint ("%6.1f avg visible/triangle\n", (float)(sum)/(float)(lowNumTris));
// Create image and clear to a biased 0 so any untouched pixels won't
// have a normal associated with them.
float* img = new float[gWidth*gHeight*4];
if (img == NULL)
{
NmPrint ("ERROR: Unable to allocate texture\n");
exit (-1);
}
float* img2 = new float[gWidth*gHeight*4];
if (img2 == NULL)
{
NmPrint ("ERROR: Unable to allocate texture\n");
exit (-1);
}
// Get samples for supersampling
Sample* samples = GetSamples (gNumSamples);
// loop over mip levels
int mipCount = 0;
int lastWidth = gWidth;
int lastHeight = gHeight;
while ((gWidth > 0) && (gHeight > 0))
{
// A little info
NmPrint ("Output normal map %d by %d\n", gWidth, gHeight);
// If this is the first time, or we are recomputing each mip level
// find the normals by ray casting.
if ((gComputeMipLevels == MIP_RECOMPUTE) || (mipCount == 0))
{
// Zero out memory
memset (img, 0, sizeof (float)*gWidth*gHeight*3);
// Loop over the triangles in the low res model and rasterize them
// into the normal texture based on the texture coordinates.
NmPrint ("Computing normals\n");
printf (" 0%%");
NmEdge edge[3];
NmEdge tmp;
for (int l = 0; l < lowNumTris; l++)
{
// Show some progress
int progress = (int)(((float)(l)/(float)(lowNumTris))*100.0);
char prog[24];
sprintf (prog, "%3d%% ", progress);
printf ("\r%s", prog);
// Save off a pointer to the triangle and create
NmRawTriangle* lTri = &lowTris[l];
// Find edges and sort by minimum Y
GetEdge (&edge[0], lTri, 0, 1);
GetEdge (&edge[1], lTri, 0, 2);
GetEdge (&edge[2], lTri, 1, 2);
if (edge[2].yMin < edge[1].yMin)
{
memcpy (&tmp, &edge[1], sizeof (NmEdge));
memcpy (&edge[1], &edge[2], sizeof (NmEdge));
memcpy (&edge[2], &tmp, sizeof (NmEdge));
}
if (edge[1].yMin < edge[0].yMin)
{
memcpy (&tmp, &edge[0], sizeof (NmEdge));
memcpy (&edge[0], &edge[1], sizeof (NmEdge));
memcpy (&edge[1], &tmp, sizeof (NmEdge));
}
// Find initial Barycentric parameter. Algorithm described at:
// http://research.microsoft.com/~hollasch/cgindex/math/barycentric.html
#if 0
double x1 = lTri->texCoord[0].u * (gWidth-1);
double x2 = lTri->texCoord[1].u * (gWidth-1);
double x3 = lTri->texCoord[2].u * (gWidth-1);
double y1 = lTri->texCoord[0].v * (gHeight-1);
double y2 = lTri->texCoord[1].v * (gHeight-1);
double y3 = lTri->texCoord[2].v * (gHeight-1);
#else
double x1 = (float)INT_ROUND_TEXCOORD_U(lTri->texCoord[0].u);
double x2 = (float)INT_ROUND_TEXCOORD_U(lTri->texCoord[1].u);
double x3 = (float)INT_ROUND_TEXCOORD_U(lTri->texCoord[2].u);
double y1 = (float)INT_ROUND_TEXCOORD_V(lTri->texCoord[0].v);
double y2 = (float)INT_ROUND_TEXCOORD_V(lTri->texCoord[1].v);
double y3 = (float)INT_ROUND_TEXCOORD_V(lTri->texCoord[2].v);
#endif
double b0 = ((x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1));
// Find min/max Y
int minY = edge[0].yMin;
int maxY = edge[0].yMax;
if (edge[1].yMax > maxY)
{
maxY = edge[1].yMax;
}
if (edge[2].yMax > maxY)
{
maxY = edge[2].yMax;
}
// Now loop over Ys doing each "scanline"
for (int y = minY; y <= maxY; y++)
{
// Find min and max X for this scanline.
// I'm sure there's a smarter way to do this.
int minX = 32767;
int maxX = 0;
for (int e = 0; e < 3; e++)
{
// See if this edge is active.
if ((edge[e].yMin <= y) && (edge[e].yMax >= y))
{
// Check it's X values to see if they are min or max.
if (edge[e].x < minX)
{
minX = edge[e].x;
}
if (edge[e].x > maxX)
{
maxX = edge[e].x;
}
// update x for next scanline
edge[e].increment += edge[e].numerator;
if (edge[e].denominator != 0)
{
if (edge[e].numerator < 0)
{
while (edge[e].increment <= 0)
{
edge[e].x--;
edge[e].increment += edge[e].denominator;
}
}
else
{
while (edge[e].increment > edge[e].denominator)
{
edge[e].x++;
edge[e].increment -= edge[e].denominator;
}
}
}
} // end if edge is active
} // end for number of edges
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -