草庐IT

c++ - 可以从纹理生成法线贴图吗?

coder 2024-02-06 原文

如果我有一个纹理,是否可以为这个纹理生成一个法线贴图,以便它可以用于凹凸贴图?

或者法线贴图通常是如何制作的?

最佳答案

是的。好吧,有点。法线贴图可以从高度贴图准确地制作出来。通常,您也可以放置规则纹理并获得不错的效果。请记住,还有其他制作法线贴图的方法,例如采用高分辨率模型,使其成为低分辨率,然后进行光线转换以查看低分辨率模型模拟较高模型的法线应该是多少。

对于高度贴图到法线贴图,您可以使用 Sobel Operator .该运算符可以在 x 方向上运行,告诉您法线的 x 分量,然后在 y 方向上运行,告诉您 y 分量。您可以使用 1.0/strength 计算 z,其中强度是法线贴图的重点或“深度”。然后,将 x、y 和 z 放入一个 vector 中,对其进行归一化,然后在该点获得法线。将其编码到像素中即可完成。

这里有一些较旧的不完整代码可以证明这一点:

// 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;
}

关于c++ - 可以从纹理生成法线贴图吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2368728/

有关c++ - 可以从纹理生成法线贴图吗?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  3. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  4. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  5. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  6. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  7. ruby - 是否可以覆盖 gemfile 进行本地开发? - 2

    我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI

  8. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  9. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  10. ruby - 可以通过多少种方法将方法添加到 ruby​​ 对象? - 2

    当谈到运行时自省(introspection)和动态代码生成时,我认为ruby​​没有任何竞争对手,可能除了一些lisp方言。前几天,我正在做一些代码练习来探索ruby​​的动态功能,我开始想知道如何向现有对象添加方法。以下是我能想到的3种方法:obj=Object.new#addamethoddirectlydefobj.new_method...end#addamethodindirectlywiththesingletonclassclass这只是冰山一角,因为我还没有探索instance_eval、module_eval和define_method的各种组合。是否有在线/离线资

随机推荐