ページ 1 / 1
Three.js
Posted: 2018年3月14日(水) 23:40
by しろうと
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に詳しい方がいらっしゃいましたら、
どうか原因と解決方法の提示をお願いいたします。
Re: Three.js
Posted: 2018年3月15日(木) 23:35
by みけCAT
JavaScriptはあまり詳しくないですが、メンバ変数をうまく参照できていないようですね。
ラムダ式を用いてthisのメンバ関数を呼び出すようにすると、上手くいきそうです。
コード:
requestAnimationFrame(() => { this.move(); });
Re: Three.js
Posted: 2018年3月16日(金) 08:41
by fabersid
Re: Three.js
Posted: 2018年3月16日(金) 08:56
by fabersid
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
Re: Three.js
Posted: 2018年3月16日(金) 09:11
by fabersid
Three.jsはJSHintに記述していないのでそのエラー・警告も含みます。
THREE変数が未定義と6いわれてますが本当に変数かどうかも
考えてこれを読む必要があります。
fabersid さんが書きました: ↑7年前
JSHintでの結果をGoogle翻訳で日本語にしました。
fabersid さんが書きました: ↑7年前
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
Posted: 2018年3月16日(金) 14:30
by かずま
=> を使わずに済ますと、こうなるのかな。
コード:
<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
Posted: 2018年3月16日(金) 20:44
by しろうと
多くの回答ありがとうございます。
ご教授通りに直し、実際に動いたものを後学の方のために下に貼っておきます。
[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
Posted: 2018年3月16日(金) 20:51
by しろうと
追加の質問になるのですが、
なぜメソッドを呼び出す際にthisを変数として宣言しなければいけなかったのでしょうか。
(const method = this; のところです。)
又、requestAnimationFrameのところで新たな関数としてそれを呼び出しているのも気になります。
どうか回答をお願いします。
Re: Three.js
Posted: 2018年3月17日(土) 09:04
by かずま
しろうと さんが書きました: ↑7年前
なぜメソッドを呼び出す際に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
Posted: 2018年3月19日(月) 01:30
by しろうと
大変分かりやすい説明をありがとうございます。
requestAnimationFrame関数の引数はコールバック関数だったのですね。
又、アロー関数式がグローバルオブジェクトのthisを束縛しないというのも初めて知りました。
非常に勉強になります。
大変分かりやすい説明をありがとうございました。
以上で私の疑問は解決したのですが、以前の様に解決を示すものが見当たらないので
ここに書いておきます。
「解決済み」