WebGL - есть ли альтернатива встраиванию шейдеров в HTML? - PullRequest
30 голосов
/ 04 мая 2011

Популярный способ использования шейдеров GLSL в WebGL, по-видимому, заключается в том, чтобы встраивать их в основной HTML-файл.Вершинные и фрагментные шейдеры встроены в такие теги, как:

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

Это то же соглашение, которое я вижу в примерах WebGL на странице Mozilla Developer Network.

Это отлично работает для простых приложений, но если у вас сложное приложение с несколькими шейдерами, HTML-файл загромождается.(Я продолжаю редактировать неправильный шейдер!) Также, если вы хотите повторно использовать ваши шейдеры, эта схема неудобна.

Поэтому я думал о том, чтобы поместить эти шейдеры в отдельные файлы XML и загрузить их с помощью XMLHttpRequest ().Затем я увидел, что у кого-то еще есть такая же идея:

http://webreflection.blogspot.com/2010/09/fragment-and-vertex-shaders-my-way-to.html

Мне нравится предложение использовать файлы .c, поскольку это дает вам подсветку синтаксиса и другие удобства редактора для GLSL.

Но проблема с вышеуказанным подходом заключается в том, что (насколько я понимаю) XMLHttpRequest () не может загрузить локальный файл .c - т.е. на стороне клиента - пока вы разрабатываете и тестируете приложение WebGL.Но во время этого процесса загружать его на сервер сложно.

Так что, если я хочу, чтобы шейдеры не попадали в html-файл, является ли единственной возможностью встроить их в код в виде строк?Но это затруднит написание и отладку ...

Буду признателен за любые предложения по управлению несколькими шейдерами GLSL в приложениях WebGL.

С уважением

Редактировать (05 мая 2011 г.)

Поскольку я использую Mac для разработки, я решил включить сервер Apache и поставить свой webglкод под http://localhost/~username/. Это обходит проблему с файлом: протокол отключен во время разработки.Теперь код загрузки файла javascript работает локально, поскольку используется http: вместо file :.Просто подумал, что я это здесь выложу на случай, если кто-нибудь найдет это полезным.

Ответы [ 11 ]

16 голосов
/ 09 мая 2011

Да, локальный сервер действительно единственный путь, если вы хотите использовать XHR.Я написал кучу уроков по WebGL и часто думал о том, чтобы отойти от встраивания шейдеров в HTML, но меня напугало количество объяснений о веб-безопасности, которые мне нужно написать ...

К счастью, запустить сервер очень просто.Просто откройте оболочку, затем

cd path-to-files
python -m SimpleHTTPServer

Затем укажите в браузере

http://localhost:8000

, которая работает для простых случаев, таких как текстуры и GLSL.Для потокового видео и аудио см.

Что является более быстрой альтернативой http.server (или SimpleHTTPServer) Python?

С другой стороны каждый браузер, который поддерживаетWebGL поддерживает многострочные литералы шаблонов ES6 , поэтому, если вам не нужны старые браузеры, вы можете просто поместить свои шейдеры в JavaScript с помощью обратных ссылок, подобных этой

var vertexShaderSource = `
  attribute vec4 position;
  uniform mat4 u_matrix;

  void main() {
    gl_Position = u_matrix * position;
  }
`;
14 голосов
/ 22 сентября 2012

Я использую require.js текстовый плагин .

Вот фрагмент:

define(
    /* Dependencies (I also loaded the gl-matrix library) */
    ["glmatrix", "text!shaders/fragment.shader", "text!shaders/vertex.shader"],

    /* Callback when all has been loaded */
    function(glmatrix, fragmentShaderCode, vertexShaderCode) {
        ....
        var vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, vertexShaderCode);
        gl.compileShader(vertexShader);
        ....
    }
);

Структура каталоговвыглядит следующим образом:

~require-gl-shaders/
 |~js/
 | |+lib/
 | |~shaders/
 | | |-fragment.shader
 | | `-vertex.shader
 | |-glmatrix.js - gl-matrix library
 | |-shader.js
 | |-text.js     - require.js's text plugin
 |-index.html
 |-main.js
 `-require.js    - the require.js library

Лично у меня была небольшая кривая изучения с требованием, но это действительно помогло мне сохранить более чистый код.

6 голосов
/ 11 мая 2015

Следуя подсказке @ droidballoon, я использовал stack.gl , который "является открытой программной экосистемой для WebGL, построенной на основе browserify и npm".

Его glslify обеспечивает преобразование просмотра, которое может использоваться вместе с gl-shader для загрузки шейдеров.Javascript будет выглядеть примерно так:

var glslify       = require('glslify');
var loadShader    = require('gl-shader');
var createContext = require('gl-context');

var canvas = document.createElement('canvas');
var gl = createContext(canvas);

var shader = loadShader(
    gl,
    glslify('./shader.vert'),
    glslify('./shader.frag')
);
6 голосов
/ 14 сентября 2011

Мой приятель создал хороший объект utils с некоторыми удобными функциями для этого типа сценария. Вы должны хранить ваши шейдеры в виде простых текстовых файлов в папке с именем "shaders":

имя файла: vertex.shader

attribute vec3 blah;

uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;

void main(void) {
    magic goes here
}

имя файла: фрагмент.shader

#ifdef GL_ES
    precision highp float;
#endif

varying vec4 vYadaYada;
uniform sampler2D uSampler;

