简体   繁体   English

什么是WebGL2RenderingContext.attachShader?

[英]What is WebGL2RenderingContext.attachShader?

I'm currently going through this WebGL tutorial and the section that I'm on is supposed to teach you to draw a white square on a black canvas. 我目前正在阅读本WebGL教程 ,本节内容应该是教您在黑色画布上绘制白色正方形。 Not very exciting, and especially unexciting since all I'm getting is a black canvas. 不太令人兴奋,尤其令人兴奋,因为我得到的只是一块黑色帆布。

The firefox console says "Argument 2 of WebGL2RenderingContext.attachShader is not an object." Firefox控制台说“ WebGL2RenderingContext.attachShader的参数2不是对象。” This doc for WebGL2RenderingContext doesn't saying anything about attachShader (which is called on lines 4 and 5 of initShaders ). 这篇关于WebGL2RenderingContext 文档没有提到关于attachShader任何内容(在attachShader第4行和第5行initShaders )。 I also find it strange that the function getShader isn't passed a 3rd argument even though it's defined with 3. 我也感到奇怪的是,即使函数getShader用3定义,也没有传递第3个参数。

Another possible issue, unrelated to what firefox says, might have to do with the fact that when I tried to keep the shader scripts and main script in separate files nothing was displayed on the page when I opened it. 与firefox所说的无关的另一个可能的问题可能与以下事实有关:当我尝试将着色器脚本和主脚本保存在单独的文件中时,在打开该文件时页面上未显示任何内容。 This could be a problem because the tutorial uses 2 scripts that I had to download from github here . 由于教程使用2个脚本,我不得不从GitHub下载这可能是一个问题在这里

Here is index.html, all my code is almost exactly the same as the tutorial, but I made it slightly more concise because they were essentially redefining functions that are already a part of the API. 这是index.html,我的所有代码几乎都与本教程完全相同,但是我使它更加简洁,因为它们本质上是重新定义了已经包含在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>

the main javascript: 主要的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);
}

frag shader: 片段着色器:

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

TL;DR TL; DR

gl.attachShader isn't exclusive to WebGL 2. Its a function that is available from any WebGL context. gl.attachShader并非WebGL 2独有。它是一个可从任何WebGL上下文获得的功能。 It's used to tie vertex\\fragment shaders together to a program to setup a rendering state [Link] . 它用于将顶点\\片段着色器绑定到一个程序以设置渲染状态[Link]

To go more in depth into what this tutorial is attempting to convey, I've provided a sample below. 为了更深入地了解本教程试图传达的内容,我在下面提供了一个示例。 Hopefully you find it useful. 希望您发现它有用。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 WebGL:INVALID_VALUE:attachShader:没有删除任何对象或对象。 这秘密有用吗? - WebGL: INVALID_VALUE: attachShader: no object or object deleted. Is this secretly helpful? WebGL-如何在Typescript中将程序参数正确传递给gl.attachShader? - WebGL - How do I pass in the program parameter to gl.attachShader correctly in Typescript? 尝试使用 tsc file.ts 运行 Typescript 时出现 WebGL2RenderingContext 错误 - WebGL2RenderingContext Error when trying to run Typescript with tsc file.ts 未捕获(承诺)DOMException:无法在“WebGL2RenderingContext”上执行“texImage2D”:可能无法加载受污染的画布 - Uncaught (in promise) DOMException: Failed to execute 'texImage2D' on 'WebGL2RenderingContext': Tainted canvases may not be loaded gl.attachShader 不是 object - gl.attachShader is not an object 什么是webgl中的VertexIndices? - What are VertexIndices in webgl? 无法在“WebGL2RenderingContext”上执行“texImage2D”。 CORS 已阻止从源“exampale.com”访问“imageurl.com”上的图像 - Failed to execute 'texImage2D' on 'WebGL2RenderingContext'. Access to image at 'imageurl.com' from origin 'exampale.com' has been blocked by CORS webgl中绑定缓冲区的逻辑是什么? - What is the logic of binding buffers in webgl? 什么是WebGL的绘制原语? - What are WebGL's draw primitives? WebGL场景的安全数量的三角形/顶点是多少? - What is a safe number of triangles/vertexes for a WebGL scene?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM