2017-08-12 3 views
0

Je passe actuellement par this WebGL tutorial et la section sur laquelle je suis est censée vous apprendre à dessiner un carré blanc sur une toile noire. Pas très excitant, et surtout pas excitant car tout ce que je reçois est une toile noire.Qu'est-ce que WebGL2RenderingContext.attachShader?

La console firefox indique "Argument 2 de WebGL2RenderingContext.attachShader n'est pas un objet." This doc pour WebGL2RenderingContext ne dit rien sur attachShader (qui est appelé sur les lignes 4 et 5 de initShaders). Je trouve également étrange que la fonction getShader ne passe pas un 3ème argument même si elle est définie avec 3.

Un autre problème possible, sans rapport avec ce que firefox dit, pourrait avoir à faire avec le fait que lorsque j'ai essayé de garder les scripts de shader et le script principal dans des fichiers séparés rien n'était affiché sur la page quand je l'ai ouvert. Cela pourrait poser un problème car le tutoriel utilise 2 scripts que j'ai dû télécharger depuis github: here.

Voici index.html, tout mon code est presque exactement le même que le tutoriel, mais je l'ai fait légèrement plus concis car ils redéfinissaient essentiellement des fonctions qui font déjà partie de l'API.

<!DOCTYPE html> 
<html lang="en"> 
<head> 
    <meta charset="utf-8"/> 

    //the two scripts from github 
    <script src="sylvester.js" type="text/javascript"/> 
    <script src="glUtils.js" type="text/javascript"/> 

    <script type="x-shader/x-vertex" id="shader-vs"> 
    //vertex shader goes here 
    </script> 
    <script type="x-shader/x-fragment" id="shader-fs"> 
    //frag shader goes here 
    </script> 
    <script type="text/javascript"> 
     //main javascript goes here 
    </script> 
</head> 
<body onload="start()"> 
    <canvas id="glCanvas" width="640" height="480"> 
    Your browser doesn't appear to support the 
    <code>&lt;canvas&gt;</code> element. 
    </canvas> 
</body> 

