5

処理中 (Java ダイアレクト) には、screenX、screenY (および screenZ ですが、ここではスキップします) というメソッドがあります。

xyz = 50、100、500 にオブジェクトがあるとします。次に、screenX と screenY を使用して、キャンバス上のどこに表示されるかを確認できます。

float x = screenX(50, 100, 500); float y = screenY(50, 100, 500);

ここに参照があります: http://processing.org/reference/screenX_.html

私が興味を持っているのは、逆メソッドのようなものです。たとえば、x=175 と y=100 のキャンバスに球体を表示したいとします。球体の az は 700 である必要があります。では、z=700 での実際の x と y の位置は、キャンバス上の 175,100 に表示されるようになるでしょうか?

したがって、メソッドはfloat unscreenX(float x, float y, float z)x 値を返します。

私の数学/プログラミングのスキルはそれほど高度ではありません (悪いと呼びましょう) (私はどちらかというとデザイナーです) ので、助けを求めています。私はすべて処理委員会に尋ねる準備ができていますが、多くの場合、行列などについてより深い知識を持っている人がここにいます.

処理からの通常の screenX メソッドは、 https ://github.com/processing/processing/blob/master/core/src/processing/opengl/PGraphicsOpenGL.java にあります。

public float screenX(float x, float y, float z) {
    return screenXImpl(x, y, z);
  }

protected float screenXImpl(float x, float y, float z) {
    float ax =
      modelview.m00*x + modelview.m01*y + modelview.m02*z + modelview.m03;
    float ay =
      modelview.m10*x + modelview.m11*y + modelview.m12*z + modelview.m13;
    float az =
      modelview.m20*x + modelview.m21*y + modelview.m22*z + modelview.m23;
    float aw =
      modelview.m30*x + modelview.m31*y + modelview.m32*z + modelview.m33;
    return screenXImpl(ax, ay, az, aw);
  }


  protected float screenXImpl(float x, float y, float z, float w) {
    float ox =
      projection.m00*x + projection.m01*y + projection.m02*z + projection.m03*w;
    float ow =
      projection.m30*x + projection.m31*y + projection.m32*z + projection.m33*w;

    if (nonZero(ow)) {
      ox /= ow;
    }
    float sx = width * (1 + ox) / 2.0f;
    return sx;
  }

もちろん、y 用と z 用もあります (z はわかりませんが、無視しましょう)。これは、それを逆にする方法についての洞察を与えるかもしれないと思いました。

modelview とプロジェクションは 3D マトリックスです。コードは次のとおり です

あなたが決して知らないので、私も処理ボードに投稿しました。それは私が望むものとは少し異なることを説明しています。 http://forum.processing.org/topic/unscreenx-and-unscreeny

この投稿を説明するタグについては、特定の原因には行きませんでした。たとえば、Java を使用したことはないが、C++ を使用したことがあり、マトリックスの経験があるプログラマーが適切な回答を提供できると想像できます。

誰かが助けてくれることを願っています。

4

4 に答える 4

3

3D グラフィックスの線形代数または行列演算を学習することを強くお勧めします。楽しくて簡単ですが、SOの回答よりも少し長くなります。でも試してみます:) 免責事項: あなたが使用している API についてはわかりません!

位置(多くの場合、頂点と呼ばれます)の3つの座標を返しているようです。しかし、射影行列についても言及しており、その関数には4つの座標があります。通常、シェーダーまたは API は頂点に対して 4 つの座標を取ります。x、y、z、w。それらを画面に表示するには、次のようにします。

xscreen = x/w
yscreen = y/w
zbuffer = z/w

これは、w を選択できるので便利です。2D 描画だけを行う場合は、w=1 と入力できます。しかし、3D を行っていて、遠近効果が必要な場合は、カメラからの距離で割ります。そして、それが射影行列の目的です。主にポイントの z を取り、z はカメラまでの距離を意味し、それを w に入れます。また、視野など、物事を少し拡大することもできます。

