OpenGL 3.x,因为我不想在技术上落后太多。
首先,是的,我知道这很多。我几乎可以肯定该vec3 transform(vec3)
功能很好,如果没有别的我知道它不包含我来这里的问题。
我遇到问题的代码是(或应该是)在vec3 project(vec3)
函数中。如果我直接看,比如说,一个盒子,它看起来很好。如果我稍微转动相机使盒子更靠近屏幕的一侧(周边视觉),我的快乐盒子开始变成一个矩形。虽然这对于我正在投入的游戏来说是我可以忍受的,但这很烦人。
投影背后的基本理论是:你有一个点(x,y,z),你找到它和原点(相机所在的位置)之间的角度,并将它投影到一个nearz
远处的平面上。找到角度是angleX = atan(x/z)
和的问题angleY = atan(y/z)
。并使用这两个角度,通过执行将它们投影到近平面上point = tan(angle) * nearz
。edgeY = tan(fovy) * nearz
然后通过和找到屏幕的外脊edgeX = tan(fovy * aspect) * nearz
。使用查找屏幕点screen = point/edge
作为一个基本的优化,我有,但为了解决这个问题而删除只是采取screen = angle/fov
我的投影函数理论有什么问题吗?这里是暗示:
#version 330
uniform vec3 model_location = vec3(0.0, 0.0, 0.0);
uniform vec3 model_rotation = vec3(0.0, 0.0, 0.0);
uniform vec3 model_scale = vec3(1.0, 1.0, 1.0);
uniform vec3 camera_location = vec3(0.0, 0.0, 0.0);
uniform vec3 camera_rotation = vec3(0.0, 0.0, 0.0);
uniform vec3 camera_scale = vec3(1.0, 1.0, 1.0);
uniform float fovy = 60.0;
uniform float nearz = 0.01;
uniform float farz = 1000.0;
uniform float aspect = 1.0;
vec3 transform(vec3 point)
{
vec3 translate = model_location - camera_location;
vec3 rotate = radians(model_rotation);
vec3 scale = model_scale / camera_scale;
vec3 s = vec3(sin(rotate.x), sin(rotate.y), sin(rotate.z));
vec3 c = vec3(cos(rotate.x), cos(rotate.y), cos(rotate.z));
float sy_cz = s.y * c.z;
float sy_sz = s.y * s.z;
float cx_sz = c.x * s.z;
vec3 result;
result.x = ( point.x * ( ( c.y * c.z ) * scale.x ) ) + ( point.y * ( ( ( -cx_sz ) + ( s.x * sy_cz ) ) * scale.y ) ) + ( point.z * ( ( ( -s.x * s.z ) + ( c.x * sy_cz ) ) * scale.z ) ) + translate.x;
result.y = ( point.x * ( ( c.y * s.z ) * scale.y ) ) + ( point.y * ( ( ( c.x * c.z ) + ( s.x * sy_sz ) ) * scale.y ) ) + ( point.z * ( ( ( -s.x * c.z ) + ( c.x * sy_sz ) ) * scale.z ) ) + translate.y;
result.z = ( point.x * ( ( -s.y ) * scale.x ) ) + ( point.y * ( ( s.x * c.y ) * scale.y ) ) + ( point.z * ( ( c.x * c.y ) * scale.z ) ) + translate.z;
return result;
}
vec4 project(vec3 point)
{
vec4 result = vec4(0.0);
vec3 rotation = radians(camera_rotation);
result.x = ( atan(point.x/point.z) - rotation.y );
result.y = ( atan(point.y/point.z) - rotation.x );
result.z = point.z/(farz - nearz);
result.w = 1.0;
result.x = tan(result.x) * nearz;
result.y = tan(result.y) * nearz;
vec2 bounds = vec2( tan(fovy * aspect) * nearz,
tan(fovy) * nearz );
result.x = result.x / bounds.x;
result.y = result.y / bounds.y;
if (camera_rotation.z == 0)
return result;
float dist = sqrt( (result.x*result.x) + (result.y*result.y) );
float theta = atan(result.y/result.x) + rotation.z;
result.x = sin(theta) * dist;
result.y = cos(theta) * dist;
return result;
}
layout(location = 0) in vec3 vertex_position;
layout(location = 1) in vec2 texCoord;
out vec2 uvCoord;
void main()
{
uvCoord = texCoord;
vec4 pos = project( transform(vertex_position) );
if (pos.z < 0.0)
return;
gl_Position = pos;
}
回答几个预期的问题:
问:为什么不使用 GLM/some-other-mathimatics-lib?
A:
-我前一阵子试过。我的“世界你好!” 三角形卡在屏幕中央。使用转换矩阵并没有将其向后移动、缩放或任何其他操作。
- 因为学习如何为自己解决问题很重要。这样做意味着我学会了如何解决这样的事情,同时如果一切都失控了,我仍然有一些可以依靠的东西。(有这个傻瓜的理由。)
问:为什么不使用矩阵?
A:
-那些也讨厌我。
-我正在以一种新的方式来做,如果我使用矩阵,那么我将完全按照每个教程所说的去做,而不是自己弄清楚。
尝试来源:
http://ogldev.atspace.co.uk/index.html
http://www.swiftless.com/opengltuts/opengl4tuts.html
从“OpenGL Shading Language Third Edition”、“Emulating the OpenGL Fixed Functionality”中复制 GLSL 着色器(vert & frag)的字母。288-293
每个都试了很多次,每次都把它弄得精神错乱。尝试编写战争游戏时,我得到了一个线框框,可以将其投影到和平符号中。
编辑:
正如 datenwolf 指出的那样,问题原来是极坐标的使用。为了使用不太高级的数学进行投影,一个更好的等式是:c = zNear * (p.x/p.y)
取自两个三角形的概念,投影点三角形和给定点三角形是正比例的;因此使用相同的角度。
假设为要投影的点给出 X 和 Y,并且它们的比例三角形边分别标记为 A 和 C。您可以从等式中取atan(Y/X) = angle
和,然后atan(C/A) = angle
从中得到
并完成,
其中 A 是到近平面的距离。C是Y方向的屏幕坐标。atan(Y/X) = atan(C/A)
Y/X = C/A
C = A * (Y/X)