2014-09-29 22 views
8

Tôi đã ghép nối các ví dụ trực tuyến để tạo ra một bộ đổ bóng tập hợp Mandelbrot Set. Trình đổ bóng đỉnh không có gì cơ bản, nó chỉ định gl_Position và trình đổ bóng phân đoạn thực hiện một số phép toán để tính toán hình ảnh.Gửi các biến JavaScript tới trình đổ đoạn phân đoạn

Tuy nhiên, tôi có một số #define mà tôi muốn thay thế bằng các biến được kiểm soát bằng JavaScript và tôi không biết cách thực hiện điều này. Nếu một ví dụ có thể được hiển thị về cách thay thế #define MAX_ITERATIONS 200 bằng biến được gán JavaScript trong mã bên dưới, tôi có thể tìm ra phần còn lại của chúng. Tôi tin rằng tôi cần chỉ định một số uniform hoặc varying nhưng không chắc chắn cách quản lý giao tiếp từ JavaScript đến GLSL.

Ngoài ra tôi không hiểu cách aPosition hoạt động giữa JavaScript và trình đổ bóng đỉnh, những gì tôi có cơ bản giống như các ví dụ.

Javascript, tôi sẽ tưởng tượng chỉ init() vấn đề cho độc giả SO, phần còn lại được đăng tải nếu cần thiết:

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; 
} 

Vertex Shader:

attribute vec2 aPosition; 

void main() { 
    gl_Position = vec4(aPosition, 0.0, 1.0); 
} 

Fragment Shader, MAX_ITERATIONS , XMIN, YMINWH nên được kiểm soát trong 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); 
    } 
} 

Trả lời

13

Câu trả lời ngắn gọn là bạn có 2 lựa chọn cơ bản

  1. giá trị đèo từ hoạt Javascript để GLSL bởi thống nhất.

    Ví dụ, nếu bạn muốn vượt qua một phao tạo một bộ đồng phục phao

    uniform float foo; 
    

    Trong JavaScript biên dịch và liên kết Shader đó, sau đó tra cứu vị trí của đồng phục

    var locationOfFoo = gl.getUniformLocation(someProgram "foo"); 
    

    Bây giờ bạn có thể vượt qua một giá trị cho GLSL với

    gl.useProgram(someProgram) 
    gl.uniform1f(locationOfFoo, valueToPass); 
    
  2. Thao tác chuỗi trước khi biên dịch ing đổ bóng

    #define MAX_INTERATIONS %maxIterations% 
    #define XMIN %xMin% 
    

    ...

    var maxIterations = 123; 
    var xMin = 4.5; 
    shaderSource = shaderSource.replace(/%maxIterations%/g, maxIterations); 
    shaderSource = shaderSource.replace(/%xMin%/g, xMin); 
    

(1) ở trên là cho đi thứ mà thay đổi thường xuyên. # 2 là để thay đổi một shader trước khi nó được biên dịch. # 1 là một kỹ thuật được sử dụng trong khá nhiều 100% các chương trình WebGL. # 2 được sử dụng thường xuyên khi tạo bóng đổ trên bay mà nhiều công cụ trò chơi làm.

0

Tôi mất khoảng 45 phút để thực hiện gman's câu trả lời vì Tôi tiếp tục mắc các lỗi nhỏ ngu ngốc.Vì vậy, đây là mã làm việc đầy đủ mẫu tạo bản đồ có thể điều chỉnh được.

Tested Trong: Chrome, Internet Explorer, và Edge:

<!DOCTYPE HTML > 
<html lang="en"> 
<head> 
<meta charset="UTF-8"> 
<title>   GL_TILE_TESTBED   </title> 
<!-- AUTHOR: John Mark Isaac Madison   --> 
<!-- EMAIL : [email protected]    --> 
<!-- SSSSSSSSS SHADER_SECTION START SSSSSSSSS --> 
<!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS --> 
<!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS --> 
<style> 

    p{ font-size:12pt;} 
    h3,p,input,button,br{ 
     padding:0px; 
     margin:0px; 
     font-family:"Andale Mono"; 
    } 
    button,input{ 
     padding:10px; 
    } 
</style> 
<script id="VERT_SHADER" type="NOT_JAVASCRIPT"> 
    precision highp float; 

    attribute vec2 a_position; 
    void main() { 
    gl_Position = vec4(a_position, 0, 1); 
    } 
</script> 


