gpt4 book ai didi

opengl - CPU 到 GPU 法线映射

转载 作者:行者123 更新时间:2023-12-04 04:05:56 27 4
gpt4 key购买 nike

我正在创建地形网格,并遵循 this SO answer我正在尝试将我的 CPU 计算法线迁移到基于着色器的版本,以便通过降低我的网格分辨率和使用在片段着色器中计算的法线贴图来提高性能。

我正在使用 MapBox height map对于地形数据。瓷砖看起来像这样:

enter image description here

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

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

速度很慢,但视觉效果令人满意:

enter image description here

现在,我删除了所有基于 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 以获得接近原始代码的结果
  • 结果不是那么好。特别是当我倾斜场景时,阴影非常暗(我倾斜得越多,它们就越暗):

enter image description here

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

编辑:我创建了两个 JSFiddles:

当您使用倾斜 slider 播放时出现问题。

最佳答案

我能找到三个问题。

一个是你看到的,通过反复试验修正的,就是你的高度计算的比例是错误的。在 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值(value),你将不得不调整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/

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

关于opengl - CPU 到 GPU 法线映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62519673/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com