草庐IT

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

coder 2024-02-20 原文

我一直在尝试使用 3dsmax 模型拼凑一个国际象棋游戏。此时,我已经能够导入模型,突出显示我有兴趣移动的所选游戏 block ,并选择我要移动到的方 block 。这是当前状态的屏幕截图:

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

我考虑做的是在模型加载完成后,以某种方式检查棋盘上的哪个方 block 。 Then, when a piece is selected and a "move to"square is selected, find the x,y,z glTranslate3f to move to that center square.

这是最好的方法吗?似乎随着游戏的进行,我将需要单独存储每件作品的 glTranslate。当一 block 从第 2 点到第 3 点时,我应该计算从原始起点到第 3 点的 glTranslate,对吗?

但是您如何确定一个游戏 block 是否占据一个正方形,以及您如何确定两个正方形之间的 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 中,并且您点击了 square4,计算平移并开始。我只是不确定如何计算每个正方形的中心,并从 square1-->square4 中找出平移坐标应该是什么。

或者我如何从一开始就确定哪些棋子占据了哪个方格。我可以在加载期间对此进行硬编码,但如果有一种合理的方法来完成此操作,它会帮助我更好地理解。

每个方 block 和游戏 block 都是一个结构 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 正方形->center = X, Y, Z

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

欢迎任何帮助。谢谢。

更新

现在我在 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);

上面列出的两个中心之间的差异要大得多。我正在做一些不正确的事情,但没有看到。

最佳答案

[有点离题] 当我编写我的大学项目时,我曾经使用简单的数学公式来确定每条线的交叉点来绘制我的“世界”(它与检查台有相似之处:它是无穷无尽的并且没有颜色区分)。当我得到这些点时,我能够简单地确定哪个特定的方形光标指向哪个。老实说,我使用简单的数学来确定最后(“生产”)版本中的那些中心。

Herethere是我的旧屏幕。

那么,有什么问题呢?当你在做 glPushMatrix() ,您的矩阵重置为默认值 - 位置变为 (0, 0, 0) 并且旋转被重置。如果你想把你的物体放在相交点 {line, plane} ,其中线是从相机原点到光标位置的光线(回想一下 OpenGL 中的相机理论:实际上,屏幕是相机“位置”点前面的平面) 并且飞机是在那条射线前面的东西。 注意:如果您不定义平面 - 您将无法确定交点。

现在,当你得到交点时,就做 glTranslatef(<intersection_point>)然后画出你的棋子或其他任何东西。

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

希望这会有所帮助。

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

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

关于c++ - 将对象移动到场景中的指定点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4775496/

有关c++ - 将对象移动到场景中的指定点?的更多相关文章

  1. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

  5. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  6. ruby - 当使用::指定模块时,为什么 Ruby 不在更高范围内查找类? - 2

    我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or

  7. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  8. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  9. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions

  10. ruby-on-rails - Rails - 使用/自定义 URL : '/dashboard' 指定根路径 - 2

    如何使此根路径转到:“/dashboard”而不仅仅是http://example.com?root:to=>'dashboard#index',:constraints=>lambda{|req|!req.session[:user_id].blank?} 最佳答案 您可以通过以下方式实现:root:to=>redirect('/dashboard')match'/dashboard',:to=>"dashboard#index",:constraints=>lambda{|req|!req.session[:user_id].b

随机推荐