幅と太さのあるThree.js3Dラインシリーズを作成する方法はありますか?
Three.jsラインオブジェクトは線幅をサポートしていますが、この属性はWebGLのすべてのプラットフォームのすべてのブラウザーでまだサポートされていません。
Three.jsで線幅を設定する場所は次のとおりです。
var material = new THREE.LineBasicMaterial({
color: 0xff0000,
linewidth: 5
});
幅のあるThree.jsリボンオブジェクトが最近削除されました。
Three.jsチューブオブジェクトは3D押し出しを生成しますが、ベジェベースであるため、線はコントロールポイントを通過しません。
Three.jsで、幅、太さ、半径など、ユーザーが定義できる「バルク」のある線のシリーズ(ポリライン、プロットライン)を描画する方法を考えられる人はいますか?
この質問は、この質問の言い換えかもしれません: three.jsでグラフを押し出す 。
すぐに利用できる方法はないと思いますので、この質問に答える簡単な関数を作成する努力に参加したいと思います。
しかし、既存の実行可能な方法を指す応答はクールでしょう...
WestLangleyが示唆しているように、考えられる解決策の1つには、一定のピクセル幅のポリラインが含まれます。これは、Three.jsキャンバスレンダラーで現在利用可能です。
2つのレンダラーの比較を次に示します。
GitHub Pagesを介して比較されたCanvasとWebGLの行
jsFiddleを介して比較されたCanvasおよびWebGL行
線幅を指定でき、両方のレンダラーで同様の結果が発生するソリューションは非常に優れています。
ただし、線に実際の物理的構造がある3D線の考え方は他にもあります。彼らは影を落とし、イベントに反応します。これらも調べる必要があります。
複数のメッシュで構成されたラインの2つのデモを含むGitHubPagesへのリンクは次のとおりです。
'高価なソリューション。各ジョイントは完全な球で構成されています。
私の推測では、これらのいずれかを滑らかな単一メッシュとして構築することは、解決すべき問題にとって複雑になるでしょう。それまでの間、幅が広く高さのある3Dラインの部分的な視覚化へのリンクがあります。
目標は、「ダミーのために、低レベルの複雑さで、つまり、ダミーのためにコーディングする必要がある」ことです。したがって、3D線は、球や立方体を追加するのと同じくらい簡単でなじみ深いものでなければなりません。ジオメトリ+マテリアル=メッシュ>シーン。また、ジオメトリは、頂点と面を作成するという点で非常に経済的である必要があります。
線には幅と高さが必要です。上は常にY方向です。デモはこれを示しています。デモに表示されていないのは、コーナーがうまくマイター接続されていることです...
私はあなたの要件のほとんどを満たすと私が信じる可能な解決策を作り上げました:
http://codepen.io/garciahurtado/pen/AGEsf?editors=001
概念は非常に単純です。「ワイヤーフレームモード」で任意のジオメトリをレンダリングしてから、フルスクリーンGLSLシェーダーを適用して、ワイヤーフレームラインに太さを追加します。
シェーダーは、ThreeJSディストリビューションのブラーシェーダーに触発されています。このシェーダーは、基本的に、水平軸と垂直軸に沿って画像を何回もコピーします。そのプロセスを自動化し、コピー数をユーザー定義のパラメーターにし、コピーが1ピクセルオフセットされるようにしました。
デモでは(オルソカメラを使用して)3Dキューブメッシュを使用しましたが、ポリラインに変換するのは簡単なはずです。
このことの本当の肉とジャガイモは、カスタムシェーダー(フラグメントシェーダー部分)にあります:
uniform sampler2D tDiffuse;
uniform int edgeWidth;
uniform int diagOffset;
uniform float totalWidth;
uniform float totalHeight;
const int MAX_LINE_WIDTH = 30; // Needed due to weird limitations in GLSL around for loops
varying vec2 vUv;
void main() {
int offset = int( floor(float(edgeWidth) / float(2) + 0.5) );
vec4 color = vec4( 0.0, 0.0, 0.0, 0.0);
// Horizontal copies of the wireframe first
for (int i = 0; i < MAX_LINE_WIDTH; i++) {
float uvFactor = (float(1) / totalWidth);
float newUvX = vUv.x + float(i - offset) * uvFactor;
float newUvY = vUv.y + (float(i - offset) * float(diagOffset) ) * uvFactor; // only modifies vUv.y if diagOffset > 0
color = max(color, texture2D( tDiffuse, vec2( newUvX, newUvY ) ));
// GLSL does not allow loop comparisons against dynamic variables. Workaround below
if(i == edgeWidth) break;
}
// Now we create the vertical copies
for (int i = 0; i < MAX_LINE_WIDTH; i++) {
float uvFactor = (float(1) / totalHeight);
float newUvX = vUv.x + (float(i - offset) * float(-diagOffset) ) * uvFactor; // only modifies vUv.x if diagOffset > 0
float newUvY = vUv.y + float(i - offset) * uvFactor;
color = max(color, texture2D( tDiffuse, vec2( newUvX, newUvY ) ));
if(i == edgeWidth) break;
}
gl_FragColor = color;
}
潜在的な解決策として。 3Dポイントを取得し、THREE.Vector3.project
メソッドを使用して画面空間の座標を計算することができます。次に、canvasを使用するだけで、lineTo
およびmoveTo
操作になります。 Canvas 2dコンテキストは、可変の線の太さをサポートします。
var w = renderer.domElement.innerWidth;
var h = renderer.domElement.innerHeight;
vector.project(camera);
context2d.lineWidth = 3;
var x = (vector.x+1)*(w/2);
var y = h - (vector.y+1)*(h/2);
context2d.lineTo(x,y);
また、同じキャンバスを使用できるとは思わないので、glレンダリングコンテキストキャンバスの上のレイヤー(別のキャンバス)である必要があります。
カメラの変更頻度が低い場合は、ポリゴンからラインを作成し、カメラの変換に基づいて頂点の位置を更新することもできます。正投影カメラの場合、回転のみが頂点位置の操作を必要とするため、これが最適に機能します。
最後に、キャンバスのクリアを無効にして、円またはボックス内にオフセットを付けて線を数回描画することができます。その後、クリアを再度有効にすることができます。これにはいくつかの追加の描画操作が必要になりますが、おそらく最もスケーラブルなアプローチです。
箱から出して期待どおりに行が機能しない理由は、ANGLEがどのように機能するかによるものです。これは、Chromeで使用され、FirefoxではDirectXを介してOpenGLをエミュレートします。Guys ANGLEによると、WebGL仕様では最大1の線の太さしかサポートされていないため、バグとは見なされず、「修正」するつもりはありません。ただし、線の太さはWindows以外のOSでも機能するはずです。使用されません。