- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
简短版本 (TL;DR)
我有一个 Camera
附在 SceneNode
只要 SceneNode
,运动就可以正常工作的旋转/轴与世界对齐。然而,当一个对象旋转到不同方向“看”并被告知“向前”移动时,它不会沿着新的“向前”方向移动。相反,它会继续沿应用旋转之前所面向的相同方向移动。
详细信息和示例
我有一个场景图来管理 3D 场景。该图是SceneNode
的树对象,它们知道它们相对于它们的父对象和世界的变换。
根据 TL; DR;片段,假设您有一个 cameraNode
零旋转(例如面向北),然后旋转 cameraNode
围绕 +Y“向上”轴向左 90 度,即使其向西看。目前一切正常。如果您现在尝试移动 cameraNode
“前进”,即现在向西,cameraNode
而是移动,好像“前进”仍然面向北方。
简而言之,它的移动就好像它从来没有旋转过一样。
下面的代码显示了我最近尝试的内容以及我(当前)在缩小最有可能与问题相关的领域的最佳猜测。
相关SceneNode
成员(member)SceneNode
implementation 具有以下字段(仅显示与此问题相关的字段):
class GenericSceneNode implements SceneNode {
// this node's parent; always null for the root scene node in the graph
private SceneNode parentNode;
// transforms are relative to a parent scene node, if any
private Vector3 relativePosition = Vector3f.createZeroVector();
private Matrix3 relativeRotation = Matrix3f.createIdentityMatrix();
private Vector3 relativeScale = Vector3f.createFrom(1f, 1f, 1f);
// transforms are derived by combining transforms from all parents;
// these are relative to the world --in world space
private Vector3 derivedPosition = Vector3f.createZeroVector();
private Matrix3 derivedRotation = Matrix3f.createIdentityMatrix();
private Vector3 derivedScale = Vector3f.createFrom(1f, 1f, 1f);
// ...
}
Camera
到场景只是意味着它被附加到
SceneNode
在图中。自
Camera
没有自己的位置/旋转信息,客户端只需处理
SceneNode
Camera
已附加,仅此而已。
SceneNode
翻译
currentPosition = currentPosition + normalizedDirectionVector * offset;
SceneNode
实现如下:
@Override
public void moveForward(float offset) {
translate(getDerivedForwardAxis().mult(-offset));
}
@Override
public void moveBackward(float offset) {
translate(getDerivedForwardAxis().mult(offset));
}
@Override
public void moveLeft(float offset) {
translate(getDerivedRightAxis().mult(-offset));
}
@Override
public void moveRight(float offset) {
translate(getDerivedRightAxis().mult(offset));
}
@Override
public void moveUp(float offset) {
translate(getDerivedUpAxis().mult(offset));
}
@Override
public void moveDown(float offset) {
translate(getDerivedUpAxis().mult(-offset));
}
@Override
public void translate(Vector3 tv) {
relativePosition = relativePosition.add(tv);
isOutOfDate = true;
}
SceneNode
回转
cameraNode
如下:
final Angle rotationAngle = new Degreef(-90f);
// ...
cameraNode.yaw(rotationAngle);
SceneNode
实现也相当简单:
@Override
public void yaw(Angle angle) {
// FIXME?: rotate(angle, getDerivedUpAxis()) accumulates other rotations
rotate(angle, Vector3f.createUnitVectorY());
}
@Override
public void rotate(Angle angle, Vector3 axis) {
relativeRotation = relativeRotation.rotate(angle, axis);
isOutOfDate = true;
}
@Override
public Vector3 getDerivedRightAxis() {
return derivedRotation.column(0);
}
@Override
public Vector3 getDerivedUpAxis() {
return derivedRotation.column(1);
}
@Override
public Vector3 getDerivedForwardAxis() {
return derivedRotation.column(2);
}
parentNode
组合变换以计算
this
的派生变换实例:
private void updateDerivedTransforms() {
if (parentNode != null) {
/**
* derivedRotation = parent.derivedRotation * relativeRotation
* derivedScale = parent.derivedScale * relativeScale
* derivedPosition = parent.derivedPosition + parent.derivedRotation * (parent.derivedScale * relativePosition)
*/
derivedRotation = parentNode.getDerivedRotation().mult(relativeRotation);
derivedScale = parentNode.getDerivedScale().mult(relativeScale);
Vector3 scaledPosition = parentNode.getDerivedScale().mult(relativePosition);
derivedPosition = parentNode.getDerivedPosition().add(parentNode.getDerivedRotation().mult(scaledPosition));
} else {
derivedPosition = relativePosition;
derivedRotation = relativeRotation;
derivedScale = relativeScale;
}
Matrix4 t, r, s;
t = Matrix4f.createTranslationFrom(relativePosition);
r = Matrix4f.createFrom(relativeRotation);
s = Matrix4f.createScalingFrom(relativeScale);
relativeTransform = t.mult(r).mult(s);
t = Matrix4f.createTranslationFrom(derivedPosition);
r = Matrix4f.createFrom(derivedRotation);
s = Matrix4f.createScalingFrom(derivedScale);
derivedTransform = t.mult(r).mult(s);
}
SceneNode
s 可以考虑其父级的转换。
Are you sure that when computing
derivedTransform
your parent'sderivedTransform
is already computed?
SceneNode
总是在更新子项之前更新。
update
逻辑是:
@Override
public void update(boolean updateChildren, boolean parentHasChanged) {
boolean updateRequired = parentHasChanged || isOutOfDate;
// update this node's transforms before updating children
if (updateRequired)
updateFromParent();
if (updateChildren)
for (Node n : childNodesMap.values())
n.update(updateChildren, updateRequired);
emitNodeUpdated(this);
}
@Override
public void updateFromParent() {
updateDerivedTransforms(); // implementation above
isOutOfDate = false;
}
最佳答案
这并不是直接的答案,而是应 OP 的要求作为引用。
使用旧 API 调用的 OpenGL v1.0:在场景类的场景图形之外的场景类中使用相机类对象时的实现。这是用 C++ 写的
相机.h
#ifndef CAMERA_H
#define CAMERA_H
#include "Core.h"
class Camera {
private:
Vector3 _v3EyePosition;
Vector3 _v3LookCenter;
Vector3 _v3Up;
public:
Camera();
~Camera();
void Get3rdPersonLocation( Vector3 &v3Position, float &fAngle );
void Set( Vector3 v3EyePosition, Vector3 v3LookCenter, Vector3 v3Up = Vector3( 0.0f, 1.0f, 0.0f ) );
void Render();
};
#endif
#include "stdafx.h"
#include "Camera.h"
Camera::Camera() {
_v3EyePosition = Vector3( 0.0f, 0.0f, 0.0f );
_v3LookCenter = Vector3( 0.0f, 0.0f, -1.0f );
_v3Up = Vector3( 0.0f, 1.0f, 0.0f );
}
Camera::~Camera() {
}
void Camera::Get3rdPersonLocation( Vector3 &v3Position, float &fAngle ) {
v3Position._fX = _v3LookCenter._fX;
v3Position._fY = _v3EyePosition._fY;
v3Position._fZ = _v3LookCenter._fZ;
// Find Angle
float fX = _v3LookCenter._fX - _v3EyePosition._fX;
float fZ = _v3LookCenter._fZ - _v3EyePosition._fZ;
// Angle In Degrees
fAngle = Math::Radian2Degree( atan2( fX, fZ ) );
}
void Camera::Set( Vector3 v3EyePosition, Vector3 v3LookCenter, Vector3 v3Up ) {
_v3EyePosition = v3EyePosition;
_v3LookCenter = v3LookCenter;
_v3Up = v3Up;
}
void Camera::Render() {
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
gluLookAt( _v3EyePosition._fX, _v3EyePosition._fY, _v3EyePosition._fZ,
_v3LookCenter._fX, _v3LookCenter._fY, _v3LookCenter._fZ,
_v3Up._fX, _v3Up._fY, _v3Up._fZ );
}
Camera
的
Render
使用旧的 OpenGL API 调用的函数首先加载到 Modelview 矩阵中,然后加载单位矩阵;然后我们最终使用 glu 的 gluLookAt(...) 方法来设置所需 vector 的位置。
Camera
对象它有一个摄像机作为成员,而不是指向摄像机的指针。
void Scene::Render() {
// Update Camera
_Camera.Set( _Player.GetPosition(), _Player.GetLookCenter() );
// Position Camera
_Camera.Render();
if ( UserSettings::Get()->_bQuit ) {
return;
}
if ( _vpNodes.size() < 1 ) {
// No SceneGraph To Render
return;
}
EnableLights();
// Send Items To Be Rendered
// Clear 2nd Render Pass Container
DeleteAllAlphaObjects();
// Render All Opaque Objects (1st Pass) & Store 2nd Pass Objects
_vpNodes[0]->RenderOGL( false, true );
// Render All Objects With Alpha Values (2nd Pass)
glEnable( GL_BLEND );
glMatrixMode( GL_MODELVIEW );
for ( std::vector<AlphaObject*>::iterator it = _vpAlphaObjects.begin(); it != _vpAlphaObjects.end(); ++it ) {
// Set Model View Matrix
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadMatrixf( &(*it)->f16Matrix[0] );
(*it)->pShape->RenderOGL( true, false );
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
}
// Show Selected Weapon
_Player.RenderWeapon();
glDisable( GL_BLEND );
DisableLights();
return;
}
Camera
独立于
Player
类以及场景的场景图层次结构,我们使用
Camera
在现场的
Render
称呼。这里我们设置了
Camera
通过获取
Player
的当前位置,以及
Player's
LookCenter
方向。
enum Action {
NO_ACTION = -1,
MOVING_FORWARD = 0,
MOVING_BACK,
MOVING_LEFT,
MOVING_RIGHT,
LOOKING_LEFT,
LOOKING_RIGHT,
LOOKING_UP,
LOOKING_DOWN,
}; // Action
#ifndef PLAYER_H
#define PLAYER_H
#include "Core.h"
class Weapon;
class NodeTransform;
class Player {
private:
enum MouseLook {
ML_NORMAL = 1,
ML_INVERT = -1,
} _MouseLookState; // MouseLook
Vector3 _v3Position;
Vector3 _v3LookCenter;
float _fLookDistance;
float _fMaxUp;
float _fMaxDown;
float _fLinearSpeed;
float _fAngularSpeed;
public:
Player( float fLookDistance );
~Player();
void SetSpeed( float fLinear, float fAngular );
void SetMouseY( bool bInvert );
void SetLocation( Vector3 v3Position, Vector3 v3Direction = Vector3( 0.0f, 0.0f, -1.0f ) );
void Move( Action action, float fDeltaTime );
bool Update();
inline void SetPosition( Vector3 v3Position );
inline Vector3 GetPosition();
inline Vector3 GetLookCenter();
inline Vector3 GetLookDirection();
};
inline void Player::SetPosition( Vector3 v3Position ) {
Vector3 v3LookDirection;
v3LookDirection = _v3LookCenter - _v3Position;
_v3Position = v3Position;
_v3LookCenter = v3Position + v3LookDirection;
}
inline Vector3 Player::GetPosition() {
return _v3Position;
}
inline Vector3 Player::GetLookCenter() {
return _v3LookCenter;
}
inline Vector3 Player::GetLookDirection() {
Vector3 v3LookDirection;
v3LookDirection = _v3LookCenter - _v3Position;
v3LookDirection.Normalize();
return v3LookDirection;
}
#endif
#include "stdafx.h"
#include "Player.h"
#include "UserSettings.h"
#include "NodeTransform.h"
Player::Player( float fLookDistance ) {
_fLookDistance = fLookDistance;
// Calculate Maximum Limits For Looking Up And Down
_fMaxUp = _fLookDistance * tan( Math::Degree2Radian( 50 ) );
_fMaxDown = _fLookDistance * tan( Math::Degree2Radian( 40 ) );
_v3Position = Vector3( 0.0f, 0.5f, 0.0f );
_v3LookCenter = Vector3( 0.0f, 0.5f, -fLookDistance );
_fLinearSpeed = 15.0f; // Units Per Second
_fAngularSpeed = 3.0f; // Radians Per Second
SetMouseY( UserSettings::Get()->GetMouseInvert() );
}
Player::~Player() {
} // ~Player
void Player::SetMouseY( bool bInvert ) {
if ( bInvert ) {
_MouseLookState = ML_INVERT;
} else {
_MouseLookState = ML_NORMAL;
}
}
void Player::SetLocation( Vector3 v3Position, Vector3 v3Direction ) {
_v3Position = v3Position;
_v3LookCenter = v3Position + _fLookDistance*v3Direction;
}
void Player::Move( Action action, float fDeltaTime ) {
Vector3 v3LookDirection;
v3LookDirection = _v3LookCenter - _v3Position;
switch ( action ) {
case MOVING_FORWARD: {
// Prevent Vertical Motion
v3LookDirection._fY = 0.0f;
_v3Position += v3LookDirection*fDeltaTime*_fLinearSpeed;
_v3LookCenter += v3LookDirection*fDeltaTime*_fLinearSpeed;
break;
}
case MOVING_BACK: {
// Prevent Vertical Motion
v3LookDirection._fY = 0.0f;
_v3Position -= v3LookDirection*fDeltaTime*_fLinearSpeed;
_v3LookCenter -= v3LookDirection*fDeltaTime*_fLinearSpeed;
break;
}
case MOVING_LEFT: {
// Get "Side" Direction & Prevent Vertical Motion
v3LookDirection._fY = v3LookDirection._fX;
v3LookDirection._fX = -v3LookDirection._fZ;
v3LookDirection._fZ = v3LookDirection._fY;
v3LookDirection._fY = 0.0f;
_v3Position -= v3LookDirection*fDeltaTime*_fLinearSpeed;
_v3LookCenter -= v3LookDirection*fDeltaTime*_fLinearSpeed;
break;
}
case MOVING_RIGHT: {
// Get "Side" Direction & Prevent Vertical Motion
v3LookDirection._fY = v3LookDirection._fX;
v3LookDirection._fX = -v3LookDirection._fZ;
v3LookDirection._fZ = v3LookDirection._fY;
v3LookDirection._fY = 0.0f;
_v3Position += v3LookDirection*fDeltaTime*_fLinearSpeed;
_v3LookCenter += v3LookDirection*fDeltaTime*_fLinearSpeed;
break;
}
case LOOKING_LEFT: {
/*float fSin = -sin( fDeltaTime*_fAngularSpeed );
float fCos = cos( fDeltaTime*_fAngularSpeed );
_v3LookCenter._fX = _v3Position._fX + (-fSin * v3LookDirection._fZ + fCos * v3LookDirection._fX );
_v3LookCenter._fZ = _v3Position._fZ + ( fCos * v3LookDirection._fZ + fSin * v3LookDirection._fX );
break;*/
// Third Person
float fSin = sin( fDeltaTime*_fAngularSpeed );
float fCos = -cos( fDeltaTime*_fAngularSpeed );
_v3Position._fX = _v3LookCenter._fX + (-fSin * v3LookDirection._fZ + fCos * v3LookDirection._fX );
_v3Position._fZ = _v3LookCenter._fZ + ( fCos * v3LookDirection._fZ + fSin * v3LookDirection._fX );
break;
}
case LOOKING_RIGHT: {
/*float fSin = sin( fDeltaTime*_fAngularSpeed );
float fCos = cos( fDeltaTime*_fAngularSpeed );
_v3LookCenter._fX = _v3Position._fX + (-fSin * v3LookDirection._fZ + fCos * v3LookDirection._fX );
_v3LookCenter._fZ = _v3Position._fZ + ( fCos * v3LookDirection._fZ + fSin * v3LookDirection._fX );
break;*/
// Third Person
float fSin = -sin( fDeltaTime*_fAngularSpeed );
float fCos = -cos( fDeltaTime*_fAngularSpeed );
_v3Position._fX = _v3LookCenter._fX + (-fSin * v3LookDirection._fZ + fCos * v3LookDirection._fX );
_v3Position._fZ = _v3LookCenter._fZ + ( fCos * v3LookDirection._fZ + fSin * v3LookDirection._fX );
break;
}
case LOOKING_UP: {
_v3LookCenter._fY -= fDeltaTime*_fAngularSpeed*_MouseLookState;
// Check Maximum Values
if ( _v3LookCenter._fY > (_v3Position._fY + _fMaxUp ) ) {
_v3LookCenter._fY = _v3Position._fY + _fMaxUp;
} else if ( _v3LookCenter._fY < (_v3Position._fY - _fMaxDown) ) {
_v3LookCenter._fY = _v3Position._fY - _fMaxDown;
}
break;
}
}
}
bool Player::Update() {
// Stripped Down This Deals With Player's Weapons
}
void Player::SetSpeed( float fLinear, float fAngular ) {
_fLinearSpeed = fLinear;
_fAngularSpeed = fAngular;
}
Scene::Update()
// -----------------------------------------------------------------------
// Update
// Animate Objects, Pickup Checks Etc. This All Happens At The
// Physics Refresh Rate
void Scene::Update() {
UserSettings* pUserSettings = UserSettings::Get();
AudioManager* pAudio = AudioManager::GetAudio();
bool bPlayerMoving = false;
// Movement
if ( pUserSettings->IsAction( MOVING_FORWARD ) ) {
_Player.Move( MOVING_FORWARD, GameOGL::GetPhysicsTimeStep() );
bPlayerMoving = true;
}
if ( pUserSettings->IsAction( MOVING_BACK ) ) {
_Player.Move( MOVING_BACK, GameOGL::GetPhysicsTimeStep() );
bPlayerMoving = true;
}
if ( pUserSettings->IsAction( MOVING_LEFT ) ) {
_Player.Move( MOVING_LEFT, GameOGL::GetPhysicsTimeStep() );
bPlayerMoving = true;
}
if ( pUserSettings->IsAction( MOVING_RIGHT ) ) {
_Player.Move( MOVING_RIGHT, GameOGL::GetPhysicsTimeStep() );
bPlayerMoving = true;
}
if ( bPlayerMoving && !_bPlayerWalking ) {
pAudio->SetLooping( AUDIO_FOOTSTEPS, true );
pAudio->Play( AUDIO_FOOTSTEPS );
_bPlayerWalking = true;
}
else if ( !bPlayerMoving && _bPlayerWalking ) {
pAudio->Stop( AUDIO_FOOTSTEPS );
_bPlayerWalking = false;
}
// ... Other Code Here
}
// Move Model View Matrix M = (T C R S C^)
void NodeTransform::RenderOGL( bool bSecondPass, bool bRenderNext ) {
if ( _pIn && _bVisible ) {
// Put Matrix Onto Stack For Later Retrieval
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
if ( _bHaveMatrix ) {
// Use Transformation Matrix
glMultMatrixf( &_f16Matrix[0] );
}
// Transalate
glTranslatef( _v3Translate._fX, _v3Translate._fY, _v3Translate._fZ );
// Move Back To Center
glTranslatef( _v3Center._fX, _v3Center._fY, _v3Center._fZ );
// Rotate
glRotatef( _fRotateAngle, _v3RotateAxis._fX, _v3RotateAxis._fY, _v3RotateAxis._fZ );
// Scale
glScalef( _v3Scale._fX, _v3Scale._fY, _v3Scale._fZ );
// Offset By -ve Center Value
glTranslatef( -_v3Center._fX, -_v3Center._fY, -_v3Center._fZ );
// Move Down The Tree
_pIn->RenderOGL( bSecondPass, true );
// Get Old Matrix
glMatrixMode( GL_MODELVIEW );
glPopMatrix();
}
if ( _pNext && bRenderNext ) {
_pNext->RenderOGL( bSecondPass, true );
}
} // RenderOGL
关于java - 修复了 3D 相机在它面对的方向上移动的问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38825659/
我将一个 div 设置为 100% 宽度,当以 1024 分辨率查看页面时,宽度应从 100% 变为 1000px,我让它与@media 查询一起正常工作,并且在 FF、safari chrome 上
希望有人能帮助我,我已经被困了几天了。 将我的 Domino 服务器更新到 9.01 Fix 3 后,我在 javascript 控制台上不断收到错误消息: TypeError: this.edito
我们正在使用一个基于RMI的java应用程序。当我们运行应用程序时,即使应用程序处于理想阶段,内存使用量仍然不断增加。我们主要使用Vector和散列图数据结构。如何最大限度地减少java内存使用/修复
概述 Internet Download Manager (IDM)是最流行的 Windows 下载管理器。如果你平时工作中使用过IDM,您会惊叹 IDM 下载文件的速度有多快。IDM
当我打开 brave 浏览器时,会打开一个窗口(如下所示)。它并没有真正干扰浏览器的处理。但令人担忧的是为什么这种情况一直发生...... Error On Opening Brave Browser
这是我今天在求职面试中被问到的一个问题: 看下面的代码: int n=20; for (int i =0; i
我不小心删除了/opt/local/bin/perl5.8.9 ,这似乎是 macports 编译的 perl 的主要二进制文件。 现在我有很多取决于 perl5 的端口,但不想卸载并重新安装所有端口
>>>flip fix (0 :: Int) (\a b -> putStrLn "abc") Output: "abc" 这是使用翻转修复的简化版本。 我在一些 YouTube 视频中看到了这种使用
这个问题已经有答案了: How can I fix 'android.os.NetworkOnMainThreadException'? (64 个回答) 已关闭 3 年前。 我在 Android 应
def main(): cash = float(input("How much money: ")) coins = 0 def changeCounter(n): whil
前一周我遇到了类似的问题,查询需要永远运行。在编写此查询时,我尝试应用从其他查询中学到的一些知识,但执行起来需要很长时间。 运行查询的两个单独部分时,每个部分需要 2 分钟才能完成,这是可以接受的,但
下午,我的 CSS 有问题。第三个下拉菜单放错了,我没有解决办法。 这是我想要的: 之前: http://i53.tinypic.com/2qu85z8.png 之后: http://i51.tiny
更新方法: override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingS
我知道这是一个很多人都遇到过的问题,但我不熟悉 Less 并且是 Bootstrap 的新手,我正在寻找一种全 CSS 解决方案来防止我的导航栏折叠到 768 像素以下:
在我的布局中,我创建了以下 jsfiddle 托管的可调整大小的粘性页脚。但是,在调整大小时它与内容重叠。有没有办法让它在所有浏览器上都能响应? http://jsfiddle.net/9aLc0mg
我想要实现的目标 racer-offset 是为了让用户可以设置图像可以以 px 为单位移动多远。偏移量管理偏移量。 Speed-racer 告诉我们图像在滚动过程中移动的速度。我的问题是它不会停止。
我有一个简单的自动换行函数,它接受一个长字符串作为输入,然后将该字符串分成更小的字符串,并将它们添加到一个数组中,以便稍后输出。现在最后一两个字没有输出。这是主要问题。但是,我还想改进功能。我知道这有
我试图在使用每个 slider 之前禁用“下一步”按钮,我不确定为什么在单击不再是 class="not-clicked"的同一个 slider 时取消禁用该按钮. JSFiddle: (这里看起来有
这个问题已经有答案了: What is a NullPointerException, and how do I fix it? (12 个回答) 已关闭 8 年前。 如何让程序输出所有信息? IT
On this page ,在“生活”下有一个带有自动生成的子菜单的菜单。子菜单存在一些问题(它会闪烁并改变大小——如果你滚动它就会看到)。我需要以某种方式覆盖它当前正在读取的 css 并使其统一。
我是一名优秀的程序员,十分优秀!