CPU 到 GPU 法线映射

2024-04-28

我正在创建一个地形网格,然后这个答案 https://stackoverflow.com/a/5284527/1356106我正在尝试将 CPU 计算法线迁移到基于着色器的版本,以便通过降低网格分辨率并使用在片段着色器中计算的法线贴图来提高性能。

我在用着MapBox高度图 https://docs.mapbox.com/help/troubleshooting/access-elevation-data/#mapbox-terrain-rgb用于地形数据。瓷砖看起来像这样:

每个像素的高程由以下公式给出:

const elevation = -10000.0 + ((red * 256.0 * 256.0 + green * 256.0 + blue) * 0.1);

我的原始代码首先创建一个密集网格(256*256 个正方形,由 2 个三角形组成),然后计算三角形和顶点法线。为了获得视觉上令人满意的结果,我将标高降低了 5000,以匹配场景中图块的宽度和高度(将来我将进行适当的计算以显示真实标高)。

我用这些简单的着色器绘图:

顶点着色器:

uniform mat4 u_Model;
uniform mat4 u_View;
uniform mat4 u_Projection;

attribute vec3 a_Position;
attribute vec3 a_Normal;
attribute vec2 a_TextureCoordinates;

varying vec3 v_Position;
varying vec3 v_Normal;
varying mediump vec2 v_TextureCoordinates;

void main() {

  v_TextureCoordinates = a_TextureCoordinates;
  v_Position = vec3(u_View * u_Model * vec4(a_Position, 1.0));
  v_Normal = vec3(u_View * u_Model * vec4(a_Normal, 0.0));
  gl_Position = u_Projection * u_View * u_Model * vec4(a_Position, 1.0);
}

片段着色器:

precision mediump float;

varying vec3 v_Position;
varying vec3 v_Normal;
varying mediump vec2 v_TextureCoordinates;

uniform sampler2D texture;

void main() {

    vec3 lightVector = normalize(-v_Position);
    float diffuse = max(dot(v_Normal, lightVector), 0.1);

    highp vec4 textureColor = texture2D(texture, v_TextureCoordinates);
    gl_FragColor = vec4(textureColor.rgb * diffuse, textureColor.a);
}

虽然速度很慢,但给出了视觉上令人满意的结果:

现在,我删除了所有基于 CPU 的法线计算代码,并用以下代码替换了我的着色器:

顶点着色器:

#version 300 es

precision highp float;
precision highp int;

uniform mat4 u_Model;
uniform mat4 u_View;
uniform mat4 u_Projection;

in vec3 a_Position;
in vec2 a_TextureCoordinates;

out vec3 v_Position;
out vec2 v_TextureCoordinates;
out mat4 v_Model;
out mat4 v_View;

void main() {

  v_TextureCoordinates = a_TextureCoordinates;
  v_Model = u_Model;
  v_View = u_View;

  v_Position = vec3(u_View * u_Model * vec4(a_Position, 1.0));
  gl_Position = u_Projection * u_View * u_Model * vec4(a_Position, 1.0);
}

片段着色器:

#version 300 es

precision highp float;
precision highp int;

in vec3 v_Position;
in vec2 v_TextureCoordinates;

in mat4 v_Model;
in mat4 v_View;

uniform sampler2D u_dem;
uniform sampler2D u_texture;

out vec4 color;

const vec2 size = vec2(2.0,0.0);
const ivec3 offset = ivec3(-1,0,1);

float getAltitude(vec4 pixel) {

  float red = pixel.x;
  float green = pixel.y;
  float blue = pixel.z;

  return (-10000.0 + ((red * 256.0 * 256.0 + green * 256.0 + blue) * 0.1)) * 6.0; // Why * 6 and not / 5000 ??
}

