VRMLを使ってみよう(座標系本番verの作成、オブジェクトの外部ファイル読み込み)

前回、VRMLを使ってみよう(導入〜1オブジェクト試作まで) - erythritolは甘味料VRMLの使い心地を試してみたが、いよいよGOが出たので本格的に色々いじってみることになった。

座標系、そもそも

前回の座標原点のサンプルをもう一度見直してみると、

座標 向き
x 横(左から右)
y 縦(下から上)
z 奥行き(奥から手前)

と表示されている。zが縦だとすっかり思い込んでいたのでびっくり!
そもそも今回扱う予定の座標系はzが縦。
これは後々悪影響を及ぼしそうなので、色々いじる前にまずはここから直してみる。

viewpointを試してみるも失敗

説明を見る限り、Viewpointノードでは視点の位置・方向を指定できるっぽい。

  • positionで視点の位置
  • orientationで視点の向き

ということなので、視点の位置を(10, 10, 10)や(10, 0, 0)とし、
原点を中心に(1, 1, 1)のベクトル周りに2/3*PI世界を回転させればいけんじゃね?
と思って試してみた。

Viewpoint {
   position 10 0 0
   orientation -1 -1 -1 2.09
}

が、しかーし!これではうまくいかない。
いかんせん見切れてしまうのでよくわからないものの、Viewpointノードのorientationはpositionの位置を中心に回転するのかな?という雰囲気。

世界座標を回転

ということで、全体の世界座標を最初から回転させる方向で。
世界全体を包むTransformノードを作成し、ここに回転を与える。
ついでなのでこのTransformには「WORLD」という名前を定義しておく。

DEF WORLD Transform {
   # 世界座標系の位置向き x軸が奥行き、y軸が横、z軸が高さになるように変換
   # ここは固定にしておく
   translation 0 0 0
   rotation -1 -1 -1 2.09
   children[
      # 以下いろんなオブジェクトを置く。
      # (中略)
   ]
}

これで、

座標 向き
x 奥行き(奥から手前)
y 横(左から右)
z 縦(下から上)

に変わった。

ちなみに、この状態で、x軸上じゃなくてもう少し斜め上から世界を見たいなーと思った時は

Viewpoint {
   position 5 5 10
}

のようにViewpointノードのpositionのみ与えてあげると視点は移動する。
しかし、世界を回転(左ドラッグ)すると視点の中心周りに回ってしまうので正直微妙。
SphereSensorを使って何とかならないかと試したものの、失敗してしまった。
視点周りは、実際のコンテンツを入れてから考えてみた方が良いのかもしれない。

座標軸表示を線にする

前回のサンプルは細長いBoxで座標軸を作成したが、後々ローカル座標原点なんかも表示することを考えると線の方が見栄えが良いかも。
ということで線で座標原点を表してみた。

#VRML V2.0 utf8
DEF WORLD Transform {
   # 世界座標系の位置向き x軸が奥行き、y軸が横、z軸が高さになるように変換
   # ここは固定にしておく
   translation 0 0 0
   rotation -1 -1 -1 2.09
   children [
      # 線による座標原点表示、矢印型
      Shape {
         geometry IndexedLineSet {
            color Color { color [ 1 0 0, 1 0 0, 0 1 0, 0 1 0, 0 0 1, 0 0 1, 
                                  1 0 0, 1 0 0, 1 0 0, 1 0 0, 
                                  0 1 0, 0 1 0, 0 1 0, 0 1 0, 
                                  0 0 1, 0 0 1, 0 0 1, 0 0 1 ] }
            coord Coordinate {
               point [
                  0 0 0,
                  1 0 0,
                  0 0 0,
                  0 1 0,
                  0 0 0,
                  0 0 1,
                  0.9 0.1 0.1,
                  0.9 -0.1 -0.1,
                  0.9 0.1 -0.1,
                  0.9 -0.1 0.1,
                  0.1 0.9 0.1,
                  -0.1 0.9 -0.1,
                  0.1 0.9 -0.1,
                  -0.1 0.9 0.1,
                  0.1 0.1 0.9,
                  -0.1 -0.1 0.9,
                  0.1 -0.1 0.9,
                  -0.1 0.1 0.9,
               ]
            }
            coordIndex [
               0, 1, -1,
               2, 3, -1,
               4, 5, -1,
               6, 1, 7, -1,
               8, 1, 9, -1, 
               10, 3, 11, -1,
               12, 3, 13, -1,
               14, 5, 15, -1,
               16, 5, 17, -1,
            ]
         }
      }
      # xyz表記
      Transform {
         translation 1 0.15 0.15
         rotation 0 1 0 1.57
         children [
            Transform {
               rotation 0 0 1 1.57
               children[
                  Shape {
                     appearance Appearance {
                        material Material { diffuseColor 1 0 0 }
                     }
                     geometry Text {
                        string ["x"]
                        fontStyle FontStyle {
                           family "SANS"
                           size 0.2
                        }
                     }
                  }
               ]
            }
         ]
      }
      Transform {
         translation 0 1 0.15
         rotation 0 1 0 1.57
         children [
            Transform {
               rotation 0 0 1 1.57
               children[
                  Shape {
                     appearance Appearance {
                        material Material { diffuseColor 0 1 0 }
                     }
                     geometry Text {
                        string ["y"]
                        fontStyle FontStyle {
                           family "SANS"
                           size 0.2
                        }
                     }
                  }
               ]
            }
         ]
      }
      Transform {
         translation 0 0.15 1
         rotation 0 1 0 1.57
         children [
            Transform {
               rotation 0 0 1 1.57
               children[
                  Shape {
                     appearance Appearance {
                        material Material { diffuseColor 0 0 1 }
                     }
                     geometry Text {
                        string ["z"]
                        fontStyle FontStyle {
                           family "SANS"
                           size 0.2
                        }
                     }
                  }
               ]
            }
         ]
      }
   ]
}