principal javascript:

 var canvas; 
     var gl; 
     var squareVerticesBuffer; 
     var mvMatrix; 
     var shaderProgram; 
     var vertexPositionAttribute; 
     var perspectiveMatrix; 
     var horizAspect = 480.0/640.0; 
     function setMatrixUniforms(){ 
      var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix"); 
      gl.uniformMatrix4fv(pUniform, false, new Float32Array(perspectiveMatrix.flatten())); 
      var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); 
      gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten())); 
     } 

     function getShader(gl, id, type){ 
      var shaderScript , theSource, currentChild, shader; 
      shaderScript = document.getElementById(id); 
      if(!shaderScript){ 
       console.log("Couldn't find shader script"); 
       return null; 
      } 
      theSource = shaderScript.text; 
      if(!type){ 
       if(shaderScript.type == 'x-shader/x-fragment'){ 
       type = gl.FRAGMENT_SHADER; 
       } 
       else if (shaderScript.type == 'x-shader/x-vertex'){ 
       type = gl.VERTEX_SHADER; 
       } 
       else { 
       console.log("Shader is not of a valid type"); 
       return null; 
       } 
      } 
      shader = gl.createShader(type); 
      gl.shaderSource(shader, theSource); 
      gl.compileShader(shader); 
      if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)){ 
       console.log("An error occured compiling the shaders:" 
       + gl.getShaderInfoLog(shader)); 
       gl.deleteShader(shader); 
       return null; 
      } 
      return shader; 
      } 

     function initShaders() { 
      var fragmentShader = getShader(gl, 'shader-fs'); 
      var vertexShader = getShader(gl, 'shader-vs'); 

      shaderProgram = gl.createProgram(); 
      gl.attachShader(shaderProgram, vertexShader); 
      gl.attachShader(shaderProgram, fragmentShader); 
      gl.linkProgram(shaderProgram); 
      if(!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { 
       console.log('Unable to initialize the shader program: ' 
          + gl.getProgramInfoLog(shaderProgram)); 
      } 
      gl.useProgram(shaderProgram); 
      vertexPositionAttribute = gl.getAttribLocation(shaderProgram, 'aVertexPosition'); 
      gl.enableVertexAttribArray(vertexPositionAttribute); 
     } 

     function initBuffers(){ 
      squareVerticesBuffer = gl.createBuffer(); 
      gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); 
      var vertices = [1.0, 1.0, 0.0, 
        -1.0, 1.0, 0.0, 
        1.0, 1.0, 0.0, 
        -1.0, -1.0, 0.0]; 
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 
     } 

     function drawScene(){ 
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 
      perspectiveMatrix = makePerspective(45, 4.0/3.0, 0.1, 100.0); 
      //perspectiveMatrix = makePerspective(45, 640.0/480.0, 0.1, 100.0); 
      mvMatrix = Matrix.I(4); 
      mvMatrix.x(Matrix.Translation($V([-0.0, 0.0, -6.0])).ensure4x4()) 
      gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer); 
      gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); 
      setMatrixUniforms(); 
      gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4); 
     } 

     function start() { 
      var canvas = document.getElementById('glCanvas'); 
      // Initialize the GL context 
      var opts = { }; 
      gl = canvas.getContext("webgl2", opts); 
      if(!gl) gl = canvas.getContext("experimental-webgl2", opts); 
      if(!gl) gl = canvas.getContext("webgl", opts); 
      if(!gl) gl = canvas.getContext("experimental-webgl", opts); 

      gl.clearColor(0.0, 0.0, 0.0, 1.0); 
      gl.enable(gl.DEPTH_TEST); 
      gl.depthFunc(gl.LEQUAL); 
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 
      gl.viewport(0, 0, canvas.width, canvas.height); 
      initShaders(); 
      initBuffers(); 
      setInterval(drawScene, 15); 
     } 

vertex shader:

attribute vec3 aVertexPosition; 

uniform mat4 uMVMatrix; 
uniform mat4 uPMatrix; 
void main(void) { 
    gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); 
} 

shader frag:

void main(void) { 
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); 
} 
+0

La méthode [ 'WebGLRenderingContext.attachShader()'] (https://developer.mozilla.org/de/docs/Web/API/WebGLRenderingContext/attachShader) de l'API WebGL attache un fragment ou un sommet WebGLShader à un WebGLProgram. – Rabbid76

+1

J'avais suggéré [ces tutoriels] (https://webgl2fundamentals.org). – gman

+0

Hey, le doc que vous suivez est basé sur 'webgl', mais dans votre code, le contexte de votre get est' webgl2' :) –

Répondre

0

TL; DR

gl.attachShader n'est pas exclusif à WebGL 2. C'est une fonction disponible dans n'importe quel contexte WebGL. Il est utilisé pour lier ensemble les vertex \ fragment shaders à un programme pour configurer un état de rendu [Link].

Pour aller plus en profondeur dans ce que ce tutoriel essaie de transmettre, j'ai fourni un exemple ci-dessous. J'espère que vous le trouverez utile.

<!doctype html> 
 
<!-- lets the browser know that this is a HTML page --> 
 

 
<html> 
 
\t <head> 
 
\t \t <!-- UTF-8 Encoding, it'll complain if you don't use this --> 
 
\t \t <meta charset="utf-8"> 
 
\t \t <!-- Just some inlined CSS to style and center the canvas --> 
 
\t \t <style> 
 
\t \t \t body { 
 
\t \t \t \t background-color: black; 
 
\t \t \t } 
 
\t \t \t 
 
\t \t \t canvas { 
 
\t \t \t \t position: absolute; 
 
\t \t \t \t margin: auto; 
 
\t \t \t \t left: 0; 
 
\t \t \t \t right: 0; 
 
\t \t \t \t border: solid 3px white; 
 
\t \t \t \t border-radius: 20px; 
 
\t \t \t } 
 
