0

OpenGL 3.x,因为我不想在技术上落后太多。

首先,是的,我知道这很多。我几乎可以肯定该vec3 transform(vec3)功能很好,如果没有别的我知道它不包含我来这里的问题。

我遇到问题的代码是(或应该是)在vec3 project(vec3)函数中。如果我直接看,比如说,一个盒子,它看起来很好。如果我稍微转动相机使盒子更靠近屏幕的一侧(周边视觉),我的快乐盒子开始变成一个矩形。虽然这对于我正在投入的游戏来说是我可以忍受的,但这很烦人。

投影背后的基本理论是:你有一个点(x,y,z),你找到它和原点(相机所在的位置)之间的角度,并将它投影到一个nearz远处的平面上。找到角度是angleX = atan(x/z)和的问题angleY = atan(y/z)。并使用这两个角度,通过执行将它们投影到近平面上point = tan(angle) * nearzedgeY = 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/AC = A * (Y/X)

4

1 回答 1

1

-那些也讨厌我。

矩阵是你的朋友。学习使用它们。

-我正在以一种新的方式来做,如果我使用矩阵,那么我将完全按照每个教程所说的去做,而不是自己弄清楚。

你的方法很糟糕。转换不会通勤,您将自己锁定在一个非常严格的框架中。还有这个:

   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;

实际上是旋转矩阵乘法,然后是平移矩阵,以过于复杂且容易出错的方式编写。你也在浪费宝贵的 GPU 资源。

您的投影功能似乎实现了某种球面投影模型。这是有问题的,因为球坐标是曲线的。只要你的基元很小,与曲率相比,事情就会解决。但是一旦一个基元变大,所有的地狱都会崩溃,因为基元边缘将在屏幕上绘制为直线,而如果您通过曲线坐标系进行变换,它们必须是曲线。您至少需要一些细分着色器和迭代顶点调整才能完成这项工作。

于 2013-02-05T19:19:00.310 回答