Three.js

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
しろうと

Three.js

#1

投稿記事 by しろうと » 6年前

Three.jsを用いた3D描画の勉強をしているものです。
現在立法形の描画を行っているのですが、
アニメーションを実施し、回転させようとしたところでエラーが現れます。
以下がコードになります。

コード:

class Draw{
  constructor(){
    this.width = window.innerWidth;
    this.height = window.innerHeight;
    this.renderer = new THREE.WebGLRenderer({ canvas : document.querySelector("#canvas")});
    this.renderer.setPixelRatio(window.devicePixelRatio);
    this.renderer.setSize(this.width,this.height);

    this.scene = new THREE.Scene();

    this.camera = new THREE.PerspectiveCamera(45, this.width / this.height);
    this.camera.position.set(0,0,1000);

    this.geometry = new THREE.BoxGeometry(100,100,100);
    this.material = new THREE.MeshNormalMaterial();
    this.box = new THREE.Mesh(this.geometry,this.material);

    this.scene.add(this.box);

    this.renderer.render(this.scene,this.camera);
  }

  move(){
    this.box.rotation.x += 1;
    this.renderer.render(this.scene,this.camera);
    requestAnimationFrame(this.move);
  }
}


window.onload = () => {
  const draw = new Draw();
  draw.move();
}
エラー内容は
Cannot read property 'box' of undefined at move
というものであり、requestで繰り返さなければ実行できるのですが、繰り返すとエラーが出てしまいます。
どうやら繰り返した時に定義がおかしなことになっているみたいなのですが、
JSに普段触れていないせいでよくわかりません。

Java Scriptに詳しい方がいらっしゃいましたら、
どうか原因と解決方法の提示をお願いいたします。

アバター
みけCAT
記事: 6734
登録日時: 13年前
住所: 千葉県
連絡を取る:

Re: Three.js

#2

投稿記事 by みけCAT » 6年前

JavaScriptはあまり詳しくないですが、メンバ変数をうまく参照できていないようですね。
ラムダ式を用いてthisのメンバ関数を呼び出すようにすると、上手くいきそうです。

コード:

requestAnimationFrame(() => { this.move(); });
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

fabersid
記事: 42
登録日時: 6年前

Re: Three.js

#3

投稿記事 by fabersid » 6年前

Three.jsのCSS3DRendererでサイコロ2とか
three-jsで立方体を回転させる
で見るとわかりやすいかもしれません。

fabersid
記事: 42
登録日時: 6年前

Re: Three.js

#4

投稿記事 by fabersid » 6年前

JSHintでの結果をGoogle翻訳で日本語にしました。
JSHint version 2.9.4が出力しました。
メトリック
このファイルには3つの関数があります。
最大シグネチャを持つ関数は0個の引数をとり、中央値は0になります。
最大の関数は13文で、中央値は3です。最も複雑な関数は1の循環複雑度値を持ち、中央値は1です。

4つの警告
1行目 'class'はES6( 'esversion:6')またはMozilla JS拡張(mozを使用)で利用できます。
31行目 '矢印関数の構文(=>)'は、ES6でのみ使用できます( 'esversion:6'を使用します)。
32行目 'const'はES6( 'esversion:6'を使う)やMozilla JS拡張(mozを使う)で利用できます。
34行目 セミコロンがありません。

1つの未定義変数
5行目 THREE
9行目 THREE
11行目 THREE
14行目 THREE
15行目 THREE
16行目 THREE

fabersid
記事: 42
登録日時: 6年前

Re: Three.js

#5

投稿記事 by fabersid » 6年前

Three.jsはJSHintに記述していないのでそのエラー・警告も含みます。
THREE変数が未定義と6いわれてますが本当に変数かどうかも
考えてこれを読む必要があります。
fabersid さんが書きました:
6年前
JSHintでの結果をGoogle翻訳で日本語にしました。
fabersid さんが書きました:
6年前
JSHint version 2.9.4が出力しました。
メトリック
このファイルには3つの関数があります。
最大シグネチャを持つ関数は0個の引数をとり、中央値は0になります。
最大の関数は13文で、中央値は3です。最も複雑な関数は1の循環複雑度値を持ち、中央値は1です。

4つの警告
1行目 'class'はES6( 'esversion:6')またはMozilla JS拡張(mozを使用)で利用できます。
31行目 '矢印関数の構文(=>)'は、ES6でのみ使用できます( 'esversion:6'を使用します)。
32行目 'const'はES6( 'esversion:6'を使う)やMozilla JS拡張(mozを使う)で利用できます。
34行目 セミコロンがありません。

1つの未定義変数
5行目 THREE
9行目 THREE
11行目 THREE
14行目 THREE
15行目 THREE
16行目 THREE

かずま

Re: Three.js

#6

投稿記事 by かずま » 6年前

=> を使わずに済ますと、こうなるのかな。

コード:

<html>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/89/three.min.js"></script>
<script>
class Draw {
    constructor() {
        const width = window.innerWidth;
        const height = window.innerHeight;
        this.renderer = new THREE.WebGLRenderer({
            canvas : document.querySelector("#canvas") });
        this.renderer.setPixelRatio(window.devicePixelRatio);
        this.renderer.setSize(width, height);
        this.scene = new THREE.Scene();
        this.camera = new THREE.PerspectiveCamera(45, width / height);
        this.camera.position.set(0, 0, 1000);
        const geometry = new THREE.BoxGeometry(200, 150, 100);
        const material = new THREE.MeshNormalMaterial();
        this.box = new THREE.Mesh(geometry, material);
        this.scene.add(this.box);
        this.renderer.render(this.scene, this.camera);
    }

