zoukankan      html  css  js  c++  java
  • OpenGL判断一个点是否可见

    关于OpenGL中判断一个点是否可见,可以分成两种情况讨论:点在2D空间中和3D空间中的时候。并且“在2D空间中”可以看作“在3D空间中”的特殊情况。

    温馨提示:

    1. 以下讨论以现代OpenGL为基础,如果您只会旧OpenGL,请先学习一些与本文相关的现代OpenGL知识。

    2. 文中除vertex shader以外的代码可以认为是GLSL。

    2D空间

    如果是2D空间,就很好判断了。这里再分成几种情况。

    1. 已知原始顶点坐标,没有矩阵变换

    设有如下vertex shader:

    #version 330 core

    layout(location = 0) in vec4 position;  // position.z为0.0,position.w为1.0

    void main()

    {

      gl_Position = position;

    }

    将position记为v,由于NDC坐标系统只渲染x、y和z位于[-1,1]区间的点(这里z为0.0),因此判断方法如下:

    bool visible(vec2 v)
    {
        return v.x >= -1.0 && v.x <= 1.0 && v.y >= -1.0 && v.y <= 1.0;
    }

    2. 已知顶点数据,有矩阵变换

    设有如下vertex shader:

    #version 330 core

    layout(location = 0) in vec4 position;  // position.z为0.0,position.w为1.0

    uniform mat4 modelViewProjection;

    void main()

    {

      gl_Position = modelViewProjection * position;

    }

    将position记为v,将modelViewProjection记为M,记v' = M * v,如果v'位于NDC坐标范围内就可见。但v'.w可能不为1,因此如果v'.x/v'.w和v'.y/v'.w位于[-1,1]就是可见的。判断方法如下:

    bool visible(vec2 v, mat4 m)
    {
        vec4 result = m * vec4(v, 0.0, 1.0);
        result.x /= result.w;
        result.y /= result.w;
        return result.x >= -1.0 && result.x <= 1.0 && result.y >= -1.0 && result.y <= 1.0;
    }

    或者合并一下:

    bool visible(vec2 v, mat4 m)
    {
        vec4 result = m * vec4(v, 0.0, 1.0);
        return result.x / result.w >= -1.0 && result.x / result.w <= 1.0 &&
    result.y / result.w >= -1.0 && result.y / result.w <= 1.0; }

    3. 已知某点的像素坐标

    设(x,y)为点v的像素坐标(不用管原点在左下角还是左上角),窗口大小为wsize(x和y分量分别表示宽和高),则判断方法如下:

    bool visible(vec2 v, vec2 wsize)
    {
        return v.x >= 0 && v.x < wsize.x && v.y >= 0 && v.y < wsize.y;
    }

    到这里都很简单,因为是2D的。

    那么3D呢?

    3D空间

    3D空间中这个事就要复杂许多了(也不多),我也很久都没想出来。最后发现是因为我对OpenGL的顶点变换不够熟悉。

    1. 已知NDC坐标

    首先,假设有一点p(x,y,z),已经在NDC坐标了,根据NDC坐标的知识,对它的判断应该是这样的:

    bool visible(vec3 v)
    {
        return v.x >= -1.0 && v.x <= 1.0 && v.y >= -1.0 && v.y <= 1.0 && v.z >= -1.0 && v.z <= 1.0;
    }

    2. 直接判断

    设有如下vertex shader:

    #version 330 core

    layout(location = 0) in vec4 position;  // position.w为1.0

    uniform mat4 modelViewProjection;

    void main()

    {

      gl_Position = modelViewProjection * position;

    }

    将position记为v,将modelViewProjection记为M,将M * v记为v',v'在clip space(NDC)中。由于v'.w可能不为1,因此需要将v'.x、v'.y和v'.z除以v'.w,再判断v'.x、v'.y和v'.z是否在[-1,1]范围内。判断方法:

    bool visible(vec3 v, mat4 m)
    {
        vec4 result = m * vec4(v, 1.0);
        result.x /= result.w;
        result.y /=  result.w;
        result.z /= result.w;  
        return result.x >= -1.0 && result.x <= 1.0 && result.y >= -1.0 && result.y <= 1.0 && result.z >= -1.0 && result.z <= 1.0;
    }

    或者合并一下:

    bool visible(vec3 v, mat4 m)
    {
        vec4 result = m * vec4(v, 1.0);
        return result.x / result.w >= -1.0 && result.x / result.w <= 1.0 &&
            result.y / result.w >= -1.0 && result.y / result.w <= 1.0 &&
            result.z / result.w >= -1.0 && result.z / result.w <= 1.0;
    }

    (现在想了想,这也不难,但是当时死活想不出来,大概是对OpenGL顶点变换了解地太少了吧……)

    3. 根据frustum进行判断

    发现这种方式就要感谢Google和Stack Overflow了,Google上搜opengl determine if object visible,第一个就是Stack Overflow。里面有人提供了一个链接(来自lighthouse3d,Index标题下方有一堆链接,有兴趣的可以自己看)。顺便再提供一个附加链接:http://www.lighthouse3d.com/tutorials/maths/。文章篇幅都比较长,这里就简单地翻译一部分,有部分更改。

    (1) 平面的确定方法

    首先要了解一些关于平面的知识。确定一个平面有多种方式,但最常用的方式是使用如下方程(A、B、C、D是常数):

    Ax + By + Cz + D = 0 (1)

    如果一个平面满足(1)式,为方便,将其称为平面Ax + By + Cz + D = 0。假设已知有3个点p0、p1和p2在同一平面上,A、B、C和D可以用下面方式确定:

    1. 记u = p1 - p0v = p2 - p0

    2. 记nu × v

    3. 将n归一化(normalize)

    4. 记n = (nx, ny, nz),则A = nx,B = ny,C = nz

    5. 由(1)式可得D = -Ax - By - Cz (2)(此时A、B、C已算出)。设p(x,y,z)为平面上的任意一点,将坐标代入(2)式,即可算出D。如果将p用p0代替,则D = -n . p0

    (2) 点到平面的距离

    设有平面Ax + By + Cz + D = 0和点p(px,py,pz),记

    d = Apx + Bpy + Cpz + D

    d= n . p + D

    则|d|为p到平面的距离。注意虽然|d|才是p到平面的距离,但d也是有用的——d的符号可以告诉我们点p在平面的哪一边。如果d > 0,则p在法线n所在的一边;如果d < 0,则p在另一边。当然如果d = 0,则说明p在平面上。这里暂且把d称为有向距离(signed distance)。

    (3)

    (TO BE CONTINUED)

    本文可转载,转载请注明出处:http://www.cnblogs.com/collectionne/p/6750285.html

  • 相关阅读:
    加入创业公司有什么利弊
    Find Minimum in Rotated Sorted Array II
    Search in Rotated Sorted Array II
    Search in Rotated Sorted Array
    Find Minimum in Rotated Sorted Array
    Remove Duplicates from Sorted Array
    Spiral Matrix
    Spiral Matrix II
    Symmetric Tree
    Rotate Image
  • 原文地址:https://www.cnblogs.com/collectionne/p/6750285.html
Copyright © 2011-2022 走看看