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

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

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

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

1053閲覧

3次元タートルグラフィックスを完成したい

katahiromz

総合スコア186

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

Three.js

Three.jsはWebGLをサポートしているJavaScriptの3D描画用ライブラリです。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

3DCG

コンピュータの演算により、3次元空間の仮想物体を、2次元平面上で表現する手法である。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

1クリップ

投稿2020/07/20 09:34

編集2020/07/20 15:04

こんにちは。いつもお世話になっております。

HTML5+JavaScript+Three.jsで三次元タートルグラフィックスに挑戦しています。
レポジトリ:http://github.com/katahiromz/3D
※ ソースは http://github.com/katahiromz/3D からダウンロードして下さい。

タートルグラフィックスとは、位置と向きを持ったタートル(亀)を操作して図形を描画しようというものです。今回は三次元のタートルグラフィックスです。数学は素人なので手加減よろしくお願い致します。

次のソースについて:http://github.com/katahiromz/3D/blob/master/4.html

  • add_line関数で一本の線分を描いています。
  • set_pos関数で位置をセットしています。
  • set_dir関数で向きをセットしています。
  • walk関数で現在の向きで前進して線分を描きます。
  • turn_dir関数で指定された向きベクトル(dx, dy, dz)だけ回転して向きを更新します。
  • turn_angle関数でangle1度とangle2度だけ回転します。
  • init関数は全体の初期化処理です。
  • draw関数は全体の描画処理です。
  • animate関数は全体のアニメーション処理です。
  • koch関数は平面的にコッホ曲線を再帰的に描画します。
  • tree関数は平面的に木構造を再帰的に描画します。

問題は、draw関数内部でコッホ曲線と45度傾いた木構造を描いていますが、木が平面的にならないことです。

描画結果

turn_dirturn_angleの設計か実装が間違えているのでしょうか。個人製作なので、仕様は自由に変更できます。4.htmlを修正して木を真っ平らになるようにできないでしょうか。正しく3次元タートルグラフィックスを実装できないでしょうか。よろしくお願い致します。

追記。後出しですが、z==0のとき二次元タートルグラフィックスと互換性のある設計でなければいけません。

追記2. draw関数は変更しません。

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

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

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

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

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

Penpen7

2020/07/21 06:10

xy平面に射影させればいいのでは?
katahiromz

2020/07/21 07:36

大事なのは、三次元空間のどの方向においても正しく描画することです。
katahiromz

2020/07/21 08:15

現状ではz軸方向にひずんでいるように思われます。あっちの方向に描画するのと、こっちの方向に描画するのが同じ形でなければなりません。
guest

回答1

0

ベストアンサー

追記の条件を満たしてはいませんが、とりあえず「二次元タートルグラフィックスを三次元空間内に配置する」例としては以下のような実装で動作しているかと思います。二次元平面の法線ベクトルを set_normal() で設定しています。
set_dir() は三次元空間内の進行方向を設定できますが、それだけでは進行方向基準で上下左右がどこなのかを決定できません。

HTML