\t \t </style> 
 
\t </head> 
 
\t 
 
\t <body> 
 
\t \t <canvas id="canvas"></canvas> 
 
\t 
 
\t \t <!-- 
 
\t \t \t The script "type" doesn't matter, we just want to use it to load shader source code 
 
\t \t \t If it isn't labled as a valid JS type the browser won't try to execute it 
 
\t \t --> 
 
\t \t <script id="vertexShader" type="glShader"> 
 
\t \t \t precision lowp float; 
 
\t \t \t 
 
\t \t \t attribute vec2 aPos; 
 
\t \t \t 
 
\t \t \t void main() { 
 
\t \t \t \t // If you are just making a square you don't need a projection matrix 
 
\t \t \t \t // The 2D coordinates are in the range of X: -1 -> +1 Y: -1 -> + 1 
 
\t \t \t \t gl_Position = vec4(aPos,0.0,1.0); 
 
\t \t \t } 
 
\t \t \t 
 
\t \t </script> 
 
\t \t <script id="fragmentShader" type="glShader"> 
 
\t \t \t precision lowp float; 
 
\t \t \t 
 
\t \t \t void main() { 
 
\t \t \t \t gl_FragColor = vec4(1.0,1.0,1.0,1.0); 
 
\t \t \t } 
 
\t \t </script> 
 
\t \t <script type="application/javascript"> 
 
\t \t \t 
 
\t \t \t // If you only want to draw a simple 2D shape, you don't really need to use any matricies 
 
\t \t \t 
 
\t \t \t // -- WebGL Variables -- 
 
\t \t \t var canvas = null; // A reference to the canvas (It doesn't contain the canvas it just has it's address) 
 
\t \t \t var gl = null; // A reference for the webGL context (You don't need to use WebGL 2) 
 
\t \t \t var VBO = null; // A reference for an OpenGL buffer that I'll use to store "Vertex Data" 
 
\t \t \t var program = null; // A reference to an OpenGL program, you can think of it as something similar to 
 
\t \t \t \t \t \t \t \t // a .exe in GPU memory that contains the code from your shaders 
 
\t \t \t 
 
\t \t \t // --------------------- 
 
\t \t \t 
 
\t \t \t // -- Normal Variables -- 
 
\t \t \t var width = 320; // Size of the canvas to set (in pixels) 
 
\t \t \t var height = 240; 
 
\t \t \t 
 
\t \t \t // A "Typed" array of 32 bit floats that will contain the vertex data that'll be uploaded to the gpu in the VBO buffer 
 
\t \t \t // (VBO means vertex buffer object, I.E. a buffer used to contain vertex data) 
 
\t \t \t // A full vertex (all the data for one corner of a mesh) would be a complete list of attributes for the vertex shader. 
 
\t \t \t // e.g. 
 
\t \t \t // 
 
\t \t \t // if in the vertex shader you had 
 
\t \t \t // attribute vec2 pos; 
 
\t \t \t // attribute vec3 colour; 
 
\t \t \t // 
 
\t \t \t // Then a single vertex would be a sequence of five floats that are split into these attribute values 
 
\t \t \t // e.g. 50.0, 50.0, 1.0,1.0,1.0, 
 
\t \t \t // would become 
 
\t \t \t // pos = vec2(50.0,50.0); 
 
\t \t \t // colour = vec3(1.0,1.0,1.0); 
 
\t \t \t // 
 
\t \t \t // The reason it's put into a "Float32Array" is so WebGL knows without having to do any checks that the 
 
\t \t \t // array you just gave it is exactly a list of 32 floats 
 
\t \t \t // You don't strictly need to do that as WebGL can figure out the type, its just not encouraged as it has quite the performance impact 
 
\t \t \t 
 
\t \t \t // Only has 1 attribute -> Pos 2D Vector 
 
