質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

Q&A

解決済

2回答

2380閲覧

正規化でポリゴンを反射させたいのに黒く映ってしまう

txty

総合スコア298

OpenGL

OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

0グッド

0クリップ

投稿2021/10/24 15:47

編集2024/01/02 03:55

1.追記ベクトルA=(2,-1,3)のベクトルAを正規化しなさい

A^2=2^2+(-1)^2+3^2=4+1+9=14

正規化したベクトルは(2/√14,-1/√14,3/√14)になります.

2.ポリゴンの3頂点をv1=(1,0,0),v2=(0,1,0),v3=(0,0,1)として法線を正規化しなさい

ベクトルv1v3=v3-v1=(0-1,0-0,1-0)=(-1,0,1),
ベクトルv1v2=v2-v1=(0-1,1-0,0-0)=(-1,1,0)
法線は直交するので、ベクトルv1v3 x ベクトルv1v2=
|i,j,k|
|-1,0,1|
|-1,1,0|=(-1,-1,-1)
法線は正規化して(-1/√3,-1/√3,-1/√3)

3.必要な計算

→AB=→b- →a

2つのベクトル(x1,y1,z1)(x2,y2,z2)の時,

v1*v2=|i,j,k|
|x1,y1,z1|
|x2,y2,z2|=(y1z2-z1y2)i-(x1z2-z1x2)j+(x1y2-y1x2)k

A=y1z2-z1y2
B=-(x1z2-z1x2)
C=(x1y2-y1x2)
だと思う。

法線は正規化する必要があるのでn=A/ √A^2+B^2+C^2  , B/√A^2+B^2+C^2,
C/√A^2+B^2+C^2,

参考文献。。3Dグラフィックスのための数学 工学社

1と2どちらがただしいでしょうか

間違えてたらすいません。責任とりません。誤差のようなものがあるようなのと、
あと、こちらも責任取りませんが、正規化した法線、V_X/la,V_Y/la,V_Z/laが
うまくコードにできませんでした。

追記.... 正規化した法線の値が-1.0~1.0の値になっていました。正規化した値は0.0~1.0かもしれないので追記します。
https://qiita.com/yoship1639/items/75505244b6c242d50f71

dot(n, normalize(-wLightDir))

dotの結果は、向きが近ければ近いほど1.0に近づき、向きが反対に近いほど-1.0に近づきます。
1.0に近いと明るく、0.0に近いと暗くなります。
マイナス部分は光の量を逆に奪ってしまうので、マイナスにならない様にします。

だそうです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/10/28 11:39

> glVertex3f(v[3*a[0]-3],v[3*a[0]-2],v[3*a[0]-1]); を見るに,頂点の座標というのは v[] という配列(?)にあると見えます. 他方, > glNormal3f(V_X/la,V_Y/la,V_Z/la); に指定する値を求めるのに用いているデータの出所は NORMAL[] という配列(?)になっています. また,v[] と NORMAL[] とでは,indexを決めるために用いられている配列(?)も,a[] と b[] で異なっています. この点は正当なのでしょうか?
txty

2021/10/28 14:27 編集

頂点で計算してないからですか?
txty

2021/10/28 13:55 編集

すいません。できました。v?とあるとおり、頂点で計算してないからでした。
guest

回答2

0

ベストアンサー

描画結果が黒くなる理由は様々考えられます.
以下のような事柄を確認してみてはどうでしょう.

  • 光源が有効になっていない

提示コードには glEnable(GL_LIGHTNING); がありますが,各光源の有効化処理はありません.
glEnable( GL_LIGHT0 ); のようなことを行っていますか?

  • 法線が光源の方を向いていない とか 物体に届く光が弱すぎる とか

使用する光源の位置とかタイプとかの設定はどうなっていますか?
デフォルト状態がどうなってるのかを私は知りませんが,明示的に設定していないならばしてみてはどうでしょうか.
その上で,法線が光源の方向に向いているのかどうか等をチェックすると良いでしょう.

  • 物体の色味の指定が「黒」相当になっている

(そんなことになっているとは思えませんが,原因のひとつとして一応挙げてみる)


ライティングON状態で三角形を1個描画するだけのコードを示します.
とりあえず↓のコードで,三角形がそれなりに白く描画されてます.
GLFW と GLM を使ったコードになってはいますが,

  • GLFW の部分は本件の内容とは無関係なのでどうでもいいところ
  • GLM については glm::vec3 という float3要素なベクトル型を使っているだけです

…という感じなので,特にこれらのせいでコードの意味がわからんとかいうことにはならないだろうと思います.

