2011-02-02 3 views
25

Просто любопытно; Как разместить мои шейдеры Webgl во внешнем файле?Javascript и 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> 

ответ

23

Для внешних файлов вам необходимо прекратить использование тега сценария. Я предлагаю использовать что-то вроде 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 один.

+5

Возможный глупый вопрос, но почему бы не использовать теги скриптов? Кроме того, как этот метод дает идентификаторы шейдерным файлам (например, «shader-fs»)? – MonkeyD

+2

'.glsl' является стандартным расширением – Parobay

+0

@MonkeyD Нет ничего плохого в использовании тегов'

-1

Я не гуру WebGL, но это работает?

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

Извините, но нет. Используя этот метод, я получаю непредвиденную ошибку EOF, даже если найден файл, указанный в части 'src' (код состояния 200). – appas

+2

Это связано с тем, что методы, используемые для получения текста сценария, работают на уровне DOM, и он просто видит пустой тег сценария. Он не знает ничего конкретного о значении атрибута «src» в теге скрипта. –

+2

soooo broken :( – Nils

5

Я была такая же проблема и обнаружил, что это работает для меня с 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.fs и shader.vs мои шейдеры (и включают
<script type="x-shader/x-fragment"> и <script type="x-shader/x-vertex"> декларации линий)

Обновление С Chro меня разумная догадка не выбирает «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' 
     });    

Update 2: Как < и & в источнике шейдерного должны быть экранированы, чтобы загрузить в качестве XML, это работает все время, даже если вы используете менее чем Comparision или и логические операторы:

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

Хотя ' dataType: «html'' работает нормально, лучше использовать' dataType: 'text'', поскольку исходный код шейдера не является HTML. – TachyonVortex

0

Вы можете использовать с открытым исходным кодом шейдера управляющей библиотекой, как у меня:

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

Он позволяет загружать шейдеры из URL-адресов и кеширования исходного кода шейдеров для будущих посещений сайта. Это также упрощает использование униформы.