将对象移动到场景中的指定点?

时间:2011-01-23 18:16:25

标签: c++ opengl 3d

我一直在尝试使用3dsmax模型拼出一款国际象棋游戏。此时,我已经能够导入模型,突出显示我感兴趣的所选游戏片段,并选择我想要移动的方块。以下是当前状态的屏幕截图:

http://img26.imageshack.us/img26/9555/chessk.png

黑色圆圈表示我点击的位置,您可以看到棋子的去向。我还没有具体计算应该去哪里。每当我用选定的棋子点击棋盘时,它总是朝同一方向移动。这是因为刚刚开始使用这个虚拟代码:

if ( isObjectSelected && isSquareSelected && moveObject )
{
    glPushMatrix();
    glTranslatef(0.2f, 0.0f, 0.0f); //PLACEHOLDER-DUMMY CODE
}

glDrawElements( GL_TRIANGLES, pMaterial->triangleCount * 3, GL_UNSIGNED_INT, model.getIndexBuffer() + pMaterial->startIndex );

if ( isObjectSelected && isSquareSelected )
    glPopMatrix();

我正在考虑做的是在模型完成加载后,以某种方式检查棋盘上的哪个方块占用了一个。然后,当选择一块并选择“移动到”方块时,找到x,y,z glTranslate3f移动到该中心方块。

这是最好的方法吗?随着游戏的进展,我需要单独存储每件作品的glTranslate。当一个片段从它的第二个到第三个点时,我应该从原始起点到第三个点计算glTranslate,对吗?

但是你怎么知道一个游戏棋子是否占据一个正方形,你怎么能在两个正方形之间找出glTranslate3f(X,Y,Z)?这是我的.OBJ文件中的一个正方形的例子

#
# object Square58
#

v  -37.1874 18.6313 80.7864
v  -67.0955 18.6313 91.4436
v  -56.4384 18.6313 121.3513
v  -26.5306 18.6313 110.6938
# 4 vertices

vn 0.0000 1.0000 -0.0000
# 1 vertex normals

vt 0.0000 0.0000 0.0000
# 1 texture coords

我假设我需要找到每个方块的中心并说一旦应用知道这个方块在square1中,然后你点击sqaure4,计算翻译&走。我只是不确定如何计算每个方块的中心,并从square1 - > square4中找出翻译坐标应该是什么。

或者我如何确定从一开始就占据哪个方块。我可以在加载过程中对其进行硬编码,但是如果有一种合理的方法可以帮助我更好地理解这一点。

每个广场&游戏块是一个结构GroupObject,如:

//A chess piece or square
struct GroupObject
{
    std::vector<Material *> materials;
    std::string             objectName;
    std::string             groupName;
    int                     index;
    std::vector<Vector3 *>  vertices;
    Vector3                 center;
};

Vector3看起来像:

#ifndef VECTOR3_H
#define VECTOR3_H

#include <math.h>

class Vector3
{
public:
Vector3(float X = 0.0f, float Y = 0.0f, float Z = 0.0f)
{
    x = X;
    y = Y;
    z = Z;
}

Vector3 operator+=(const Vector3 &vec)
{
    return (*this = (*this + vec) );
}

Vector3 operator+(const Vector3 &vec)
{
    return Vector3(vec.x + x, vec.y + y, vec.z + z);
}

Vector3 operator-=(const Vector3 &vec)
{
    return (*this = (*this - vec) );
}

Vector3 operator-(const Vector3 &vec)
{
    return Vector3(x - vec.x, y - vec.y, z - vec.z);
}

Vector3 operator*=(float num)
{
    return (*this = (*this * num) );
}

Vector3 operator*(float num)
{
    return Vector3(x * num, y * num, z * num);
}

Vector3 operator/=(float num)
{
    return (*this = (*this / num) );
}

Vector3 operator/(float num)
{
    return Vector3(x / num, y / num, z / num);
}

Vector3 operator-(void)
{
    //invert direction of vector
    return Vector3(-x, -y, -z);
}

float Dot(Vector3 &vec)
{
    return (x * vec.x + y * vec.y + z * vec.z);
}

Vector3 operator*(const Vector3 &vec)
{
    //cross product
    return Vector3( y * vec.z - z * vec.y,
                    z * vec.x - x * vec.z,
                    x * vec.y - y * vec.x );
}

float Length(void)
{
    //length of vector
    return sqrt( x * x + y * y + z * z);
}

Vector3 Normalize(void)
{
    float length = Length();
    x /= length;
    y /= length;
    z /= length;

    return *this;
}

float Distance(Vector3 &vec)
{
    //find distance between two separate vectors
    float disX = vec.x - x;
    float disY = vec.y - y;
    float disZ = vec.z - z;

    return sqrt(disX * disX + disY * disY + disZ * disZ);
}

bool operator==(Vector3 &vec)
{
    return (vec.x == x && vec.y == y && vec.z == z);
}

bool operator!=(Vector3 &vec)
{
    return !(vec == *this);
}

公共:     float x,y,z; };

#endif

我打算用它来存储每个方块的中心,如:

Vector3 square-&gt; center = X,Y,Z