このコードで,例えば以下のいずれかを行えば,三角形は黒くなりますね.

  • glLightfv( ... ) をやらない:

(その場合の光源設定がどうなるのか私は知らないけども)なんか光が当たらん感じの設定になるのだと思われ.

  • glEnable( GL_LIGHT0 ); をやらない:

光源が有効化されないので.

  • 法線を逆向きにする:

例えば Normal = -Normal; とかすると,法線が光源が無い方向に向くことになるので.

int main() { //※GLFW ウィンドウ準備処理 GLFWwindow *pWindow = nullptr; { if( !(pWindow = glfwCreateWindow( 640, 480, "GLFW", NULL, NULL )) )return 1; //ウィンドウ生成 glfwMakeContextCurrent( pWindow ); //ウィンドウをGLの処理対象にする } //Clear Color 設定 : ※てきとーに「黒」とかとは区別がつく色にしている glClearColor( 0.1f, 0.35f, 0.1f, 0.0f ); //三角形の3つの頂点の座標 const glm::vec3 Vtx[3] = { { -0.7, -0.7, 0 }, { -0.5, 0.75, 0 }, { 0.8, 0, 0 } }; //法線を求む(3頂点で同一値を使用) glm::vec3 Normal = glm::cross( Vtx[1]-Vtx[0], Vtx[2]-Vtx[0] ); //外積 Normal = glm::normalize( Normal ); //正規化.→結果は(0,0,-1)になっている. {//光源 LIGHT0 の設定. float LightPos[] = { 0,0,-1, 0 }; //平行光源 glLightfv(GL_LIGHT0, GL_POSITION, LightPos ); } //※念のためマトリクスを単位行列にしておく glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); //※GLFW的なメインループ while( glfwWindowShouldClose( pWindow ) == 0 ) { //※ESCキーで終了するためのGLFW的な記述 if( glfwGetKey( pWindow, GLFW_KEY_ESCAPE ) == GLFW_PRESS ){ glfwDestroyWindow( pWindow ); break; } //描画処理 glClear( GL_COLOR_BUFFER_BIT ); glEnable( GL_LIGHTING ); //ライティング処理有効化 glEnable( GL_LIGHT0 ); //光源 LIGHT0 有効化 glBegin( GL_TRIANGLES ); { for( int i=0; i<3; ++i ) { glNormal3f( Normal.x, Normal.y, Normal.z ); glVertex3f( Vtx[i].x, Vtx[i].y, Vtx[i].z ); } } glEnd(); glDisable( GL_LIGHTING ); //ライティング処理無効化 //※GLFWの処理 glfwSwapBuffers( pWindow ); glfwWaitEvents(); } return 0; }


[編集:コメント欄の内容のうち,質問内容への回答的な要素がある部分を以下に移植しておく]

質問文記載の法線計算方法の話について

1と2どちらがただしいでしょうか。

とのことですが…

1.追記ベクトルA=(2,-1,3)のベクトルAを正規化しなさい

これは,単なる ベクトルの単位化 の話ですね.
L2ノルムで全要素を除すことで単位ベクトルが得られる,という普通の話です.

2.ポリゴンの3頂点をv1=(1,0,0),v2=(0,1,0),v3=(0,0,1)として法線を正規化しなさい

こっちは,三角形の法線方向ベクトルを外積で求めて,
その後でそれを前記1の話で単位化する,という話.

…なので,1と2の関係性というのは「2の計算は1の話を用いている」であり,「どちらが正しいか」という関係性ではないですよね.

1, 2 の話自体はごくごく普通の内容と見えます.

glScale の影響の話

glSacle のスケーリングが,glNormal3f で設定している値にまで効果を及ぼしてしまう,ということなんだと思います.
例えば,

glScalef( 2, 2, 2 ); ... glNormal3f( /*単位法線ベクトルのx,y,z*/ );

という形で書くと,結果として法線が長さ2になってしまうんでしょうね.
(で,変な単位ベクトルでない変な値で計算されてしまって,結果の色がおかしくなる,と.)

GL_NOMALIZE とかいうのはこの嫌らしい効果に対抗するための手段…ということなのかな.
(ライティング処理の前に法線を正規化してくれる機能っぽい)

投稿2021/10/28 05:10

編集2021/10/28 11:35
fana

総合スコア11654

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

txty

2021/11/09 02:48 編集

>glLightfv( ... ) をやらない: >(その場合の光源設定がどうなるのか私は知らないけども)なんか光が当たらん感じの設定になるのだ>と思われ. 設定していません。光はデフォルト位置で、当たる(?)ようです。。。shinessを調整すれば、それらしくなる >glEnable( GL_LIGHT0 ); をやらない: >光源が有効化されないので. もっと上のコードでglEnable(GL_LIGHT0);をしているのですが、やはり、コードをのっけていません。その点ですいません >法線を逆向きにする: >例えば Normal = -Normal; とかすると,法線が光源が無い方向に向くことになるので. 裏返しのコードはgl何やらですべて表にしてしまいました。 で、glscale を書き込むのが黒くなる原因で、コードから除外すると、黒から、マテリアルの色をふくめた白色で反射しましたが、 そもそもの法線の正規化の計算式が正しいのか疑問に思い、 質問内容が、計算方法が1の方法と2の方法どちらかが正しいのかということになりました。 glm::vec3 Normal = glm::cross( Vtx[1]-Vtx[0], Vtx[2]-Vtx[0] ); //外積 Normal = glm::normalize( Normal ); //正規化.→結果は(0,0,-1)になっている. すいません。glm使わないので、 理解不足ですが、 急いで書いたのもあって、文章にまとまりがなくすいません。
fana

2021/10/28 06:34

> 質問内容が、計算方法が1の方法と2の方法どちらかが正しいのかということになりました。 とのことですが… > 1.追記ベクトルA=(2,-1,3)のベクトルAを正規化しなさい これは,単なる ベクトルの単位化 の話ですね. L2ノルムで全要素を除すことで単位ベクトルが得られる,という普通の話です. > 2.ポリゴンの3頂点をv1=(1,0,0),v2=(0,1,0),v3=(0,0,1)として法線を正規化しなさい こっちは,三角形の法線方向ベクトルを外積で求めて, その後でそれを前記1の話で単位化する,という話. …なので,1と2の関係性というのは「2の計算は1の話を用いている」であり,「どちらが正しいか」という関係性ではないですよね. --- 1, 2 の話自体はごくごく普通の内容と見えます.
fana

2021/10/28 06:46 編集

> glscale を書き込むのが黒くなる原因で、コードから除外すると、黒から、マテリアルの色で反射しましたが、 glsacle のスケーリングが,glNormal3f で設定している値にまで効果を及ぼしてしまう,ということなんだと思います. 例えば, glscalef( 2, 2, 2 ); ... glnormal3f( /*単位法線ベクトルのx,y,z*/ ); という形で書くと,結果として法線が長さ2になってしまうんでしょうね. (で,変な単位ベクトルでない変な値で計算されてしまって,結果の色がおかしくなる,と.) --- ( GL_NOMALIZE とかいうのはこの嫌らしい効果に対抗するための手段…ということなのかな)
txty

2022/05/14 08:58 編集

問題が解消されました。いろいろ教えていただきありがとうございます。GL_NOMALIZEは座標の拡大・縮小にも対応できるしかわからなかったです。
fana

2021/10/28 07:07

* 法線はライティング計算が行われる時点で単位ベクトルじゃないとまずい(=結果が変になる) * GL_NORMALIZE というのはライティング処理の前に法線を正規化してくれる機能っぽい …ので,この2点を総合すると,GL_NORMALIZE はとりあえず enable にしておけばよさそうな物に思えますが,何か問題を起こすのでしょうか? (私自身は使ったことないので実際の挙動を知らないです) --- (ググると GL_RESCALE_NORMAL とかいうのもあるね.違いはわからぬ.)
txty

2022/05/14 08:42 編集

以下、抜粋です。 openglによる3次元CGプログラミングの本 によると次のいずれかの方法により、単位ベクトル(長さが 1)となるように規格化すること 方法1ベクトルm=(p,q,r)とすれば、ベクトルの長さ l=√p^2+q^2+r^2 単位ベクトル n=(p/l,q/l,r/l) 方法2法線ベクトルを規格化する範囲を以下で囲む。 glEnable (GL_NORMALIZE).....glDisable(GL_NORMALIZE); 方法2を用いると座標の拡大・縮小にも対応できるため、今後は方法2を推奨するだそうです。 あと、1のやり方ですが3Dグラフィックスのための数学の本によると正規化の方法が2通りあるようなので、別途質問しました。
guest

0

式等に誤りがあったら教えてください。正規化の方法だとおそらくglScaleが使えないので、

反射した状態からgluLookAtだけを使い位置を調整しました。反射した状態ですが、誤りがあったら、教えて

ください。

投稿2021/10/25 05:24

編集2022/04/22 02:49
txty

総合スコア298

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問