27

HTML からシェーダーを削除する方法について誰かが尋ねた次の質問を見たことがあります: WebGL - HTML にシェーダーを埋め込む代替手段はありますか?

質問への回答で提案されているシェーダーを含むファイルにロードするための精巧な回避策があります。

私が見たチュートリアルでは、シェーダー コードは html に直接埋め込まれています。JavaScript コードは、getElementById を使用してそれを参照します。しかし、多くの理由から、シェーダーを html に直接埋め込むのは見苦しいものです。src= 属性を使用して外部から参照できないのはなぜですか?

<script type="x-shader/x-fragment" id="shader-fs" src="util/fs"></script>

上記は機能しません。理由を知りたいだけです。これは明らかにスクリプト自体の制限と関係がありますが、私にはわかりません。

4

3 に答える 3

38

<script>シェーダー プログラムをロードするためにタグを使用する必要はまったくありません。ほとんどのチュートリアルと例では、それらをコンテナーとして使用して、Web ページの DOM に文字列を格納します。スクリプトの種類"x-shader/x-fragment"は Web ブラウザーにとっては意味がないため、スクリプトを実行しません。ただし、そのタグのコンテンツを文字列として DOM に保存し、後で「実際の」スクリプトからアクセスできるようにします。これは、スクリプト コンテンツが HTML ファイルにある場合にのみ機能します。src 属性を介してスクリプトをロードすると、コンテンツは script タグのテキストの子ノードにならないため、DOM ツリーからアクセスできません

シェーダーのソースコードを文字列として Javascript ファイルに保存することもできます。

// myVertextShader.glsl.js
var myVertexShaderSrc =         
        "attribute vec3 pos;"+      
        "void main() {"+        
        "   gl_Position = vec4(pos, 1.0);"+     
        "}"
    ;

次に、シェーダーを次のようにコンパイルします。

var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, myVertexShaderSrc);
gl.compileShader(vertexShader);

gl.attachShader(program, vertexShader);
于 2013-01-10T08:43:07.050 に答える
34

2018年アップデート

2018年には、シェーダーをバッククォートで囲むように複数行のテンプレートリテラルを使用することをお勧めします。これは複数の行にまたがることができます

const someShaderSource = `
attribute vec4 position;
uniform mat4 matrix;
void main() {
  gl_Position = matrix * position;
}
`;

シェーダーを別々のファイルに入れたい場合は、2018 年に JavaScript モジュールを使用して簡単に行うことができます。シェーダー ファイルは次のようになります。

// someshader.glsl.js
export default `
attribute vec4 position;
uniform mat4 matrix;
void main() {
  gl_Position = matrix * position;
}
`;

JavaScript モジュールを使用するには、メインの JavaScript を別のファイルにする必要があります。インポートすることで、シェーダー ソースにアクセスできます。

// main.js

import someShaderSource from './someshader.glsl.js';

// use someShadeSource

そして、それをHTMLに含めます

<script src="main.js" type="module"></script>

または、このようにページ自体のスクリプトタグから使用できます

<script type="module">
import someShaderSource from './someshader.glsl.js';

// use someShadeSource
</script>

古いブラウザーをサポートしたい場合は、すべてのステートメントを読み取り、1 つの大きな JavaScript ファイルを生成するロールアップなどのツールを使用できます。importこれが three.js の機能です。

IE11 をサポートする必要がある場合は、babelを使用して複数行のテンプレートを変換できます。他のすべてのブラウザーは、長年にわたって複数行のテンプレートをサポートしてきました。

元の回答

webgl プログラムでシェーダーを html ファイルにする必要があるのはなぜですか?

彼らはしません

シェーダーを外部 JavaScript に配置できます。例えば

// --myshader.js--
var myFragmentShader = 
  "void main() {\n" +
  "  gl_FragColor = vec4(1,0,0,1);\n" +
  "}n\";

または別の一般的な形式

// --myshader.js--
var myFragmentShader = [
  "void main() {",
  "  gl_FragColor = vec4(1,0,0,1);", 
  "}",
].join("\n");

WebGL をサポートするすべてのブラウザで、テンプレート リテラルを使用できます

