简体   繁体   English

OpenGL根据x和y计算z坐标

[英]OpenGL Calculate z coordinate from x and y

Say i have drawn a quad with points A(0,0,a) B(1,0,b) C(1,1,c) and D(0,1,d) and want to find out the coordinates P(0.6,0.25,p), how would i go about doing this? 假设我绘制了一个具有点A(0,0,a)B(1,0,b)C(1,1,c)和D(0,1,d)的四边形并想找出坐标P( 0.6,0.25,p),我该​​怎么做呢? I'm hoping theres something less processor heavy i've missed, because thus far i've been trying to take the difference of Ax and Bx and then Cx and Dx and then finding the difference between those and its all a bit messy. 我希望我能错过一些减轻处理器负担的东西,因为到目前为止,我一直在尝试求出Ax和Bx,然后是Cx和Dx的区别,然后发现它们之间的区别,并且有点混乱。

For example, say i want to find the point where the mouse is in this picture : 例如,假设我想找到鼠标在这张图片中的位置:

在此处输入图片说明

Is there an easier or less processor heavy way of finding the point there? 有没有更简单或更省力的方法来找到该点? (Not picking or raycasting, because the mouse wont be there, the mouse was just pointing at where i'd like it to happen, for example) (例如,不进行拾取或光线投射,因为鼠标不会在那里,所以鼠标只是指向我希望它发生的位置)

FYI: Using ray-casting should be adequate to do what you are looking for. 仅供参考:使用光线投射应足以满足您的需求。 You need to rotate the perspective of your fulcrum to focus from the absolute 0 above and absolute 1 of the location of your model. 您需要旋转支点的透视图,以从模型上方的绝对0和模型位置的绝对1聚焦。 If you want another way to check quickly, barycentric coordinates are also useful. 如果您需要另一种快速检查的方法,则重心坐标也很有用。

Using barycentric coordinates you can determine a point inside a triangle: 使用重心坐标,可以确定三角形内的点:

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;
}

Barycentric coordinate allows to express new p coordinates as a linear combination of p1, p2, p3. 重心坐标允许将新的p坐标表示为p1,p2,p3的线性组合。 More precisely, it defines 3 scalars a, b, c: 更准确地说,它定义了3个标量a,b,c:

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

The way to compute a, b, c is as follows: 计算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 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 is inside of T if and only if 0 <= a <= 1 and 0 <= b <= 1 and 0 <= c <= 1 当且仅当0 <= a <= 1和0 <= b <= 1并且0 <= c <= 1

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

This is not going to be the prettiest read, but here are a couple of samples of what you are looking to do. 这不是最漂亮的读物,但是这里有一些您想要做的事的样本。 A downloadable project would probably be more useful for you, not sure that I could post all of that here though. 可下载的项目可能对您更有用,但是不确定我是否可以在此处发布所有内容。

(This is basic ray-triangle intersection) (这是基本的射线三角相交)

The use of OpenGL should be noted (this is c++ code below) The key part of the code that you would want to replicate outside of OpenGL (if glaux.lib is not used): 应该注意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;

A basic collision class should be created: 应该创建一个基本的碰撞类:

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 );
};

The definitions are as follows: 定义如下:

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;
}

The way to use the code above is to capture the input and specify the needed data: 使用上面的代码的方法是捕获输入并指定所需的数据:

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

); ); } That would be using a mouse click as the capture, though we want to do it from a perspective matrix in all reality. }尽管我们希望从所有现实中的透视矩阵中进行操作,但这将使用鼠标单击作为捕获。

This code above comes from a working terrain generator I wrote back in 2005. 上面的代码来自我在2005年写的一个工作地形生成器。

Alternatively, another way would be to run the inTriangle code I previously provided, then detecting slope for each side of the triangle. 或者,另一种方法是运行我之前提供的inTriangle代码,然后检测三角形每一侧的斜率。 This would require rolling through all points. 这将需要遍历所有点。

A better way would be to create a perspective matrix like the one we described above. 更好的方法是创建一个像我们上面所述的透视矩阵。 For a visual example of what you need to do: 有关您需要做什么的直观示例:

rotate a camera to be looking directly down on the player 旋转相机使其直接向下观看播放器

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

now, using the same concept I originally posted, you can identify the intersect point by creating a near/far vector from the perspective. 现在,使用我最初发布的相同概念,您可以通过从透视图创建近/远矢量来识别相交点。 This never needs to be drawn, but you are casting a ray to the exact point. 无需绘制,但是您正在将射线投射到确切的位置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM