如果我有一个纹理,那么是否可以为这个纹理生成一个法线贴图,以便它可以用于凹凸贴图?
或者法线贴图通常是如何制作的?
发布于 2010-03-03 12:32:58
是。嗯,算是吧。法线贴图可以从高度贴图中精确地生成。一般来说,你也可以通过一个常规纹理,并获得良好的结果。请记住,还有其他方法可以制作法线贴图,例如采用高分辨率模型,使其分辨率较低,然后进行光线投射,以查看低分辨率模型模拟较高模型的法线应该是什么。
对于高度映射到法线映射,您可以使用Sobel Operator。这个运算符可以在x方向上运行,告诉你法线的x分量,然后是y方向,告诉你y分量。可以使用1.0 / strength计算z,其中强度是法线贴图的重点或“深度”。然后,把x,y,z放到一个向量中,归一化,你就得到了那个点的法线。将其编码到像素中,就完成了。
以下是一些较旧的不完整代码,演示了这一点:
// pretend types, something like this
struct pixel
{
uint8_t red;
uint8_t green;
uint8_t blue;
};
struct vector3d; // a 3-vector with doubles
struct texture; // a 2d array of pixels
// determine intensity of pixel, from 0 - 1
const double intensity(const pixel& pPixel)
{
const double r = static_cast<double>(pPixel.red);
const double g = static_cast<double>(pPixel.green);
const double b = static_cast<double>(pPixel.blue);
const double average = (r + g + b) / 3.0;
return average / 255.0;
}
const int clamp(int pX, int pMax)
{
if (pX > pMax)
{
return pMax;
}
else if (pX < 0)
{
return 0;
}
else
{
return pX;
}
}
// transform -1 - 1 to 0 - 255
const uint8_t map_component(double pX)
{
return (pX + 1.0) * (255.0 / 2.0);
}
texture normal_from_height(const texture& pTexture, double pStrength = 2.0)
{
// assume square texture, not necessarily true in real code
texture result(pTexture.size(), pTexture.size());
const int textureSize = static_cast<int>(pTexture.size());
for (size_t row = 0; row < textureSize; ++row)
{
for (size_t column = 0; column < textureSize; ++column)
{
// surrounding pixels
const pixel topLeft = pTexture(clamp(row - 1, textureSize), clamp(column - 1, textureSize));
const pixel top = pTexture(clamp(row - 1, textureSize), clamp(column, textureSize));
const pixel topRight = pTexture(clamp(row - 1, textureSize), clamp(column + 1, textureSize));
const pixel right = pTexture(clamp(row, textureSize), clamp(column + 1, textureSize));
const pixel bottomRight = pTexture(clamp(row + 1, textureSize), clamp(column + 1, textureSize));
const pixel bottom = pTexture(clamp(row + 1, textureSize), clamp(column, textureSize));
const pixel bottomLeft = pTexture(clamp(row + 1, textureSize), clamp(column - 1, textureSize));
const pixel left = pTexture(clamp(row, textureSize), clamp(column - 1, textureSize));
// their intensities
const double tl = intensity(topLeft);
const double t = intensity(top);
const double tr = intensity(topRight);
const double r = intensity(right);
const double br = intensity(bottomRight);
const double b = intensity(bottom);
const double bl = intensity(bottomLeft);
const double l = intensity(left);
// sobel filter
const double dX = (tr + 2.0 * r + br) - (tl + 2.0 * l + bl);
const double dY = (bl + 2.0 * b + br) - (tl + 2.0 * t + tr);
const double dZ = 1.0 / pStrength;
math::vector3d v(dX, dY, dZ);
v.normalize();
// convert to rgb
result(row, column) = pixel(map_component(v.x), map_component(v.y), map_component(v.z));
}
}
return result;
}发布于 2010-03-03 12:53:13
可能有很多方法可以生成法线贴图,但就像其他人所说的,你可以从高度贴图中生成法线贴图,像XSI/3dsmax/Blender/它们中的任何一个3d包都可以为你输出一个作为图像。
然后,您可以使用photoshop的Nvidia插件输出RGB图像,转换算法,或者您可以使用第三方插件直接从这些3d包中输出图像。
请注意,在某些情况下,可能需要从生成的法线贴图中反转通道(R、G或B)。
这里有一些例子和更完整的解释的资源链接:
发布于 2010-03-03 12:28:57
我不认为法线贴图是从纹理生成的。它们是从模型中生成的。
就像纹理允许你用最少的多边形来定义复杂的颜色细节(而不是仅仅使用数百万的技巧和仅仅的顶点颜色来定义网格上的颜色)
法线贴图允许您使用最少的多边形定义复杂的法线细节。
我认为法线贴图通常是从较高分辨率网格生成的,然后与低分辨率网格一起使用。
我相信3D工具,如3ds max或maya,以及更具体的工具将会为你做这件事。与纹理不同,我不认为它们通常是手工完成的。
但它们是从网格生成的,而不是纹理。
https://stackoverflow.com/questions/2368728
复制相似问题