void main(void) {
    fragic magic goes here      
}

И вы просто вызываете это, чтобы создать новую программу с этими файлами шейдеров:

var shaderProgram = utils.addShaderProg(gl, 'vertex.shader', 'fragment.shader');    

А вот сладкий объект util для управления бизнесом:

utils = {};

utils.allShaders = {};
utils.SHADER_TYPE_FRAGMENT = "x-shader/x-fragment";
utils.SHADER_TYPE_VERTEX = "x-shader/x-vertex";

utils.addShaderProg = function (gl, vertex, fragment) {

    utils.loadShader(vertex, utils.SHADER_TYPE_VERTEX);
    utils.loadShader(fragment, utils.SHADER_TYPE_FRAGMENT);

    var vertexShader = utils.getShader(gl, vertex);
    var fragmentShader = utils.getShader(gl, fragment);

    var prog = gl.createProgram();
    gl.attachShader(prog, vertexShader);
    gl.attachShader(prog, fragmentShader);
    gl.linkProgram(prog);

    if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {alert("Could not initialise main shaders");}

    return prog;
};

utils.loadShader = function(file, type) {
    var cache, shader;

    $.ajax({
        async: false, // need to wait... todo: deferred?
        url: "shaders/" + file, //todo: use global config for shaders folder?
        success: function(result) {
           cache = {script: result, type: type};
        }
    });

    // store in global cache
    uilts.allShaders[file] = cache;
};

utils.getShader = function (gl, id) {

    //get the shader object from our main.shaders repository
    var shaderObj = utils.allShaders[id];
    var shaderScript = shaderObj.script;
    var shaderType = shaderObj.type;

    //create the right shader
    var shader;
    if (shaderType == "x-shader/x-fragment") {
        shader = gl.createShader(gl.FRAGMENT_SHADER);
    } else if (shaderType == "x-shader/x-vertex") {
        shader = gl.createShader(gl.VERTEX_SHADER);
    } else {
        return null;
    }

    //wire up the shader and compile
    gl.shaderSource(shader, shaderScript);
    gl.compileShader(shader);

    //if things didn't go so well alert
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(shader));
        return null;
    }

    //return the shader reference
    return shader;

};//end:getShader

Спасибо, приятель, за приятную кодеезию ... наслаждайся его вкладом в сообщество webgl .. упрощает управление программами / шейдерами.

4 голосов
/ 09 августа 2015

Я использую это: https://www.npmjs.com/package/webpack-glsl-loader Это соответствует приоритету, чтобы подсветка синтаксиса не имела надлежащих файлов glsl вместо текстовых фрагментов. Позже я сообщу, как это работает.

[править 17 августа 2015 г.] Этот подход хорошо работает для меня. Предполагается, что веб-пакет находится в процессе сборки, но это не так уж плохо.

[редактировать 11 июня 2016 года] https://github.com/kulicuu/Spacewar_WebGL_React имеет рабочий пример для импорта файлов glsl через сборку Webpack. Сама игра должна быть разработана в течение ближайшей недели.

2 голосов
/ 25 января 2015

Хороший способ сделать это через расширение browserify-shader для Browserify.

1 голос
/ 19 мая 2011

Если вы можете использовать серверные сценарии, вы можете написать небольшой сценарий, который читает файлы шейдеров и возвращает файл JavaScript со сценариями в глобальном объекте. Таким образом, вы можете включить его с помощью простого старого и редактировать сценарии как файлы .c.

Примерно такой сценарий Ruby CGI

require 'cgi'
require 'json'

cgi = CGI.new
prefix = File.expand_path(cgi["prefix"])
cwd = Dir.getwd + "/"
exit!(1) unless prefix.start_with?(cwd)

shader = prefix + ".c"
source = File.read(shader)
cgi.out("text/javascript") {
  <<-EOF
    if (typeof Shaders == 'undefined') Shaders = {};
    Shaders[#{cgi["prefix"]}] = #{source.to_json};
  EOF
}
0 голосов
/ 26 июня 2017

Не точное решение, но это хорошо для меня.Я использую Pug (старый Jade) для компиляции HTML, и я использую теги сценариев внутри шейдеров

script#vertexShader(type="x-shader/x-vertex")
    include shader.vert

script#fragmentShader(type="x-shader/x-fragment")
    include shader.frag

Результат тот же, HTML с встроенным кодом, но вы можете работать с шейдером отдельно.

0 голосов
/ 05 марта 2015

Не лучший способ, но я использую php.Я помещаю шейдеры в отдельный файл, а затем вы просто используете:

<?php include('shaders.html'); ?>

отлично работает для меня.

0 голосов
/ 25 июня 2014

Вы можете поместить свои шейдеры в разные файлы так же, как вы помещаете свой код JavaScript в разные файлы.Эта библиотека https://github.com/codecruzer/webgl-shader-loader-js выполняет это со знакомым синтаксисом:

Пример использования (взято дословно со страницы выше):

[index.html]:

    <script data-src="shaders/particles/vertex.js" data-name="particles"
            type="x-shader/x-vertex"></script>
    <script data-src="shaders/particles/fragment.js" data-name="particles"
            type="x-shader/x-fragment"></script>

[example.js]:

    SHADER_LOADER.load (
        function (data)
        {
            var particlesVertexShader = data.particles.vertex;
            var particlesFragmentShader = data.particles.fragment;
        }
    );
...