希望这有助于它确定移动的位置,如果某些东西占据了那个空间,但我认为我应该得到一些帮助,因为我之前没有这样做过。我也不确定如何计算它,或者仍然完全清楚如何判断一个正方形是否有一个在开始时占据它的游戏块,或者它是空的。

欢迎任何和所有帮助。谢谢。

更新

现在我在3ds max和一个方形对象属性上有一个好友的样子,它说尺寸为x:40.565 y:40.565

然后我挑选了两个正方形,一个在另一个正面。我通过将所有顶点加在一起并除以顶点之和来计算每个顶点的中心。我明白了:

#square 1
x: 111.12125
y: 18.631268
z: 78.286982

#square 2
x: 82.276817
y: 17.615297
z: 88.545845

但是从我最初的例子来看,我能够接近移动到正确位置的唯一方法是移动glTranslatef(0.2f,0.0f,0.0f);

上面列出的两个中心之间的差异要大得多。我做错了什么,但看不到。

2 个答案:

答案 0 :(得分:3)

[a比特-offtopic] 当我编写我的univercity项目时,我习惯于使用简单的数学公式来确定每个线交叉点,从而绘制我的“世界”(它与检查台类似:它是无穷无尽的,没有颜色区别)。当我得到这些点时,我能够简单地确定哪个特定方形光标指向。说实话,我用简单的数学来确定最后一个('生产')版本的那些中心。

Herethere是我以前的屏幕。

那么,有什么麻烦?当您执行glPushMatrix()时,矩阵将重置为其默认值 - 位置变为(0,0,0)并重置旋转。如果你想把你的物体放在相交点{line,plane},那里的线是从相机原点到光标位置的光线(在OpenGL中调用相机理论:实际上,屏幕是相机'位置'点前面的平面并且飞机在那条射线前面。 注意:如果您不定义飞机 - 您将无法确定交叉点。

现在,当你得到交叉点时,只需做glTranslatef(<intersection_point>)然后绘制你的棋子或其他什么。

如果您对如何确定交叉点的纯代码感兴趣 - 请在评论中通知我。

希望这会有所帮助。

UPD:这是我之前提到过的交叉点代码。它使用sf::Vector3f结构/类 - 它取自SFML(我将它用于所有我的GL项目来处理输入事件并忘记'回合窗口创建)。您可以将其定义为具有3个浮点数的简单结构。函数参数是鼠标光标的坐标。调用它可以为您提供交叉点坐标。

sf::Vector3f ScreenToSpace(int x, int y)
{
    GLint viewport[4];
    GLdouble modelview[16];
    GLdouble projection[16];
    GLfloat winX, winY, winZ;
    GLdouble posX, posY, posZ;

    glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
    glGetDoublev(GL_PROJECTION_MATRIX, projection);
    glGetIntegerv(GL_VIEWPORT, viewport);

    winX = (float) x;
    winY = (float) viewport[3] - (float) y;
    glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);

    gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);

    return sf::Vector3f((float) posX, (float) posY, (float) posZ);
}

这是关于你应该如何使用它的例子(据我了解你的问题):

sf::Vector3f v = ScreenToSpace(App.GetInput().GetMouseX(), App.GetInput().GetMouseY()); // get global coordinates
v = SpaceToDeskCorrection(v.x, v.y, v.z); // align v to the check-desk cell center

glPushMatrix(); // reset matrix state (incl. position and rotation) and save previous one
  glTranslatef(v.x, v.y, v.z); // set matrix position to the intersection point
  DrawPawn(); // well, you'll understand this line, right? =)
glPopMatrix();

答案 1 :(得分:2)

我最近自己做了一个跳棋游戏,2D,但同样的原则适用。首先,我建议你保留一个带有棋盘方块的数组,正如你在结构中定义的那样,有一个中心变量。

要知道每个部分的位置,您可以例如添加一个变量,该变量是指向给定方块的指针,或者只是添加一个像'E4'或'A8'(方形代码)的表示。有了这个,你会自动获得该片所在的x,y坐标,一旦你想要将它移动到哪个方格,你只需将指针替换成新的片段并获得它的中心信息,这就是你想要的地方将作品翻译成。这还有一个额外的好处,它可以让你以后更容易检查一件作品从对手那里接过另一件,或者只是它可以移动到某个正方形(如果它们中的任何一个正在铺设,则通过所有部件)在你要去的广场上,不要允许搬家。)

找出任何方块的中心,假设你在创建板时不知道它(不是吗?),并在所有构成顶点x和y坐标上做一个平均值(如果板是躺在xy飞机上)。例如,Square58 center =(v1(x)+ v2(x)+ v3(x)+ v4(x); v1(y)+ v2(y)+ v3(y)+ v4(y))。

我希望这很清楚,如果不是让我知道你没有得到什么,我会试着解释。

编辑:对不起,我写错了。在Square58中心....行中,您将最终总和除以4(得到平均值)..即:

Square58 center =((v1(x)+ v2(x)+ v3(x)+ v4(x))/ 4;(v1(y)+ v2(y)+ v3(y)+ v4(y ))/ 4)。