void main() {

    float s01 = getAltitude(textureOffset(u_dem, v_TextureCoordinates, offset.xy));
    float s21 = getAltitude(textureOffset(u_dem, v_TextureCoordinates, offset.zy));
    float s10 = getAltitude(textureOffset(u_dem, v_TextureCoordinates, offset.yx));
    float s12 = getAltitude(textureOffset(u_dem, v_TextureCoordinates, offset.yz));

    vec3 va = (vec3(size.xy, s21 - s01));
    vec3 vb = (vec3(size.yx, s12 - s10));

    vec3 normal = normalize(cross(va, vb));
    vec3 transformedNormal = normalize(vec3(v_View * v_Model * vec4(normal, 0.0)));

    vec3 lightVector = normalize(-v_Position);
    float diffuse = max(dot(transformedNormal, lightVector), 0.1);

    highp vec4 textureColor = texture(u_texture, v_TextureCoordinates);
    color = vec4(textureColor.rgb * diffuse, textureColor.a);
}

现在它几乎立即加载,但有些问题:

  • 在片段着色器中,我必须将高程乘以 6,而不是除以 5000,才能得到接近原始代码的值
  • 结果不太好。特别是当我倾斜场景时,阴影非常暗(倾斜得越多,阴影就越暗):

你能找出造成这种差异的原因吗?

编辑:我创建了两个 JSFiddles:

  • CPU 计算顶点法线的第一个版本:http://jsfiddle.net/tautin/tmugzv6a/10 http://jsfiddle.net/tautin/tmugzv6a/10
  • 使用 GPU 计算法线贴图的第二个版本:http://jsfiddle.net/tautin/8gqa53e1/42 http://jsfiddle.net/tautin/8gqa53e1/42

当您使用倾斜滑块时会出现问题。


我发现了三个问题。

您看到并通过反复试验修复了一个问题,即您的身高计算比例错误。在 CPU 中,颜色坐标从 0 到 255 变化,但在 GLSL 上,纹理值从 0 到 1 标准化,因此正确的高度计算是:

return (-10000.0 + ((red * 256.0 * 256.0 + green * 256.0 + blue) * 0.1 * 256.0)) / Z_SCALE;

但对于此着色器目的,-10000.00 并不重要,因此您可以执行以下操作:

return (red * 256.0 * 256.0 + green * 256.0 + blue) * 0.1 * 256.0 / Z_SCALE;

第二个问题是你的 x 和 y 坐标的比例也是错误的。在CPU代码中,两个相邻点之间的距离是(SIZE * 2.0 / (RESOLUTION + 1)),但在 GPU 中,您已将其设置为 1。定义您的正确方法size变量是:

const float SIZE = 2.0;
const float RESOLUTION = 255.0;

const vec2 size = vec2(2.0 * SIZE / (RESOLUTION + 1.0), 0.0);

请注意,我将分辨率提高到255因为我认为这就是您想要的(一减去纹理分辨率)。此外,这需要匹配的值offset,您将其定义为:

const ivec3 offset = ivec3(-1,0,1);

要使用不同的RESOLUTION值,你必须调整offset因此,例如为了RESOLUTION == 127, offset = ivec3(-2,0,2),即偏移量必须是<real texture resolution>/(RESOLUTION + 1),这限制了可能性RESOLUTION,因为偏移量必须是整数。

第三个问题是你在GPU中使用了不同的正常计算算法,这让我觉得它的分辨率比CPU上使用的算法低,因为你使用了十字的四个外部像素,但忽略了中心像素。似乎这不是故事的全部,但我无法解释为什么它们如此不同。我尝试按照我的想法实现准确的 CPU 算法,但它产生了不同的结果。相反,我必须使用以下算法,该算法相似但不完全相同,才能获得几乎相同的结果(如果将 CPU 分辨率提高到 255):

    float s11 = getAltitude(texture(u_dem, v_TextureCoordinates));
    float s21 = getAltitude(textureOffset(u_dem, v_TextureCoordinates, offset.zy));
    float s10 = getAltitude(textureOffset(u_dem, v_TextureCoordinates, offset.yx));

    vec3 va = (vec3(size.xy, s21 - s11));
    vec3 vb = (vec3(size.yx, s10 - s11));

    vec3 normal = normalize(cross(va, vb));

这是原始的 CPU 解决方案,但 RESOLUTION=255:http://jsfiddle.net/k0fpxjd8/ http://jsfiddle.net/k0fpxjd8/

这是最终的 GPU 解决方案:http://jsfiddle.net/7vhpuqd8/ http://jsfiddle.net/7vhpuqd8/

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