<script id="FRAG_SHADER" type="NOT_JAVASCRIPT"> 

    //Must declare precision before declaring 
    //any uniforms: 
    //////////////////////////////////////////////// 
    #ifdef GL_FRAGMENT_PRECISION_HIGH 
    precision highp float; 
    #else 
    precision mediump float; 
    #endif 
    precision mediump int; 
    //////////////////////////////////////////////// 

    #define CANVAS_WID 640.0 
    #define CANVAS_HIG 480.0 

    #define TIL_WID  64.0 
    #define TIL_HIG  64.0 

    //Uniforms exposed to HTML/JAVASCRIPT: 
    uniform float TIL_WID_EDIT; 
    uniform float TIL_HIG_EDIT; 

    float til_wid; 
    float til_hig; 


    void main() { 

    //If uniforms have not set by user, 
    //use the default values set by the #define(s) 
    //==========================================// 
    if(TIL_WID_EDIT > 0.0){ 
     til_wid = TIL_WID_EDIT; 
    }else{ 
     til_wid = TIL_WID; 
    } 

    if(TIL_HIG_EDIT > 0.0){ 
     til_hig = TIL_HIG_EDIT; 
    }else{ 
     til_hig = TIL_HIG; 
    } 
    //==========================================// 

    //NOTE: on "gl_FragCoord" range: 
    //******************************************// 
    //web-gl: In terms of pixel/canvas coords. 
    //OpenGL: In terms of 0 to 1. 
    //******************************************// 

    //:Calculate number of tiles shown on screen: 
    //:This may be fractional: 
    float NUM_TIL_X = CANVAS_WID/til_wid; 
    float NUM_TIL_Y = CANVAS_HIG/til_hig; 


    vec2 FC_MOD; 
    FC_MOD.x = gl_FragCoord.x; 
    FC_MOD.y = gl_FragCoord.y; 

    //You want all tiles to have the full range 
    //of colors, so you always modulate by 
    //CANVAS_WID and CANVAS_HIG, You scale by the 
    //# of tiles on each axis which means the 
    //gradient becomes steeper as the # of tiles 
    //increases. 
    FC_MOD.x = mod(gl_FragCoord.x*NUM_TIL_X, CANVAS_WID); 
    FC_MOD.y = mod(gl_FragCoord.y*NUM_TIL_Y, CANVAS_HIG); 

    //[N]ormalize values into range 0 to 1: 
    //NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN// 
    float norm_X = (FC_MOD.x)/CANVAS_WID; 
    float norm_Y = (FC_MOD.y)/CANVAS_HIG; 
    //NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN// 

    //Use [B]lue channel because why not? 
    //BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB// 
    float GRAD_X = gl_FragCoord.x/CANVAS_WID; 
    //BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB// 

    //Set the final [F]ragment colors: 
    //FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF// 
    gl_FragColor = vec4(norm_X, norm_Y, GRAD_X, 1.0); 
    //FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF// 
    } 
</script> 
<!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS --> 
<!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS --> 
<!-- SSSSSSSSSS SHADER_SECTION END SSSSSSSSSS --> 
</head> 
<!-- HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH --> 

<!-- BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB -->      
<body onload="ON_LOADED_FUNCTION()" > 
<!-- BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB --> 

    <h3> Open GL Tile TestBed   <h3> 
    <p> Author: John Mark Isaac Madison <p> 
    <p> Email : [email protected] <p> 

    <canvas id="glCanvas"></canvas> 

    </br> 
    <button onClick="PUT_WID();">TILE_WIDTH__IN_PIXELS</button> 
    <input type="text" id="INPUT_WID" value="45"> 
    </br> 

    </br> 
    <button onClick="PUT_HIG();">TILE_HEIGHT_IN_PIXELS</button> 
    <input type="text" id="INPUT_HIG" value="45"> 
    </br> 