\t \t \t // Triangles are drawn in groups of three verticies 
 
\t \t \t var squareVerticies = Float32Array.from([ 
 
\t \t \t \t // Top right -> top left -> bottom right (Its best to do triangles counter clockwise, look up gl.CULL_FACE for why is this the case) 
 
\t \t \t \t 0.5, 0.5, 
 
\t \t \t \t -0.5, 0.5, 
 
\t \t \t \t 0.5,-0.5, 
 
\t \t \t \t 
 
\t \t \t \t // Bottom Right -> top left -> bottom left 
 
\t \t \t \t 0.5,-0.5, 
 
\t \t \t \t -0.5, 0.5, 
 
\t \t \t \t -0.5,-0.5 
 
\t \t \t ]); 
 
\t \t \t // ---------------------- 
 
\t \t \t 
 
\t \t \t // Called after the page has loaded 
 
\t \t \t window.onload = function() { 
 
\t \t \t \t // Get canvas reference and set size 
 
\t \t \t \t canvas = document.getElementById("canvas"); 
 
\t \t \t \t canvas.width = width; 
 
\t \t \t \t canvas.height = height; 
 
\t \t \t \t 
 
\t \t \t \t // get WebGL context reference 
 
\t \t \t \t // No need to do checking, as 99% of modern browsers support WebGL 
 
\t \t \t \t gl = canvas.getContext("webgl"); 
 
\t \t \t \t 
 
\t \t \t \t // In essence to draw your square you need to seperate things 
 
\t \t \t \t // A program (made of a vertex and fragment shader) that will say how to render the square 
 
\t \t \t \t // And some input data (In this case the VBO) that will be what you want to render (The coordinates of the square) 
 
\t \t \t \t // So each one should be considered seperately and can be setup in either order 
 
\t \t \t \t 
 
\t \t \t \t // -- Program Setup -- 
 
\t \t \t \t 
 
\t \t \t \t // Extract shader code from script tags 
 
\t \t \t \t var vertexShaderCode = document.getElementById("vertexShader").innerHTML; 
 
\t \t \t \t var fragmentShaderCode = document.getElementById("fragmentShader").innerHTML; 
 
\t \t \t \t 
 
\t \t \t \t // Create references to brand new shaders in GPU memory 
 
\t \t \t \t var vertexShader = gl.createShader(gl.VERTEX_SHADER); 
 
\t \t \t \t var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER); 
 
\t \t \t \t 
 
\t \t \t \t // Upload shader source code 
 
\t \t \t \t gl.shaderSource(vertexShader,vertexShaderCode); 
 
\t \t \t \t gl.shaderSource(fragmentShader,fragmentShaderCode); 
 
\t \t \t \t 
 
\t \t \t \t // Compile Shaders 
 
\t \t \t \t gl.compileShader(vertexShader); 
 
\t \t \t \t gl.compileShader(fragmentShader); 
 
\t \t \t \t 
 
\t \t \t \t // This function returns true/false depending on if the shaders compiled correctly 
 
\t \t \t \t // In this case I'm checking if either one is false, I.e. if either failed to compile 
 
\t \t \t \t if (!gl.getShaderParameter(vertexShader,gl.COMPILE_STATUS) || 
 
\t \t \t \t \t !gl.getShaderParameter(vertexShader,gl.COMPILE_STATUS)) { 
 
\t \t \t \t \t 
 
\t \t \t \t \t // This runs if either shader had an error 
 
\t \t \t \t \t console.error(
 
\t \t \t \t \t \t "Vertex Shader: " + gl.getShaderInfoLog(vertexShader) + "\n" + 
 
\t \t \t \t \t \t "Fragment Shader: " + gl.getShaderInfoLog(fragmentShader) 
 
\t \t \t \t \t); 
 
\t \t \t \t \t 
 
\t \t \t \t \t // Release shader references since we don't need them if they don't work 
 
\t \t \t \t \t gl.deleteShader(vertexShader); 
 
\t \t \t \t \t gl.deleteShader(fragmentShader); 
 
\t \t \t \t \t 
 
\t \t \t \t \t // End the function early since no rendering will work with broken shaders 
 
\t \t \t \t \t return; 
 
\t \t \t \t } 
 
