Lex*_*x R 7 c++ opengl glsl point-sprites opengl-3
我正在使用仅用于大学的核心OpenGL 3.3编写Wolfenstein 3D的克隆,我遇到了精灵的一些问题,即让它们根据距离正确缩放.
据我所知,以前版本的OGL实际上会为你做这件事,但是这个功能已被删除,而我所有重新实现它的尝试都导致完全失败.
我目前的实施方式是可以在距离上通过,在中距离时不是太破旧,而在近距离时也是如此.
主要问题(我认为)是我对我正在使用的数学没有理解.
精灵的目标大小略大于视口,因此当你接近它时它应该"走出画面",但事实并非如此.它变小了,这让我很困惑.
我录制了一个小视频,以防单词不够.(我在右边)

谁能指引我到我错的地方,并解释原因?
代码:
C++
// setup
glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
glEnable(GL_PROGRAM_POINT_SIZE);
// Drawing
glUseProgram(StaticsProg);
glBindVertexArray(statixVAO);
glUniformMatrix4fv(uStatixMVP, 1, GL_FALSE, glm::value_ptr(MVP));
glDrawArrays(GL_POINTS, 0, iNumSprites);
Run Code Online (Sandbox Code Playgroud)
顶点着色器
#version 330 core
layout(location = 0) in vec2 pos;
layout(location = 1) in int spriteNum_;
flat out int spriteNum;
uniform mat4 MVP;
const float constAtten = 0.9;
const float linearAtten = 0.6;
const float quadAtten = 0.001;
void main() {
spriteNum = spriteNum_;
gl_Position = MVP * vec4(pos.x + 1, pos.y, 0.5, 1); // Note: I have fiddled the MVP so that z is height rather than depth, since this is how I learned my vectors.
float dist = distance(gl_Position, vec4(0,0,0,1));
float attn = constAtten / ((1 + linearAtten * dist) * (1 + quadAtten * dist * dist));
gl_PointSize = 768.0 * attn;
}
Run Code Online (Sandbox Code Playgroud)
片段着色器
#version 330 core
flat in int spriteNum;
out vec4 color;
uniform sampler2DArray Sprites;
void main() {
color = texture(Sprites, vec3(gl_PointCoord.s, gl_PointCoord.t, spriteNum));
if (color.a < 0.2)
discard;
}
Run Code Online (Sandbox Code Playgroud)
Chr*_*ica 13
首先,我真的不明白你使用的原因pos.x + 1.
接下来,就像内森所说,你不应该使用剪辑空间点,而应该使用眼睛空间点.这意味着您只能使用模型视图转换点(无投影)来计算距离.
uniform mat4 MV; //modelview matrix
vec3 eyePos = MV * vec4(pos.x, pos.y, 0.5, 1);
Run Code Online (Sandbox Code Playgroud)
此外,我不完全了解你的衰减计算.目前,较高的constAtten值意味着较少的衰减.为什么不使用OpenGL不推荐使用的点参数的模型:
float dist = length(eyePos); //since the distance to (0,0,0) is just the length
float attn = inversesqrt(constAtten + linearAtten*dist + quadAtten*dist*dist);
Run Code Online (Sandbox Code Playgroud)
编辑:但总的来说,我认为这种衰减模型不是一个好方法,因为通常你只是希望精灵保持其对象空间大小,你可以完全摆弄衰减因子来达到我的想法.
更好的方法是输入其对象空间大小,并gl_PointSize根据使用当前视图和投影设置计算屏幕空间大小(实际上是这样):
uniform mat4 MV; //modelview matrix
uniform mat4 P; //projection matrix
uniform float spriteWidth; //object space width of sprite (maybe an per-vertex in)
uniform float screenWidth; //screen width in pixels
vec4 eyePos = MV * vec4(pos.x, pos.y, 0.5, 1);
vec4 projCorner = P * vec4(0.5*spriteWidth, 0.5*spriteWidth, eyePos.z, eyePos.w);
gl_PointSize = screenWidth * projCorner.x / projCorner.w;
gl_Position = P * eyePos;
Run Code Online (Sandbox Code Playgroud)
这样,精灵总是获得当渲染为宽度为的纹理四边形时的大小spriteWidth.
编辑:当然你也应该记住点精灵的局限性.点精灵根据其中心位置进行裁剪.这意味着当它的中心移出屏幕时,整个精灵会消失.对于大精灵(就像你的情况,我认为),这可能真的是一个问题.
所以我宁愿建议你使用简单的纹理四边形.这样你就可以绕过整个衰减问题,因为四边形像其他每个3d对象一样被转换.您只需要向查看器实现旋转,这可以在CPU上或在顶点着色器中完成.
基于Christian Rau的回答(最后编辑),我实现了一个几何着色器,它在ViewSpace中构建了一个广告牌,它似乎解决了我所有的问题:

以下是着色器:(请注意,我已修复了需要原始着色器向x添加1的对齐问题)
顶点着色器
#version 330 core
layout (location = 0) in vec4 gridPos;
layout (location = 1) in int spriteNum_in;
flat out int spriteNum;
// simple pass-thru to the geometry generator
void main() {
gl_Position = gridPos;
spriteNum = spriteNum_in;
}
Run Code Online (Sandbox Code Playgroud)
几何着色器
#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 4) out;
flat in int spriteNum[];
smooth out vec3 stp;
uniform mat4 Projection;
uniform mat4 View;
void main() {
// Put us into screen space.
vec4 pos = View * gl_in[0].gl_Position;
int snum = spriteNum[0];
// Bottom left corner
gl_Position = pos;
gl_Position.x += 0.5;
gl_Position = Projection * gl_Position;
stp = vec3(0, 0, snum);
EmitVertex();
// Top left corner
gl_Position = pos;
gl_Position.x += 0.5;
gl_Position.y += 1;
gl_Position = Projection * gl_Position;
stp = vec3(0, 1, snum);
EmitVertex();
// Bottom right corner
gl_Position = pos;
gl_Position.x -= 0.5;
gl_Position = Projection * gl_Position;
stp = vec3(1, 0, snum);
EmitVertex();
// Top right corner
gl_Position = pos;
gl_Position.x -= 0.5;
gl_Position.y += 1;
gl_Position = Projection * gl_Position;
stp = vec3(1, 1, snum);
EmitVertex();
EndPrimitive();
}
Run Code Online (Sandbox Code Playgroud)
片段着色器
#version 330 core
smooth in vec3 stp;
out vec4 colour;
uniform sampler2DArray Sprites;
void main() {
colour = texture(Sprites, stp);
if (colour.a < 0.2)
discard;
}
Run Code Online (Sandbox Code Playgroud)