WebGLでGLSLシェーダーを使用する一般的な方法は、メインのhtmlファイルに埋め込むことです。頂点シェーダーとフラグメントシェーダーは次のようなタグに埋め込まれています。
<script id="shader-fs" type="x-shader/x-fragment">
これは、Mozilla Developer NetworkページのWebGLサンプルで見られるのと同じ規則です。
これは単純なアプリでは問題なく機能しますが、多数のシェーダーを備えた複雑なアプリがある場合、htmlファイルが乱雑になります。 (私は間違ったシェーダーを編集し続けます!)また、シェーダーを再利用したい場合、このスキームは不便です。
したがって、これらのシェーダーを別のXMLファイルに入れ、XMLHttpRequest()を使用してそれらをロードすることを考えていました。次に、他の誰かが同じ考えを持っていることがわかりました:
http://webreflection.blogspot.com/2010/09/fragment-and-vertex-shaders-my-way-to.html
GLSLの構文の強調表示やその他のエディターの便利さを提供するので、私は.cファイルを使用する提案を気に入っています。
しかし、上記のアプローチの問題は、(私が理解している限り)XMLHttpRequest()がWebGLアプリの開発とテストを行っている間、ローカル.cファイル(つまり、クライアント側)をロードできないことです。ただし、このプロセス中にサーバーにアップロードし続けるのは面倒です。
シェーダーをhtmlファイルに含めないようにする場合、それらをコードに文字列として埋め込む唯一のオプションは何ですか?しかし、それではデバッグだけでなく作成も困難になります...
WebGLアプリで複数のGLSLシェーダーを管理するための提案があれば幸いです。
よろしく
編集(2011年5月5日)
私はMacを開発に使用しているので、Apacheサーバーを有効にすることに決め、webglコードを http:// localhost /〜username / の下に置きました。これにより、ファイルの問題が回避されます。開発中にプロトコルが無効になります。 file:ではなくhttp:が使用されているため、javascriptファイルロードコードがローカルで機能するようになりました。誰かが便利だと思ったときに備えて、ここに置いておきます。
うん、ローカルサーバーは、XHRを使用する場合の唯一の方法です。私はたくさんのWebGLレッスンを書いて、シェーダーをHTMLに埋め込むことから離れることをしばしば考えましたが、私が書く必要があるWebセキュリティについての多くの説明に怖がっています...
幸い、サーバーを実行するのは非常に簡単です。シェルを開いて
cd path-to-files
python -m SimpleHTTPServer
次に、ブラウザで
http://localhost:8000
これは、テクスチャやGLSLのような単純なケースで機能します。ビデオとオーディオのストリーミングについては、
Pythonのhttp.server(またはSimpleHTTPServer)のより高速な代替手段は何ですか?
一方、 WebGLをサポートするすべてのブラウザー は ES6マルチラインテンプレートリテラル をサポートするため、古いブラウザーを気にしない場合は、バックティックを使用してJavaScriptにシェーダーを配置できますこのような
var vertexShaderSource = `
attribute vec4 position;
uniform mat4 u_matrix;
void main() {
gl_Position = u_matrix * position;
}
`;
require.js の テキストプラグイン を使用しています。
これがスニペットです:
define(
/* Dependencies (I also loaded the gl-matrix library) */
["glmatrix", "text!shaders/fragment.shader", "text!shaders/vertex.shader"],
/* Callback when all has been loaded */
function(glmatrix, fragmentShaderCode, vertexShaderCode) {
....
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderCode);
gl.compileShader(vertexShader);
....
}
);
ディレクトリ構造は次のとおりです。
~require-gl-shaders/
|~js/
| |+lib/
| |~shaders/
| | |-fragment.shader
| | `-vertex.shader
| |-glmatrix.js - gl-matrix library
| |-shader.js
| |-text.js - require.js's text plugin
|-index.html
|-main.js
`-require.js - the require.js library
個人的には、私はrequireについて少し習得しましたが、コードをよりクリーンに保つのに本当に役立ちました。
私の相棒は、このタイプのシナリオのためのいくつかの便利な機能を備えたNice utilsオブジェクトを作成しました。 「shaders」という名前のフォルダー内のプレーンテキストファイルにシェーダーを保存します。
ファイル名:vertex.shader
attribute vec3 blah;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;
void main(void) {
magic goes here
}
ファイル名:fragment.shader
#ifdef GL_ES
precision highp float;
#endif
varying vec4 vYadaYada;
uniform sampler2D uSampler;
void main(void) {
fragic magic goes here
}
そして、あなたは単にこれを呼び出して、これらのシェーダーファイルで新しいプログラムを作成します:
var shaderProgram = utils.addShaderProg(gl, 'vertex.shader', 'fragment.shader');
そして、これはビジネスを処理するための甘いutilオブジェクトです:
utils = {};
utils.allShaders = {};
utils.SHADER_TYPE_FRAGMENT = "x-shader/x-fragment";
utils.SHADER_TYPE_VERTEX = "x-shader/x-vertex";
utils.addShaderProg = function (gl, vertex, fragment) {
utils.loadShader(vertex, utils.SHADER_TYPE_VERTEX);
utils.loadShader(fragment, utils.SHADER_TYPE_FRAGMENT);
var vertexShader = utils.getShader(gl, vertex);
var fragmentShader = utils.getShader(gl, fragment);
var prog = gl.createProgram();
gl.attachShader(prog, vertexShader);
gl.attachShader(prog, fragmentShader);
gl.linkProgram(prog);
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {alert("Could not initialise main shaders");}
return prog;
};
utils.loadShader = function(file, type) {
var cache, shader;
$.ajax({
async: false, // need to wait... todo: deferred?
url: "shaders/" + file, //todo: use global config for shaders folder?
success: function(result) {
cache = {script: result, type: type};
}
});
// store in global cache
uilts.allShaders[file] = cache;
};
utils.getShader = function (gl, id) {
//get the shader object from our main.shaders repository
var shaderObj = utils.allShaders[id];
var shaderScript = shaderObj.script;
var shaderType = shaderObj.type;
//create the right shader
var shader;
if (shaderType == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderType == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
//wire up the shader and compile
gl.shaderSource(shader, shaderScript);
gl.compileShader(shader);
//if things didn't go so well alert
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
//return the shader reference
return shader;
};//end:getShader
甘いcodeezyに感謝します。webglコミュニティへの彼の貢献を楽しんでください。プログラム/シェーダー管理を簡素化する方法を簡単にします。
@droidballoonのヒントに続いて、私は stack.gl を使用することになりました。
その glslify は、シェーダーをロードするために gl-shader と組み合わせて使用できるbrowserify変換を提供します。 JavaScriptは次のようになります。
var glslify = require('glslify');
var loadShader = require('gl-shader');
var createContext = require('gl-context');
var canvas = document.createElement('canvas');
var gl = createContext(canvas);
var shader = loadShader(
gl,
glslify('./shader.vert'),
glslify('./shader.frag')
);
私はこれを使用しています: https://www.npmjs.com/package/webpack-glsl-loader 構文の強調表示が適切に行われないようにするために優先度に適合しますテキストフラグメントの代わりにglslファイル。仕組みについては後で報告します。
[2015年8月17日編集]このアプローチは私には問題なく機能しています。ビルドフローにwebpackが含まれていることを前提としていますが、それはそれほど悪いことではありません。
[2016年6月11日編集] https://github.com/kulicuu/Spacewar_WebGL_React には、Webpackビルドを介してglslファイルをインポートするための実用的な例があります。ゲーム自体は今後1週間で開発する必要があります。
これを行うための良い方法は、Browserifyの browserify-shader 拡張を使用することです。
サーバー側のスクリプトを使用できる場合は、シェーダーファイルを読み込んで、スクリプトを含むJavaScriptファイルをグローバルオブジェクトに返す小さなスクリプトを作成できます。そうすれば、プレーンな古い<script src = "shader?prefix = foo">を使用してスクリプトを含め、スクリプトを.cファイルとして編集できます。
このようなものRuby CGIスクリプト
require 'cgi'
require 'json'
cgi = CGI.new
prefix = File.expand_path(cgi["prefix"])
cwd = Dir.getwd + "/"
exit!(1) unless prefix.start_with?(cwd)
shader = prefix + ".c"
source = File.read(shader)
cgi.out("text/javascript") {
<<-EOF
if (typeof Shaders == 'undefined') Shaders = {};
Shaders[#{cgi["prefix"]}] = #{source.to_json};
EOF
}
Cマクロを使用する#include
およびgcc -E
(-Eキーはコンパイラーなしでプリプロセッサーを実行します)
これをあなたのjsファイルに追加してください:
const shader = `
#include "shader.fg"
`
シェルを使用する:
mov main.js main.c
gcc -E --no-warnings main.c | sed '/^#.*/d' > main.js
sed
ここでは、プリプロセッサによって生成された余分なコメントを削除します
できます! ;)
最善の方法ではないかもしれませんが、私はphpを使用しています。シェーダーを別のファイルに入れて、使用するだけです:
<?php include('shaders.html'); ?>
私にとってはうまくいきます。
私もRequire.jsを使用してファイルを整理していますが、@ Vlrが示唆するようにテキストプラグインを使用するのではなく、シェーダーを取得してRequire.jsモジュールに変換するスクリプトがあり、それを他の場所で使用できます。したがって、シェーダーファイル、simple.frag
は次のようになります。
uniform vec3 uColor;
void main() {
gl_FragColor = vec4(uColor, 1.0);
}
ファイルに変換されますshader.js
:
define( [], function() {
return {
fragment: {
simple: [
"uniform vec3 uColor;",
"void main() {",
" gl_FragColor = vec4(uColor, 1.0);",
"}",
].join("\n"),
},
}
} );
見た目は面倒ですが、人間が読めるということではありません。次に、このシェーダーをどこかで使用したい場合は、shader
モジュールをプルし、shader.fragment.simple
を使用してそれにアクセスします。
var simple = new THREE.ShaderMaterial( {
vertexShader: shader.vertex.simple,
fragmentShader: shader.fragment.simple
} );
詳細とデモコードへのリンクを含むブログ投稿をここに書きました: http://www.pheelicks.com/2013/12/webgl-working-with-glsl-source-files/ =
正確な解決策ではありませんが、私には適しています。 HTMLのコンパイルにはPug(旧Jade)を使用し、シェーダースクリプトタグ内にインクルードを使用しています
script#vertexShader(type="x-shader/x-vertex")
include shader.vert
script#fragmentShader(type="x-shader/x-fragment")
include shader.frag
結果は同じで、コードがインライン化されたHTMLですが、シェーダーを個別に操作できます。
JavaScriptコードを別のファイルに配置するのと同じように、シェーダーを別のファイルに配置できます。このライブラリ https://github.com/codecruzer/webgl-shader-loader-js は、おなじみの構文でそれを実現します。
使用例(上記のページから逐語的に取得):
[index.html]:
<script data-src="shaders/particles/vertex.js" data-name="particles"
type="x-shader/x-vertex"></script>
<script data-src="shaders/particles/fragment.js" data-name="particles"
type="x-shader/x-fragment"></script>
[example.js]:
SHADER_LOADER.load (
function (data)
{
var particlesVertexShader = data.particles.vertex;
var particlesFragmentShader = data.particles.fragment;
}
);