web-dev-qa-db-ja.com

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

誰かがhtmlからシェーダーを削除する方法を尋ねた次の質問を見ました: WebGL-HTMLにシェーダーを埋め込む代わりの方法はありますか?

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

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

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

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

24
Dov

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

2018年の更新

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

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

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

// 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>

古いブラウザをサポートしたい場合は、 rollup のようなツールを使用して、すべてのimportステートメントを読み取り、1つの大きなJavaScriptファイルを生成できます。これは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に入れる理由は、それが簡単で、効率的で、同期しているからです。

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

efficient:テキストファイルやjsファイルとは異なり、サーバーへのリクエストは1つだけです。もちろん、jsファイルでコンカテネーターを実行してその一部を修正する人もいます。

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

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

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

28
gman

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

編集:まあ、私はいくつかのものを取り戻す必要があります。私は4つのブラウザ(Chrome、Firefox、IE9、Opera)を使用して、回線があるときに何が起こるかを確認することにしました。

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

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

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

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

3
JayC