📄 normalmapper.cpp
字号:
//=============================================================================
// NormalMapper.cpp -- Program that converts a low and high res model into
// a normal map, lots of options see main() for details.
//=============================================================================
// $File: //depot/3darg/Tools/NormalMapper/NormalMapper.cpp $ $Revision: #35 $ $Author: gosselin $
//=============================================================================
// (C) 2002 ATI Research, Inc., All rights reserved.
//=============================================================================
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <float.h>
#include "NmFileIO.h"
#include "TGAIO.h"
#include "ArgFileIO.h"
#include "SMDFileIO.h"
#define PACKINTOBYTE_MINUS1TO1(X) ((BYTE)((X)*127.5+127.5))
#define UNPACKBYTE_MINUS1TO1(x) ((((float)(x)-127.5)/127.5))
#define PACKINTOBYTE_0TO1(x) ((BYTE)((x)*255))
#define UNPACKBYTE_0TO1(x) (((float)(x)/255.0f))
#define PACKINTOSHORT_0TO1(x) ((unsigned short)((x)*65535))
#define UNPACKSHORT_0TO1(x) (((float)(x)/65535.0f))
#define PACKINTOSHORT_MINUS1TO1(X) ((short)((X)*32767.5+32767.5))
#define UNPACKSHORT_MINUS1TO1(x) ((((float)(x)-32767.5)/32767.5))
#define PACKINTOSHORT_SMINUS1TO1(x) ((short)((x)*32767.5))
#define UNPACKSHORT_SMINUS1TO1(x) (((float)(x))/32767.5)
#define VEC_Subtract(a, b, c) ((c)[0] = (a)[0] - (b)[0], \
(c)[1] = (a)[1] - (b)[1], \
(c)[2] = (a)[2] - (b)[2])
#define VEC_Add(a, b, c) ((c)[0] = (a)[0] + (b)[0], \
(c)[1] = (a)[1] + (b)[1], \
(c)[2] = (a)[2] + (b)[2])
#define VEC_Cross(a, b, c) ((c)[0] = (a)[1] * (b)[2] - (a)[2] * (b)[1], \
(c)[1] = (a)[2] * (b)[0] - (a)[0] * (b)[2], \
(c)[2] = (a)[0] * (b)[1] - (a)[1] * (b)[0])
#define VEC_DotProduct(a, b) ((a)[0] * (b)[0] + \
(a)[1] * (b)[1] + \
(a)[2] * (b)[2])
#define INT_ROUND_TEXCOORD_U(X) (int)(((X)*(float)(gWidth-1))+0.5f)
#define INT_ROUND_TEXCOORD_V(X) (int)(((X)*(float)(gHeight-1))+0.5f)
#define INT_TEXCOORD_U(X) (int)((X)*(float)(gWidth-1))
#define INT_TEXCOORD_V(X) (int)((X)*(float)(gHeight-1))
// Value that's close enough to be called 0.0
#define EPSILON 1.0e-7
// Edge structure.
typedef struct
{
int idx0;
int idx1;
// Min/max info
int yMin;
int yMax;
int x;
int x1;
int increment;
int numerator;
int denominator;
} NmEdge;
// Tangent space structure.
typedef struct
{
double m[3][9];
} NmTangentMatrix;
// High res "visibility"
typedef struct
{
int numTris;
unsigned int* index;
} NmVisible;
// Experimental pixel format.
typedef union
{
struct { BYTE r, g, b, a; };
struct { BYTE v[4]; };
} JohnPixel;
// Local print routines.
void NmErrorLog (const char *szFmt, ...);
void NmErrorLog (char *szFmt);
#define NmPrint NmErrorLog
// Width and height of the resultant texture
int gWidth;
int gHeight;
// Supersampling variables.
int gNumSamples = 1;
typedef union
{
struct { float x, y; };
struct { float v[2]; };
} Sample;
// Rules for figuring out which normal is better.
enum
{
NORM_RULE_CLOSEST = 0,
NORM_RULE_BEST_CLOSEST,
NORM_RULE_BEST_FARTHEST,
NORM_RULE_FARTHEST,
NORM_RULE_MIXED,
NORM_RULE_BEST_MIXED,
NORM_RULE_BEST,
NORM_RULE_FRONT_FURTHEST,
NORM_RULE_FRONT_BEST_FURTHEST,
NORM_RULE_FRONT_CLOSEST,
NORM_RULE_FRONT_BEST_CLOSEST
};
int gNormalRules = NORM_RULE_BEST_CLOSEST;
// The output format
enum
{
NORM_OUTPUT_8_8_8_TGA = 0,
NORM_OUTPUT_JOHN_TGA,
NORM_OUTPUT_16_16_ARG,
NORM_OUTPUT_16_16_16_16_ARG,
NORM_OUTPUT_10_10_10_2_ARG,
NORM_OUTPUT_10_10_10_2_ARG_MS,
NORM_OUTPUT_11_11_10_ARG_MS,
};
int gOutput = NORM_OUTPUT_8_8_8_TGA;
// How to generate mip levels
enum
{
MIP_NONE = 0,
MIP_RECOMPUTE,
MIP_BOX
};
int gComputeMipLevels = MIP_NONE;
double gEpsilon = 0.0; // Tolerance value
double gDistance = FLT_MAX; // Maximum distance that a normal is considered
bool gInTangentSpace = true; // Are we putting the normals into tangent space
bool gExpandTexels = true; // Expand the border texels so we don't get crud
// when bi/trilinear filtering
bool gBoxFilter = false; // Perform a post-box filter on normal map?
//////////////////////////////////////////////////////////////////////////////
// Get the sample offsets for supersampling.
//////////////////////////////////////////////////////////////////////////////
Sample*
GetSamples (int numSamples)
{
static Sample s1[] = { {0.0f, 0.0f} };
switch (numSamples)
{
case 1:
{
return s1;
}
case 2:
{
static Sample s2[2] = { {0.5f, 0.5f},
{-0.5f, -0.5f} };
return s2;
}
case 3:
{
static Sample s3[3] = { {0.5f, 0.5f},
{0.0f, 0.0f},
{-0.5f, -0.5f} };
return s3;
}
case 4:
{
static Sample s4[4] = { {0.5f, 0.5f},
{-0.5f, 0.5f},
{0.5f, -0.5f},
{-0.5f, -0.5f} };
return s4;
}
case 5:
{
static Sample s5[5] = { {0.5f, 0.5f},
{-0.5f, 0.5f},
{0.0f, 0.0f},
{0.5f, -0.5f},
{-0.5f, -0.5f} };
return s5;
}
case 9:
{
static Sample s9[9] = { {0.5f, 0.5f},
{0.0f, 0.5f},
{-0.5f, 0.5f},
{-0.5f, 0.0f},
{0.0f, 0.0f},
{0.5f, 0.0f},
{0.5f, -0.5f},
{0.0f, -0.5f},
{-0.5f, -0.5f} };
return s9;
}
case 13:
{
static Sample s13[13] = { { 0.33f, 0.33f},
{ 0.0f, 0.33f},
{-0.33f, 0.33f},
{-0.33f, 0.0f},
{ 0.0f, 0.0f},
{ 0.33f, 0.0f},
{ 0.33f,-0.33f},
{ 0.0f, -0.33f},
{-0.33f,-0.33f},
{ 0.66f, 0.00f},
{-0.66f, 0.00f},
{ 0.00f, 0.66f},
{ 0.00f, 0.66f}};
return s13;
}
case 21:
{
static Sample s21[21] = { { 0.33f, 0.33f},
{ 0.0f, 0.33f},
{-0.33f, 0.33f},
{-0.33f, 0.0f},
{ 0.0f, 0.0f},
{ 0.33f, 0.0f},
{ 0.33f,-0.33f},
{ 0.0f, -0.33f},
{-0.33f,-0.33f},
{ 0.66f, 0.00f},
{ 0.66f, 0.33f},
{ 0.66f,-0.33f},
{-0.66f, 0.00f},
{-0.66f, 0.33f},
{-0.66f,-0.33f},
{ 0.00f, 0.66f},
{ 0.33f, 0.66f},
{-0.33f, 0.66f},
{ 0.33f,-0.66f},
{-0.33f,-0.66f},
{ 0.00f,-0.66f}};
return s21;
}
case 37:
{
static Sample s37[37] = { { 0.25f, 0.25f},
{ 0.0f, 0.25f},
{-0.25f, 0.25f},
{-0.25f, 0.0f},
{ 0.0f, 0.0f},
{ 0.25f, 0.0f},
{ 0.25f,-0.25f},
{ 0.0f, -0.25f},
{-0.25f,-0.25f},
{ 0.50f, 0.00f},
{ 0.50f, 0.25f},
{ 0.50f,-0.25f},
{-0.50f, 0.00f},
{-0.50f, 0.25f},
{-0.50f,-0.25f},
{ 0.00f, 0.50f},
{ 0.25f, 0.50f},
{-0.25f, 0.50f},
{ 0.25f,-0.50f},
{-0.25f,-0.50f},
{ 0.00f,-0.50f},
{ 0.75f, 0.25f},
{ 0.75f, 0.00f},
{ 0.75f,-0.25f},
{ 0.50f, 0.50f},
{ 0.50f,-0.50f},
{ 0.25f, 0.75f},
{ 0.25f,-0.75f},
{ 0.00f, 0.75f},
{ 0.00f,-0.75f},
{-0.25f, 0.75f},
{-0.25f,-0.75f},
{-0.50f, 0.50f},
{-0.50f,-0.50f},
{-0.75f, 0.25f},
{-0.75f, 0.00f},
{-0.75f,-0.25f}};
return s37;
}
case 57:
{
static Sample s57[57] = { {-0.8f, 0.2f},
{-0.8f, 0.0f},
{-0.8f,-0.2f},
{-0.6f, 0.4f},
{-0.6f, 0.2f},
{-0.6f, 0.0f},
{-0.6f,-0.2f},
{-0.6f,-0.4f},
{-0.4f, 0.6f},
{-0.4f, 0.4f},
{-0.4f, 0.2f},
{-0.4f, 0.0f},
{-0.4f,-0.2f},
{-0.4f,-0.4f},
{-0.4f,-0.6f},
{-0.2f, 0.8f},
{-0.2f, 0.6f},
{-0.2f, 0.4f},
{-0.2f, 0.2f},
{-0.2f, 0.0f},
{-0.2f,-0.2f},
{-0.2f,-0.4f},
{-0.2f,-0.6f},
{-0.2f,-0.8f},
{-0.0f, 0.8f},
{-0.0f, 0.6f},
{-0.0f, 0.4f},
{-0.0f, 0.2f},
{-0.0f, 0.0f},
{-0.0f,-0.2f},
{-0.0f,-0.4f},
{-0.0f,-0.6f},
{-0.0f,-0.8f},
{ 0.2f, 0.8f},
{ 0.2f, 0.6f},
{ 0.2f, 0.4f},
{ 0.2f, 0.2f},
{ 0.2f, 0.0f},
{ 0.2f,-0.2f},
{ 0.2f,-0.4f},
{ 0.2f,-0.6f},
{ 0.2f,-0.8f},
{ 0.4f, 0.6f},
{ 0.4f, 0.4f},
{ 0.4f, 0.2f},
{ 0.4f, 0.0f},
{ 0.4f,-0.2f},
{ 0.4f,-0.4f},
{ 0.4f,-0.6f},
{ 0.6f, 0.4f},
{ 0.6f, 0.2f},
{ 0.6f, 0.0f},
{ 0.6f,-0.2f},
{ 0.6f,-0.4f},
{ 0.8f, 0.2f},
{ 0.8f, 0.0f},
{ 0.8f,-0.2f}};
return s57;
}
}
return s1;
}
//////////////////////////////////////////////////////////////////////////
// Test if the new normal is a better fit than the last one.
//////////////////////////////////////////////////////////////////////////
inline bool
IntersectionIsBetter (int rule, NmRawPointD* norm,
double nNorm[3], NmRawPointD* nIntersect,
double lNorm[3], NmRawPointD* lIntersect)
{
// First see if the normal is roughly in the same direction as the low
// resoultion normal.
if (VEC_DotProduct (nNorm, norm->v) > 0.1)
{
// If this is the first intersection we've found.
if ((lNorm[0] == 0.0) && (lNorm[1] == 0.0) && (lNorm[2] == 0.0))
{
return true;
}
// Which ruleset to use.
switch (rule)
{
default:
NmPrint ("Error: Unknown rules set (%d)!\n", rule);
exit (-1);
case NORM_RULE_CLOSEST:
// Pick the closest
if ( (fabs (nIntersect->x) < gDistance) &&
(fabs(nIntersect->x) < fabs(lIntersect->x)) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -