Подтвердить что ты не робот

Почему шейдеры должны быть в html файле для программы webgl?

Я видел следующий вопрос, когда кто-то спросил, как удалить шейдеры из html: WebGL - есть ли альтернатива встраиванию шейдеров в HTML?

Существуют сложные обходные пути для загрузки в файл, содержащий шейдер, предложенный в ответах на вопрос.

В учебнике, который я видел, шейдерный код встроен непосредственно в html. Код javascript ссылается на него с помощью getElementById. Но это уродливое вложение шейдеров прямо в html по многим причинам. Почему я не могу просто ссылаться на него извне с помощью атрибута src=?

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

Вышеуказанное не работает, я просто хочу знать, почему нет. Это явно связано с ограничениями на script, но я не понимаю.

4b9b3361

Ответ 1

Вам вообще не нужно использовать теги <script> для загрузки шейдерной программы. Большинство учебников и примеров просто используют их в качестве контейнера для хранения строки в DOM веб-страницы. Тип script "x-shader/x-fragment" не имеет смысла для веб-браузеров, поэтому они не выполняют script. Тем не менее, они сохраняют содержимое этого тега в виде строки в DOM, к которой впоследствии могут быть доступны "реальные" сценарии. Это работает только тогда, когда содержимое script находится в файле HTML. Когда вы загружаете script через атрибут src, содержимое не становится текстовым дочерним типом тега script и, следовательно, не может быть доступно через дерево DOM.

Вы также можете сохранить исходный код для шейдера как строку в файле Javascript:

// myVertextShader.glsl.js
var myVertexShaderSrc =         
        "attribute vec3 pos;"+      
        "void main() {"+        
        "   gl_Position = vec4(pos, 1.0);"+     
        "}"
    ;

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

var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, myVertexShaderSrc);
gl.compileShader(vertexShader);

gl.attachShader(program, vertexShader);

Ответ 2

Почему шейдеры должны быть в html файле для программы webgl?

Они не

Вы можете помещать шейдеры во внешний javascript. Например

// --myshader.js--
var myFragmentShader = 
  "void main() {\n" +
  "  gl_FragColor = vec4(1,0,0,1);\n" +
  "}n\";

Или другой общий формат

// --myshader.js--
var myFragmentShader = [
  "void main() {",
  "  gl_FragColor = vec4(1,0,0,1);", 
  "}",
].join("\n");

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

// --myshader.js--
var myFragmentShader = `
  void main() {
    gl_FragColor = vec4(1,0,0,1); 
  }
`;

В противном случае вы можете поместить их в текстовые файлы и загрузить их с помощью XMLHTTPRequest

// --myshader.txt
  void main() {
    gl_FragColor = vec4(1,0,0,1); 
  }

Затем в JavaScript

function loadTextFile(url, callback) {
  var request = new XMLHttpRequest();
  request.open('POST', url, true);
  request.addEventListener('load', function() {
     callback(request.responseText);
  }
  request.send();
}

loadTextFile("myshader.txt", function(text) {
  // use text...
});

Причина, по которой люди помещают их в HTML, состоит в том, что она проста, эффективна и синхронна.

easy: в отличие от версий JS файлов вам не нужно окружать каждую строку кавычками и другими пунктуациями. Хотя теперь с es6 это уже не проблема. Каждый браузер, поддерживающий WebGL, поддерживает строки шаблонов es6.

эффективный: в отличие от текстовых и js файлов есть только один запрос на сервер. Конечно, некоторые люди могут запускать конкатенатор в своих файлах js, чтобы исправить некоторые из них.

синхронный: в отличие от текстовых файлов их использование синхронно. Нет необходимости в обратных вызовах или promises или иным образом иметь дело с асинхронными проблемами при загрузке файлов.

Что касается того, почему ваш пример не работает, я уверен, причина в том, что он позволит получить доступ к ресурсам на основе перекрестного источника. Тег <script> был разработан до того, как люди поняли, что доступ к перекрестному происхождению был проблемой, поэтому они не могли отключить скрипты с крестовым началом, не разбирая кучу сайтов. Они могли бы сделать все остальное более строгим.

XMLHttpRequest, например, не разрешает доступ к перекрестному контенту, если только сервер, с которым вы связываетесь, дает разрешение. Если теги script позволяют вам получить доступ к этому контенту, вы можете использовать теги script, чтобы обойти это ограничение. Другими словами, вместо создания XMLHttpRequest и чтения request.responseText для результата вы просто программно создали тэг script, установите его src на нужный URL-адрес и затем прочитайте его поле text, когда оно будет завершено, Чтобы убедиться, что вы не можете этого сделать, вам не разрешено читать поле text тега script с атрибутом src

Ответ 3

Шейдерные скрипты - это просто текст. Текст может быть захвачен или сгенерирован из любого места (что вы можете читать или генерировать текст). Многие учебники просто пропускают часть, где происходит волшебство, и экземпляры шейдера WebGL создаются из полученной строки. Нет причин, по которым вы не могли бы ссылаться на скрипты извне, как вы предлагаете, но для загрузки содержимого, а не из браузера, вам понадобится дополнительный JavaScript. Теги Script, скорее всего, используются в учебниках, главным образом потому, что если вы даете тегу Script тип, который браузер не понимает, браузер пропускает выполнение содержимого тега или извлечения источника Script/strike > , поэтому содержимое тегов и атрибуты можно использовать, как вам угодно.

Править: Ну, я должен кое-что вернуть. Я решил пройти через четыре браузера (Chrome, Firefox, IE9, Opera) и посмотреть, что произойдет, когда у вас есть строка

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

в вашем html. Оказывается, браузер загружает файл в каждом браузере, который я пробовал, поэтому я ошибся. Однако это не означает, что браузер знает, что делать с файлом, кроме кэша. Я не знаю, что вы подразумеваете под "Почему не работает src=" util/fs "?". В каждом браузере, который я пробовал,

alert(document.getElementById('shader-fs').src);

предупреждает полный путь к файлу, когда ему задан частичный путь. (Возможно, это ваша проблема? Вы ожидаете частичный путь, когда браузер дает вам полную версию?) Кроме того, я не уверен, как интерпретировать вашу проблему.