2016-09-15 15 views
5

iPad上でOpenGL ESを使用してオブジェクトを表示しました。モデルは、頂点、法線、および頂点へのインデックスによって定義されます。モデルの原点は0,0,0です。 UIGestureRecognizerを使用して、さまざまなジェスチャーを検出できます.2本の指で水平方向にスワイプしてyについて回転し、xについては垂直にスワイプします。 yを中心に回転するための2指の回転ジェスチャ。パンでモデルを移動します。ピンチ/ズームジェスチャーをスケールします。私は、視聴者がモデルを操作して、モデルの逆や一気に見ることができるようにしたい。タッチポイントによって定義された軸の周りに回転を適用する

基本的な方法はRay Wenderlich's tutorialですが、私はこれをSwiftに書き直しました。

四元数はベクトルと角度であると私は理解しています。 uprightfront三の軸表すベクトル:

front = GLKVector3Make(0.0, 0.0, 1.0) 
right = GLKVector3Make(1.0, 0.0, 0.0) 
up = GLKVector3Make(0.0, 1.0, 0.0) 

ようクォータニオンリンゴ三の軸(dxの一方のみしかし、dyの各々の周りに回転し、dzジェスチャ認識によって決定値を有します。)

func rotate(rotation : GLKVector3, multiplier : Float) { 

    let dx = rotation.x - rotationStart.x 
    let dy = rotation.y - rotationStart.y 
    let dz = rotation.z - rotationStart.z 
    rotationStart = GLKVector3Make(rotation.x, rotation.y, rotation.z) 
    rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(dx * multiplier, up), rotationEnd) 
    rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(dy * multiplier, right), rotationEnd) 
    rotationEnd = GLKQuaternionMultiply((GLKQuaternionMakeWithAngleAndVector3Axis(-dz, front)), rotationEnd) 
    state = .Rotation 

} 

図面は、以下の関数によって計算modelViewMatrix、使用:

func modelViewMatrix() -> GLKMatrix4 { 

    var modelViewMatrix = GLKMatrix4Identity 
    // translation and zoom 
    modelViewMatrix = GLKMatrix4Translate(modelViewMatrix, translationEnd.x, translationEnd.y, -initialDepth); 
    // rotation 
    let quaternionMatrix = GLKMatrix4MakeWithQuaternion(rotationEnd) 
    modelViewMatrix = GLKMatrix4Multiply(modelViewMatrix, quaternionMatrix) 
    // scale 
    modelViewMatrix = GLKMatrix4Scale(modelViewMatrix, scaleEnd, scaleEnd, scaleEnd); 
    // rotation 

    return modelViewMatrix 
} 

ほとんどの場合、これが動作します。しかし、すべてが原点に相対的です。 モデルを回転させると、ピボットは常に原点を通る軸になります。原点から離れたモデルの端を拡大して回転して回転させると、モデルは急速に見えなくなります。モデルが拡大縮小されている場合、原点は固定小数点で常に大きくなります。原点がオフスクリーンでスケールが縮小されていると、モデルは原点に向かって崩壊するとビューから消えます。

何が起こるべきかは、現在のビューが何であっても、モデルは現在のビューに対して相対的に回転または拡大します。 y軸を中心とする回転の場合、回転が発生するy軸を現在のビューの中央を通って垂直に通過するように定義することを意味します。スケール操作の場合、モデルの固定小数点は画面の中央にあり、モデルはその点に向かって縮むか、その点から外側に伸びます。

私は2Dで解決策が常に原点に変換されることを知っています。回転を適用し、最初の平行移動の逆を適用します。私はなぜこれが3Dで違うべきか分かりませんが、私は四元数だけの行列でこれを行う例は見つけられません。回転の周りに平行移動と逆平行を適用しようとしましたが、何も効果がありません。

だから私は、回転機能でこれを実行しようとしました:

let xTranslation : Float = 300.0 
let yTranslation : Float = 300.0 
let translation = GLKMatrix4Translate(GLKMatrix4Identity, xTranslation, yTranslation, -initialDepth); 
rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithMatrix4(translation) , rotationEnd) 

rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(dx * multiplier, up), rotationEnd) 
rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithAngleAndVector3Axis(dy * multiplier, right), rotationEnd) 
rotationEnd = GLKQuaternionMultiply((GLKQuaternionMakeWithAngleAndVector3Axis(-dz, front)), rotationEnd) 

// inverse translation 
let inverseTranslation = GLKMatrix4Translate(GLKMatrix4Identity, -xTranslation, -yTranslation, -initialDepth); 
rotationEnd = GLKQuaternionMultiply(GLKQuaternionMakeWithMatrix4(inverseTranslation) , rotationEnd) 

翻訳は300300ですが、何の効果は全くありません、私はあることを、原点を知っている場所、それはまだ周りに旋回します。私はサンプルコードのために長い時間を捜してきましたが、何も見つかりませんでした。

modelViewMatrixを有する)(更新に適用される:

effect?.transform.modelviewMatrix = modelViewMatrix 

0,0,0が中心点に収まるように、私は、モデルのすべての値を調整することにより、カンニングができた - それは希望依然として固定された起源であり、ほんのわずかしか改善されないであろう。

+0

行列の乗算は非常に直感的であることができます - 私の最初の思考(私は何度もこれを混乱させてしまったので)は、間違った順序で行列を掛けているということです。 私はあなたが探している動作が正確ではないと思います。ビューに対して固定原点を維持する[このモデル表示サイト](https://sketchfab.com/models/7355bbb7edf14fed9273eedadf513f5c)と比較してください。これはあなたのために起こっているのでしょうか、あなたはどうやって違うのですか? –

+0

固定原点の良い例です。自転車を中心から離れて動かすと、中央の周りに広い円弧でスイングします。私は回転の軸を回転のジェスチャーを作る2本の指の間の点にしたいと思います。今は2次元の点しか定義していませんが、回転の原点と同じzを維持することは問題ありません。 –

+0

あなたが望むものをさらに明確にすることはできますか?たとえば、質問のリストを入力できますか? – ELKA

答えて

2

問題は、あなたが作った最後の操作である、あなたはrotationEndinverseTranslationを交換する必要があります

rotationEnd = GLKQuaternionMultiply(rotationEnd, GLKQuaternionMakeWithMatrix4(inverseTranslation)) 

そして、私は部分的に回転(DX、DY、DZ)が同じルールに従うべきだと思います。

実際にあなたがピボットを変更したい場合は、これはあなたの行列の乗算が行われるべきかです:

modelMatrix = translationMatrix * rotationMatrix * inverse(translationMatrix) 

と、次のように同次座標で結果が計算されます。

newPoint = translationMatrix * rotationMatrix * inverse(translationMatrix) * v4(x,y,z,1) 

これは、遊び場で実行できる2Dテストの例です。規模については

enter image description here

let v4 = GLKVector4Make(1, 0, 0, 1) // Point A 

let T = GLKMatrix4Translate(GLKMatrix4Identity, 1, 2, 0); 
let rot = GLKMatrix4MakeWithQuaternion(GLKQuaternionMakeWithAngleAndVector3Axis(Float(M_PI)*0.5, GLKVector3Make(0, 0, 1))) //rotate by PI/2 around the z axis. 
let invT = GLKMatrix4Translate(GLKMatrix4Identity, -1, -2, 0); 

let partModelMat = GLKMatrix4Multiply(T, rot) 
let modelMat = GLKMatrix4Multiply(partModelMat, invT) //The parameters were swapped in your code 
//and the result would the rot matrix, since T*invT will be identity 

var v4r = GLKMatrix4MultiplyVector4(modelMat, v4) //ModelMatrix multiplication with pointA 
print(v4r.v) //(3,2,0,1) 

//Step by step multiplication using the relation described above 
v4r = GLKMatrix4MultiplyVector4(invT, v4) 
v4r = GLKMatrix4MultiplyVector4(rot, v4r) 
v4r = GLKMatrix4MultiplyVector4(T, v4r) 
print(v4r.v) //(3,2,0,1) 

私はあなたが欲しいものを正しく理解していれば、私はそれがここで行われているようにそれを行うことをお勧めします:https://gamedev.stackexchange.com/questions/61473/combining-rotation-scaling-around-a-pivot-with-translation-into-a-matrix

+0

詳細な説明をいただき、ありがとうございます。 –

関連する問題