我正在制作一款使用整个星球作为 map 的游戏。我已经镶嵌了球形行星 using this technique ,现在正在添加相机控件。
球体的维度为 1 到 -1,因此球体上的每个点也是归一化 vector 。在任何时候,构成球体的六角形瓷砖之一是“选定”瓷砖。然后玩家可以使用方向键将选择移动到相邻的图 block 。他们还可以使用模拟摇杆独立旋转相机
我需要对选定的图 block 和相机做两件事。首先,我需要能够将选择切换到离相机最近的图 block 。其次,我需要将相机对准突出显示的图 block
球体位于原点,相机位于点 (0,0,1)。图形引擎只允许我绕 X 轴和 Y 轴旋转相机,所以为了解决第一个问题,我使用四元数绕 x 轴旋转点 (0,0,1),然后绕 y 轴找到点相机所在的 3D 空间:
private Quaternion quat = new Quaternion(0,0,0,0);
private double[] output = new double[4];
private double[] cam = new double[3];
private double camX = 0;
private double camY = 0;
private double camZ = 1;
private double[] getCamPosition(){
quat.setAxisAngle(1, 0, 0, Math.toRadians(-graphicsEngine.getRotationX()));
quat.RotateVector(camX, camY, camZ, output);
cam[0] = output[0];
cam[1] = output[1];
cam[2] = output[2];
quat.setAxisAngle(0, 1, 0, Math.toRadians(-graphicsEngine.getRotationY()));
quat.RotateVector(cam[0], cam[1], cam[2], output);
cam[0] = output[0];
cam[1] = output[1];
cam[2] = output[2];
return cam;
}
然后我比较每个图 block 的质心与相机位置之间的距离,并选择最接近的图 block 作为新选择的图 block 。
但是,要解决第二个问题,我想反其道而行之。我想取质心(它已经是归一化 vector 的形式),并找出使相机以其为中心所需的围绕 X 的旋转和围绕 Y 的旋转
目前,我将相机旋转回 (0,0,1),然后获取 (0,0,1) 和质心之间的 X 轴和 Y 轴角度,并使用它进行旋转第二次相机:
private double[] outputArray = new double[2];
/**
* Cam is always (0,0,1)
*/
public void centreOnSelected(double camX, double camY, double camZ){
selectedTile.getCentroidAngles(outputArray);
outputArray[0] -= Math.atan2(camZ, camY);
outputArray[1] -= Math.atan2(camX, camZ);
// this determines if the centroid is pointing away from the camera
// I.e. is on the far side of the sphere to the camera point (0,0,1)
if(!selected.getCentroidDirectionY(camX, camZ)){
outputArray[0] = -Math.PI - outputArray[0];
}
graphicsEngine.rotateCam(Math.toDegrees(outputArray[0]), Math.toDegrees(outputArray[1]));
}
并在 selected(tile 类)中
void getCentroidAngles(double[] outputArray){
outputArray[0] = Math.atan2(centroidZ, centroidY);
outputArray[1] = Math.atan2(centroidX, centroidZ);
}
问题是这不起作用,(x 轴似乎总是在外面),我很确定这与获取角度和进行旋转的数学有关
注意:图形引擎首先绕 X 轴旋转,然后绕 Y 轴旋转:
gl.glRotatef(mRotateX, 1, 0, 0);
gl.glRotatef(mRotateY, 0, 1, 0);
质心都在正确的位置,并且相机绝对旋转了正确的量,所以我确定问题不在图形引擎上。这也不是将相机重新定位回 (0,0,1),因为我已经通过逐步执行程序检查了这项工作
我也做了一个视频来说明这个问题:
http://www.youtube.com/watch?v=Uvka7ifZMlE
这已经困扰我好几天了,所以非常感谢任何帮助解决这个问题的人!
谢谢 詹姆斯
最佳答案
不幸的是,我并不完全理解这里发生了什么,也无法提供完整的解决方案,但至少可以指出一些需要研究的问题。
我从未使用过 glRotatef,但我对此处转换的顺序和符号有点困惑 - 例如,根据 glRotatef 调用的顺序,您真的是先进行 x 旋转吗?
无论如何,至少这里的部分问题来自于这些方程式
outputArray[0] = Math.atan2(centroidZ, centroidY);
outputArray[1] = Math.atan2(centroidX, centroidZ);
首先,您的意思是第一个中的 (centroidY, centroidZ) 吗?更严重的是,您在此处获得的角度不能用于构建携带 (0,0,1) 到质心的旋转,反之亦然。例如,假设您想将质心 vector 旋转到 (0,0,1)。您的 2 个旋转中的每一个都可以用于围绕单个轴旋转,将一个组件设置为零。例如,围绕适当符号的 x 轴旋转 outputArray[0] 会将 y 分量设置为零(假设交换了 atan2 的参数)。或者,通过 outputArray[1] 的右符号围绕 y 轴旋转可以将 x 分量设置为 0。但是在先进行 x 旋转(比如)将 y 分量设置为 0 之后,质心 vector 更改 - 现在,outputArray[1] 不再描述将 x 分量设置为 0 的围绕 y 轴的旋转。
这些东西的正确公式总是有一个角度的 atan2 和另一个角度的 acos 或 asin。例如,如果您想要将 vector (1,0,0) 带到 (x,y,z) 上的主动旋转的角度,您将使用
first_angle_around_x = -asin(y)
second_angle_around_y = atan2(x, z)
要将 (x,y,z) 携带到 (1,0,0) 上,您将使用
first_angle_around_x = atan2(y, z)
second_angle_around_y = -asin(x)
(这些角度描述了绕 x、y 轴的旋转,当该轴“戳到你的眼睛”时逆时针旋转。)
这里还有一个问题
outputArray[0] -= Math.atan2(camZ, camY);
outputArray[1] -= Math.atan2(camX, camZ);
像这样减去角度仅适用于围绕单个轴的旋转。一旦您根据围绕不同轴的旋转构建复合变换,关系就会变得更加复杂——这就是矩阵和四元数派上用场的原因。我想如果 camX-Z 输入按照方法前面的注释所建议的那样是冗余的,那么这段代码可能无关紧要(尽管目前 Z 和 Y 组件在这里的方式会给出一个非零结果,这可能是补偿它们在我提到的第一个方程式中的“错误”方式;我不确定这是否是故意的)。
将相机移动到所选图 block 的方式也存在一个基本问题,尽管它是否真的是一个问题有点主观。因为您只围绕 x 轴和 y 轴进行旋转,所以您的星球上的每个点都有一个独特的相机方向。问题是没有办法连续选择这样的方向 - 想象一下地球上的 vector 场,其中每个点的 vector 是一个单位 vector ,当相机位于该点上方时,沿屏幕 x 方向指向。此字段不能由 Hairy Ball Theorem 连续.这实际上意味着在地球上的某个点上,对相机位置进行看似微小的调整,将使行星在屏幕上转动最多 180 度。如果你想避免这种情况,你可以选择基于当前相机位置的方向,以尽量减少旋转量。这确实意味着,例如,如果相机在闭环中移动,行星最终可能会在屏幕上“滚动”,这在您的游戏中可能是不可取的。它还要求您的引擎能够在所有 3 个轴上进行旋转。
关于java - 将相机旋转到一个点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14911904/
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我有一个正在构建的应用程序,我需要一个模型来创建另一个模型的实例。我希望每辆车都有4个轮胎。汽车模型classCar轮胎模型classTire但是,在make_tires内部有一个错误,如果我为Tire尝试它,则没有用于创建或新建的activerecord方法。当我检查轮胎时,它没有这些方法。我该如何补救?错误是这样的:未定义的方法'create'forActiveRecord::AttributeMethods::Serialization::Tire::Module我测试了两个环境:测试和开发,它们都因相同的错误而失败。 最佳答案
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的rubyyaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www