Iba a escribir un tutorial y publicarlo en mi blog, pero no sé cuándo tendré tiempo para terminar, así que esto es lo que tengo
Here's a more detailed set of posts on my blog.
WebGL es en realidad una biblioteca de rasterización. Obtengo atributos (flujos de datos), uniformes (variables) y espero que proporcione coordenadas de "espacio de clip" en 2d y datos de color para píxeles.
Aquí está un ejemplo simple de 2D en WebGL (algunos detalles quedan fuera)
// Get A WebGL context
var gl = canvas.getContext("experimental-webgl");
// setup GLSL program
vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);
// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "a_position");
// Create a buffer and put a single clipspace rectangle in
// it (2 triangles)
var 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);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// draw
gl.drawArrays(gl.TRIANGLES, 0, 6);
aquí está el 2 shaders
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
void main() {
gl_Position = vec4(a_position, 0, 1);
}
</script>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
void main() {
gl_FragColor = vec4(0,1,0,1); // green
}
</script>
Esto dibujará un rectángulo verde todo el tamaño del lienzo.
En WebGL es su responsabilidad proporcionar un sombreador de vértices que proporcione coordenadas de espacio de clips. Las coordenadas del espacio de clips siempre van de -1 a +1 independientemente del tamaño del lienzo. Si desea 3d le toca a usted para suministrar shaders que convierten a partir de 3d a 2d porqueWebGL es sólo una API de rasterización
En un ejemplo sencillo, si se desea trabajar en píxeles que podría pasar en un rectángulo que utiliza píxeles en lugar de las coordenadas espaciales de clip y Convertir en clip espacio en el shader
por ejemplo:
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
uniform vec2 u_resolution;
void main() {
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position/u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace, 0, 1);
}
</script>
Ahora podemos dibujar rectángulos cambiando los datos que la oferta
// set the resolution
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
// setup a rectangle from 10,20 to 80,30 in pixels
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
10, 20,
80, 20,
10, 30,
10, 30,
80, 20,
80, 30]), gl.STATIC_DRAW);
Notará que WebGL considera que la esquina inferior derecha es 0,0. Para que sea la esquina superior derecha más tradicional que se usa para los gráficos 2D, solo volteamos la coordenada y.
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
Quiere manipular las imágenes que necesita para pasar las texturas.De la misma manera el tamaño del lienzo está representado por clipspace coordina las texturas se están referenciados por las coordenadas de texturas que van de 0 a 1.
<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position/u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace, 0, 1);
// pass the texCoord to the fragment shader
// The GPU will interpolate this value between points.
v_texCoord = a_texCoord;
}
</script>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision float mediump;
// our texture
uniform sampler2D u_image;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
void main() {
gl_FragColor = texture2D(u_image, v_texCoord);
}
</script>
Para dibujar una imagen requiere cargar la imagen y puesto que esto suceda de forma asíncrona que necesitamos para cambiar nuestro código un poco. Tome todo el código que teníamos y lo puso en una función llamada "render"
var image = new Image();
image.src = "http://someimage/on/our/server"; // MUST BE SAME DOMAIN!!!
image.onload = function() {
render();
}
function render() {
...
// all the code we had before except gl.draw
// look up where the vertex data needs to go.
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
// provide texture coordinates for the rectangle.
var texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
1.0, 1.0,
0.0, 0.0,
1.0, 0.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(texCoordLocation);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.draw(...)
Si usted quiere hacer el procesamiento de la imagen que acaba de cambiar de sombreado. Ejemplo, Cambiar rojo y azul
void main() {
gl_FragColor = texture2D(u_image, v_texCoord).bgra;
}
O combinar con los píxeles junto a él.
uniform vec2 u_textureSize;
void main() {
vec2 onePixel = vec2(1.0, 1.0)/u_textureSize;
gl_FragColor = (texture2D(u_image, v_texCoord) +
texture2D(u_image, v_texCoord + vec2(onePixel.x, 0.0)) +
texture2D(u_image, v_texCoord + vec2(-onePixel.x, 0.0)))/3.0;
}
y tenemos que pasar en el tamaño de la textura
var textureSizeLocation = gl.getUniformLocation(program, "u_textureSize");
...
gl.uniform2f(textureSizeLocation, image.width, image.height);
etc ... Haga clic en el último eslabón abajo para una muestra de convolución.
Aquí están las versiones trabajando con una progresión ligeramente diferente
Draw Rect in Clip Space
Draw Rect in Pixels
Draw Rect with origin at top left
Draw a bunch of rects in different colors
Draw an image
Draw an image red and blue swapped
Draw an image with left and right pixels averaged
Draw an image with a 3x3 convolution
Draw an image with multiple effects
Ahora puedo renderizar una imagen plana en el lienzo. ¿Es posible escribirlo sin la parte 3D? En cuanto a los materiales de aprendizaje, ¿qué debería buscar exactamente? Parece que hay OpenGL ES, el OpenGL normal, GLSL, WebGL junto con todas las versiones diferentes también. –
Podrías dibujar tu textura con proyección orográfica con un cuadrante alineado con la pantalla. De los materiales de aprendizaje puede enfocarse en GLSL, que es el idioma que va a usar para sus efectos. – Chiguireitor