投稿したコードを振り返ってみると、これはまさに最後の ScreenXImpl 関数が行うことです。これは射影行列を適用しますが、これは主に z を w に移動し、次に w で除算します。最後に、追加のスケールと (-1,1) から (0,widhtinpixels) へのオフセットを行いますが、それは無視できます。

さて、なぜ私はこのことについてとりとめのないのですか?あなたがしたいことは、与えられた xscreen、yscreen、zbuffer の x、y、z 座標を取得することですよね? まあ、トリックは逆に行くだけです。そのためには、前進することをしっかりと把握する必要があります:)

逆行には 2 つの問題があります。2) 射影行列が何をしたか知っていますか? 1) 気にしないとしましょう。これには多くの可能な値があるため、1 つだけ選択することもできます。2)については、それが何をするかを見る必要があります。一部の射影行列は、(x,y,z,w) を取り、(x,y,z,1) を出力する場合があります。2dでしょう。または (x,y+z,z,1) 等角図になります。しかし、遠近法では、通常は (x,y,1,z) になります。さらに、いくつかのスケーリングなど。

2 番目の screenXImpl が既に x、y、z、w を次のステージに渡していることに気付きました。これは便利な場合もありますが、実際には w が 1 になるすべてのケースで有効です。

この時点で、私は物事を説明するのがひどいことに気づきました。:) あなたは本当にその線形代数の本を拾うべきです、私はこの本から学びました: http://www.amazon.com/Elementary-Linear-Algebra-Howard-Antonそれ自体がどれほど有用かを知ってください。

とにかく!もっと実践的にいきましょう。コードに戻ります: screenXImpl の最後の関数です。入力が w=1 で、ow=~z および ox=~x であることがわかりました。ここでの波線は、あるスケールとオフセットを掛けたものを意味します。そして、始めなければならない画面 x は ~ox/ow です。(+1/2、*幅..それが波線の目的です)。そして今、私たちは 1) に戻っています... 特別なオンスが必要な場合は、今すぐお選びください。それ以外の場合は、どれでも選択できます。レンダリングでは、カメラの前で操作しやすいものを選択するのがおそらく理にかなっています。1のように。

protected float screenXImpl(float x, float y, float z, float w==1) {
float ox = 1*x + 0*y + 0*z + 0*w; // == x
float ow = 0*x + 0*y + 1*z + 0*w; // == z == 1

ox /= ow; // == ox

float sx = width * (1 + ox) / 2.0f;
return sx;
}

なんてこと?sx = 幅 * (1+ox)/2 ? なぜ私はそう言わなかったのですか?まあ、私が入れたすべてのゼロはおそらくゼロではありません。しかし、それは同じように単純に終わるでしょう。ものはものではないかもしれません。元に戻るために必要な重要な仮定を示してみました。これで、sx から ox に戻るのと同じくらい簡単になります。

それが難しい部分でした!ただし、最後の関数から 2 番目の関数に移動する必要があります。最初から2番目は簡単だと思います。:) その関数は線形行列変換を行っています。これは私たちにとって良いことです。4 つの値 (x、y、z) および (w=1) の暗黙的な入力を取り、他の 4 つの値 (ax、ay、az、aw) を出力します。手動でそこに戻る方法を見つけることができました! 私は学校でそれをしなければなりませんでした.. 4つの未知数、4つの方程式。ax、ay、az、aw... x、y、z を解くと、w=1 が無料で得られます。非常に可能性が高く、良い練習になりますが、退屈でもあります。幸いなことに、これらの方程式の書き方は行列と呼ばれます。(x,y,z,1) * MODELMATRIX = (ax,ay,az,aw)。MODELMATRIX^-1 を求めることができるので非常に便利です。逆子といいます!1/2 が実数の乗算の 2 の逆数であるように、または -1 が加算の 1 の逆数です。あなたは本当にこれを読んでおくべきです。それは楽しいことであり、難しいことではありません.ところで:)。とにかく、標準ライブラリを使用してモデル行列の逆を取得してください。おそらく、modelView.Inverse() のようなものです。そして、それで同じ機能を実行すると、逆になります。簡単!

