WebGL - 有替代方法在HTML中嵌入着色器吗?

M-V*_*M-V 32 glsl webgl

在WebGL中使用GLSL着色器的流行方式似乎是将它们嵌入到主html文件中.顶点和片段着色器嵌入在以下标记中:

<script id="shader-fs" type="x-shader/x-fragment">
Run Code Online (Sandbox Code Playgroud)

这与我在Mozilla Developer Network页面中的WebGL示例中看到的相同.

这适用于简单的应用程序,但是当你有一个带有许多着色器的复杂应用程序时,html文件会变得混乱.(我一直在编辑错误的着色器!)另外,如果你想重复使用着色器,这个方案很不方便.

所以我考虑将这些着色器放在一个单独的XML文件中,并使用XMLHttpRequest()加载它们.然后我看到其他人有同样的想法:

http://webreflection.blogspot.com/2010/09/fragment-and-vertex-shaders-my-way-to.html

我喜欢使用.c文件的建议,因为这为GLSL提供了语法高亮和其他编辑器便利.

但是上述方法的问题是(据我所知)XMLHttpRequest()在开发和测试WebGL应用程序时无法加载本地.c文件 - 即在客户端.但是在此过程中继续将其上传到服务器是很麻烦的.

因此,如果我想将着色器保留在html文件之外,那么将它们作为字符串嵌入代码中是唯一的选择吗?但这会使编写和调试变得困难......

我很感激有关在WebGL应用程序中管理多个GLSL着色器的任何建议.

问候

编辑(2011年5月5日)

由于我使用Mac进行开发,我决定启用Apache服务器,并将我的webgl代码放在http:// localhost/~username /下.这避免了在开发期间禁用文件:协议的问题.现在javascript文件加载代码在本地工作,因为使用了http:而不是file:.我以为我会把它放在这里以防万一有人发现它有用.

Gil*_*mas 18

是的,如果你想使用XHR,本地服务器真的是唯一的出路.我写过一堆WebGL课程,经常考虑不再在HTML中嵌入着色器,但是我已经被大量关于网络安全的解释吓到了......

幸运的是,运行服务器非常容易.然后打开一个shell

cd path-to-files
python -m SimpleHTTPServer
Run Code Online (Sandbox Code Playgroud)

然后将浏览器指向

http://localhost:8000
Run Code Online (Sandbox Code Playgroud)

这适用于纹理和GLSL等简单情况.对于视频和音频流看看

什么是Python的http.server(或SimpleHTTPServer)的更快的替代品?

在另一方面,支持WebGL的每一个浏览器支持ES6辑阵行模板文字,所以如果你不关心旧的浏览器你可以把你的着色器在JavaScript中使用这样的反引号

var vertexShaderSource = `
  attribute vec4 position;
  uniform mat4 u_matrix;

  void main() {
    gl_Position = u_matrix * position;
  }
`;
Run Code Online (Sandbox Code Playgroud)

  • 像`cd path/to/files`一样简单地运行本地服务器,然后运行`python -m SimpleHTTPServer`然后转到`http:// localhost:8000` (3认同)
  • 对于python3:`python -m http.server` (2认同)

Val*_*ler 15

我一直在使用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);
        ....
    }
);
Run Code Online (Sandbox Code Playgroud)

目录结构如下:

~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
Run Code Online (Sandbox Code Playgroud)

就个人而言,我有一点学习曲线与require,但它确实帮助我保持清洁代码.


Joh*_*ive 7

我的好友创建了一个很好的utils对象,为这种场景提供了一些方便的功能.您可以将着色器存储在纯文本文件中名为"着色器"的文件夹中:

filename:vertex.shader

attribute vec3 blah;

uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;

void main(void) {
    magic goes here
}
Run Code Online (Sandbox Code Playgroud)

filename:fragment.shader

#ifdef GL_ES
    precision highp float;
#endif

varying vec4 vYadaYada;
uniform sampler2D uSampler;

void main(void) {
    fragic magic goes here      
}
Run Code Online (Sandbox Code Playgroud)

你只需调用它来创建一个包含这些着色器文件的新程序:

var shaderProgram = utils.addShaderProg(gl, 'vertex.shader', 'fragment.shader');    
Run Code Online (Sandbox Code Playgroud)

这里是处理biz的sweet 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
Run Code Online (Sandbox Code Playgroud)

感谢好友为甜蜜的codeezy ...享受他对webgl社区的贡献..使简化程序/着色器管理更容易.

  • 而不是依赖于`$ .ajax()`来对正确的`dataType`进行"智能猜测",最好在settings对象中指定`dataType:"text"`. (2认同)

小智 7

在@ droidballoon的提示后,我最终使用了stack.gl,"这是一个开源的WebGL生态系统,建立在browserify和npm之上".

它的glslify提供了一个browserify变换,可以与gl-shader一起使用以加载着色器.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')
);
Run Code Online (Sandbox Code Playgroud)


Wyl*_*lik 5

我正在使用: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文件。游戏本身应在未来一周内开发。