\t \t \t \t 
 
\t \t \t \t // At this point if there is no error, you have a valid vertex & fragment shader in GPU memory 
 
\t \t \t \t // But to be able to use them the two shaders need to be linked to gether 
 
\t \t \t \t // The "Thing" that will hold them together is called a program 
 
\t \t \t \t 
 
\t \t \t \t // Create reference to a new program in GPU memory (GPU memory is just RAM thats physically part of the GPU, often called VRAM) 
 
\t \t \t \t program = gl.createProgram(); 
 
\t \t \t \t 
 
\t \t \t \t // attachShader is used to link a vertex shader then a fragment shader with a new program 
 
\t \t \t \t gl.attachShader(program,vertexShader); 
 
\t \t \t \t gl.attachShader(program,fragmentShader); 
 
\t \t \t \t 
 
\t \t \t \t // Once you have two shaders attached linkProgram glues everything together and makes it ready for rendering 
 
\t \t \t \t gl.linkProgram(program); 
 
\t \t \t \t 
 
\t \t \t \t // You can now delete the shader references since the program now contains them 
 
\t \t \t \t gl.deleteShader(vertexShader); 
 
\t \t \t \t gl.deleteShader(fragmentShader); 
 
\t \t \t \t \t 
 
\t \t \t \t // And if you want to use different shaders, all you have to do is switch the current program 
 
\t \t \t \t gl.useProgram(program); 
 
\t \t \t \t \t 
 
\t \t \t \t // ------------------- 
 
\t \t \t \t 
 
\t \t \t \t // -- Vertex Buffer (VBO) Setup -- 
 
\t \t \t \t 
 
\t \t \t \t // this just creates a generic empty block of memory on the GPU you can use for anything! 
 
\t \t \t \t // (These blocks are called buffers) 
 
\t \t \t \t VBO = gl.createBuffer(); 
 
\t \t \t \t 
 
\t \t \t \t // In WebGL and OpenGL if you want to operate on peices of data in GPU memory (buffers & textures mostly) 
 
\t \t \t \t // They aren't directly access with a variable name but you need to "bind" them to the gl context 
 
\t \t \t \t // Think of it as having this kind of effect 
 
\t \t \t \t // \t \t currentBuffer = VBO; 
 
\t \t \t \t // \t \t currentBuffer.doThing() 
 
\t \t \t \t 
 
\t \t \t \t // This looks confusing but ARRAY_BUFFER is just the name of a varialbe in WebGL 
 
\t \t \t \t // Its a reference that is being set to the new buffer (literally just ARRAY_BUFFER = VBO) 
 
\t \t \t \t gl.bindBuffer(gl.ARRAY_BUFFER,VBO); 
 
\t \t \t \t 
 
\t \t \t \t // This uploads the vertex data explained earlier to the GPU 
 
\t \t \t \t // \t \t Here ARRAY_BUFFER = VBO 
 
\t \t \t \t // \t \t squareVerticies is the data being uploaded 
 
\t \t \t \t // \t \t and STATIC_DRAW is a hint to WebGL, its just giving it a hint what we intend to do with the data 
 
\t \t \t \t // \t \t all STATIC_DRAW means is that we're uploading some data we're going to use to render but we aren't going to be changing it 
 
\t \t \t \t // \t \t WebGL uses these hints to optimize the memory layout on the GPU, it does all this for you 
 
\t \t \t \t gl.bufferData(gl.ARRAY_BUFFER,squareVerticies,gl.STATIC_DRAW); 
 
\t \t \t \t 
 
\t \t \t \t // ------------------------- 
 
\t \t \t \t 
 