では、なぜ以前に PROJECTION マトリックスで同じことをしなかったのでしょうか? よろしくお願いします!これは 4 つの入力 (x、y、z、w) を受け取り、3 つの出力 (screenx、screeny、zbufferz) のみを吐き出します。したがって、いくつかの仮定をしなければ、それを解決することはできませんでした! それを直観的に見ると、2D スクリーンに投影する 3D ポイントがある場合、多くの解決策が考えられるということです。ですから、何かを選ばなければなりません。また、便利な行列逆関数が使えません。

これが多少役に立ったかどうか教えてください。違う気がするけど書いてて楽しかった!また、処理中のアンプロジェクトのグーグルはこれを提供します: http://forum.processing.org/topic/read-3d-positions-gluunproject

于 2013-06-10T11:02:25.200 に答える
0

これは簡単な三角法で計算できます。必要なのは、hキャンバスの中心から目の距離と、キャンバスの中心cxcy表す と です。簡単にするために、cxcyは 0 であると仮定します。実際の目の距離ではなく、3D シーンで遠近法を構築するために使用される仮想の目の距離であることに注意してください。

次に、 と が与えられsxsy中心までの距離を計算します。b = sqrt(sx * sx + sy * sy)

bこれで、底辺と高さの直角三角形ができましたh。この三角形は、「目」、キャンバス上の中心、および画面上のオブジェクトの目的の位置によって形成されます(sx, sy)

この三角形は、「目」によって形成される別の直角三角形の上部を形成します。キャンバス上の中心は、与えられた深さによって押し戻されz、オブジェクト自体: (x, y).

三角形の底辺と高さの比率はまったく同じなので、bb高さが与えられた場合、hh = zまたは値が目からのものかキャンバスからのものhh = h + zかに応じて、大きな三角形の底辺を計算するのは簡単です。z使用する方程式はb / h = bb / hh、あなたが知っているところbhあり、hh

(x, y)2 つのベースが水平線から同じ角度にあるため、そこから簡単に計算できます。私はe。sy / sx = y / x.

面倒な部分は、目の距離とキャンバスの距離、および 3D セットアップからキャンバスの中心を抽出することだけです。

于 2013-06-15T20:55:26.967 に答える
0

この作業を行う前に、プロジェクト マトリックスを知る必要がありますが、これは Processing では提供されません。ただし、3 つのベクトル (1,0,0)、(0,1,0)、および (0,0,1) の screenX/Y/Z 値をチェックすることで、自分で解決できます。それらから、スクリーンの平面式が何であるかを理解できます (これは、技術的には、3D 空間を通る切り抜かれた平らな 2D サーフェスにすぎません)。次に、「スクリーン」サーフェス上の (x,y) 座標と所定のz値が与えられると、スクリーン平面を通る法線と の平面との交点を見つけることができますz=...

ただし、やりたいことのために座標系を簡単にリセットできるため、これはやりたいことではありません。現在の 3D 変換をpushMatrix「保存」し、resetMatrixすべてを「まっすぐ」に戻してから、ワールド軸とビュー軸が整列しているという事実に基づいて球を描画します。その後、完了したら、呼び出しpopMatrixて以前の世界の変換を復元し、完了します。数学を実装するという頭痛の種を自分で救ってください =)

于 2013-06-06T23:53:12.780 に答える
0

3D ポイントを 2D 画面に変換する概要

オブジェクトの 3D 表現 (x、y、z) がある場合、これを 2D のモニターに「投影」したいとします。これを行うには、3 次元座標を取り込み、2 次元座標を吐き出す変換関数があります。内部では (少なくとも openGL では)、実行される変換関数は特別な行列です。変換を行うには、ポイント (ベクトルで表される) を取得し、単純な行列の乗算を行います。

いくつかの素敵な図と派生物 (興味がある場合は必要ありません) については、こちらをご覧ください: http://www.songho.ca/opengl/gl_projectionmatrix.html

私にscreenXImplは、行列の乗算を行っているように見えます。

逆のことをする

逆変換は、元の変換の単純な逆行列です。

于 2013-06-16T07:42:49.987 に答える