asi*_*mes 13 javascript glsl webgl
我一直在拼凑在线示例,以制作Mandelbrot Set片段着色器.顶点着色器基本上什么都不做,它分配gl_Position并且片段着色器做一些数学计算图像.
但是,我有一些#define我想用JavaScript控制变量替换的s,我不知道如何做到这一点.如果一个例子可以显示如何#define MAX_ITERATIONS 200用下面的代码中的JavaScript指定变量替换,我可能会弄清楚其余的.我相信我需要指定一个uniform或者varying不确定如何管理从JavaScript到GLSL的通信.
另外我不明白aPositionJavaScript和顶点着色器之间的工作原理,我所拥有的与示例基本相同.
JavaScript,我认为只init()对SO读者有用,其余部分如果需要发布:
var canvas, gl, shaderProgram;
function draw() {
window.requestAnimationFrame(draw, canvas);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
function init() {
canvas = document.getElementById("theCanvas");
gl = initGl(canvas);
if (!gl) {
alert("Could not initialize WebGL");
return;
}
shaderProgram = initShaders();
if (!shaderProgram) {
alert("Could not initialize shaders");
return;
}
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(
gl.ARRAY_BUFFER,
new Float32Array([
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
1.0, 1.0,
]),
gl.STATIC_DRAW
);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
var aPosition = gl.getAttribLocation(shaderProgram, "aPosition");
gl.enableVertexAttribArray(aPosition);
gl.vertexAttribPointer(aPosition, 2, gl.FLOAT, false, 0, 0);
draw();
}
function initGl(inCanvas) {
gl = false;
try { gl = inCanvas.getContext("webgl") || inCanvas.getContext("experimental-webgl"); }
catch (e) {}
return !gl ? false : gl;
}
function initShaders() {
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, document.getElementById("vertexShader").text);
gl.compileShader(vertexShader);
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(vertexShader));
return false;
}
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, document.getElementById("fragmentShader").text);
gl.compileShader(fragmentShader);
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(fragmentShader));
return false;
}
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) return false;
gl.useProgram(shaderProgram);
return shaderProgram;
}
Run Code Online (Sandbox Code Playgroud)
顶点着色器:
attribute vec2 aPosition;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
}
Run Code Online (Sandbox Code Playgroud)
片段着色器,MAX_ITERATIONS,XMIN,YMIN,并WH应在JavaScript控制:
#ifdef GL_FRAGEMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
precision mediump int;
#define MAX_ITERATIONS 200
#define XMIN -2.5
#define YMIN -2.0
#define WH 4.0
#define LOG_TWO log(2.0)
#define LOG_MAX log(200.0)
void main() {
// Normalized pixel position to complex plane position
float maxPwh = max(640.0, 480.0);
float x = XMIN+(gl_FragCoord.x/maxPwh)*WH;
float y = YMIN+(gl_FragCoord.y/maxPwh)*WH;
// Complex plane window offsets for pixel windows that are not square
float halfDelta = WH/maxPwh*0.5;
x -= min((640.0-480.0)*halfDelta, 0.0);
y -= min((480.0-640.0)*halfDelta, 0.0);
// Mandelbrot Set code
float zr = x;
float zi = y;
int iterations = 0;
for (int i = 0; i < MAX_ITERATIONS; i++) {
iterations = i;
float sqZr = zr*zr;
float sqZi = zi*zi;
float twoZri = 2.0*zr*zi;
zr = sqZr-sqZi+x;
zi = twoZri+y;
if (sqZr+sqZi > 16.0) break;
}
if (iterations == MAX_ITERATIONS-1) gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
else {
float fn = float(iterations)+1.0-log(log(sqrt(zr*zr+zi*zi)))/LOG_TWO;
float logVal = log(fn)/LOG_MAX;
gl_FragColor = vec4(logVal, logVal, logVal, 1.0);
}
}
Run Code Online (Sandbox Code Playgroud)
gma*_*man 19
简短的回答是你基本上有两个选择
通过统一将值从JavaScript传递到GLSL.
例如,如果要传递浮点,请创建浮点均匀
uniform float foo;
Run Code Online (Sandbox Code Playgroud)
在JavaScript中编译并链接该着色器,然后查找制服的位置
var locationOfFoo = gl.getUniformLocation(someProgram "foo");
Run Code Online (Sandbox Code Playgroud)
您现在可以将值传递给GLSL
gl.useProgram(someProgram)
gl.uniform1f(locationOfFoo, valueToPass);
Run Code Online (Sandbox Code Playgroud)在编译着色器之前处理字符串
#define MAX_INTERATIONS %maxIterations%
#define XMIN %xMin%
Run Code Online (Sandbox Code Playgroud)
...
var maxIterations = 123;
var xMin = 4.5;
shaderSource = shaderSource.replace(/%maxIterations%/g, maxIterations);
shaderSource = shaderSource.replace(/%xMin%/g, xMin);
Run Code Online (Sandbox Code Playgroud)(1)以上是为了传递经常变化的东西.#2用于在编译之前更改着色器.#1是几乎100%的WebGL程序中使用的技术.在许多游戏引擎动态生成着色器时经常使用#2.
我花了大约 45 分钟来实现gman 的答案,因为\n我不断犯愚蠢的小错误。这是完整的工作代码\n示例,用于创建可调整的图块地图。
\n测试于: Chrome、Internet Explorer 和 Edge:
\n <!DOCTYPE HTML >\n <html lang="en">\n <head>\n <meta charset="UTF-8">\n <title> GL_TILE_TESTBED </title>\n <!-- AUTHOR: John Mark Isaac Madison -->\n <!-- EMAIL : J4M4I5M7@hotmail.com -->\n <!-- SSSSSSSSS SHADER_SECTION START SSSSSSSSS -->\n <!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS -->\n <!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS -->\n <style>\n \n p{ font-size:12pt;}\n h3,p,input,button,br{ \n padding:0px; \n margin:0px; \n font-family:"Andale Mono";\n }\n button,input{\n padding:10px;\n }\n </style>\n <script id="VERT_SHADER" type="NOT_JAVASCRIPT">\n precision highp float;\n \n attribute vec2 a_position;\n void main() {\n gl_Position = vec4(a_position, 0, 1);\n }\n </script>\n \n \n <script id="FRAG_SHADER" type="NOT_JAVASCRIPT">\n \n //Must declare precision before declaring\n //any uniforms:\n ////////////////////////////////////////////////\n #ifdef GL_FRAGMENT_PRECISION_HIGH\n precision highp float;\n #else\n precision mediump float;\n #endif\n precision mediump int;\n ////////////////////////////////////////////////\n \n #define CANVAS_WID 640.0\n #define CANVAS_HIG 480.0\n \n #define TIL_WID 64.0\n #define TIL_HIG 64.0\n \n //Uniforms exposed to HTML/JAVASCRIPT:\n uniform float TIL_WID_EDIT;\n uniform float TIL_HIG_EDIT;\n \n float til_wid;\n float til_hig;\n \n \n void main() {\n \n //If uniforms have not set by user,\n //use the default values set by the #define(s)\n //==========================================//\n if(TIL_WID_EDIT > 0.0){\n til_wid = TIL_WID_EDIT;\n }else{\n til_wid = TIL_WID;\n }\n \n if(TIL_HIG_EDIT > 0.0){\n til_hig = TIL_HIG_EDIT;\n }else{\n til_hig = TIL_HIG;\n }\n //==========================================//\n \n //NOTE: on "gl_FragCoord" range:\n //******************************************//\n //web-gl: In terms of pixel/canvas coords.\n //OpenGL: In terms of 0 to 1.\n //******************************************//\n \n //:Calculate number of tiles shown on screen:\n //:This may be fractional:\n float NUM_TIL_X = CANVAS_WID / til_wid;\n float NUM_TIL_Y = CANVAS_HIG / til_hig;\n \n \n vec2 FC_MOD;\n FC_MOD.x = gl_FragCoord.x;\n FC_MOD.y = gl_FragCoord.y;\n \n //You want all tiles to have the full range \n //of colors, so you always modulate by \n //CANVAS_WID and CANVAS_HIG, You scale by the \n //# of tiles on each axis which means the \n //gradient becomes steeper as the # of tiles\n //increases.\n FC_MOD.x = mod( gl_FragCoord.x*NUM_TIL_X, CANVAS_WID );\n FC_MOD.y = mod( gl_FragCoord.y*NUM_TIL_Y, CANVAS_HIG );\n \n //[N]ormalize values into range 0 to 1:\n //NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN//\n float norm_X = (FC_MOD.x) / CANVAS_WID;\n float norm_Y = (FC_MOD.y) / CANVAS_HIG;\n //NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN//\n \n //Use [B]lue channel because why not?\n //BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB//\n float GRAD_X = gl_FragCoord.x / CANVAS_WID;\n //BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB//\n \n //Set the final [F]ragment colors:\n //FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF//\n gl_FragColor = vec4(norm_X, norm_Y, GRAD_X, 1.0);\n //FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF//\n }\n </script>\n <!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS -->\n <!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS -->\n <!-- SSSSSSSSSS SHADER_SECTION END SSSSSSSSSS -->\n </head> \n <!-- HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH -->\n \n <!-- BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB --> \n <body onload="ON_LOADED_FUNCTION()" >\n <!-- BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB -->\n \n <h3> Open GL Tile TestBed <h3>\n <p> Author: John Mark Isaac Madison <p>\n <p> Email : J4M4I5M7@hotmail.com <p>\n \n <canvas id="glCanvas"></canvas>\n \n </br>\n <button onClick="PUT_WID();">TILE_WIDTH__IN_PIXELS</button> \n <input type="text" id="INPUT_WID" value="45">\n </br>\n \n </br>\n <button onClick="PUT_HIG();">TILE_HEIGHT_IN_PIXELS</button> \n <input type="text" id="INPUT_HIG" value="45">\n </br>\n \n \n \n <!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS --> \n <script id="BOILER_PLATE_CODE">\n function ON_LOADED_FUNCTION(){\n console.log("[ON_LOADED_FUNCTION]");\n main();\n }\n \n //:Takes the gl context object, if the input\n //:is null, we likely failed to get the\n //:context.\n function HAS_OPEN_GL_CHECK(gl){\n // Only continue if WebGL is \n // available and working\n if (!gl) {\n var msg = "";\n msg += "[Unable to initialize WebGL.]";\n msg += "[your browser or machine may]";\n msg += "[not support it.]"\n alert( msg );\n return;\n }\n }\n \n function GET_INPUT_BOX_VALUE( elem_id ){\n var box; //DOM input box\n var val; //Value in input box.\n box = document.getElementById( elem_id );\n val = box.value;\n return (0 + val); //cast to number.\n }\n \n function PUT_WID(){\n assert_program_and_gl_exist();\n var val = GET_INPUT_BOX_VALUE("INPUT_WID");\n SET_ATTR("TIL_WID_EDIT", val);\n }\n \n function PUT_HIG(){\n assert_program_and_gl_exist();\n var val = GET_INPUT_BOX_VALUE("INPUT_HIG");\n SET_ATTR("TIL_HIG_EDIT", val); \n }\n \n function SET_ATTR(gl_var_name, val){\n if(val < 0 || val > 256 ){\n alert("choose value between 0 to 256");\n return;\n }\n \n var loc; //<--location of variable.\n loc = gl.getUniformLocation(\n program , \n gl_var_name\n );\n gl.useProgram(program);\n gl.uniform1f(loc, val);\n }\n \n function assert_program_and_gl_exist(){\n if(!program){\xe6\x85\x8c("[NO_PROGRAM_EXISTS]");}\n if(!gl ){\xe6\x85\x8c("[NO_GL_EXISTS]");}\n }\n \n //\xe6\x85\x8c: "disconcerted, be confused, lose one\'s head"\n //\xe6\x85\x8c: In Code: ~Panic~\n function \xe6\x85\x8c( panic_message ){\n console.log( panic_message );\n alert ( panic_message );\n throw ( panic_message );\n }\n \n function makeOpenGlContextUsingCanvas(c){\n \n //:Try what works in chrome and all the\n //:respectable browsers first:\n gl = c.getContext("webgl");\n \n if(!gl){\n console.log("[Probably_In_IE]");\n gl = c.getContext("experimental-webgl");\n }else{\n console.log("[Probably_NOT_IE]");\n }\n \n HAS_OPEN_GL_CHECK( gl );\n return gl;\n }\n \n //: No "var" prefix, making them global:\n function initGlobals(){\n canvas = document.querySelector("#glCanvas");\n if(!canvas){\n alert("FAILED_TO_GET_CANVAS");\n }else{\n console.log("[GOT_CANVAS]");\n }\n \n gl = makeOpenGlContextUsingCanvas(canvas);\n \n \n //These dimensions are hard-coded into\n //fragment shader code, so be careful\n //about changing them:\n canvas.width = 640;\n canvas.height= 480;\n \n buffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.bufferData(\n gl.ARRAY_BUFFER, \n new Float32Array([\n -1.0, -1.0, \n 1.0, -1.0, \n -1.0, 1.0, \n -1.0, 1.0, \n 1.0, -1.0, \n 1.0, 1.0]), \n gl.STATIC_DRAW\n );\n \n //G == Global Container.\n //To fix problems with rendering in I.E.\n //(Internet Explorer)\n //GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG//\n var G = {}; \n G.canvas = canvas;\n G.gl = gl;\n G.buffer = buffer;\n \n if( ! G.canvas ||\n ! G.gl ||\n ! G.buffer ){\n \xe6\x85\x8c("[Global_Container_Broken]");\n }\n \n return G;\n //GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG//\n }\n \n function main(){\n \n G = initGlobals();\n HAS_OPEN_GL_CHECK( G );\n \n gl.viewport(0,0,gl.drawingBufferWidth, gl.drawingBufferHeight);\n \n setup();\n render();\n }\n \n function setup(){\n var frag_dom = document.getElementById("FRAG_SHADER");\n var frag_src = frag_dom.text;\n console.log( frag_src );\n \n F = createShader(\n gl,gl.FRAGMENT_SHADER, frag_src\n );\n \n var vert_dom = document.getElementById("VERT_SHADER");\n var vert_src = vert_dom.text;\n console.log( vert_src );\n \n V = createShader(\n gl, gl.VERTEX_SHADER, vert_src\n );\n \n //**** MAKE "program" a GLOBAL VAR ****//\n program = createProgram(gl,V,F);\n gl.useProgram( program );\n \n if(!program){\n \xe6\x85\x8c("PROGRAM_IS_NULL");\n }\n }\n \n function render(){\n window.requestAnimationFrame(render,canvas);\n \n // Set clear color to black, fully opaque\n gl.clearColor(0.0, 0.0, 0.5, 1.0);\n \n // Clear the color buffer with specified clear color\n gl.clear(gl.COLOR_BUFFER_BIT);\n \n //Directly before call to gl.drawArrays:\n positionLocation = gl.getAttribLocation(program, "a_position");\n gl.enableVertexAttribArray( positionLocation );\n gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);\n \n \n gl.drawArrays(gl.TRIANGLES, 0, 6);\n }\n \n function createShader(gl,type,source){\n //:Error Check For Bad Inputs:\n if(!gl ){\xe6\x85\x8c("[NULL_GL]");}\n if(!type ){\xe6\x85\x8c("[NULL_TY]");}\n if(!source){\xe6\x85\x8c("[NULL_SR]");}\n \n var shader = gl.createShader(type);\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n var res = gl.getShaderParameter(shader, gl.COMPILE_STATUS);\n if( res ){\n console.log("[SHADER_COMPILED!]");\n return shader;\n }\n \n console.log(gl.getShaderInfoLog(shader));\n gl.deleteShader(shader);\n \xe6\x85\x8c("[FAILED_TO_COMPILE_SHADER]");\n }\n \n //:gl : openGL context :\n //:vert: vertex shader :\n //:frag: fragment shader:\n function createProgram(gl,vert, frag){\n var program = gl.createProgram();\n gl.attachShader(program, vert);\n gl.attachShader(program, frag);\n gl.linkProgram (program);\n var res = gl.getProgramParameter(program, gl.LINK_STATUS);\n if( res ){\n console.log("[PROGRAM_CREATED!]");\n return program;\n }\n \n console.log(gl.getProgramInfoLog(program));\n gl.deleteProgram(program);\n }\n \n </script>\n <!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS -->\n \n <!-- BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB -->\n </body>\n </html>Run Code Online (Sandbox Code Playgroud)\r\n