Javascript and WebGL, external scripts

99封情书 提交于 2020-01-19 21:34:10

问题


Just curious; How do I place my webgl shaders, in an external file?

Currently I'm having;

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

In my html header, how do I link in this from an external file? - I tried the usual javascript approach;

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

回答1:


For external files, you need to stop using the script tag. I suggest using something like XMLHttpRequest. I would also suggest renaming your files, they are shaders not Javascript so use a different extension to avoid confusion. I use something like "shiny_surface.shader".

This is what I do:

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 + '"');
}); 

If you're using a library like JQuery, they probably have a function similar to my loadFiles one.




回答2:


I had the same issue and found that this has worked for me with 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();
       });
});   

Where shader.fs and shader.vs are my shaders (and include the
<script type="x-shader/x-fragment"> and <script type="x-shader/x-vertex"> declaration lines)

Update With Chrome the intelligent guess does not select 'xml'. The following code works in Chrome as well:

$.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'
        });               

Update 2: As < and & in the shader source need to be escaped to load in as XML, this works all of the time even if you use the less than comparision or the and logic operators:

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'
});



回答3:


You could use an open source shader managing library like mine:

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

It lets you load shaders from urls and caches shader source code for future visits to the site. It also makes it simpler to use uniforms.




回答4:


I am no WebGL guru, but does this work?

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


来源:https://stackoverflow.com/questions/4878145/javascript-and-webgl-external-scripts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!