1<!DOCTYPE html> 2<html> 3 <head> 4 <meta charset="utf-8"> 5 <title>My first three.js app</title> 6 <style> 7 body { margin: 0; } 8 canvas { display: block; } 9 </style> 10 </head> 11 <body> 12 <!-- Please download file "three.min.js" from https://raw.githubusercontent.com/mrdoob/three.js/dev/build/three.min.js --> 13 <script src="./three.min.js"></script> 14 <!-- Please download file "OrbitControls.js" from https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/js/controls/OrbitControls.js --> 15 <script src="./OrbitControls.js"></script> 16 <!-- Please download file "Vector3.js" from https://github.com/mrdoob/three.js/blob/master/src/math/Vector3.js --> 17 <script src="./Vector3.js"></script> 18 <!-- Please download file "Quaternion.js" from https://github.com/mrdoob/three.js/blob/master/src/math/Quaternion.js --> 19 <script src="./Quaternion.js"></script> 20 <script> 21 var scene, renderer, camera, controls; 22 var turtle_x = 0, turtle_y = 0, turtle_z = 0; 23 var turtle_dx = 0, turtle_dy = 0, turtle_dz = 0, turtle_spin = 0; 24 var normal_x = 0, normal_y = 0, normal_z = 1; 25 var pen_on = true; 26 27 function add_line(x0, y0, z0, x1, y1, z1) { 28 var points = []; 29 points.push(new THREE.Vector3(x0, y0, z0)); 30 points.push(new THREE.Vector3(x1, y1, z1)); 31 32 var geometry = new THREE.BufferGeometry().setFromPoints(points); 33 var material = new THREE.LineBasicMaterial({ color: 0xffffff }); 34 35 var line = new THREE.Line(geometry, material); 36 scene.add(line); 37 } 38 function set_pos(x, y, z=0) { 39 turtle_x = x; 40 turtle_y = y; 41 turtle_z = z; 42 } 43 function set_normal(x, y, z=1) { 44 var r = Math.sqrt(x*x + y*y + z*z); 45 normal_x = x / r; 46 normal_y = y / r; 47 normal_z = z / r; 48 } 49 function set_dir(dx, dy, dz=0) { 50 var r = Math.sqrt(dx*dx + dy*dy + dz*dz); 51 turtle_dx = dx / r; 52 turtle_dy = dy / r; 53 turtle_dz = dz / r; 54 } 55 function walk(r) { 56 var x0 = turtle_x, y0 = turtle_y, z0 = turtle_z; 57 turtle_x += r * turtle_dx; 58 turtle_y += r * turtle_dy; 59 turtle_z += r * turtle_dz; 60 if (pen_on) 61 add_line(x0, y0, z0, turtle_x, turtle_y, turtle_z); 62 } 63 function add_spin(delta) { 64 turtle_spin += delta; 65 } 66 function turn_angle(angle) { 67 var quaternion = new THREE.Quaternion(); 68 quaternion.setFromAxisAngle( new THREE.Vector3( normal_x, normal_y, normal_z ).normalize(), angle * Math.PI / 180 ); 69 70 var vector = new THREE.Vector3( turtle_dx, turtle_dy, turtle_dz ); 71 vector.applyQuaternion( quaternion ); 72 set_dir(vector.x, vector.y, vector.z); 73 } 74 function init() { 75 renderer = new THREE.WebGLRenderer(); 76 renderer.setSize(window.innerWidth, window.innerHeight); 77 document.body.appendChild(renderer.domElement); 78 79 camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500); 80 camera.position.set(0, 0, 100); 81 camera.lookAt(0, 0, 0); 82 83 controls = new THREE.OrbitControls(camera, renderer.domElement); 84 controls.enableDamping = true; 85 controls.dampingFactor = 0.25; 86 controls.enableZoom = true; 87 controls.autoRotate = true; 88 89 scene = new THREE.Scene(); 90 scene.add(new THREE.AxisHelper(50)); 91 } 92 function koch(degree, step) { 93 if (degree == 0) { 94 walk(step); 95 } else { 96 koch(degree - 1, step/3); 97 turn_angle(60); 98 koch(degree - 1, step/3); 99 turn_angle(-120); 100 koch(degree - 1, step/3); 101 turn_angle(60); 102 koch(degree - 1, step/3); 103 } 104 } 105 function tree(size, angle, depth) { 106 if (depth == 0) 107 return; 108 walk(size); 109 turn_angle(angle); 110 tree(size * 0.75, angle, depth - 1); 111 turn_angle(-2 * angle); 112 tree(size * 0.75, angle, depth - 1); 113 turn_angle(angle); 114 walk(-size); 115 } 116 function draw() { 117 set_pos(0, 0, 0); 118 set_dir(0, 100, 0); 119 set_normal(0, 0, 1); 120 koch(6, 50); 121 set_pos(0, 0, 0); 122 set_dir(0, 100, 100); 123 set_normal(1, 0, 0); 124 tree(10, 40, 10); 125 } 126 function animate() { 127 controls.update(); 128 requestAnimationFrame(animate); 129 renderer.render(scene, camera); 130 } 131 132 init(); 133 draw(); 134 animate(); 135 </script> 136 </body> 137</html>

上の例は左右に曲がるだけですが、上下にも曲がれるようにするなら以下のような実装でいいのかなあ。一応、動作しているように思えます。
上下に曲がる場合は法線ベクトルも回転させるような感じです。適切な処理かどうかは不明です。

HTML