    move() {
        this.box.rotation.x += 0.03;
        this.box.rotation.y += 0.05;
        this.renderer.render(this.scene, this.camera);
        var that = this;
        requestAnimationFrame(function() { that.move(); });
    }
}

window.onload = function() {
    const draw = new Draw();
    draw.move();
};
</script>
<body> <canvas id="canvas"></canvas> </body>
</html>
three.js ではなく、サイズが半分の three.min.js を使用しています。

しろうと

Re: Three.js

#7

投稿記事 by しろうと » 6年前

多くの回答ありがとうございます。
ご教授通りに直し、実際に動いたものを後学の方のために下に貼っておきます。

[code = "JScript"]
class Input{
constructor(){
this.input_key = new Array();
}

check_key(position){
document.onkeydown = (e) => this.input_key[e.keyCode] = true;

if(this.input_key["W".charCodeAt(0)] == true) position.z -= 10;
if(this.input_key["A".charCodeAt(0)] == true) position.x -= 10;
if(this.input_key["S".charCodeAt(0)] == true) position.z += 10;
if(this.input_key["D".charCodeAt(0)] == true) position.x += 10;

document.onkeyup = (e) => this.input_key[e.keyCode] = false;
}
}

class System{
constructor(){
this.width = window.innerWidth;
this.height = window.innerHeight;
this.renderer = new THREE.WebGLRenderer({ canvas : document.querySelector("#canvas")});
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.setSize(this.width,this.height);

this.scene = new THREE.Scene();

this.camera = new THREE.PerspectiveCamera(45, this.width / this.height);
this.camera.position.set(200,0,1000);

const geometry = new THREE.SphereGeometry(300,300,300);
const loader = new THREE.TextureLoader();
const texture = loader.load("aa.png");
const material = new THREE.MeshStandardMaterial({map: texture});
//const material = new THREE.MeshStandardMaterial({color:0xFF0000});
this.thing = new THREE.Mesh(geometry,material);
this.scene.add(this.thing);

this.geometry = new THREE.BoxGeometry(300,10,300);
this.material = new THREE.MeshStandardMaterial({color:0xFFFFFF});
this.floor = new THREE.Mesh(this.geometry, this.material);
this.scene.add(this.floor);
this.floor.position.y -= 300;

this.light = new THREE.DirectionalLight(0xFFFFFF);
this.light.position.set(50,0,100);
this.scene.add(this.light);

this.renderer.render(this.scene,this.camera);

this.input = new Input();
}

update(){
this.thing.rotation.x += 1;
this.thing.rotation.y += 1;
this.input.check_key(this.thing.position);
const method = this;
this.renderer.render(this.scene,this.camera);
requestAnimationFrame(() => method.update());
}
}

window.onload = () => {
const system = new System();
system.update();
}
[/code]

しろうと

Re: Three.js

#8

投稿記事 by しろうと » 6年前

追加の質問になるのですが、
なぜメソッドを呼び出す際にthisを変数として宣言しなければいけなかったのでしょうか。
(const method = this; のところです。)
又、requestAnimationFrameのところで新たな関数としてそれを呼び出しているのも気になります。
どうか回答をお願いします。

かずま

Re: Three.js

#9

投稿記事 by かずま » 6年前

しろうと さんが書きました:
6年前
なぜメソッドを呼び出す際にthisを変数として宣言しなければいけなかったのでしょうか。
(const method = this; のところです。)
又、requestAnimationFrameのところで新たな関数としてそれを呼び出しているのも気になります。
=> を使ったアロー関数式の場合、this をそのまま使用できます。
const method = this; を削除し、
requestAnimationFrame(() => this.update());
としても構いません。

変数が必要なのは function式の場合です。
const method = this;
requestAnimationFrame(function() { method.update(); });

requestAnimationFrame の引数は、コールバック関数です。
コールバック関数はグローバル関数でなければなりません。

update はグローバル関数ではなく、Systemクラスのメソッドです。
メソッドの呼び出しには、そのメソッドを持つオブジェクトの
存在が必要です。

requestAnimationFrame(update); で、
updateメソッドを登録して、「後で呼び出してね」とお願いしても
呼び出すほうは、Systemオブジェクトの存在を知りません。

そこで、メソッドではないグローバル関数を式として新たに
用意したいのですが、それには function式とアロー関数式が
あります。

function式の this はグローバルオブジェクトなので、
this.update() と書いても、グローバル関数の update は
存在しないのでエラーになります。

アロー関数式は this を束縛しないので、その時点での this、
すなわち Systemオブジェクトになります。
オフトピック
送信前に、プレビューしましょう。
codeタグは、code = "JScript" ではなく、code=JScript にしてみてください。

しろうと

Re: Three.js

#10

投稿記事 by しろうと » 6年前

大変分かりやすい説明をありがとうございます。
requestAnimationFrame関数の引数はコールバック関数だったのですね。
又、アロー関数式がグローバルオブジェクトのthisを束縛しないというのも初めて知りました。
非常に勉強になります。
大変分かりやすい説明をありがとうございました。



以上で私の疑問は解決したのですが、以前の様に解決を示すものが見当たらないので
ここに書いておきます。

「解決済み」

返信

“C言語何でも質問掲示板” へ戻る