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 法线映射 的相关文章

  • 如何计算正切和副法线?

    谈谈OpenGL着色语言 GLSL 中的凹凸贴图 镜面高光之类的东西 I have 顶点数组 例如 0 2 0 5 0 1 0 2 0 4 0 5 法线数组 例如 0 0 0 0 1 0 0 0 1 0 0 0 世界空间中点光源的位置 例如
  • 为什么我的 CAOpenGLLayer 更新速度比之前的 NSOpenGLView 慢?

    我有一个在 Mac OS X 上渲染 OpenGL 内容的应用程序 最初它渲染到 NSOpenGLView 然后我将其更改为渲染到 CAOpenGLLayer 子类 当我这样做时 我看到了巨大的性能损失 帧速率减半 鼠标响应能力降低 卡顿
  • 按像素值偏移 gl_Position 或 gl_Vertex

    我的属性包含像素值 我想用这个属性值来偏移我的 gl vertex 问题是我的 gl vertex 以世界单位为单位 而 offset attribute 以像素为单位 如果我将屏幕尺寸作为统一发送 然后将像素转换为 1 到 1 值 并将其
  • OpenGL - 自动生成 glDrawArrays 的索引/步幅参数

    我正在渲染一个包含大量数据点 gt 1M 的网格结构 我的数据结构如图所示 所以我的索引缓冲区的内容看起来像这样0 100 1 101 2 102 3 103 我对索引缓冲区的巨大尺寸有点恼火 我需要它来定义我的三角形带 是否有可能告诉 O
  • 在 OpenGL 中实例化数百万个对象:提高每秒帧数

    我的最终目标是以 60 fps 渲染 100 万个不同尺寸和颜色的球体 我也希望能够在屏幕上移动相机 我已经修改了代码我正在学习的教程的这一页 http learnopengl com Advanced OpenGL Instancing尝
  • 创建并使用我自己的纹理图集的 mipmap

    我目前正在使用自动 mipmap 生成 C OpenTK GL GenerateMipmap GenerateMipmapTarget Texture2D 我使用的纹理平铺为 16px 的块 所以我的问题是 是否可以使用不会缩小至 1x1
  • 渲染到一个颜色通道而不影响其他通道

    使用 OpenGL 任何版本 如何通过一次仅影响一个颜色通道来渲染到帧缓冲区对象 例如 我的帧缓冲区对象具有 GL BGRA 布局 现在我想执行一些渲染命令 这些命令应该只改变红色通道 因此 如果片段用颜色 204 0 0 0 渲染并且像素
  • 金属中的 SCN 着色器修改器 - 将统一传递给着色器

    我正在尝试将着色器修改器与 Metal 一起使用 我无法弄清楚如何声明制服 到目前为止我的片段修饰符是 color changes pragma arguments float4x4 u color transformation pragm
  • WGL:没有双缓冲 + 多重采样 = 失败?

    我通常使用创建像素格式wglChoosePixelFormatARB 与这些论点 除其他外 WGL DOUBLE BUFFER ARB GL TRUE WGL SAMPLE BUFFERS ARB GL TRUE WGL SAMPLES A
  • Windows 上的 OpenGL SDK

    我正在尝试编写一个 OpenGL 应用程序 因此我安装了 Windows 7 SDK 然而 它似乎是OpenGL 1 1 define GL VERSION 1 1 1 如何找到我安装的 OpenGL 版本 dll 以及在哪里可以找到较新的
  • Retina 显示屏中具有 QOpenGLWIdget 的 Qt MainWindow 显示错误大小

    我有一个 Qt 应用程序MainWindow 我嵌入一个QOpenGLWidget在里面 一切正常 直到我开始使用 Apple Retina 显示屏并在高 DPI 模式下运行我的应用程序 我的QOpenGLWidget只是它应该具有的大小的
  • 如何创建自己的 openGL 上下文并将其绑定到 GLCanvas?

    所以当我开始掌握java时 paint Graphics g 我继续创建自己的渲染方法 但我必须了解缓冲区策略以及如何 获取 图形 所以现在我在学习openGL 我必须掌握方法 Override public void display GL
  • 如何使用OpenGL数组纹理?

    我正在尝试在OpenGL中使用精灵表 通过数组纹理实现它这就是我加载纹理的方式 QImage image image load C QtProjects project images spritesheet png png const un
  • glTranslatef 不在 glBegin .. glEnd 中工作

    我正在尝试并排绘制不同颜色的两个方块 我的问题是我无法让 glTranslatef 将第二个方块向右移动 第二个方块只是绘制在第一个方块上 void display void glClear GL COLOR BUFFER BIT glMa
  • 新显卡上的 nvoglv32.dll 中的绘制调用崩溃

    几天前 由于一些硬件更改 我设置了计算机并安装了新的 Windows 8 副本 其中 我将显卡从 Radeon HD 7870 更改为 Nvidia GTX 660 再次设置 Visual Studio 11 后 我从 Github 下载了
  • OpenGL 新手: glutMouseFunc

    我试图在单击鼠标后更改球体位置 但在使用 glutMouseFunc 中的 x 和 y 时它不起作用 以下是代码 include stdafx h include
  • sRGB 纹理。它是否正确?

    我最近阅读了一些有关 sRGB 格式以及它们如何允许硬件自动对典型显示器执行色彩校正的文章 作为我阅读的一部分 我发现您可以使用普通纹理和返回结果上的 pow 函数来模拟此步骤 无论如何 我想问两个问题 因为我以前从未使用过此功能 首先 有
  • 如何连接重叠的圆圈?

    我想在视觉上连接两个重叠的圆圈 以便 becomes 我已经有部分圆的方法 但现在我需要知道每个圆的重叠角度有多大 但我不知道该怎么做 有人有主意吗 Phi ArcTan Sqrt 4 R 2 d 2 d HTH Edit 对于两个不同的半
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 并排显示图像的一半 - OpenGL

    我为两个图像创建了两个纹理 现在我想在opengl中按图像2的左侧部分 完整的图像1 图像2的右侧部分的顺序显示该纹理 我已经做了如下 Image1 显示在 opengl 屏幕的中央 但屏幕的左右部分不正确 应分别显示 image2 的左侧

随机推荐

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

    我正在完成一个项目 在该项目中我实现了一个暴力算法来解决凸包问题 我还需要为该算法创建视觉效果 我试图在 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 计算法线迁移到基于着色器的版本 以便通过降低网格分辨率并使用在片段着色器中计算的法线贴图来提高性能