gpt4 book ai didi

javascript - 什么是 WebGL2RenderingContext.attachShader?

转载 作者:行者123 更新时间:2023-11-28 04:18:20 27 4
gpt4 key购买 nike

我目前正在经历this WebGL tutorial我现在所在的部分应该教您在黑色 Canvas 上绘制白色正方形。不是很令人兴奋,尤其是平淡无奇,因为我得到的只是一 block 黑色 Canvas 。

Firefox 控制台显示“WebGL2RenderingContext.attachShader 的参数 2 不是对象。” This doc for WebGL2RenderingContext 没有提及任何关于 attachShader 的内容(在 initShaders 第 4 行和第 5 行调用)。我还发现奇怪的是,函数 getShader 没有传递第三个参数,即使它是用 3 定义的。

另一个可能的问题,与 Firefox 所说的无关,可能与以下事实有关:当我尝试将着色器脚本和主脚本保存在单独的文件中时,当我打开页面时,页面上没有显示任何内容。这可能是一个问题,因为本教程使用了 2 个脚本,我必须从 github here 下载这些脚本。 .

这里是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>

主要的 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);
}

顶点着色器:

attribute vec3 aVertexPosition;

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

碎片着色器:

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

最佳答案

TL;DR

gl.attachShader 并不是 WebGL 2 独有的。它是一个可从任何 WebGL 上下文中使用的函数。它用于将顶点\片段着色器与程序绑定(bind)在一起以设置渲染状态 [Link] .

为了更深入地了解本教程试图传达的内容,我在下面提供了一个示例。希望您觉得它有用。

<!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, I.E. 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.
// e.g.
//
// 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
// e.g. 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, I.e. 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.
//
// E.G.
// 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
); // E.G. 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>

关于javascript - 什么是 WebGL2RenderingContext.attachShader?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45655091/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com