Javascript y WebGL, scripts externos


Solo curiosidad; ¿Cómo puedo colocar mis shaders webgl, en un archivo externo?

Actualmente estoy teniendo;

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

En mi encabezado html, ¿cómo enlazo esto desde un archivo externo? - Probé el enfoque habitual de javascript;

<script type="text/javascript" src="webgl_shader.js"></script>
Author: Skeen, 2011-02-02

4 answers

Para los archivos externos, debe dejar de usar la etiqueta script. Sugiero usar algo como XMLHttpRequest. También sugeriría cambiar el nombre de sus archivos, son shaders no Javascript, así que use una extensión diferente para evitar confusiones. Yo uso algo como "shiny_surface.sombreado".

Esto es lo que hago:

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

Si está utilizando una biblioteca como jQuery, probablemente tengan una función similar a mi loadFiles.

 23
Author: David Roe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-02 22:24:14

Tuve el mismo problema y descubrí que esto me ha funcionado con 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();
       });
});   

Donde shader.fs y shader.vs son mis shaders (e incluyen el
<script type="x-shader/x-fragment"> y <script type="x-shader/x-vertex"> líneas de declaración)

Actualización Con Chrome la conjetura inteligente no selecciona 'xml'. El siguiente código funciona en Chrome también:

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

Actualización 2: Como < y & en la fuente del sombreador deben ser escapadas para cargarse como XML, esto funciona todo el tiempo incluso si utiliza el menos que la comparación o los operadores lógicos y:

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'
});
 5
Author: brian_d,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-29 18:32:13

Podría usar una biblioteca de gestión de sombreadores de código abierto como la mía:

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

Le permite cargar sombreadores desde url y cachés de código fuente del sombreador para futuras visitas al sitio. También facilita el uso de uniformes.

 0
Author: ILOVEPIE,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-24 21:05:12

No soy un gurú de WebGL, pero ¿funciona esto?

<script id="shader-fs" type="x-shader/x-fragment" src="fragment-shader.fs" />
 -1
Author: Arne Bergene Fossaa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-08 00:53:52