座標軸を矢印にしたり、x, y, zという文字を振ったりしていたら
思いのほか長くなってしまった。。。

オブジェクト形状の外部VRMLファイルからの読み込み

Inlineノードを使うことで、他のVRML空間を子ノードとして組み込める。
これで、ファイルごとにオブジェクトの形状を定義し、組み合わせだけ別ファイル、のようにファイルを分けて作れるというわけ。

今日やった

  • 世界座標をZが縦になるように回転
  • この空間に線で描画した(回転前の)座標軸を読み込む

というのを試す。
予め、上の座標軸の「一番外側のTransform (=WORLD)」を削除したものをlocalcoord.wrlという名前で保存しておく。

#VRML V2.0 utf8
DEF WORLD Transform {
   # 世界座標系の位置向き x軸が奥行き、y軸が横、z軸が高さになるように変換
   # ここは固定にしておく
   translation 0 0 0
   rotation -1 -1 -1 2.09
   children [
      Inline {
         url ["localcoord.wrl"]
      }
   ]
}

さっきと同様の表示ができたので成功。

オブジェクトファイルの作成

あとはひたすらサクサク作るのみ。向きが狙い通りかどうかは適宜上記のInlineで確認しながら作成する。
しかし、ただの円柱ばかりではつまらないのでExtrusionも使ってみる。
縮尺は後の面倒を省くため、

  • 縮尺を変えるつもりの所は長さが1になるようにする
  • 縮尺を変えないつもりの所は、長さが1になるところに対する比率が合っているようにする
#VRML V2.0 utf8
#右腕  filename=RUpperArm.wrl

# ローカル座標原点
# 回転・移動はしないがオブジェクトのサイズに合わせて適度にリスケール
Transform {
   scale 0.1 0.1 0.1
   children [
      Inline {
         url ["localcoord.wrl"]
      }
   ]
}

# ZX平面で押し出した図形を、あたかもXY平面で押し出したかのように変換
Transform {
   rotation 0 1 0 1.57
   children [
      Transform {
         rotation 0 0 1 1.57
         children[
            # ここからが本番
            Shape {
               appearance Appearance {
                  material Material {
                     diffuseColor 0.8 0.8 0.3
                  }
               }
               geometry Extrusion {
                  crossSection [0 0.7, 0.7 0.5, 1 0, 0.7 -0.3, 
                                0 -0.5, -0.7 -0.3, -1 0, -0.7 0.5, 
                                0 0.7 ]
                  spine [0 -1 0, 0 0 0]
                  scale [0.2 0.2  0.3 0.3]
                  solid TRUE
                  beginCap TRUE
                  endCap TRUE
               }
            }
         ]
      }
   ]
}

Inlineの中身のDEFは、引用先でも使えるのか?

試しにInlineで引用される側にDEFしたものを、引用した側で参照しようとしたが
どうやら駄目な模様。。。

ERROR:ROUTE: Expected a valid DEF name; found "; current token :RUARM: at: ".set_diffuseColor"
Parsing complete, but have unrecognized data at end of input: ".set_diffuseColor

というエラーが出てしまった。