CPU 到 GPU 法线映射 的相关文章

  • LWJGL 窗口具有透明背景?

    我想创建一个没有 黑色背景 区域的窗口 但您可以看到任何其他打开的窗口等 也就是说 渲染场景并且仅渲染场景 不留框架 不留背景区域 我读过一种方法 该方法涉及渲染到隐藏的 OpenGL 窗口并将其缓冲在内存中 创建透明分层窗口以及从内存复制
  • OpenGL:多个顶点的单个顶点属性?

    我有一个接受以下属性的顶点着色器 a posCoord 顶点位置 a texCoord 纹理坐标 传递给片段着色器 a alpha 透明度因子 传递给片段着色器 我正在渲染的对象都是 广告牌 一对直角三角形组成一个矩形 我正在使用一次调用g
  • Unity 后处理 PostProcessEffectRenderer 在编辑器中显示,但在构建中不显示

    将 PostProcessEffectRenderer 的实现添加到 Unity 后处理堆栈后 效果在 Unity 编辑器中完美运行 但不会在构建的游戏中显示 对构建质量的更改没有效果 使用针对 Windows x86 64 构建的最高质量
  • OpenGL Z 偏置(多边形偏移)限制

    我有两个共面的多边形 我尝试做 glEnable GL POLYGON OFFSET FILL glPolygonOffset 0 1 并期望其中一个明显 位于 另一个之上 这种情况直到大约 70 75 个单位之外 近剪裁平面为 1 远剪裁
  • 交错顶点提交如何提高性能?

    我已经阅读并看到了其他问题 这些问题通常都指向将顶点位置和颜色等交错到一个数组中的建议 因为这可以最大限度地减少从 cpu 发送到 gpu 的数据 我不清楚的是 即使使用交错数组 您仍然必须对位置和颜色指针进行单独的 GL 调用 OpenG
  • 使用 Opengl 绘制立方体 3D

    我想使用 OpenGL 绘制 3D 立方体这是我的代码如何纠正错误 float ver 8 3 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0
  • 如何用opengl制作2D地形?

    我想制作一个简单的二维地形 只有一些颠簸和高度变化 我想过只使用随机数来描述某个顶点的高度 但我不知道如何从中制作一个网格 我正在寻找一种方法来查找地形的顶点和索引缓冲区 我该怎么做呢 您可以仅将 GL POLYGON 与所有顶点的列表一起
  • 法线在 openGL 中表现得很奇怪

    我一直在为 openGl 编写一个 obj 加载器 几何体加载得很好 但法线总是混乱的 我尝试在两个不同的程序中导出模型 但似乎没有任何效果 据我所知 这就是将法线放入 GL TRIANGLES 的方法 glNormal3fv norm1
  • OpenGL 和加载/读取 AoSoA(混合 SoA)格式的数据

    假设我有以下 AoSoA 格式的简化结构来表示顶点或点 struct VertexData float px 4 position x float py 4 position y 也就是说 每个实例VertexData存储4个顶点 我见过的
  • glEnableVertexAttribArray 中“index”参数的含义以及(可能)OS X OpenGL 实现中的错误

    1 我是否正确理解 要使用顶点数组或VBO进行绘制 我需要所有属性在着色器程序链接之前调用glBindAttribLocation 或者在着色器程序成功链接后调用glGetAttribLocation 然后使用glVertexAttribP
  • 阻止 OpenGL.framework 在 Cocoa 应用程序中加载

    我的应用程序链接到这些框架 Cocoa Framework AppKit Framework CoreData Framework Foundation Framework 请注意 OpenGL Framework 是NOT已链接 但是 设
  • LibGDX - 着色器适用于桌面但不适用于 Android

    我编写了一个简单的程序 可以在 3D 环境中渲染球体 并根据球体周围的四个光源为其着色 当我在桌面上运行该程序时 它工作得很好 但在 Android 设备上 球体只是纯色的 下面是一些图片来说明我正在谈论的内容 gt Desktop gt
  • 将像素传递给 glTexImage2D() 后会发生什么?

    例如 如果我创建一个像素数组 如下所示 int getPixels int pixels new int 10 pixels 0 1 pixels 1 0 pixels 1 1 etc glTexImage2D getPixels glTe
  • 使用draw()而不是eventloop时的pyglet

    我正在尝试用 pyglet 画一个圆 但当我使用 draw 函数而不是 app run 循环时 它是不可见的 有什么建议我可以做什么吗 谢谢 from math import from pyglet gl import window pyg
  • NV_path_rendering替代方案[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我刚刚观看了 Siggraph 2012 的一个非常令人印象深刻的演示 http nvidia fullviewmedia com sig
  • glut 库中缺少 glutInitContextVersion()

    我正在练习一些 opengl 代码 但是当我想通过以下方式强制 opengl 上下文使用特定版本的 opengl 时glutInitContextVersion 它编译过程失败并给出以下消息 使用未声明的标识符 glutInitContex
  • SDL 鼠标位置调整大小后裁剪

    我在 SDL 中的鼠标位置上遇到了一些奇怪的行为 如果我将窗口大小调整得更大 则任一鼠标事件的 x y 位置似乎都限制为原始窗口的宽度和高度 如果我缺少一些函数调用来告诉 SDL 鼠标区域的大小已增加 应用程序的相关部分 void Resi
  • 如何在 GTX 560 及更高版本上使用 OpenGL 进行立体 3D?

    我正在使用在 Windows 7 上运行的开源触觉和 3D 图形库 Chai3D 我重写了该库以使用 Nvidia nvision 执行立体 3D 我将 OpenGL 与 GLUT 一起使用 并使用 glutInitDisplayMode
  • 如果我用opengl绘图的话SDL Renderer就没用了吗?

    我正在学习 SDL2 但我也在使用使用 OpenGL 调用的 imgui 库 从我在网上各种博客上读到的内容来看 我无法轻松混合 SDL2 渲染器和 opengl 调用 我要么使用其中之一 要么使用另一个 我读过的大多数教程都使用渲染器 所
  • 为什么OpenGL使用float而不是double? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi

随机推荐

  • 有没有办法在坐标平面上动态绘制点之间的线?

    我正在完成一个项目 在该项目中我实现了一个暴力算法来解决凸包问题 我还需要为该算法创建视觉效果 我试图在 x 轴和 y 轴上创建一个范围从 100 100 的坐标平面 绘制完整集中的所有点 并在点之间动态绘制线条以创建凸包 例如 假设我有
  • 如何在Python中的滚动平均计算中忽略NaN

    对于时间序列销售预测任务 我想创建一个代表过去 3 天平均销售额的功能 当我想预测未来几天的销售额时遇到问题 因为这些数据点没有销售数据 NaN 值 Pandas 提供rolling mean 但当窗口中的任何数据点为 NaN 时 该函数会
  • 当考虑性能时如何从文件中读取整数?

    我正在 CodeEval 上执行一些任务 基本上任务非常简单 打印出从文件中读取的所有整数的总和 我的解决方案如下 import java io File import java io IOException import java io
  • HDP 3.1.0.0-78 升级后无法使用 ResourceManager UI 终止 YARN 应用程序

    我最近将 HDP 从 2 6 5 升级到 3 1 0 它运行 YARN 3 1 0 并且我无法再使用旧的 8088 cluster apps 或新的 8088 从 YARN ResourceManager UI 终止应用程序 ui2 ind
  • qt 读取就绪信号

    我正在尝试与运行 1996 年处理器的设备建立串行连接 这意味着数据传输回我可能需要几秒钟的时间 我知道readyRead每次有新数据可用时都会生成信号 但我的问题是生成多长时间 这也是我可以测试就绪读取是否较低的一种方法 因为如果当它们不
  • 初学者 MYSQL 错误 - 访问被拒绝

    错误 1045 28000 用户 root localhost 的访问被拒绝 使用密码 N 哦 我已经尝试了一切 我已经阅读了一页又一页的答案 但似乎没有人知道正确的答案 当我尝试登录我的数据库时 我只是收到上述错误 我还没有设置密码或其他
  • Xamarin Mac 中 AttributeName 的用途

    我正在尝试对 Xamarin 中的 NSMutableAttributedString 中的子字符串进行着色 但它似乎缺少正确的常量 我应该在那里放什么 Update 这越来越接近 var s new NSMutableAttributed
  • 将行追加到 Pandas DataFrame 添加 0 列

    我正在创建一个 Pandas DataFrame 来存储数据 不幸的是 我无法提前知道我将拥有的数据行数 所以我的方法如下 首先 我声明一个空的 DataFrame df DataFrame columns col1 col2 然后 我附加
  • 在 JavaScript 中将带有哈希值的十六进制字符串转换为带有 0x 的十六进制值的最佳方法?

    这个问题不是问如何将哈希字符串十六进制值转换为其相反的颜色 这个问题询问如何将哈希字符串十六进制值转换为常规十六进制值 如下所述 我从元素的存储样式中获取元素的十六进制颜色值 我需要将它们的十六进制值 带有像 FFFFFF 这样的哈希值的字
  • 如何让供应商与 Google App Engine 配合使用?

    我正在尝试引入 Go 供应商 将依赖项存储在名为的文件夹中 vendor 到现有的 App Engine 项目 我已将所有依赖项存储在供应商文件夹中 使用 Godep 作为助手 它看起来是正确的 但在本地运行应用程序时出现以下错误 go a
  • Java 8 中接口和抽象类之间的根本区别[重复]

    这个问题在这里已经有答案了 考虑到接口现在可以为其提供的方法提供实现 我无法正确合理地解释接口和抽象类之间的差异 有谁知道如何正确解释其中的差异 我还被告知 从性能角度来看 接口比抽象类更轻量 有人可以证实这一点吗 接口仍然不能有任何状态
  • Firefox 中的代理设置不会“粘连”

    在家里我们有一个代理服务器 在工作中我们不会 Firefox 在这方面令人恼火 每当我启动它时 它都会默认使用代理服务器 如果我执行 工具 gt 选项 gt 设置 并选择 无代理 则没有问题 但是 如果我关闭 Firefox 并重新启动它
  • 使用 zeppelin 在 kubernetes 上 Spark

    我按照本指南在使用 minikube 设置的本地 kubernetes 集群中运行 zeppelin 容器 https zeppelin apache org docs 0 9 0 SNAPSHOT quickstart kubernete
  • 哪个是对的? catch (_com_error e) 还是 catch (_com_error& e)?

    我应该使用哪一个 catch com error e or catch com error e 第二 这是我试图引用萨特的话 按值抛出 按引用捕获 学会catch正确 按值 而不是指针 抛出异常 通过引用捕获它们 通常是const 这是组合
  • 如何在“Where”子句之前写“Order By”子句

    我想写一个ORDER BY我之前的子句WHERE条件 因为我需要将结果截断为 10 但我需要首先按字母顺序对它们进行排序 我知道你不能把ORDER BY before WHERE那我该怎么办呢 我需要做类似以下的事情 SELECT FROM
  • protobuf-net v2 和 Monotouch:它如何混合?

    我一直在尝试将 protobuf net 与 MonoTouch 一起使用 但我不知道如何使用 尽管听说这是可能的 但我还没有找到任何教程或任何实际有效的示例 马克 格拉维尔证实了这一消息在他的博客上 http marcgravell bl
  • 在网络视图中打开 pdf 文件。

    我有一个应用程序 在网页视图中呈现的网页上有按钮 现在点击按钮 就会下载一个 pdf 文件 然后需要在同一个 web 视图中打开该文件 将下载侦听器附加到 Web 视图并更改 url 如下所示 https docs google com g
  • 主屏幕活动快捷方式

    我有 2 项活动 1 主要活动 2 第二个活动 我希望创建第二个活动的主屏幕快捷方式 Intent shortcutIntent new Intent getApplicationContext SecondActivity class s
  • Android - 深色模式问题:深色背景上的黑色文本

    当我启用深色模式时 我的应用程序上的某些菜单看起来很糟糕 非常暗的背景上的黑色文本 我对颜色完全是一个初学者 我还没有接触过 android studio 上默认颜色设置的任何内容 所以我有默认的两个主题 XML 和 Color Xml
  • CPU 到 GPU 法线映射

    我正在创建一个地形网格 然后这个答案 https stackoverflow com a 5284527 1356106我正在尝试将 CPU 计算法线迁移到基于着色器的版本 以便通过降低网格分辨率并使用在片段着色器中计算的法线贴图来提高性能