<!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS --> 
<script id="BOILER_PLATE_CODE"> 
    function ON_LOADED_FUNCTION(){ 
     console.log("[ON_LOADED_FUNCTION]"); 
     main(); 
    } 

    //:Takes the gl context object, if the input 
    //:is null, we likely failed to get the 
    //:context. 
    function HAS_OPEN_GL_CHECK(gl){ 
     // Only continue if WebGL is 
     // available and working 
     if (!gl) { 
     var msg = ""; 
     msg += "[Unable to initialize WebGL.]"; 
     msg += "[your browser or machine may]"; 
     msg += "[not support it.]" 
     alert(msg); 
     return; 
     } 
    } 

    function GET_INPUT_BOX_VALUE(elem_id){ 
     var box; //DOM input box 
     var val; //Value in input box. 
     box = document.getElementById(elem_id); 
     val = box.value; 
     return (0 + val); //cast to number. 
    } 

    function PUT_WID(){ 
     assert_program_and_gl_exist(); 
     var val = GET_INPUT_BOX_VALUE("INPUT_WID"); 
     SET_ATTR("TIL_WID_EDIT", val); 
    } 

    function PUT_HIG(){ 
     assert_program_and_gl_exist(); 
     var val = GET_INPUT_BOX_VALUE("INPUT_HIG"); 
     SET_ATTR("TIL_HIG_EDIT", val); 
    } 

    function SET_ATTR(gl_var_name, val){ 
     if(val < 0 || val > 256){ 
      alert("choose value between 0 to 256"); 
      return; 
     } 

     var loc; //<--location of variable. 
     loc = gl.getUniformLocation(
      program , 
      gl_var_name 
     ); 
     gl.useProgram(program); 
     gl.uniform1f(loc, val); 
    } 

    function assert_program_and_gl_exist(){ 
     if(!program){慌("[NO_PROGRAM_EXISTS]");} 
     if(!gl ){慌("[NO_GL_EXISTS]");} 
    } 

    //慌: "disconcerted, be confused, lose one's head" 
    //慌: In Code: ~Panic~ 
    function 慌(panic_message){ 
     console.log(panic_message); 
     alert  (panic_message); 
     throw  (panic_message); 
    } 

    function makeOpenGlContextUsingCanvas(c){ 

     //:Try what works in chrome and all the 
     //:respectable browsers first: 
     gl = c.getContext("webgl"); 

     if(!gl){ 
      console.log("[Probably_In_IE]"); 
      gl = c.getContext("experimental-webgl"); 
     }else{ 
      console.log("[Probably_NOT_IE]"); 
     } 

     HAS_OPEN_GL_CHECK(gl); 
     return gl; 
    } 

    //: No "var" prefix, making them global: 
    function initGlobals(){ 
     canvas = document.querySelector("#glCanvas"); 
     if(!canvas){ 
      alert("FAILED_TO_GET_CANVAS"); 
     }else{ 
      console.log("[GOT_CANVAS]"); 
     } 

     gl = makeOpenGlContextUsingCanvas(canvas); 


     //These dimensions are hard-coded into 
     //fragment shader code, so be careful 
     //about changing them: 
     canvas.width = 640; 
     canvas.height= 480; 

     buffer = gl.createBuffer(); 
     gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 
     gl.bufferData(
     gl.ARRAY_BUFFER, 
     new Float32Array([ 
      -1.0, -1.0, 
      1.0, -1.0, 
      -1.0, 1.0, 
      -1.0, 1.0, 
      1.0, -1.0, 
      1.0, 1.0]), 
     gl.STATIC_DRAW 
     ); 

     //G == Global Container. 
     //To fix problems with rendering in I.E. 
     //(Internet Explorer) 
     //GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG// 
     var G = {}; 
     G.canvas = canvas; 
     G.gl  = gl; 
     G.buffer = buffer; 

     if(! G.canvas || 
      ! G.gl  || 
      ! G.buffer ){ 
      慌("[Global_Container_Broken]"); 
     } 

     return G; 
     //GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG// 
    } 

    function main(){ 

     G = initGlobals(); 
     HAS_OPEN_GL_CHECK(G); 

     gl.viewport(0,0,gl.drawingBufferWidth, gl.drawingBufferHeight); 

     setup(); 
     render(); 
    } 

    function setup(){ 
     var frag_dom = document.getElementById("FRAG_SHADER"); 
     var frag_src = frag_dom.text; 
     console.log(frag_src); 

     F = createShader(
      gl,gl.FRAGMENT_SHADER, frag_src 
     ); 

     var vert_dom = document.getElementById("VERT_SHADER"); 
     var vert_src = vert_dom.text; 
     console.log(vert_src); 

     V = createShader(
      gl, gl.VERTEX_SHADER, vert_src 
     ); 

     //**** MAKE "program" a GLOBAL VAR ****// 
     program = createProgram(gl,V,F); 
     gl.useProgram(program); 

     if(!program){ 
      慌("PROGRAM_IS_NULL"); 
     } 
    } 

    function render(){ 
     window.requestAnimationFrame(render,canvas); 

     // Set clear color to black, fully opaque 
     gl.clearColor(0.0, 0.0, 0.5, 1.0); 

     // Clear the color buffer with specified clear color 
     gl.clear(gl.COLOR_BUFFER_BIT); 

     //Directly before call to gl.drawArrays: 
     positionLocation = gl.getAttribLocation(program, "a_position"); 
     gl.enableVertexAttribArray(positionLocation); 
     gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); 


     gl.drawArrays(gl.TRIANGLES, 0, 6); 
    } 

    function createShader(gl,type,source){ 
     //:Error Check For Bad Inputs: 
     if(!gl ){慌("[NULL_GL]");} 
     if(!type ){慌("[NULL_TY]");} 
     if(!source){慌("[NULL_SR]");} 

     var shader = gl.createShader(type); 
     gl.shaderSource(shader, source); 
     gl.compileShader(shader); 
     var res = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 
     if(res){ 
      console.log("[SHADER_COMPILED!]"); 
      return shader; 
     } 

     console.log(gl.getShaderInfoLog(shader)); 
     gl.deleteShader(shader); 
     慌("[FAILED_TO_COMPILE_SHADER]"); 
    } 

    //:gl : openGL context : 
    //:vert: vertex shader : 
    //:frag: fragment shader: 
    function createProgram(gl,vert, frag){ 
     var program = gl.createProgram(); 
     gl.attachShader(program, vert); 
     gl.attachShader(program, frag); 
     gl.linkProgram (program); 
     var res = gl.getProgramParameter(program, gl.LINK_STATUS); 
     if(res){ 
      console.log("[PROGRAM_CREATED!]"); 
      return program; 
     } 

     console.log(gl.getProgramInfoLog(program)); 
     gl.deleteProgram(program); 
    } 

</script> 
<!-- SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS --> 

<!-- BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB --> 
</body> 
</html> 
Các vấn đề liên quan