\t \t \t \t // and that is generally all you need to do to setup for rendering 
 
\t \t \t \t // All thats left is to make sure that the program you want to use is set and you tell 
 
\t \t \t \t // WebGL how to feed data from the VBO (squareVerticies on the GPU) 
 
\t \t \t \t // Into the vertex shader 
 
\t \t \t \t 
 
\t \t \t \t // The vertex shader operates on a single vertex at a time, and a vertex in terms of data is each collection of the attributes you made in the vertex shader 
 
\t \t \t \t // that can be taken from your VBO. 
 
\t \t \t \t // 
 
\t \t \t \t // E.G. 
 
\t \t \t \t // \t for this setup I'm using one attribute, "attribute vec2 aPos;" 
 
\t \t \t \t // that would mean every two floats in the array form one complete vertex 
 
\t \t \t \t // So what I need to do is tell WebGL that data format 
 
\t \t \t \t 
 
\t \t \t \t var posAttributeLocation = gl.getAttribLocation(program,"aPos"); 
 
\t \t \t \t gl.vertexAttribPointer(
 
\t \t \t \t \t posAttributeLocation, // The index of the attribute I'm telling you about 
 
\t \t \t \t \t 2, // The number of floats in that attribute (2D vector => 2 floats) 
 
\t \t \t \t \t gl.FLOAT, // The type of data I'm using, 
 
\t \t \t \t \t gl.FALSE, // If to normalize (You can ignore this, just keep it as false or gl.FALSE) 
 
\t \t \t \t \t 2 * Float32Array.BYTES_PER_ELEMENT, // The total size of a complete vertex in bytes (it's the number of floats of all the attributes combined * The size of a float in bytes (4 bytes)) 
 
\t \t \t \t \t 0 * Float32Array.BYTES_PER_ELEMENT // The offset in bytes that this attribute is at from the beginning of a vertex 
 
\t \t \t \t); \t \t \t \t \t \t \t \t \t \t // E.G. a float attribute thats after a 2D vector attribute would have an offset of 2 * Float32Array.BYTES_PER_ELEMENT = 8 bytes 
 
\t \t \t \t 
 
\t \t \t \t // The last step per attribute is to tell WebGL to "turn on" use of this attribute 
 
\t \t \t \t gl.enableVertexAttribArray(posAttributeLocation); 
 
\t \t \t \t 
 
\t \t \t \t // Repeating that process for each attribute will tell WebGL how to send the data to your vertex shader 
 
\t \t \t \t // This is also called setting up the buffers state 
 
\t \t \t \t // It's also worthy to keep in mind that when you bind a different buffer you will need to repeat this step, because until you repeat your calls to vertexAttribPointer. 
 
\t \t \t \t // Your vertex shader will still receive data from the previous buffer 
 
\t \t \t \t 
 
\t \t \t \t // Set RGBA value for the background color 
 
\t \t \t \t gl.clearColor(0.5,0.5,0.5,1.0); 
 
\t \t \t \t 
 
\t \t \t \t // Clears the canvas with the colour you gave 
 
\t \t \t \t gl.clear(gl.COLOR_BUFFER_BIT); 
 
\t \t \t \t 
 
\t \t \t \t // Draw using triangles from index 0 in the buffer to index 6 (With triangles it must be a factor of 3) 
 
\t \t \t \t gl.drawArrays(gl.TRIANGLES,0,6); 
 
\t \t \t } 
 
\t \t \t 
 
\t \t \t // Called when the page is about to close 
 
\t \t \t // Here I'll let go off the resources I asked WebGL to get on the GPU 
 
\t \t \t window.onbeforeunload = function() { 
 
\t \t \t \t gl.deleteProgram(program); 
 
\t \t \t \t gl.deleteBuffer(VBO); 
 
\t \t \t \t gl = null; 
 
\t \t \t } 
 
\t \t \t 
 
\t \t </script> 
 
\t </body> 
 
</html>