c# - 从纹理创建法线贴图背后的逻辑是什么?

标签 c# xna textures hlsl

我在 google 上看过,但我唯一能找到的是关于如何使用 photoshop 创建一个的教程。不感兴趣!我需要它背后的逻辑。 (而且我不需要如何“使用”凹凸贴图的逻辑,我想知道如何“制作”凹凸贴图!)

我正在编写我自己的 HLSL 着色器,并且已经意识到两个像素之间存在某种渐变,这将显示其正常 - 因此可以相应地照亮光的位置。

我想实时执行此操作,这样当纹理发生变化时,凹凸贴图也会发生变化。

谢谢

最佳答案

我意识到我来晚了,但我最近在尝试为 3ds max 编写自己的法线贴图生成器时也遇到了同样的情况。有庞大且不必要的 C# 库,但没有任何东西妨碍基于数学的简单解决方案。

所以我使用转换背后的数学运算:Sobel 运算符。这就是您希望在着色器脚本中使用的内容。

以下类是我见过的最简单的 C# 实现。它做的正是它应该做的,并完全实现了所期望的:基于高度图、纹理甚至您提供的以编程方式生成的程序的法线贴图。

正如您在代码中看到的那样,我已经实现了 if/else 以减少在边缘检测宽度和高度限制时引发的异常。

它的作用:对每个像素/相邻像素的 HSB 亮度进行采样,以确定输出色调/饱和度值的比例,这些值随后会转换为 RGB 以用于 SetPixel 操作。

顺便说一句:您可以实现一个输入控件来缩放输出色相/饱和度值的强度,以缩放输出法线贴图将提供您的几何/照明的后续影响。

就是这样。无需再处理已弃用的小窗口 PhotoShop 插件。天空是极限。

C# winforms 实现的屏幕截图(源/输出):

enter image description here

C# 类从源图像实现基于 Sobel 的法线贴图:

using System.Drawing;
using System.Windows.Forms;

namespace heightmap.Class
{
    class Normal
    {
        public void calculate(Bitmap image, PictureBox pic_normal)
        {
            Bitmap image = (Bitmap) Bitmap.FromFile(@"yourpath/yourimage.jpg");
            #region Global Variables
            int w = image.Width - 1;
            int h = image.Height - 1;
            float sample_l;
            float sample_r;
            float sample_u;
            float sample_d;
            float x_vector;
            float y_vector;
            Bitmap normal = new Bitmap(image.Width, image.Height);
            #endregion
            for (int y = 0; y < w + 1; y++)
            {
                for (int x = 0; x < h + 1; x++)
                {
                    if (x > 0) { sample_l = image.GetPixel(x - 1, y).GetBrightness(); }
                    else { sample_l = image.GetPixel(x, y).GetBrightness(); }
                    if (x < w) { sample_r = image.GetPixel(x + 1, y).GetBrightness(); }
                    else { sample_r = image.GetPixel(x, y).GetBrightness(); }
                    if (y > 1) { sample_u = image.GetPixel(x, y - 1).GetBrightness(); }
                    else { sample_u = image.GetPixel(x, y).GetBrightness(); }
                    if (y < h) { sample_d = image.GetPixel(x, y + 1).GetBrightness(); }
                    else { sample_d = image.GetPixel(x, y).GetBrightness(); }
                    x_vector = (((sample_l - sample_r) + 1) * .5f) * 255;
                    y_vector = (((sample_u - sample_d) + 1) * .5f) * 255;
                    Color col = Color.FromArgb(255, (int)x_vector, (int)y_vector, 255);
                    normal.SetPixel(x, y, col);
                }
            }
            pic_normal.Image = normal; // set as PictureBox image
        }
    }
}

关于c# - 从纹理创建法线贴图背后的逻辑是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10652797/

相关文章:

c# - 阻止 WP7 模拟器在 Windows 版本调试时启动

c# - 在瓷砖照明中混合颜色的最佳方式? (新华社)

c++ - Cuda - 从设备全局内存复制到纹理内存

c# - HTTP 错误 500.37 - ANCM 无法在启动时间限制内启动

c# - 将类型转换为引用类型

c# - BackgroundWorker RunWorkerCompleted 事件

image - JOGL:一些 GL 常量无法解析

c# - 如何将字符串连接到 int* ?

c++ - 为 wp7 构建了一个可以在 wp8 和 w8 上运行的游戏?

C++ DirectX 11 内存管理关注释放 ShaderResourceView