OpenGL从x和y计算z坐标

时间:2014-03-05 19:27:06

标签: java opengl

假设我画了一个带有点A(0,0,a)B(1,0,b)C(1,1,c)和D(0,1,d)的四边形并且想要找出坐标P(0.6,0.25,p),我该​​怎么做呢?我希望有更少的处理器重,我错过了,因为到目前为止,我一直在尝试取得Ax和Bx的差异,然后是Cx和Dx,然后找到它们之间的区别,它有点混乱。 / p>

例如,假设我想找到鼠标在此图片中的位置:

enter image description here

是否有一种更容易或更少处理器的重要方法来找到重点? (没有采摘或光线投射,因为鼠标不会在那里,鼠标只是指向我希望它发生的地方,例如)

2 个答案:

答案 0 :(得分:0)

仅供参考:使用光线投射应该足以满足您的需求。您需要旋转支点的透视图,以从模型位置的绝对值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 <= a <= 1且0 <= b <= 1且0 <= c <= 1

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

答案 1 :(得分:0)

这不是最漂亮的阅读,但这里有几个你想要做的样本。一个可下载的项目可能对你更有用,但不确定我是否可以在这里发布所有这些。

(这是基本的射线 - 三角交叉点)

应注意使用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)中-----&GT;玩家[(地形)

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

相关问题