【问题标题】:OpenGL Calculate z coordinate from x and yOpenGL从x和y计算z坐标
【发布时间】:2014-03-05 19:27:06
【问题描述】:

假设我已经绘制了一个四边形,其中点 A(0,0,a) B(1,0,b) C(1,1,c) 和 D(0,1,d) 并想找出坐标 P(0.6,0.25,p),我该怎么做呢?我希望我错过了一些不那么重的处理器,因为到目前为止,我一直在尝试区分 A.x 和 B.x,然后是 C.x 和 D.x,然后找到它们之间的区别,这有点混乱。

例如,假设我想在这张图片中找到鼠标所在的点:

有没有一种更简单或更少处理器负担的方法来找到那里的点? (不是拾取或光线投射,因为鼠标不会在那里,鼠标只是指向我希望它发生的地方,例如)

【问题讨论】:

    标签: java opengl


    【解决方案1】:

    仅供参考:使用光线投射应该足以满足您的需求。您需要旋转支点的视角以从模型位置的绝对 0 和绝对 1 聚焦。如果您想通过其他方式快速检查,重心坐标也很有用。

    使用重心坐标可以确定三角形内的一点:

    function pointInTriangle(x1, y1, x2, y2, x3, y3, x, y:Number):Boolean
    {
     var denominator:Number = ((y2 - y3)*(x1 - x3) + (x3 - x2)*(y1 - y3));
     var a:Number = ((y2 - y3)*(x - x3) + (x3 - x2)*(y - y3)) / denominator;
     var b:Number = ((y3 - y1)*(x - x3) + (x1 - x3)*(y - y3)) / denominator;
     var c:Number = 1 - a - b;
    
     return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
    }
    

    重心坐标允许将新的 p 坐标表示为 p1、p2、p3 的线性组合。更准确地说,它定义了 3 个标量 a、b、c:

    x = a * x1 + b * x2 + c * x3 y = a * y1 + b * y2 + c * y3 a + b + c = 1

    a、b、c的计算方法如下:

    a = ((y2 - y3)(x - x3) + (x3 - x2)(y - y3)) / ((y2 - y3)(x1 - x3) + (x3 - x2)(y1 - y3)) b = ((y3 - y1)(x - x3) + (x1 - x3)(y - y3)) / ((y2 - y3)(x1 - x3) + (x3 - x2)(y1 - y3)) c = 1 - a - b

    p 在 T 内当且仅当 0

    参考http://totologic.blogspot.fr/2014/01/accurate-point-in-triangle-test.html

    【讨论】:

    • 天哪,看起来很复杂... 对,所以我正在尝试计算绘制的四边形的 z 值,它位于将在其上方移动的实体下方。如果我仍然可以进行射线投射,我愿意,因为它让我觉得很有帮助
    • 已经好几年了,但我会看看我是否可以提取一些对你有帮助的旧代码。我过去做过。光线投射既快速又准确。
    • 我如何将光线从世界上的一个点投射到另一个点?我想不通,我目前用于生成实体的光线投射方法只能在屏幕上工作
    • 你用的是什么图形库?
    • LWJGL,但只要有足够的时间,我就可以从任何东西转换,我已经尝试了大约 6 个小时,坦率地说,任何帮助都是帮助
    【解决方案2】:

    这不会是最漂亮的读物,但这里有几个您想要做的示例。一个可下载的项目可能对你更有用,但我不确定我是否可以在这里发布所有这些内容。

    (这是基本的射线-三角形相交)

    OpenGL的使用要注意(下面这个是c++代码) 您希望在 OpenGL 之外复制的代码的关键部分(如果未使用 glaux.lib):

    gluUnProject( PosX, PosY, 0, modelview, projection, viewport, &x1, &x2, &x3);
    vnear.x = (float)x1; vnear.y = (float)x2; vnear.z = (float)x3;
    gluUnProject( PosX, PosY, 1.0, modelview, projection, viewport, &x1, &x2, &x3);
    vfar.x = (float)x1; vfar.y = (float)x2; vfar.z = (float)x3;
    

    应该创建一个基本的碰撞类:

    class CCollision
    {
    public:
            CVec vnear;     // Where is 0 and where is 100% of fulcrum
            CVec vfar;
    public:
        CCollision(void);
        ~CCollision(void);
    public:
        bool checkLine (CVec &v1, CVec &v2,CVec &v3, CVec &p );
        bool checkLine( float *triangle, CVec &p );
        bool checkLine( float* v1, float* v2, float* v3, CVec &p ); 
        void projectRay ( int x, int y );
    };
    

    定义如下:

    CCollision::CCollision(void){}
    CCollision::~CCollision(void){}
    
    bool CCollision::checkLine( float *triangle, CVec &p )
    {
        CVec p1 = CVec( triangle[0], triangle[1], triangle[2] );
        CVec p2 = CVec( triangle[3], triangle[4], triangle[5] );
        CVec p3 = CVec( triangle[6], triangle[7], triangle[8] );
        return checkLine( p1, p2, p3, p );
    
    }
    
    bool CCollision::checkLine( float *v1, float *v2, float *v3, CVec &p )
    {
        CVec p1 = CVec( v1[0], v1[1], v1[2] );
        CVec p2 = CVec( v2[0], v2[1], v2[2] );
        CVec p3 = CVec( v3[0], v3[1], v3[2] );
        return checkLine( p1, p2, p3, p );
    }
    
    bool CCollision::checkLine( CVec &v1, CVec &v2, CVec &v3, CVec &p )
    {
        CVec sect;
    
        // Find Triangle Normal, then normalize it (use Magnitude)
        CVec Normal;
        Normal = ( v2 - v1 )%( v3 - v1 );
        Normal.Normalize(); // Normalize
    
        // Find the distance to the plane, based on the Normal.
        float distanceNear = (vnear-v1)^Normal;
        float distanceFar  = (vfar-v1)^Normal;
    
        if (( (distanceNear * distanceFar) >= 0.0f)||( distanceNear == distanceFar))
            return false; // Are they equal?
    
        // Find exact intersection point.
        sect = vnear + (vfar-vnear) * ( -distanceNear/(distanceFar-distanceNear) );
    
        // Check all points against the Normalized vector.
        CVec v;
    
        // Point 1
        v = Normal%( v2-v1 );
        if ( (v^( sect-v1 )) < 0.0f )
            return false;
    
        // Point 2
        v = Normal%( v3-v2 );
        if ( (v^( sect-v2 )) < 0.0f )
            return false;
    
        // Point 3
        v = Normal%( v1-v3 );
        if ( (v^( sect-v1 )) < 0.0f )
            return false;
    
        // Lastly, lets set the intersection point.
        p = sect;
    
        return true;
    }
    
    
    void CCollision::projectRay( int x, int y )
    {
        GLint viewport[4];
        GLdouble modelview[16];
        GLdouble projection[16];
        GLdouble PosX, PosY, x1, x2, x3;
    
        glGetDoublev(GL_MODELVIEW_MATRIX, modelview );
        glGetDoublev(GL_PROJECTION_MATRIX, projection);
    
        glGetIntegerv(GL_VIEWPORT, viewport);
    
        PosX = (float)x;
        PosY = (float)viewport[3] - (float)y;
    
        gluUnProject( PosX, PosY, 0, modelview, projection, viewport, &x1, &x2, &x3);
        vnear.x = (float)x1; vnear.y = (float)x2; vnear.z = (float)x3;
        gluUnProject( PosX, PosY, 1.0, modelview, projection, viewport, &x1, &x2, &x3);
        vfar.x = (float)x1; vfar.y = (float)x2; vfar.z = (float)x3;
    }
    

    上面代码的使用方式是捕获输入并指定需要的数据:

    case WM_LBUTTONDOWN:
        project->scene->bCheckForCollision = true;
    project->scene->collision.projectRay(
            LOWORD(((LPARAM *)m.LParam.ToPointer())),
            HIWORD((LPARAM *)m.LParam.ToPointer())
    

    ); } 这将使用鼠标单击作为捕获,尽管我们希望在所有现实中从透视矩阵中进行。

    上面的这段代码来自我在 2005 年写的一个工作的地形生成器。

    另外,另一种方法是运行我之前提供的 inTriangle 代码,然后检测三角形每一边的斜率。这需要滚动所有点。

    更好的方法是创建一个像我们上面描述的那样的透视矩阵。有关您需要做什么的直观示例:

    旋转相机直接俯视玩家

    (c)-----> 玩家[(地形)

    现在,使用我最初发布的相同概念,您可以通过从视角创建近/远矢量来识别相交点。这永远不需要绘制,但您正在将光线投射到确切的点。

    【讨论】:

    • 我将首先尝试这段代码,我在 cpp 中有 cpp 和 opengl 的经验,所以一切都会顺利。看起来这很完美,我唯一没有得到的是 LOWORD(((LPARAM *)m.LParam.ToPointer())), HIWORD((LPARAM *)m.LParam.ToPointer()) 这是什么意思?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-06
    • 1970-01-01
    相关资源
    最近更新 更多