【发布时间】:2020-06-22 17:01:08
【问题描述】:
我正在创建一个地形网格,并遵循this SO answer 我正在尝试将我的 CPU 计算法线迁移到基于着色器的版本,以便通过降低我的网格分辨率和使用在片段着色器。
我将MapBox height map 用于地形数据。瓷砖看起来像这样:
每个像素的高程由以下公式给出:
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
- 带有 GPU 计算法线贴图的第二个版本:http://jsfiddle.net/tautin/8gqa53e1/42
使用倾斜滑块玩游戏时会出现问题。
【问题讨论】:
-
256x256 网格的唯一用途是通过法线?你不是用它来做高度位移吗? IE。你在第二种方法中画了多少个三角形?
-
256*256 图片包含每个像素的高程,而不是法线。我将它传递给计算法线。我不知道你所说的高度位移是什么意思(对不起,我对 OpenGL/WebGL 的经验非常有限),所以我想答案是否定的:)
-
高度位移是指
a_Position变量的“向上”坐标。您是否根据高度图中的高度设置顶点的高度? -
哦,好的,那么是的,我正在这样做。但在新版本中,我的网格的分辨率要低得多(32*32)。编辑:我将顶点位置除以 5000,而不是乘以 6。
-
现在我看到这不是一个手游,它只在需要时渲染,不,我不认为会有性能问题(但你永远不知道在什么硬件上客户端正在运行)。现在我也理解了性能问题,因为法线贴图计算是在 JavaScript 中完成的,而不是在某些编译语言上。
标签: opengl shader fragment-shader normals glsles