Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/opengl/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/apache-kafka/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Opengl CPU到GPU的法线映射_Opengl_Shader_Fragment Shader_Normals_Glsles - Fatal编程技术网

Opengl CPU到GPU的法线映射

Opengl CPU到GPU的法线映射,opengl,shader,fragment-shader,normals,glsles,Opengl,Shader,Fragment Shader,Normals,Glsles,我正在创建一个地形网格,接下来我尝试将CPU计算的法线迁移到基于着色器的版本,以便通过降低网格分辨率和使用片段着色器中计算的法线贴图来提高性能 我用的是地形数据。瓷砖如下所示: 每个像素处的高程由以下公式给出: const elevation = -10000.0 + ((red * 256.0 * 256.0 + green * 256.0 + blue) * 0.1); 我的原始代码首先创建一个密集网格(2个三角形的256*256个正方形),然后计算三角形和顶点法线。为了得到一个视觉上令

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

我用的是地形数据。瓷砖如下所示:

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

const elevation = -10000.0 + ((red * 256.0 * 256.0 + green * 256.0 + blue) * 0.1);
我的原始代码首先创建一个密集网格(2个三角形的256*256个正方形),然后计算三角形和顶点法线。为了得到一个视觉上令人满意的结果,我将标高降低了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);
}
#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);
}
片段着色器:

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);
}
#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);
}
虽然速度很慢,但视觉效果令人满意:

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

顶点着色器:

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);
}
#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);
}
片段着色器:

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);
}
#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,才能得到接近原始代码的值
  • 结果不太好。特别是当我倾斜场景时,阴影非常暗(倾斜越深):

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

编辑:我创建了两个JSIDdle:

  • 具有CPU计算顶点法线的第一个版本:
  • 具有GPU计算法线贴图的第二个版本:

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

我发现有三个问题

一个是你看到的,经过反复试验修正的,那就是你身高计算的比例是错误的。在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代码中,两个相邻点之间的距离是
(大小*2.0/(分辨率+1))
,但在GPU中,您已将其设置为1。定义
大小
变量的正确方法是:

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

const vec2 size = vec2(2.0 * SIZE / (RESOLUTION + 1.0), 0.0);
请注意,我将分辨率增加到了
255
,因为我假设这是您想要的(一减去纹理分辨率)。此外,这需要与
偏移量
的值相匹配,您将其定义为:

const ivec3 offset = ivec3(-1,0,1);
要使用不同的
分辨率
值,您必须相应地调整
偏移量
,例如对于
分辨率==127
偏移量=ivec3(-2,0,2)
,即偏移量必须是
/(分辨率+1)
,这限制了
分辨率的可能性,因为偏移量必须是整数

第三个问题是,你在GPU中使用了不同的常规计算算法,我觉得它的分辨率比CPU上使用的低,因为你使用了十字的四个外部像素,但忽略了中心像素。这似乎不是全部,但我无法解释为什么它们如此不同。我试图实现我认为应该实现的精确CPU算法,但结果不同。取而代之的是,我不得不使用下面的算法,这是类似的,但并不完全相同,以获得几乎相同的结果(如果您将CPU分辨率增加到255):

这是原始的CPU解决方案,但分辨率为255:


这是最终的GPU解决方案:

256x256网格的唯一用途是通过法线?你不是用它来做高度位移吗?例如,在第二种方法中,您绘制了多少个三角形?256*256图片包含每个像素的高程,而不是法线。我通过它来计算法线。我不知道你所说的高度位移是什么意思(对不起,我在OpenGL/WebGL方面的经验非常有限),所以我想答案是否定的:)高度位移是指
a_位置
变量的“向上”坐标。你是否根据高度贴图中的高度设置顶点的高度?哦,好的,那么是的,我正在这样做。但在新版本中,我的网格分辨率要低得多(32*32)。编辑:我将顶点位置除以5000,而不是乘以6。现在我看到这不是一个移动游戏,它只在需要时渲染,不,我认为不会有性能问题(但你永远不知道客户端运行的是什么硬件)。现在我也理解了性能问题,因为正常的映射计算是用JavaScript完成的,而不是在某些编译语言上。非常感谢!!现在它确实几乎完全相同:)。为了使它们完全相同,我们可以简单地在GPU示例中将网格分辨率增加到255。不过,将其增加到63就足以得到一个不错的结果。我还将尝试使用GPU算法在CPU上计算法线贴图,它可能比我的逐顶点版本快得多。如果你愿意,你可以尝试WebAssembly,这在理论上对于浏览器上的数值计算来说要快得多,但我从未使用过它,也不知道初始化时间。谢谢,我来看看!