🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Three.js

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

JavaScript

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

Q&A

解決済

3回答

3522閲覧

THREE.ExtrudeGeometryの表面と裏面と側面にTextureを貼りたい

takahashi-one

総合スコア120

Three.js

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

JavaScript

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

0グッド

1クリップ

投稿2020/12/01 14:57

編集2020/12/11 14:33

THREE.ExtrudeGeometryの表面と裏面と側面にTextureを貼りたいのですがうまくいきません。単なる単色になってしまいます。ググるとUVGeneratorを指定するみたいなことが書いてありTHREE.ExtrudeGeometry.BoundingBoxUVGeneratorを指定したのですが相変わらず単なる単色です。どうすればTextureをうまく張ることができるでしょうか?

下記は歪なハート型のshapeです。テクスチャがちゃんと張り付かないコードです。どこが間違っているでしょうか?

javascript

1<script type="text/javascript"> 2function init() { 3 var scene = new THREE.Scene(); 4 var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); 5 var webGLRenderer = new THREE.WebGLRenderer(); 6 webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE)); 7 webGLRenderer.setSize(window.innerWidth, window.innerHeight); 8 webGLRenderer.shadowMap.enabled = true; 9 10 var options = { 11 amount: 2, 12 bevelThickness: 2, 13 bevelSize: 0.5, 14 bevelEnabled: true, 15 bevelSegments: 3, 16 bevelEnabled: true, 17 curveSegments: 12, 18 steps: 1 19 }; 20 21 shape = createMesh(new THREE.ExtrudeGeometry(drawShape(), options)); 22 23 scene.add(shape); 24 25 camera.position.x = -80; 26 camera.position.y = 54; 27 camera.position.z = 80; 28 camera.lookAt(new THREE.Vector3(60, -60, 0)); 29 30 var ambientLight = new THREE.AmbientLight(0x0c0c0c); 31 scene.add(ambientLight); 32 33 var spotLight = new THREE.SpotLight(0xffffff); 34 spotLight.position.set(-70, -20, 170); 35 spotLight.castShadow = true; 36 scene.add(spotLight); 37 38 spotLight.target = shape; 39 40 scene.add(spotLight); 41 42 document.getElementById("WebGL-output").appendChild(webGLRenderer.domElement); 43 44 orbit = new THREE.OrbitControls(camera, webGLRenderer.domElement); 45 46 var step = 0; 47 48 render(); 49 50 function drawShape() { 51 var xy = new Array(); 52 xy.push(["M", 75, 40]); 53 xy.push(["C", 75, 37, 70, 25, 50, 25]); 54 xy.push(["C", 20, 25, 20, 62.5, 20, 62.5]); 55 xy.push(["C", 20, 80, 40, 102, 75, 120]); 56 xy.push(["C", 110, 102, 130, 80, 130, 62.5]); 57 xy.push(["C", 130, 62.5, 130, 25, 100, 25]); 58 xy.push(["C", 85, 25, 75, 37, 75, 40]); 59 xy.push(["Z", 75, 40]); 60 61 var shapepath = new THREE.Shape(); 62 for (var i = 0; i < xy.length; i++) { 63 if (xy[i][0] == "M") { 64 shapepath.moveTo(xy[i][1], xy[i][2]); 65 } else if (xy[i][0] == "L") { 66 shapepath.lineTo(xy[i][1], xy[i][2]); 67 } else if (xy[i][0] == "C") { 68 shapepath.bezierCurveTo(xy[i][1], xy[i][2], xy[i][3], xy[i][4], xy[i][5], xy[i][6]); 69 } else { //Z 70 shapepath.lineTo(xy[0][1], xy[0][2]); 71 } 72 } 73 return shapepath; 74 } 75 76 function createMesh(geom) { 77 geom.applyMatrix(new THREE.Matrix4().makeTranslation(-75, -70, 0)); 78 const texture = new THREE.TextureLoader().load('abc.jpg'); 79 const mat = new THREE.MeshBasicMaterial({ 80 map: texture 81 }); 82 var mesh = new THREE.Mesh(geom, mat); 83 mesh.rotation.z = Math.PI; 84 return mesh; 85 } 86 87 function render() { 88 shape.rotation.y = step += 0.005; 89 requestAnimationFrame(render); 90 webGLRenderer.render(scene, camera); 91 } 92 93} 94window.onload = init; 95</script>

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

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

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

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

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

guest

回答3

0

ベストアンサー

確認しました。原因はいくつかありました。

テクスチャのロード後にMaterial.needsUpdate=trueがされていません。
非同期ロードの完了後にテクスチャが更新されたことを伝える必要があります。
同じ色で塗られてしまうのは、wrapS,wrapTがClampToEdge(デフォルト)なので端の色だけが連続して塗られていた為です。

r123で試したところ古いAPIを使っている箇所があったので変更しています。

<html> <head> <meta charset="utf-8" /> <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r123/three.min.js"></script> <script type="text/javascript"> async function init() { var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); var webGLRenderer = new THREE.WebGLRenderer({ canvas: document.getElementById("WebGL-output") }); webGLRenderer.setClearColor(new THREE.Color(0xEEEEEE)); webGLRenderer.setSize(window.innerWidth, window.innerHeight); webGLRenderer.shadowMap.enabled = true; var options = { depth: 2, bevelThickness: 2, bevelSize: 0.5, bevelEnabled: true, bevelSegments: 3, bevelEnabled: true, curveSegments: 12, steps: 1 }; shape = createMesh(new THREE.ExtrudeGeometry(drawShape(), options)); scene.add(shape); camera.position.x = -80; camera.position.y = 54; camera.position.z = 80; camera.lookAt(new THREE.Vector3(60, -60, 0)); var ambientLight = new THREE.AmbientLight(0x0c0c0c); scene.add(ambientLight); var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-70, -20, 170); spotLight.castShadow = true; scene.add(spotLight); spotLight.target = shape; scene.add(spotLight); // orbit = new THREE.OrbitControls(camera, webGLRenderer.domElement); var step = 0; render(); function drawShape() { var xy = new Array(); xy.push(["M", 75, 40]); xy.push(["C", 75, 37, 70, 25, 50, 25]); xy.push(["C", 20, 25, 20, 62.5, 20, 62.5]); xy.push(["C", 20, 80, 40, 102, 75, 120]); xy.push(["C", 110, 102, 130, 80, 130, 62.5]); xy.push(["C", 130, 62.5, 130, 25, 100, 25]); xy.push(["C", 85, 25, 75, 37, 75, 40]); xy.push(["Z", 75, 40]); var shapepath = new THREE.Shape(); for (var i = 0; i < xy.length; i++) { if (xy[i][0] == "M") { shapepath.moveTo(xy[i][1], xy[i][2]); } else if (xy[i][0] == "L") { shapepath.lineTo(xy[i][1], xy[i][2]); } else if (xy[i][0] == "C") { shapepath.bezierCurveTo(xy[i][1], xy[i][2], xy[i][3], xy[i][4], xy[i][5], xy[i][6]); } else { //Z shapepath.lineTo(xy[0][1], xy[0][2]); } } return shapepath; } function createMesh(geom) { // applyMatrixはdeprecated geom.applyMatrix4(new THREE.Matrix4().makeTranslation(-75, -70, 0)); const mat = new THREE.MeshBasicMaterial({}); var mesh = new THREE.Mesh(geom, mat); mesh.rotation.z = Math.PI; const loader = new THREE.TextureLoader() loader.load('abc.jpg', (texture) => { // 非同期ロードした場合はテクスチャの設定とTexture.neesUpdate=trueが必須です。 mat.map = texture; mat.needsUpdate = true; // UVが大きいのとリピートモードがTHREE.ClampToEdgeWrappingになっているのでテクスチャの端の色だけが繰り返し表示されています。 // とりあえずUVのサイズに合わせてマッピングの変更とリピート表示にしてみました。 TEXTURE_SCALE = 1 / 50 texture.matrixAutoUpdate = false; texture.matrix.set(TEXTURE_SCALE, 0, 0, 0, TEXTURE_SCALE, 0, 0, 0, 1); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; }) return mesh; } function render() { shape.rotation.y = step += 0.005; requestAnimationFrame(render); webGLRenderer.render(scene, camera); } } window.onload = init; </script> </head> <body> <canvas id="WebGL-output"></canvas> </body> </html>

投稿2020/12/11 16:10

KphP9

総合スコア78

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

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

takahashi-one

2020/12/12 13:48

テクスチャがちゃんと張り付いてます。 感動しました。ありがとうございました。
guest

0

簡単にパスをTHREE.Shape()する方法は知らないので試しません。すみません。

pathの値を見たところ大きい値が含まれているので、テクスチャのマッピングで小さくなりすぎているかもしれません。ジオメトリの座標がuvに反映されるので。

THREE.Textureにはテクセルのサンプリング時の変換行列が設定できるのでそれを利用してテクスチャが大きく表示されるようにしてみました。これでダメなら私にはお手上げです。実際のコードがあればわかるかもしれませんが。

loader.loadAsync("./test.png").then((img) => { img.wrapS = img.wrapT = THREE.RepeatWrapping // 追加ここから // テクスチャのスケーリング。とりあえず16倍表示 img.matrixAutoUpdate = false TEXTURE_SCALE = 1/16 img.matrix.set( TEXTURE_SCALE,0,0, 0, TEXTURE_SCALE,0,0,0,1); // ここまで const geometry = new THREE.ExtrudeBufferGeometry(shape, extrudeSettings); const material = new THREE.MeshBasicMaterial({ map: img }); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh); })

投稿2020/12/10 14:44

KphP9

総合スコア78

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

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

takahashi-one

2020/12/11 14:34

回答ありがとうございます。テクスチャがちゃんと張り付かないコードを追加しました。どこが間違っているでしょうか?
guest

0

テクスチャを貼るだけなら公式のコードをベースにすると以下のような感じになります。
uvはジオメトリの座標と同一です。
任意の場所に張るならthree.jsでこねくり回すよりもBlenderなどのモデリングツールを使った方が楽だと思われます。

three.js/ExtrudeBufferGeometry

{ const length = 12, width = 8; const shape = new THREE.Shape(); shape.moveTo(0, 0); shape.lineTo(0, width); shape.lineTo(length, width); shape.lineTo(length, 0); shape.lineTo(0, 0); const extrudeSettings = { steps: 2, depth: 16, bevelEnabled: true, bevelThickness: 1, bevelSize: 1, bevelOffset: 0, bevelSegments: 1 }; const loader = new THREE.TextureLoader() loader.loadAsync("./test.png").then((img) => { img.wrapS = img.wrapT = THREE.RepeatWrapping const geometry = new THREE.ExtrudeBufferGeometry(shape, extrudeSettings); const material = new THREE.MeshBasicMaterial({ map: img }); const mesh = new THREE.Mesh(geometry, material); scene.add(mesh); }) }

r123でテスト済み。

投稿2020/12/10 05:38

KphP9

総合スコア78

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

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

takahashi-one

2020/12/10 13:43

回答ありがとうございます。ExtrudeBufferGeometryを使用したのですが相変わらず単色です。 例えばレンガのテクスチャだと単なる赤茶色になってしまいます。 テクスチャを張り付けたいshapeのパスを質問に追加しました。 時間があったらテクスチャがちゃんと張り付くか試してほしいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問