【问题标题】:Javascript and WebGL, external scriptsJavascript 和 WebGL,外部脚本
【发布时间】:2011-06-20 04:09:07
【问题描述】:

只是好奇;如何将我的 webgl 着色器放在外部文件中?

目前我有;

    <script id="shader-fs" type="x-shader/x-fragment">
        #ifdef GL_ES
            precision highp float;
        #endif

        void main(void)
        {
            gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
        }
    </script>

    <script id="shader-vs" type="x-shader/x-vertex">
        attribute vec3 aVertexPosition;

        uniform mat4 uMVMatrix;
        uniform mat4 uPMatrix;

        void main(void)
        {
            gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
        }
    </script>

在我的 html 标头中,如何从外部文件中链接? - 我尝试了通常的 javascript 方法;

<script type="text/javascript" src="webgl_shader.js"></script>

【问题讨论】:

    标签: javascript external extern webgl opengl-es-2.0


    【解决方案1】:

    对于外部文件,您需要停止使用脚本标签。我建议使用XMLHttpRequest 之类的东西。我还建议重命名您的文件,它们是着色器而不是 Javascript,因此请使用不同的扩展名以避免混淆。我使用类似“shiny_surface.shader”的东西。

    这就是我的工作:

    function loadFile(url, data, callback, errorCallback) {
        // Set up an asynchronous request
        var request = new XMLHttpRequest();
        request.open('GET', url, true);
    
        // Hook the event that gets called as the request progresses
        request.onreadystatechange = function () {
            // If the request is "DONE" (completed or failed)
            if (request.readyState == 4) {
                // If we got HTTP status 200 (OK)
                if (request.status == 200) {
                    callback(request.responseText, data)
                } else { // Failed
                    errorCallback(url);
                }
            }
        };
    
        request.send(null);    
    }
    
    function loadFiles(urls, callback, errorCallback) {
        var numUrls = urls.length;
        var numComplete = 0;
        var result = [];
    
        // Callback for a single file
        function partialCallback(text, urlIndex) {
            result[urlIndex] = text;
            numComplete++;
    
            // When all files have downloaded
            if (numComplete == numUrls) {
                callback(result);
            }
        }
    
        for (var i = 0; i < numUrls; i++) {
            loadFile(urls[i], i, partialCallback, errorCallback);
        }
    }
    
    var gl;
    // ... set up WebGL ...
    
    loadFiles(['vertex.shader', 'fragment.shader'], function (shaderText) {
        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, shaderText[0]);
        // ... compile shader, etc ...
        var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fragmentShader, shaderText[1]);
    
        // ... set up shader program and start render loop timer
    }, function (url) {
        alert('Failed to download "' + url + '"');
    }); 
    

    如果您使用的是 JQuery 之类的库,它们可能具有类似于我的 loadFiles 的功能。

    【讨论】:

    • 可能是个愚蠢的问题,但为什么要避免使用脚本标签呢?另外,如何使用这种方法为着色器文件(例如,'shader-fs')提供 id?
    • .glsl 是标准扩展
    • @MonkeyD 使用&lt;script&gt; 标签并没有错,但是如果你有很多着色器,HTML 文件会变得非常混乱。使用 XHR 时,着色器文件没有 ID;着色器源代码位于 XHR 对象的responseText 属性中。
    • @Parobay 不,不是。 GLSL specification 没有为着色器指定标准文件扩展名。常用的扩展名有.vert.frag。请参阅this question 了解更多信息。
    【解决方案2】:

    我不是 WebGL 专家,但这行得通吗?

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

    【讨论】:

    • 抱歉,没有。使用这种方法,我得到一个 Unexpected EOF 错误,即使找到了src 部分中指定的文件(状态代码 200)。
    • 这是因为用于检索脚本文本的方法在 DOM 级别运行,并且只看到一个空的脚本标记。它不知道脚本标签上“src”属性的具体含义。
    • 请参阅this answer 了解有关为什么这不起作用的更多信息。
    【解决方案3】:

    我遇到了同样的问题,发现这对我使用 jQuery 有效:

    var fragmentShaderSRC = null,
    var vertexShaderSRC = null;
    ...
    function executeProgram(){ //main program }
    ...
    $.get("shader.fs", function(data){ 
           fragmentShaderSRC = data.firstChild.textContent;
           $.get("shader.vs", function(data){
                 vertexShaderSRC = data.firstChild.textContent;
                 executeProgram();
           });
    });   
    

    shader.fsshader.vs 是我的着色器(包括
    &lt;script type="x-shader/x-fragment"&gt;&lt;script type="x-shader/x-vertex"&gt; 声明行)

    更新 使用 Chrome,智能猜测不会选择“xml”。以下代码也适用于 Chrome:

    $.ajax({
              url: 'shader.fs', 
              success: function(data){ 
                  fragmentShaderSRC = data.firstChild.textContent;
                  $.ajax({
                      url: 'shader.vs', 
                      success: function(data){
                          vertexShaderSRC = data.firstChild.textContent;
                          executeProgram();
                       },
                       dataType: 'xml'
                  })
               },
               dataType: 'xml'
            });               
    

    更新 2: 由于着色器源代码中的&lt;&amp; 需要转义以作为XML 加载,因此即使您使用小于比较或逻辑运算符,这也始终有效:

    var vs_source = null,
        fs_source = null;
    $.ajax({
        async: false,
        url: './my_shader.vs',
        success: function (data) {
            vs_source = $(data).html();
        },
        dataType: 'html'
    });
    
    $.ajax({
        async: false,
        url: './my_shader.fs',
        success: function (data) {
            fs_source = $(data).html();
        },
        dataType: 'html'
    });
    

    【讨论】:

    • 虽然dataType: 'html' 似乎工作正常,但最好使用dataType: 'text',因为着色器源代码不是HTML。
    【解决方案4】:

    您可以使用像我这样的开源着色器管理库:

    https://github.com/ILOVEPIE/Shader.js

    它允许您从 url 加载着色器并缓存着色器源代码以供将来访问该站点。 它还让制服的使用变得更简单。

    【讨论】:

      猜你喜欢
      • 2019-03-12
      • 1970-01-01
      • 2012-04-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多