WebGL - czy istnieje alternatywa dla osadzania shaderów w HTML?
Popularnym sposobem używania shaderów GLSL w WebGL wydaje się osadzanie ich w głównym pliku html. Shadery wierzchołków i fragmentów są osadzone w znacznikach takich jak:
<script id="shader-fs" type="x-shader/x-fragment">
Jest to ta sama Konwencja, którą widzę w próbkach WebGL na stronie Mozilla Developer Network.
To działa dobrze dla prostych aplikacji, ale gdy masz złożoną aplikację z wieloma shaderami, plik html staje się zaśmiecony. (Ciągle edytuję zły shader!) Również jeśli chcesz ponownie użyć shaderów, ten schemat to niewygodne.
Więc myślałem o umieszczeniu tych shaderów w osobnych plikach XML i załadowaniu ich za pomocą XMLHttpRequest (). Potem zobaczyłem, że ktoś inny miał ten sam pomysł:
Http://webreflection.blogspot.com/2010/09/fragment-and-vertex-shaders-my-way-to.html
Podoba mi się ta sugestia .pliki c, ponieważ daje to podświetlanie składni i inne wygody edytora dla GLSL.Ale problem z powyższym podejściem jest taki, że (o ile XMLHttpRequest () nie może załadować lokalnego .plik c-czyli po stronie klienta-podczas tworzenia i testowania aplikacji WebGL. Ale jest uciążliwe przesyłanie go na serwer podczas tego procesu.
Więc jeśli chcę trzymać shadery z dala od pliku html, czy jest jedyna opcja, aby osadzić je jako ciągi znaków w kodzie? Ale to utrudniłoby pisanie i debugowanie...
Byłbym wdzięczny za wszelkie sugestie dotyczące zarządzania wieloma shaderami GLSL w aplikacjach WebGL.
Pozdrawiam
Edit (Maj 05 2011)
Ponieważ używam Mac do rozwoju, postanowiłem włączyć serwer Apache i umieścić mój kod webgl pod http://localhost / ~ username / . To omija problem wyłączenia file: protocol podczas programowania. Teraz kod wczytywania plików javascript działa lokalnie, ponieważ używany jest http:, a nie file:. Pomyślałem, że postawię to tutaj na wypadek, gdyby ktoś uznał to za przydatne.
11 answers
Yup, lokalny serwer jest naprawdę jedynym sposobem, aby przejść, jeśli chcesz korzystać z XHR. Napisałem kilka lekcji WebGL i często rozważałem odejście od osadzania shaderów w HTML, ale byłem przerażony ilością wyjaśnień dotyczących bezpieczeństwa sieci, które muszę napisać...
Na szczęście bardzo łatwo jest uruchomić serwer. Po prostu Otwórz powłokęcd path-to-files
python -m SimpleHTTPServer
Następnie wskaż przeglądarkę na
http://localhost:8000
To działa w prostych przypadkach, takich jak tekstury i GLSL. Do wideo i audio streaming see
Co to jest szybsza alternatywa dla HTTP Pythona.serwer (lub SimpleHTTPServer)?
Z drugiej strony każda przeglądarka, która obsługuje WebGL obsługuje ES6 mutli-liniowe literały szablonów więc jeśli nie dbasz o stare przeglądarki, możesz po prostu umieścić shadery w JavaScript za pomocą takich backtików
var vertexShaderSource = `
attribute vec4 position;
uniform mat4 u_matrix;
void main() {
gl_Position = u_matrix * position;
}
`;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:07
Używałem require.js ' S text plugin .
Oto fragment:
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);
....
}
);
Struktura katalogów jest następująca:
~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
Osobiście miałem trochę krzywej uczenia się z require, ale to naprawdę pomogło mi zachować czystszy kod.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-21 21:10:46
Mój kumpel stworzył ładny obiekt utils z kilkoma przydatnymi funkcjami do tego typu scenariuszy. Shadery można przechowywać w plikach tekstowych w folderze o nazwie "shadery":
Nazwa pliku: vertex.shader
attribute vec3 blah;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
uniform mat3 uNMatrix;
void main(void) {
magic goes here
}
Nazwa pliku: fragment.shader
#ifdef GL_ES
precision highp float;
#endif
varying vec4 vYadaYada;
uniform sampler2D uSampler;
void main(void) {
fragic magic goes here
}
I po prostu wywołujesz to, aby utworzyć nowy program z tymi plikami shader:
var shaderProgram = utils.addShaderProg(gl, 'vertex.shader', 'fragment.shader');
A oto słodki obiekt util do obsługi biz:
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
Dzięki kolego za słodki kodeezy.. ciesz się jego wkładem w społeczność webgl.. znacznie ułatwia zarządzanie programami / shaderami.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-14 02:40:16
Podążając za podpowiedzią @ droidballoon skończyłem używając stack.gl który "jest otwartym ekosystemem oprogramowania dla WebGL, zbudowanym na bazie browserify i npm".
Its glslify zapewnia transformację browserify, która może być używana w połączeniu z GL-shader w celu załadowania shaderów. Javascript wyglądałby mniej więcej tak:
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')
);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-11 11:48:12
Używam tego: https://www.npmjs.com/package/webpack-glsl-loader Pasuje do priorytetu, aby podświetlanie składni nie miało odpowiednich plików glsl zamiast fragmentów tekstu. Później opiszę, jak to działa.
[edytuj Sierpień-17, 2015] to podejście działa dobrze dla mnie. Zakłada, że webpack jest w Twoim przepływie budowania, ale to nie jest taka zła rzecz.
[edytuj 11-czerwiec-2016] https://github.com/kulicuu/Spacewar_WebGL_React ma działający przykład importowania glsl pliki poprzez tworzenie Webpacka. Sama gra powinna być rozwijana w nadchodzącym tygodniu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-11 09:25:42
Dobrym sposobem na to jest rozszerzenie browserify-shader do Browserify.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-24 21:13:15
Jeśli możesz używać skryptów po stronie serwera, możesz napisać mały skrypt, który odczytuje pliki shadera i zwraca plik JavaScript ze skryptami w obiekcie globalnym. W ten sposób możesz dołączyć go używając zwykłego i edytować skrypty jako .pliki C.
Coś takiego jak skrypt 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
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-19 10:16:31
Może nie jest to najlepszy sposób, ale używam php. Ja wrzucam shadery do osobnego pliku, a ty po prostu używasz:
<?php include('shaders.html'); ?>
Dla mnie działa świetnie.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-05 18:57:39
Używam również Require.js do organizowania moich plików, ale zamiast używać wtyczki tekstowej ,jak sugeruje @ Vlr, mam skrypt, który bierze shadery i konwertuje go na Wymaganie.moduł js, który mogę wykorzystać gdzie indziej. Więc plik shader, simple.frag
w ten sposób:
uniform vec3 uColor;
void main() {
gl_FragColor = vec4(uColor, 1.0);
}
Zostanie przekonwertowany do pliku shader.js
:
define( [], function() {
return {
fragment: {
simple: [
"uniform vec3 uColor;",
"void main() {",
" gl_FragColor = vec4(uColor, 1.0);",
"}",
].join("\n"),
},
}
} );
Wygląda to na bałagan, ale nie chodzi o to, że jest czytelny dla człowieka. Następnie, jeśli chcę gdzieś użyć tego shadera, po prostu wciągam moduł shader
i uzyskuję do niego dostęp używając shader.fragment.simple
, w ten sposób:
var simple = new THREE.ShaderMaterial( {
vertexShader: shader.vertex.simple,
fragmentShader: shader.fragment.simple
} );
Napisałem post na blogu z bardziej szczegółowymi informacjami i linkami do kodu demo tutaj: http://www.pheelicks.com/2013/12/webgl-working-with-glsl-source-files/
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-10 16:47:19
Shadery można umieszczać w różnych plikach, podobnie jak kod javascript w różnych plikach. Ta biblioteka https://github.com/codecruzer/webgl-shader-loader-js osiąga to ze znajomą składnią:
Przykładowe użycie (zaczerpnięte dosłownie z powyższej strony):
[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;
}
);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-25 18:59:05
Nie jest to dokładne rozwiązanie, ale jest dobre dla mnie. Używam Pug (old Jade) do kompilacji HTML i używam includes inside shaders script tags
script#vertexShader(type="x-shader/x-vertex")
include shader.vert
script#fragmentShader(type="x-shader/x-fragment")
include shader.frag
Wynik jest taki sam, HTML z kodem w linii, ale można pracować z shaderem osobno.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-26 09:52:50