gpt4 book ai didi

c++ - 根据与相机的距离调整点 Sprite 的大小

转载 作者:可可西里 更新时间:2023-11-01 18:09:28 26 4
gpt4 key购买 nike

我正在为大学编写仅使用核心 OpenGL 3.3 的 Wolfenstein 3D 的克隆,但我遇到了一些 Sprite 问题,即让它们根据距离正确缩放。

据我所知,以前版本的 OGL 实际上会为您执行此操作,但该功能已被删除,我所有重新实现它的尝试都以失败告终。

我目前的实现在远距离还算过得去,中距离不太差,近距离也不太奇怪。

主要问题(我认为)是我不了解我正在使用的数学。
Sprite 的目标大小比视口(viewport)稍大,所以当你接近它时它应该“走出画面”,但事实并非如此。它变小了,这让我很困惑。
我录制了一个小视频,以防文字不够。 (右边是我的)

Expected Result Actual Result

谁能告诉我哪里出错了,并解释原因?

代码:
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);

顶点着色器

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

片段着色器

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

最佳答案

首先,我不太明白你为什么要使用pos.x + 1

接下来,就像Nathan说的,你不应该使用clip-space点,而应该使用eye-space点。这意味着您仅使用模型 View 转换点(没有投影)来计算距离。

uniform mat4 MV;       //modelview matrix

vec3 eyePos = MV * vec4(pos.x, pos.y, 0.5, 1);

另外我不完全理解你的衰减计算。目前,较高的 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);

编辑:但总的来说,我认为这种衰减模型不是一个好方法,因为通常你只是想让 Sprite 保持它的对象空间大小,你不得不摆弄衰减因子实现我认为的目标。

更好的方法是输入其对象空间大小,然后根据当前 View 和投影设置计算屏幕空间大小(以像素为单位)(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;

这样,当渲染为宽度为 spriteWidth 的带纹理的四边形时, Sprite 始终会获得它应有的大小。

编辑:当然,您还应该牢记点 Sprite 的局限性。点 Sprite 根据其中心位置进行裁剪。这意味着当它的中心移出屏幕时,整个 Sprite 就会消失。对于大型 Sprite (我认为就像您的情况一样),这可能真的是个问题。

因此我宁愿建议您使用简单的纹理四边形。这样您就可以绕过整个衰减问题,因为四边形就像所有其他 3d 对象一样被转换。您只需要实现朝向观察者的旋转,这可以在 CPU 上或在顶点着色器中完成。

关于c++ - 根据与相机的距离调整点 Sprite 的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8608844/

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