简体   繁体   English

Javascript和WebGL,外部脚本

[英]Javascript and WebGL, external scripts

Just curious; 只是好奇; How do I place my webgl shaders, in an external file? 如何将我的webgl着色器放在外部文件中?

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? 在我的html标题中,如何从外部文件中链接? - I tried the usual javascript approach; - 我尝试了通常的javascript方法;

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

For external files, you need to stop using the script tag. 对于外部文件,您需要停止使用脚本标记。 I suggest using something like XMLHttpRequest . 我建议使用类似XMLHttpRequest的东西。 I would also suggest renaming your files, they are shaders not Javascript so use a different extension to avoid confusion. 我还建议重命名你的文件,它们是着色器而不是Javascript所以使用不同的扩展名以避免混淆。 I use something like "shiny_surface.shader". 我使用类似“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. 如果您使用的是像JQuery这样的库,它们可能具有类似于我的loadFiles的函数。

I had the same issue and found that this has worked for me with jQuery: 我有同样的问题,发现这对我有用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 shader.fsshader.vs是我的着色器(包括
<script type="x-shader/x-fragment"> and <script type="x-shader/x-vertex"> declaration lines) <script type="x-shader/x-fragment"><script type="x-shader/x-vertex">声明行)

Update With Chrome the intelligent guess does not select 'xml'. 更新使用Chrome时,智能猜测不会选择“xml”。 The following code works in Chrome as well: 以下代码也适用于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'
        });               

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: 更新2:由于着色器源中的<&需要转义为以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'
});

You could use an open source shader managing library like mine: 您可以像我一样使用开源着色器管理库:

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

It lets you load shaders from urls and caches shader source code for future visits to the site. 它允许您从URL加载着色器并缓存着色器源代码,以便将来访问该站点。 It also makes it simpler to use uniforms. 它还使得使用制服更简单。

我不是WebGL大师,但这有用吗?

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM