初始情况
我想在 openGL 中可视化模拟数据。我的数据由粒子位置(x、y、z)组成,其中每个粒子都有一些属性(如密度、温度……),这些属性将用于着色。这些 (SPH) 粒子(10 万到数百万)组合在一起,实际上代表行星,以防您想知道。我想将这些粒子渲染为小的 3D 球体,并添加环境光、漫反射光和镜面光。
现状与问题
- 在我的情况下:我在哪个坐标系中进行闪电计算?哪种方式是通过管道传递各种组件的“最佳”方式?
我看到在视图空间中执行此操作很常见,这也非常直观。但是:不同片段位置的法线是在片段着色器中以剪辑空间坐标计算的(请参阅附加的片段着色器)。我真的可以将它们“返回”到视图空间中,以便在视图空间中为所有片段进行闪电计算吗?与在剪辑空间中进行比较有什么优势吗?
- 如果我为每个球体使用网格,那么在视图空间中获得法线会更容易,但我认为使用数百万个粒子会大大降低性能,所以最好使用球体相交,你同意吗?
PS:我不需要模型矩阵,因为所有粒子都已经到位。
//VERTEX SHADER
#version 330 core
layout (location = 0) in vec3 position;
layout (location = 2) in float density;
uniform float radius;
uniform vec3 lightPos;
uniform vec3 viewPos;
out vec4 lightDir;
out vec4 viewDir;
out vec4 viewPosition;
out vec4 posClip;
out float vertexColor;
// transformation matrices
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
lightDir = projection * view * vec4(lightPos - position, 1.0f);
viewDir = projection * view * vec4(viewPos - position, 1.0f);
viewPosition = projection * view * vec4(lightPos, 1.0f);
posClip = projection * view * vec4(position, 1.0f);
gl_Position = posClip;
gl_PointSize = radius;
vertexColor = density;
}
- 我知道 gl_Position 变量会发生投影除法,这是否真的发生在从顶点传递到片段着色器的所有 vec4 上?如果不是,也许片段着色器中的计算会出错?
片段着色器在剪辑空间中计算法线和漫反射/镜面反射闪电:
//FRAGMENT SHADER
#version 330 core
in float vertexColor;
in vec4 lightDir;
in vec4 viewDir;
in vec4 posClip;
in vec4 viewPosition;
uniform vec3 lightColor;
vec4 colormap(float x); // returns vec4(r, g, b, a)
out vec4 vFragColor;
void main(void)
{
// AMBIENT LIGHT
float ambientStrength = 0.0;
vec3 ambient = ambientStrength * lightColor;
// Normal calculation done in clip space (first from texture (gl_PointCoord 0 to 1) coord to NDC( -1 to 1))
vec3 normal;
normal.xy = gl_PointCoord * 2.0 - vec2(1.0); // transform from 0->1 point primitive coords to NDC -1->1
float mag = dot(normal.xy, normal.xy); // sqrt(x=1) = sqrt(x)
if (mag > 1.0) // discard fragments outside sphere
discard;
normal.z = sqrt(1.0 - mag); // because x^2 + y^2 + z^2 = 1
// DIFFUSE LIGHT
float diff = max(0.0, dot(vec3(lightDir), normal));
vec3 diffuse = diff * lightColor;
// SPECULAR LIGHT
float specularStrength = 0.1;
vec3 viewDir = normalize(vec3(viewPosition) - vec3(posClip));
vec3 reflectDir = reflect(-vec3(lightDir), normal);
float shininess = 64;
float spec = pow(max(dot(vec3(viewDir), vec3(reflectDir)), 0.0), shininess);
vec3 specular = specularStrength * spec * lightColor;
vFragColor = colormap(vertexColor / 8) * vec4(ambient + diffuse + specular, 1);
}
- 现在这实际上“有点”有效,但我感觉球体的不面向光源的侧面也被照亮,这是不应该发生的。我怎样才能解决这个问题?
一些奇怪的效果:此时光源实际上位于左侧行星的后面(它只是在左上角稍微突出一点),仍然存在漫反射和镜面反射效果。这边其实应该挺黑的!=(
同样在这一刻,我在片段着色器中得到一些 glError: 1282 错误,我不知道它来自哪里,因为着色器程序实际编译并运行,有什么建议吗?:)