1(文字数オーバーのようなので、上の例の65行目までをここに貼り付けて下さい) 2 function turn_angle1(angle) { 3 var quaternion = new THREE.Quaternion(); 4 quaternion.setFromAxisAngle( new THREE.Vector3( normal_x, normal_y, normal_z ).normalize(), angle * Math.PI / 180 ); 5 6 var vector = new THREE.Vector3( turtle_dx, turtle_dy, turtle_dz ); 7 vector.applyQuaternion( quaternion ); 8 set_dir(vector.x, vector.y, vector.z); 9 } 10 function turn_angle2(angle) { 11 var quaternion = new THREE.Quaternion(); 12 quaternion.setFromAxisAngle( new THREE.Vector3( normal_x, normal_y, normal_z ).normalize(), 90 * Math.PI / 180 ); 13 14 var vector = new THREE.Vector3( turtle_dx, turtle_dy, turtle_dz ); 15 vector.applyQuaternion( quaternion ); 16 var temp_x = vector.x; 17 var temp_y = vector.y; 18 var temp_z = vector.z; 19 20 quaternion = new THREE.Quaternion(); 21 quaternion.setFromAxisAngle( new THREE.Vector3( temp_x, temp_y, temp_z ).normalize(), angle * Math.PI / 180 ); 22 23 vector = new THREE.Vector3( normal_x, normal_y, normal_z ); 24 vector.applyQuaternion( quaternion ); 25 set_normal(vector.x, vector.y, vector.z); 26 27 vector = new THREE.Vector3( turtle_dx, turtle_dy, turtle_dz ); 28 vector.applyQuaternion( quaternion ); 29 set_dir(vector.x, vector.y, vector.z); 30 } 31 function init() { 32 renderer = new THREE.WebGLRenderer(); 33 renderer.setSize(window.innerWidth, window.innerHeight); 34 document.body.appendChild(renderer.domElement); 35 36 camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 500); 37 camera.position.set(0, 0, 100); 38 camera.lookAt(0, 0, 0); 39 40 controls = new THREE.OrbitControls(camera, renderer.domElement); 41 controls.enableDamping = true; 42 controls.dampingFactor = 0.25; 43 controls.enableZoom = true; 44 controls.autoRotate = true; 45 46 scene = new THREE.Scene(); 47 scene.add(new THREE.AxisHelper(50)); 48 } 49 function koch(degree, step) { 50 if (degree == 0) { 51 walk(step); 52 } else { 53 koch(degree - 1, step/3); 54 turn_angle1(60); 55 koch(degree - 1, step/3); 56 turn_angle1(-120); 57 koch(degree - 1, step/3); 58 turn_angle1(60); 59 koch(degree - 1, step/3); 60 } 61 } 62 function tree(size, angle1, depth, angle2=0) { 63 if (depth == 0) 64 return; 65 walk(size); 66 turn_angle1(angle1); 67 turn_angle2(angle2); 68 tree(size * 0.75, angle1, depth - 1, angle2); 69 turn_angle2(-angle2); 70 turn_angle1(-2 * angle1); 71 turn_angle2(angle2); 72 tree(size * 0.75, angle1, depth - 1, angle2); 73 turn_angle2(-angle2); 74 turn_angle1(angle1); 75 walk(-size); 76 } 77 function draw() { 78 set_pos(0, 0, 0); 79 set_dir(0, 100, 0); 80 set_normal(0, 0, 1); 81 koch(6, 50); 82 set_pos(0, 0, 0); 83 set_dir(0, 100, 100); 84 set_normal(1, 0, 0); 85 tree(10, 40, 10, 10); 86 } 87 function animate() { 88 controls.update(); 89 requestAnimationFrame(animate); 90 renderer.render(scene, camera); 91 } 92 93 init(); 94 draw(); 95 animate(); 96 </script> 97 </body> 98</html>

投稿2020/07/21 13:29

okrt

総合スコア366

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

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

katahiromz

2020/07/22 08:03 編集

ご回答ありがとうございます。見るとdirとnormalを直交させないといけないのですね。 turn_dirで方向を変えたとき、normalも直交させないとおかしくなるように思えます。 枝が三脚みたいに三方向に分かれる木構造はどのように書いたらいいでしょうか?
okrt

2020/07/22 12:42

>枝が三脚みたいに三方向に分かれる木構造はどのように書いたらいいでしょうか? 120度回転させても同じ形になる物を描画するならば、回答内容のソースに新しい関数を追加するべきかもしれません。 http://guppy.eng.kagawa-u.ac.jp/Seminar/OpenCampus/Programs/turtle3D.html で言うところのturn()は回答内容のturn_angle1()に相当、pitch()はturn_angle2()に相当します。(符号の向きは逆かもしれません) 回答内容のソースにはbank()に相当する関数がありません。追加実装するなら、進行方向はそのままで法線ベクトルだけ回転させる感じですかね。 それができたら、あとは例えば function tree3(size, angle1, depth, angle2=0) { if (depth == 0) return; walk(size); turn_angle2(angle2); tree3(size * 0.75, angle1, depth - 1, angle2); turn_angle2(-angle2); bank(120); turn_angle2(angle2); tree3(size * 0.75, angle1, depth - 1, angle2); turn_angle2(-angle2); bank(-240); turn_angle2(angle2); tree3(size * 0.75, angle1, depth - 1, angle2); turn_angle2(-angle2); bank(120); walk(-size); } こんな感じでいけると思います。何だか冗長な書き方ではありますが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問