// --myshader.js--
var myFragmentShader = `
  void main() {
    gl_FragColor = vec4(1,0,0,1); 
  }
`;

それ以外の場合は、それらをテキスト ファイルに入れて、XMLHTTPRequest でロードできます。

// --myshader.txt
  void main() {
    gl_FragColor = vec4(1,0,0,1); 
  }

次に、JavaScript で次のようにします。

function loadTextFile(url, callback) {
  var request = new XMLHttpRequest();
  request.open('GET', url, true);
  request.addEventListener('load', function() {
     callback(request.responseText);
  });
  request.send();
}

loadTextFile("myshader.txt", function(text) {
  // use text...
});

人々がそれらを HTML に入れる理由は、それが簡単で、効率的で、同期的だからです。

簡単: JS ファイル バージョンとは異なり、すべての行を引用符やその他の句読点で囲む必要はありません。es6 になった今では、それはもはや問題ではありません。WebGL をサポートするすべてのブラウザーは、es6 テンプレート文字列をサポートします。

効率的: テキスト ファイルや js ファイルとは異なり、サーバーへの要求は 1 つだけです。もちろん、js ファイルで連結子を実行してその一部を修正する人もいます。

synchronous : テキスト ファイルとは異なり、それらの使用は同期的です。コールバックや約束、またはファイルのダウンロードの非同期の問題を処理する必要はありません。

あなたの例が機能しない理由については、クロスオリジンリソースアクセスが許可されることが理由だと確信しています。この<script>タグは、クロス オリジン アクセスが問題であると人々が理解する前に設計されたため、多くのサイトを壊さずにクロス オリジン スクリプトをオフにすることはできませんでした。彼らは他のすべてをより厳密にすることができました。

たとえば、XMLHttpRequest は、接続しているサーバーが許可を与えない限り、クロス オリジン アクセスを許可しません。スクリプト タグを使用してそのコンテンツにアクセスできる場合は、スクリプト タグを使用してその制限を回避できます。つまり、XMLHttpRequest を作成しrequest.responseTextて結果を読み取る代わりに、プログラムでスクリプト タグを作成し、src目的の URL に設定し、終了時にそのtextフィールドを読み取るだけです。属性textを持つスクリプトタグのフィールドを読み取ることが許可されていないことを確認するにはsrc

于 2013-01-10T00:23:16.667 に答える
3

シェーダー言語のスクリプトは単なるテキストです。 テキストはどこからでも取得または生成できます (テキストを読み取ったり生成したりできます)。多くのチュートリアルでは、マジックが発生し、取得した文字列から WebGL シェーダー インスタンスが作成される部分をスキップするだけです。あなたが提案するように外部からスクリプトを参照できない理由はありませんが、 browser ではなく、コンテンツをロードするために追加の JavaScript が必要になります。スクリプト タグがチュートリアルで使用される可能性が高いのは、主に、スクリプト タグにブラウザが理解できないタイプを指定すると、ブラウザはタグのコンテンツの実行またはスクリプトのソースの取得をスキップし、タグのコンテンツと属性を使用できるようにするためです。しかし、あなたが望む。

編集:ええと、私はいくつかのものを取り戻さなければなりません. 4 つのブラウザー (Chrome、Firefox、IE9、Opera) を調べて、回線があるとどうなるかを確認することにしました。

<script type="x-shader/x-fragment" id="shader-fs" src="util/fs"></script>

あなたのhtmlで。結局のところ、ブラウザ私が試したすべてのブラウザでファイルをロードするので、私は間違っていました. ただし、それはブラウザがファイルをキャッシュする以外に何をすべきかを知っているという意味ではありません。「なぜ src="util/fs" が機能しないのですか???」という言葉の意味がわかりません。私が試したすべてのブラウザで、

alert(document.getElementById('shader-fs').src);

部分パスが指定された場合、ファイルへのフル パスを警告します。(多分これはあなたの問題ですか? ブラウザーが完全なパスを提供するとき、部分的なパスを期待しているのでしょうか?) それに加えて、あなたの問題をどのように解釈すればよいかわかりません。

于 2013-01-09T08:40:15.153 に答える