diff options
Diffstat (limited to 'files/es/web/api/webgl_api/tutorial')
8 files changed, 1082 insertions, 0 deletions
diff --git a/files/es/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html b/files/es/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html new file mode 100644 index 0000000000..595b0f57f1 --- /dev/null +++ b/files/es/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html @@ -0,0 +1,276 @@ +--- +title: Agregando Contenido 2D en el Contexto WebGL +slug: Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context +translation_of: Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context +--- +<div>{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL", "Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL")}}</div> + +<p>Una vez que has logrado <a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL">crear el contexto WebGL</a>, estás listo para crear objetos dentro del mismo. Algo sencillo que podemos hacer es pintar un simple cuadrado plano sin texturas, así que vamos a empezar desde ahí, creando el código para dibujar el cuadrado plano.</p> + +<h2 id="Dibujando_la_Escena">Dibujando la Escena</h2> + +<p>Lo mas importante que tenemos que entender antes de empezar, es que aún cuando dibujaremos un cuadrado plano en este ejemplo, estaremos trabajando en un espacio 3D. Lo que estaremos haciendo es dibujar un cuadrado plano y posicionándolo frente de la camara de forma perpendicular. Necesitaremos definir los Shaders que definirán el color para nuestra escena además de dibujar nuestro objeto. Esto establecerá cómo aparece el cuadrado plano en nuestra pantalla.</p> + +<h3 id="Los_Shaders">Los Shaders </h3> + +<p>Los shaders usan especificamente <a href="https://www.khronos.org/files/opengles_shading_language.pdf">OpenGL ES Shading Language</a>. Los detalles de la forma de trabajar de los shaders estan fuera del alcance de este articulo, como tambien la sintaxis del lenguaje de los shaders sin embargo la version corta es que hay 2 tipos de shaders (funciones que se ejecutan en la GPU) que necesitas escribir. shaders de vertices y shaders de fragmentos. Estos son pasados al WebGL como una cadena y compilados para ejecutarse en el GPU.</p> + +<h4 id="Shaders_de_Vértices">Shaders de Vértices</h4> + +<p>La responsabilidad de los Shaders de Vértices es asignar un valor a una variable especial <code>gl_Position</code> para crear los valores del espacio de trabajo (valores entre -1 y +1) en toda la zona del canvas. En nuestro Shader de Vértices de abajo estamos recibiendo valores de un atributo que definiremos como <code>aVertexPosition</code>. Estamos entonces multiplicando esa posición por dos matrices 4x4 que definimos como <code>uProjectionMatrix</code> y <code>uModelMatrix</code> e igualando <code>gl_Position</code> al resultado. Para más información sobre proyección y otras matrices <a href="https://webglfundamentals.org/webgl/lessons/webgl-3d-perspective.html">puedes encontrar útil este artículo</a>.</p> + +<pre class="brush: html"> // Vertex shader program + + const vsSource = ` + attribute vec4 aVertexPosition; + + uniform mat4 uModelViewMatrix; + uniform mat4 uProjectionMatrix; + + void main() { + gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition; + } + `; +</pre> + +<h4 id="Shaders_de_Fragmentos">Shaders de Fragmentos</h4> + +<p>Cada vez que el Shader de Vértices escribe de 1 a 3 valores al <code>gl_Position</code> este también dibujará un punto, una linea o un triángulo. Mientras éste esta dibujando, llamará al Shader de Fragmentos y preguntará: ¿De qué color debería dibujar este pixel? En este caso, simplemente retornaremos blanco cada vez.</p> + +<p><code>gl_FragColor</code> es una variable built-in de GL que es usada para el color del fragmento. Al definir su valor se establece el color del pixel, como se ve a continuación:</p> + +<pre class="brush: html"> const fsSource = ` + void main() { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + } + `; +</pre> + +<h3 id="Inicializando_los_shaders">Inicializando los shaders</h3> + +<p>Ahora que hemos definido los dos shaders, necesitamos pasarlos a WebGL, compilarlos y enlazarlos juntos. El código de abajo crea dos shaders al llamar <code>loadShader</code>, pasando el tipo y la fuente para el shader. Entonces crea un programa, adjunta los shaders y los enlaza juntos. Si la compilación o el enlace fallan, el código muestra una alerta.</p> + +<pre class="brush: js">// +// Initialize a shader program, so WebGL knows how to draw our data +// +function initShaderProgram(gl, vsSource, fsSource) { + const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); + const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); + + // Create the shader program + + const shaderProgram = gl.createProgram(); + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + // If creating the shader program failed, alert + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram)); + return null; + } + + return shaderProgram; +} + +// +// creates a shader of the given type, uploads the source and +// compiles it. +// +function loadShader(gl, type, source) { + const shader = gl.createShader(type); + + // Send the source to the shader object + + gl.shaderSource(shader, source); + + // Compile the shader program + + gl.compileShader(shader); + + // See if it compiled successfully + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader)); + gl.deleteShader(shader); + return null; + } + + return shader; +} +</pre> + +<p>Para usar este código lo llamamos así:</p> + +<pre class="brush: js"> const shaderProgram = initShaderProgram(gl, vsSource, fsSource); +</pre> + +<p>Después de haber creado el programa de sombreado necesitaremos buscar las ubicaciones que WebGL asignó a nuestras entradas (inputs). En este caso tenemos un attribute y 2 uniforms. Los attribute reciben valores de los buffers. Cada iteración del Shader de Vértices recibe el siguiente valor desde el buffer asignado al attribute. Los uniforms son similares a variables globales en Javascript, estos mantienen el mismo valor para todas las iteraciones de un shader. Como las ubicaciones attribute y uniform son específicas de un solo programa de sombreado, los almacenamos juntos para que sean fáciles de pasar.</p> + +<pre class="brush: js"> const programInfo = { + program: shaderProgram, + attribLocations: { + vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'), + }, + uniformLocations: { + projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), + modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), + }, + }; +</pre> + +<h2 id="Creando_el_cuadrado_plano">Creando el cuadrado plano</h2> + +<p>Antes de que podamos renderizar nuestro cuadrado plano, necesitamos crear el buffer que contenga sus posiciones de vértice y poner las posiciones de vértice en él. Lo haremos usando una función que llamaremos <code>initBuffers()</code>. Mientras vayamos explorando conceptos WebGL más avanzados, esta rutina crecerá para crear objetos 3D más y más complejos.</p> + +<pre class="brush: js">function initBuffers(gl) { + + // Create a buffer for the square's positions. + + const positionBuffer = gl.createBuffer(); + + // Select the positionBuffer as the one to apply buffer + // operations to from here out. + + gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + + // Now create an array of positions for the square. + + const positions = [ + 1.0, 1.0, + -1.0, 1.0, + 1.0, -1.0, + -1.0, -1.0, + ]; + + // Now pass the list of positions into WebGL to build the + // shape. We do this by creating a Float32Array from the + // JavaScript array, then use it to fill the current buffer. + + gl.bufferData(gl.ARRAY_BUFFER, + new Float32Array(positions), + gl.STATIC_DRAW); + + return { + position: positionBuffer, + }; +} +</pre> + +<p>Esta rutina es muy sencilla dada la naturaleza de la escena en este ejemplo. Empieza llamando el método {{domxref("WebGLRenderingContext.createBuffer()", "createBuffer()")}} del objeto <code>gl</code> para obtener un buffer dentro del cual almacenaremos las posiciones del vértice. Este es ligado al contexto al llamar el método {{domxref("WebGLRenderingContext.bindBuffer()", "bindBuffer()")}}.</p> + +<p>Una vez terminado, creamos un array de Javascript almacenando la posición de cada vértice en el cuadrado plano. Este es convertido entonces en un array de flotantes y es pasado al método {{domxref("WebGLRenderingContext.bufferData()", "bufferData()")}} del objeto <code>gl</code> para establecer las posiciones de vértice para el objeto.</p> + +<h2 id="Renderizando_la_escena">Renderizando la escena</h2> + +<p>Una vez que los shaders estan establecidos, se buscan las ubicaciones, y las posiciones de vértice del cuadrado plano puestas en un buffer, podemos renderizar la escena. Como no estamos animando nada en este ejemplo, nuestra función <code>drawScene()</code> es muy simple. Esta usa unas rutinas de utilidad que cubriremos en breve.</p> + +<pre class="brush: js">function drawScene(gl, programInfo, buffers) { + gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque + gl.clearDepth(1.0); // Clear everything + gl.enable(gl.DEPTH_TEST); // Enable depth testing + gl.depthFunc(gl.LEQUAL); // Near things obscure far things + + // Clear the canvas before we start drawing on it. + + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + // Create a perspective matrix, a special matrix that is + // used to simulate the distortion of perspective in a camera. + // Our field of view is 45 degrees, with a width/height + // ratio that matches the display size of the canvas + // and we only want to see objects between 0.1 units + // and 100 units away from the camera. + + const fieldOfView = 45 * Math.PI / 180; // in radians + const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight; + const zNear = 0.1; + const zFar = 100.0; + const projectionMatrix = mat4.create(); + + // note: glmatrix.js always has the first argument + // as the destination to receive the result. + mat4.perspective(projectionMatrix, + fieldOfView, + aspect, + zNear, + zFar); + + // Set the drawing position to the "identity" point, which is + // the center of the scene. + const modelViewMatrix = mat4.create(); + + // Now move the drawing position a bit to where we want to + // start drawing the square. + + mat4.translate(modelViewMatrix, // destination matrix + modelViewMatrix, // matrix to translate + [-0.0, 0.0, -6.0]); // amount to translate + + // Tell WebGL how to pull out the positions from the position + // buffer into the vertexPosition attribute. + { + const numComponents = 2; // pull out 2 values per iteration + const type = gl.FLOAT; // the data in the buffer is 32bit floats + const normalize = false; // don't normalize + const stride = 0; // how many bytes to get from one set of values to the next + // 0 = use type and numComponents above + const offset = 0; // how many bytes inside the buffer to start from + gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position); + gl.vertexAttribPointer( + programInfo.attribLocations.vertexPosition, + numComponents, + type, + normalize, + stride, + offset); + gl.enableVertexAttribArray( + programInfo.attribLocations.vertexPosition); + } + + // Tell WebGL to use our program when drawing + + gl.useProgram(programInfo.program); + + // Set the shader uniforms + + gl.uniformMatrix4fv( + programInfo.uniformLocations.projectionMatrix, + false, + projectionMatrix); + gl.uniformMatrix4fv( + programInfo.uniformLocations.modelViewMatrix, + false, + modelViewMatrix); + + { + const offset = 0; + const vertexCount = 4; + gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount); + } +} + +</pre> + +<p>El primer paso es limpiar el canvas de nuestro color de fondo; establecemos la perspectiva de la cámara. Configuramos un campo de 45º, con una relación ancho/alto que coincide con las dimensiones de nuestro canvas. También especificamos que queremos objetos entre 0.1 y 100 unidades de la cámara para ser renderizados.</p> + +<p>Entonces establecemos la posición del cuadrado plano al cargar la posición de identidad y alejando la cámara en 6 unidades. Déspues de eso, enlazamos el buffer del vértice del cuadrado al atributo que el shader estaba usando para <code>aVertexPosition</code> y le decimos a WebGL como jalar los datos fuera de este. Finalmente dibujamos el objeto al llamar el método {{domxref("WebGLRenderingContext.drawArrays()", "drawArrays()")}}.</p> + +<p>{{EmbedGHLiveSample('webgl-examples/tutorial/sample2/index.html', 670, 510) }}</p> + +<p><a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial/sample2">Ver código completo</a> | <a href="http://mdn.github.io/webgl-examples/tutorial/sample2/">Abrir esta demostración en una nueva página</a></p> + +<h2 id="Utilidades_para_operaciones_de_Matrices">Utilidades para operaciones de Matrices</h2> + +<p>Las operaciones de matrices pueden parecer complicadas pero <a href="https://webglfundamentals.org/webgl/lessons/webgl-2d-matrices.html">en realidad son muy fáciles si las tomas un paso a la vez</a>. Generalmente la gente usa una librería de matrices antes que escribir la suya. En nuestro caso estamos usando la popular <a href="http://glmatrix.net/">librería glMatrix</a>.</p> + +<p>Ver también</p> + +<ul> + <li><a href="https://webglfundamentals.org/webgl/lessons/webgl-2d-matrices.html">Matrices</a> en WebGLFundamentals</li> + <li><a class="external" href="http://mathworld.wolfram.com/Matrix.html">Matrices</a> en Wolfram MathWorld</li> + <li><a class="external" href="http://en.wikipedia.org/wiki/Matrix_(mathematics)">Matriz</a> en Wikipedia</li> +</ul> + +<p>{{PreviousNext("Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL", "Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL")}}</p> diff --git a/files/es/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html b/files/es/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html new file mode 100644 index 0000000000..ad9b98310a --- /dev/null +++ b/files/es/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html @@ -0,0 +1,119 @@ +--- +title: Animación de Objetos con WebGL +slug: Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL +tags: + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL +--- +<p>{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL", "Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL") }}</p> + +<p>Our existing code from the previous examples is already configured to redraw our WebGL scene every 15 milliseconds. Until now, it's simply redrawing everything exactly the same way every time. It's time to change that, so that our square actually moves.</p> + +<p>In this example, we'll actually rotate and move our 2D square in all three dimensions; this will prove that even though we're only creating a 2D object, it still exists in 3D space.</p> + +<h2 id="Making_the_square_rotate">Making the square rotate</h2> + +<p>Let's start by making the square rotate. The first thing we'll need is a variable in which to track the current rotation of the square:</p> + +<pre class="brush: js">var squareRotation = 0.0; +</pre> + +<p>Now we need to update the <code>drawScene()</code> function to apply the current rotation to the square when drawing it. After translating to the initial drawing position for the square, we apply the rotation like this:</p> + +<pre class="brush: js">mvPushMatrix(); +mvRotate(squareRotation, [1, 0, 1]); +</pre> + +<p>This saves the current model-view matrix, then rotates the matrix by the current value of <code>squareRotation</code>, around the X and Z axes.</p> + +<p>After drawing, we need to restore the original matrix:</p> + +<pre class="brush: js"> mvPopMatrix(); +</pre> + +<p>We save and restore the original matrix to avoid having this rotation applied to other objects we might draw.</p> + +<p>To actually animate, we need to add code that changes the value of <code>squareRotation</code> over time. We can do that by creating a new variable to track the time at which we last animated (let's call it <code>lastSquareUpdateTime</code>), then adding the following code to the end of the <code>drawScene()</code> function:</p> + +<pre class="brush: js"> var currentTime = (new Date).getTime(); + if (lastSquareUpdateTime) { + var delta = currentTime - lastSquareUpdateTime; + + squareRotation += (30 * delta) / 1000.0; + } + + lastSquareUpdateTime = currentTime; +</pre> + +<p>This code uses the amount of time that's passed since the last time we updated the value of <code>squareRotation</code> to determine how far to rotate the square.</p> + +<h2 id="Making_the_square_move">Making the square move</h2> + +<p>We can also move the square around by translating to a different position before drawing it. This example is going to do some very basic animation; obviously in the real world you'd want to do something less insane.</p> + +<p>Let's track offsets to each axis for our translation in new variables:</p> + +<pre class="brush: js">var squareXOffset = 0.0; +var squareYOffset = 0.0; +var squareZOffset = 0.0; +</pre> + +<p>And the amount by which to change our position on each axis in these variables:</p> + +<pre class="brush: js">var xIncValue = 0.2; +var yIncValue = -0.4; +var zIncValue = 0.3; +</pre> + +<p>Now we can simply add this code to the previous code that updates the rotation:</p> + +<pre class="brush: js"> squareXOffset += xIncValue * ((30 * delta) / 1000.0); + squareYOffset += yIncValue * ((30 * delta) / 1000.0); + squareZOffset += zIncValue * ((30 * delta) / 1000.0); + + if (Math.abs(squareYOffset) > 2.5) { + xIncValue = -xIncValue; + yIncValue = -yIncValue; + zIncValue = -zIncValue; + } +</pre> + +<p>This causes our square to zoom around, moving haphazardly around the context as well as toward and away from the viewer, all while rotating. It looks rather like a screen saver.</p> + +<p>If your browser supports WebGL, <a href="/samples/webgl/sample4/index.html" title="https://developer.mozilla.org/samples/webgl/sample4/index.html">click here to take a look at this example</a> in action.</p> + +<h2 id="More_matrix_operations">More matrix operations</h2> + +<p>This example uses a few additional matrix operations, including two routines to push and pop matrices from a stack to preserve them, and one that rotates a matrix a given number of degrees. These follow, for your reference:</p> + +<pre class="brush: js">var mvMatrixStack = []; + +function mvPushMatrix(m) { + if (m) { + mvMatrixStack.push(m.dup()); + mvMatrix = m.dup(); + } else { + mvMatrixStack.push(mvMatrix.dup()); + } +} + +function mvPopMatrix() { + if (!mvMatrixStack.length) { + throw("Can't pop from an empty matrix stack."); + } + + mvMatrix = mvMatrixStack.pop(); + return mvMatrix; +} + +function mvRotate(angle, v) { + var inRadians = angle * Math.PI / 180.0; + + var m = Matrix.Rotation(inRadians, $V([v[0], v[1], v[2]])).ensure4x4(); + multMatrix(m); +} +</pre> + +<p>These routines were borrowed from a sample previously written by Vlad Vukićević.</p> + +<p>{{PreviousNext("Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL", "Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL") }}</p> diff --git a/files/es/web/api/webgl_api/tutorial/animating_textures_in_webgl/index.html b/files/es/web/api/webgl_api/tutorial/animating_textures_in_webgl/index.html new file mode 100644 index 0000000000..0274f91187 --- /dev/null +++ b/files/es/web/api/webgl_api/tutorial/animating_textures_in_webgl/index.html @@ -0,0 +1,106 @@ +--- +title: Animating textures in WebGL +slug: Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL +translation_of: Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL +--- +<p>{{WebGLSidebar("Tutorial") }} {{Previous("Web/API/WebGL_API/Tutorial/Lighting_in_WebGL")}}</p> + +<p>En esta demostración nos basamos en el ejemplo anterior, solo que ahora reemplazaremos nuestra textura estática con los fotogramas de un video Ogg.</p> + +<p>Esto es de hecho muy fácil de entender y de hacer, así que vamos a empezar. </p> + +<p>Podemos utilizar un código similar para usar, como fuente para las texturas, otros tipos de datos tales como {{ HTMLElement("canvas") }}.</p> + +<h2 id="Obteniendo_acceso_al_video">Obteniendo acceso al video</h2> + +<p>El primer paso es añadir el HTML para crear el elemento {{ HTMLElement("video") }} que usaremos para obtener los fotogramas de video:</p> + +<pre class="brush: js"><video id="video"> + Parece ser que tu navegador no soporta el elemento HTML5. <code>&lt;video&gt;</code> +</video> +</pre> + +<p>Esto simplemente crea un elemento para reproducir el archivo de video "Firefox.ogv". Usaremos CSS para ocultar el video</p> + +<pre class="brush: css">video { + display: none; +} +</pre> + +<p>Ahora pasamos al código JavasScript, empezando por añadir una línea de código a la función start() para obtener la referencia al elemento de video:</p> + +<pre class="brush: js">videoElement = document.getElementById("video"); +</pre> + +<p>Y reemplazamos el código que configura las llamadas de "interval-driven" en drawScecene() por esto:</p> + +<pre class="brush: js">videoElement.addEventListener("canplaythrough", startVideo, true); +videoElement.addEventListener("ended", videoDone, true); +</pre> + +<p>Finalmente configuramos el atributo src para empezar a cargar el video. FIXME (bjacob): También se debe configurar preload="auto" o si no, el video nunca ejecuta canplaythrough en Firefox. En Chrome se debería cargar el video aun sin usar preload="auto".</p> + +<pre class="brush: js">video.preload = "auto"; +videoElement.src = "Firefox.ogv";</pre> + +<p>El objetivo aquí es no empezar la animación hasta que una parte suficiente del video se haya cargado de modo que pueda ser reproducido sin interrupciones. Para esto añadimos un event listener para esperar a que el elemento de video nos diga que ya ha cargado los suficientes datos como para reproducir el video puede ser reproducido sin pausas.</p> + +<p>The <code>startVideo()</code> quedará así:</p> + +<pre class="brush: js">function startVideo() { + videoElement.play(); + intervalID = setInterval(drawScene, 15); +} +</pre> + +<p>Esto simplemente reproduce el video, entonces establece las llamadas "interval-driven" a drawScene() para gestionar el renderizado del cubo.</p> + +<p>Añadiremos también un segundo event listener en el "ended" del video de modo que cuando el video haya finalizado de reproducirse nosotros podamos parar la animación.</p> + +<pre class="brush: js">function videoDone() { + clearInterval(intervalID); +}</pre> + +<p>La función de videoDone() simplemente llama a {{ domxref("window.clearInterval()") }} para terminar de llamar a la función de actualizar la animación.</p> + +<h2 id="Usando_los_fotogramas_del_video_como_textura">Usando los fotogramas del video como textura</h2> + +<p>El siguiente paso es initTexture(), el cual se ha vuelto mucho más simple desde que no es necesario cargar un archivo de imagen. En lugar de esto, todo lo que vamos a hacer es crear un objeto de textura vacío para configurar el filtering cuando lo usemos más tarde:</p> + +<pre class="brush: js">function initTextures() { + cubeTexture = gl.createTexture(); + gl.bindTexture(gl.TEXTURE_2D, cubeTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + 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); +} +</pre> + +<div>La función updateTexture() quedaría así; Aquí es donde se realiza el trabajo real.</div> + +<pre class="brush: js">function updateTexture() { + gl.bindTexture(gl.TEXTURE_2D, cubeTexture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, + gl.UNSIGNED_BYTE, videoElement); +} +</pre> + +<p>Has visto este código antes. Es prácticamente idéntico a la rutina de handleTextureLoaded() en el ejemplo anterior, excepto que cuando llamamos a texImage2D() en lugar de pasarle un objeto Image, lo pasamos en el elemento {{ HTMLElement("video") }}. Ya que WebGL sabe como obtener el fotograma actual y usarlo como textura.</p> + +<p><code>updateTexture()</code> se llama cada vez que estamos preparados para que la función drawScene() redibuje la escena. La única diferencia es que añadimos la llamada de updateTexture() antes de hacer nada más.</p> + +<p>¡Esto es todo al respecto!</p> + +<p>{{EmbedGHLiveSample('webgl-examples/tutorial/sample8/index.html', 670, 510) }}</p> + +<p><a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial/sample8">Ver el código completo</a> | <a href="http://mdn.github.io/webgl-examples/tutorial/sample8/">Abrir esta demo en una nueva página</a></p> + +<h2 id="Artículos_relacionados">Artículos relacionados</h2> + +<ul> + <li><a href="/es/Using_HTML5_audio_and_video">Usar audio y video en Firefox</a></li> +</ul> + +<p>{{Previous("Web/API/WebGL_API/Tutorial/Lighting_in_WebGL")}}</p> diff --git a/files/es/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html b/files/es/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html new file mode 100644 index 0000000000..a56004e010 --- /dev/null +++ b/files/es/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html @@ -0,0 +1,106 @@ +--- +title: Primeros pasos con WebGL +slug: Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL +tags: + - Intro + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL +--- +<p>{{WebGLSidebar("Tutorial")}} {{Next("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context")}}</p> + +<p>WebGL <span id="result_box" lang="es"><span>permite que el contenido web </span></span>utilice una API basada en <a class="external" href="http://www.khronos.org/opengles/" hreflang="en" title="http://www.khronos.org/opengles/">OpenGL ES</a> 2.0 para llevar a cabo la representación 2D y 3D en un elemento <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">canvas</a> HTML en los navegadores que lo soporten sin el uso de plug-ins. WebGL consiste en código de control escrito en JavaScript y código de efectos especiales (código shader) que se ejecuta en la unidad de procesamiento gráfico de una computadora (GPU). Los elementos WebGL se pueden mezclar con otros elementos HTML y componerse con otras partes de la página o el fondo de la misma.</p> + +<p>Este artículo le dará a conocer los conceptos básicos de WebGL. Se asume que ya tiene una comprensión de las matemáticas implicadas en gráficos 3D, y este artículo no pretende tratar de enseñar OpenGL en sí.</p> + +<h2 id="Preparando_el_renderizado_en_3D">Preparando el renderizado en 3D</h2> + +<p>Lo primero que necesitas para poder usar WebGL para renderizar en 3D es un HTML <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">canvas</a>. El fragmento HTML a continuación establece un <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">canvas</a> y configura un controlador de eventos <code>onload</code> que se utilizarán para inicializar nuestro contexto WebGL.</p> + +<pre class="brush: html"><body onload="start()"> + <canvas id="glcanvas" width="640" height="480"> + Tu navegador parece no soportar el elemento HTML5 <code>&lt;canvas&gt;</code>. + </canvas> +</body> +</pre> + +<h3 id="Preparando_el_contexto_de_WebGL">Preparando el contexto de WebGL</h3> + +<p>La función <code>start()</code>, en nuestro código JavaScript, es llamada después de que el documento fue cargado. Su misión es establecer el contexto WebGL y empezar a renderizar contenido.</p> + +<pre class="brush: js">var gl; // Un variable global para el contexto WebGL + +function start() { + var canvas = document.getElementById("glcanvas"); + + gl = initWebGL(canvas); // Inicializar el contexto GL + + // Solo continuar si WebGL esta disponible y trabajando + + if (gl) { + gl.clearColor(0.0, 0.0, 0.0, 1.0); // Establecer el color base en negro, totalmente opaco + gl.enable(gl.DEPTH_TEST); // Habilitar prueba de profundidad + gl.depthFunc(gl.LEQUAL); // Objetos cercanos opacan objetos lejanos + gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT); // Limpiar el buffer de color asi como el de profundidad + } +} +</pre> + +<p>La primer cosa que hacemos aqui es obtener una referencia al <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">canvas</a>, ocultándolo en una variable llamada <code>canvas</code>. Obviamente si no necesitas referenciar repetidamente, deberías evitar guardar este valor globalmente, y solo guardarlo en una variable local o miembro de un objeto.</p> + +<p>Una vez tenemos el canvas, llamamos a la función llamada <code>initWebGL()</code>; esta es una función que definiremos momentaneamente; su trabajo es inicializar el contexto WebGL.</p> + +<p>Si el contexto es exitosamente inicializado, <code>gl</code> sera una referencia a este. En este caso, establecemos el color base a negro, después limpiamos el contexto a ese color. Después, el contexto es configurado estableciendo parametros. En este caso, estamos habilitando la prueba de profundidad y especificando que los objetos cercanos opacaran a los objetos lejanos.</p> + +<p>Para los propositos de esta introducción al código, eso sera todo lo que haremos. Empezaremos a ver como crear algo después.</p> + +<h3 id="Crear_el_contexto_de_WebGL">Crear el contexto de WebGL</h3> + +<p>La función <code>initWebGL()</code>se ve como esto:</p> + +<pre class="brush: js">function initWebGL(canvas) { + gl = null; + + try { + // Tratar de tomar el contexto estandar. Si falla, retornar al experimental. + gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); + } + catch(e) {} + + // Si no tenemos ningun contexto GL, date por vencido ahora + if (!gl) { + alert("Imposible inicializar WebGL. Tu navegador puede no soportarlo."); + gl = null; + } + + return gl; +} + +</pre> + +<p>Para obtener el contexto WebGL de un canvas, pedimo el contexto llamado "webgl" del canvas. Si este falla, intentamos con el nombre "experimental-webgl". Si este igualmente, falla, mostramos una alerta permitiendo al usuario conocer que parece no tener soporte WebGL. Eso es todo al respecto. En este punto, <code>gl</code> es nulo (no hay ningun contexto WebGL disponible) o es una referencia al contexto WebGL en donde renderizaremos.</p> + +<div class="note"><strong>Nota:</strong> El nombre de contexto "experimental-webgl" es nombre temporal para usar durante el desarrollo de las especificaciones; el nombre "webgl" sera usado una vez se termine el desarrollo.</div> + +<p>En este punto, tienes suficiente código para que el contexto WebGL, inicialice exitosamente, y deberias terminar con una gran cuadro negro y vacio, listo y esperando a recibir contenido .</p> + +<p><a href="/samples/webgl/sample1/index.html" title="https://developer.mozilla.org/samples/webgl/sample1/index.html">Prueba este ejemplo</a> si estas usando un navegador compatible con WebGL.</p> + +<h3 id="Cambiando_el_tamaño_del_contexto_WebGL">Cambiando el tamaño del contexto WebGL</h3> + +<p>Un nuevo contexto WebGL establecera el tamaño de su ventana a la altura y anchura del elemento canvas, sin CSS, al instante el contexto fue obtenido. Editando el estilo del elemento canvas cambiara su tamaño mostrado pero no cambiara la resolución de renderizado. Editando los atributos de anchura y altura de un elemento canvas después de crear el contexto tampoco cambiara el numero de pixeles a ser renderizados. Para cambiar la resolución en la cual WebGL renderiza, como cuando el usuario cambia el tamaño de ventana de un canvas de documento completo o quieres proveer ajustes graficos ajustables dentro de la aplicación, necesitaras llamar a la función del contexto WebGL llamada <code>viewport()</code> para hacer efectivo el cambio.</p> + +<p>Para modificar la resolución renderizada de un contexto WebGL con las variables <code>gl</code> y <code>canvas</code> como fue usado en el ejemplo de arriba:</p> + +<pre class="brush: js">gl.viewport(0, 0, canvas.width, canvas.height);</pre> + +<p>Un lienzo experimentara escalado cuando es renderizado en una resolución diferente a la establecida en el estilo CSS . Cambiar el tamaño con CSS es muy util para salvar recursos renderizando a una baja resolución y permitiendo que el navegador aumente la escala; bajar la escala es posible, lo que producira un efecto de Super Sample AntiAliasing (SSAA) (con resultados sencillos y un costo alto de rendimiento). Es mejor usar el <abbr style="line-height: 24px;" title='"Multisample'>MSAA (Multi Sample AntiAliasing)</abbr> e implementar un filtrado de texturas en el navegador del usuario, si es que esta disponible y es apropiado, en lugar de hacerlo por medio de la fuerza bruta, esperando que el algoritmo de reducción de la imagen del navegador produzca un resultado limpio.</p> + +<h2 id="También_podría_interesarte">También podría interesarte</h2> + +<ul> + <li><a href="https://dev.opera.com/articles/introduction-to-webgl-part-1/">Una introducción a WebGL - </a>Escrito por Luz Caballero, publicado en dev.opera.com. Este articulo cita que es WebGL, explica como funciona WebGL (incluyendo el concepto del proceso de renderizado), e introduce algunas librerias WebGL</li> + <li><a href="http://duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Table-of-Contents.html">Una introducción al OpenGL moderno</a> - Una serie de articulos escritos por Joe Groff. Joe da una limpia introducción sobre OpenGL desde su historia al importante concepto del proceso de graficos y provee algunos ejemplos sobre como OpenGL trabaja. Si no tienes ninguna idea sobre OpenGL, este es un buen lugar para comenzar.</li> +</ul> + +<p>{{Next("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context")}}</p> diff --git a/files/es/web/api/webgl_api/tutorial/index.html b/files/es/web/api/webgl_api/tutorial/index.html new file mode 100644 index 0000000000..47a0aceb5e --- /dev/null +++ b/files/es/web/api/webgl_api/tutorial/index.html @@ -0,0 +1,42 @@ +--- +title: Tutoral de WebGL +slug: Web/API/WebGL_API/Tutorial +tags: + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial +--- +<div>{{WebGLSidebar}}</div> + +<div class="summary"> +<p><a class="external" href="http://www.khronos.org/webgl/" title="http://www.khronos.org/webgl/">WebGL</a> enables web content to use an API based on <a class="external" href="http://www.khronos.org/opengles/" title="http://www.khronos.org/opengles/">OpenGL ES</a> 2.0 to perform 3D rendering in an HTML {{HTMLElement("canvas")}} in browsers that support it without the use of plug-ins. WebGL programs consist of control code written in JavaScript and special effects code(shader code) that is executed on a computer's Graphics Processing Unit (GPU). WebGL elements can be mixed with other HTML elements and composited with other parts of the page or page background.</p> +</div> + +<p><span class="seoSummary">This tutorial describes how to use the <code><canvas></code> element to draw WebGL graphics, starting with the basics. The examples provided should give you some clear ideas what you can do with WebGL and will provide code snippets that may get you started in building your own content.</span></p> + +<p><strong>Antes de que inicies</strong></p> + +<p>Using the <code><canvas></code> element is not very difficult, but you do need a basic understanding of <a href="/en-US/docs/Web/HTML" title="HTML">HTML</a> and <a href="/en-US/docs/Web/JavaScript" title="JavaScript">JavaScript</a>. The <code><canvas></code> element and WebGL are not supported in some older browsers, but are supported in recent versions of all major browsers. In order to draw graphics on the canvas we use a JavaScript context object, which creates graphics on the fly.</p> + +<p> </p> + +<h2 id="En_este_tutorial">En este tutorial</h2> + +<dl> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL">Getting started with WebGL</a></dt> + <dd>How to set up a WebGL context.</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context">Adding 2D content to a WebGL context</a></dt> + <dd>How to render simple flat shapes using WebGL.</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL">Using shaders to apply color in WebGL</a></dt> + <dd>Demonstrates how to add color to shapes using shaders.</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL">Animating objects with WebGL</a></dt> + <dd>Shows how to rotate and translate objects to create simple animations.</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL">Creating 3D objects using WebGL</a></dt> + <dd>Shows how to create and animate a 3D object (in this case, a cube).</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL">Using textures in WebGL</a></dt> + <dd>Demonstrates how to map textures onto the faces of an object.</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Lighting_in_WebGL">Lighting in WebGL</a></dt> + <dd>How to simulate lighting effects in your WebGL context.</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL">Animating textures in WebGL</a></dt> + <dd>Shows how to animate textures; in this case, by mapping an Ogg video onto the faces of a rotating cube.</dd> +</dl> diff --git a/files/es/web/api/webgl_api/tutorial/objetos_3d_utilizando_webgl/index.html b/files/es/web/api/webgl_api/tutorial/objetos_3d_utilizando_webgl/index.html new file mode 100644 index 0000000000..91e6bf3d37 --- /dev/null +++ b/files/es/web/api/webgl_api/tutorial/objetos_3d_utilizando_webgl/index.html @@ -0,0 +1,133 @@ +--- +title: Creación de objetos 3D utilizando WebGL +slug: Web/API/WebGL_API/Tutorial/Objetos_3D_utilizando_WebGL +tags: + - Cubo 3D + - Objetos 3D + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL +--- +<p>{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL", "Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL")}}</p> + +<p>Vamos a llevar nuestro cuadrado hacia la tercera dimensión agregando cinco caras más para crear el cubo. Para hacer esto de manera eficiente, vamos a cambiar el dibujado por medio de vertices utilizando el método {{domxref("WebGLRenderingContext.drawArrays()", "gl.drawArrays()")}}<code> </code>por el uso de un arreglo de vértices como tabla, esto por medio del llamado hacia {{domxref("WebGLRenderingContext.drawElements()", "gl.drawElements()")}}.</p> + +<p>Considerar: cada cara cuatro vértices para su definición, pero cada vértice es compartido por 3 caras. Realizando una lista con los 24 vértices es como nosotros haremos un menor intercambio de datos, después haremos referencia hacia cada vértic por medio se su índice en la lista en lugar de pasar el juego entero de coordenadas. Si te preguntas por qué necesitamos 24 vértices, y no solo 8, es porque cada esquina pertenece a tres caras de diferente color, y un solo vértice necesita tener un solo color específico, por lo tanto crearemos 3 copias de cada vértice en tres colores diferentes, uno por cada cara.</p> + +<h2 id="Definir_la_posición_de_los_vértices_del_cubo">Definir la posición de los vértices del cubo</h2> + +<p>Primero, construiremos el buffer para la posición de los vértices actualizando el código en <code>initBuffers()</code>. Esto es muy parecido a lo como si fuera para el cuadraro, pero más lardo debido a que ahora son 24 vértices (4 por lado):</p> + +<pre class="brush: js">var vertices = [ + // Cara delantera + -1.0, -1.0, 1.0, + 1.0, -1.0, 1.0, + 1.0, 1.0, 1.0, + -1.0, 1.0, 1.0, + + // Cara trasera + -1.0, -1.0, -1.0, + -1.0, 1.0, -1.0, + 1.0, 1.0, -1.0, + 1.0, -1.0, -1.0, + + // Top face + -1.0, 1.0, -1.0, + -1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, + 1.0, 1.0, -1.0, + + // Bottom face + -1.0, -1.0, -1.0, + 1.0, -1.0, -1.0, + 1.0, -1.0, 1.0, + -1.0, -1.0, 1.0, + + // Right face + 1.0, -1.0, -1.0, + 1.0, 1.0, -1.0, + 1.0, 1.0, 1.0, + 1.0, -1.0, 1.0, + + // Left face + -1.0, -1.0, -1.0, + -1.0, -1.0, 1.0, + -1.0, 1.0, 1.0, + -1.0, 1.0, -1.0 +]; +</pre> + +<h2 id="Definir_los_colores_de_los_vértices">Definir los colores de los vértices</h2> + +<p>Necesitamos construir un arreglo de colores por cada uno de los 24 vertices. Este código comienza por definir un color para cada cara, después utiliza un ciclo para ensamblar el arreglo de colores por cada uno de los vértices.</p> + +<pre class="brush: js">var colors = [ + [1.0, 1.0, 1.0, 1.0], // Cara delantera: blanco + [1.0, 0.0, 0.0, 1.0], // Cara trasera: rojo + [0.0, 1.0, 0.0, 1.0], // Cara superior: verde + [0.0, 0.0, 1.0, 1.0], // Cara inferior: azul + [1.0, 1.0, 0.0, 1.0], // Cara derecha: amarillo + [1.0, 0.0, 1.0, 1.0] // Cara izquierda: morado +]; + +var generatedColors = []; + +for (j=0; j<6; j++) { + var c = colors[j]; + + for (var i=0; i<4; i++) { + generatedColors = generatedColors.concat(c); + } +} + +var cubeVerticesColorBuffer = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesColorBuffer); +gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(generatedColors), gl.STATIC_DRAW); +</pre> + +<h2 id="Definir_el_elemento_arreglo">Definir el elemento arreglo</h2> + +<p>Una ves que el vértice es generado, nosotros necesitamos contruir el elemento arreglo.</p> + +<pre class="brush: js">var cubeVerticesIndexBuffer = gl.createBuffer(); +gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); + +// Este arrelgo define cada cara como 2 triángulos utilizando +// los índices dentro de cada arreglo de vértices +// para especificar cada posición en los tríangulos. + +var cubeVertexIndices = [ + 0, 1, 2, 0, 2, 3, // enfrente + 4, 5, 6, 4, 6, 7, // atrás + 8, 9, 10, 8, 10, 11, // arriba + 12, 13, 14, 12, 14, 15, // fondo + 16, 17, 18, 16, 18, 19, // derecha + 20, 21, 22, 20, 22, 23 // izquierda +]; + +// Ahora enviamos el elemento arreglo a GL + +gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, + new Uint16Array(cubeVertexIndices), gl.STATIC_DRAW); +</pre> + +<p>El arreglo <code>cubeVertexIndices</code> define cada cara como un par de triángulos, especificando cada vértice del triángulo como un índice dentro del arreglo de vértices en el cubo. Así el cubo es descrito como una colección de 12 triángulos. </p> + +<h2 id="Dibujando_el_cubo">Dibujando el cubo</h2> + +<p>Para continuar necesitaremos agregar el código a nuestra función <code>drawScene()</code> esto para poder dibujar utilizando el buffer índice del cubo, agregaremos un nuevo llamado a {{domxref("WebGLRenderingContext.bindBuffer()", "gl.bindBuffer()")}} y {{domxref("WebGLRenderingContext.drawElements()", "gl.drawElements()")}}como se muestra a continuación:</p> + +<pre class="brush: js">gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVerticesIndexBuffer); +setMatrixUniforms(); +gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); +</pre> + +<p>Desde que cada cara de nuestro cubo está compuesto de dos triángulos, tenemos 6 vértices en el cubo, se podría pensar que algunos de ellos son duplicados. Sin embargo, desde que nuestro arreglo índice se encuentra compuesto de enteros simples, esto no es una cantidad excesiva de intercambio de datos para pasar por cada cuadro de la animación.</p> + +<p>En este punto ahora tenemos un cubo animado rebotando y rotando, cuenta con seis caras coloreadas vívidamente.</p> + +<p>{{EmbedGHLiveSample('webgl-examples/tutorial/sample5/index.html', 670, 510) }}</p> + +<p><a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial/sample5">Ver el Código completo</a> | <a href="http://mdn.github.io/webgl-examples/tutorial/sample5/">Abrir esta demostración en una página nueva</a></p> + +<p>{{PreviousNext("Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL", "Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL")}}</p> diff --git a/files/es/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html b/files/es/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html new file mode 100644 index 0000000000..25192a8281 --- /dev/null +++ b/files/es/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html @@ -0,0 +1,91 @@ +--- +title: Utilizar los shaders para aplicar color en WebGL +slug: Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL +translation_of: Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL +--- +<p>{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context", "Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL")}}</p> + +<p>Habiendo creado un cuadrado en la <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context">demostración anterior</a>, el siguiente paso es agregar algo de color. Nosotros podemos hacer esto a través de los shaders.</p> + +<h2 id="Aplicando_color_a_los_vértices">Aplicando color a los vértices</h2> + +<p>En WebGL, los objetos son construidos utilizando conjuntos de vértices, donde cada uno de ellos posee una posición y un color. Por defecto, los colores de los otros pixeles (y todos sus atributos, incluyendo la posición) son procesados utilizando interpolación, creando automáticamente gradientes suaves. Anteriormente, nuestro sombreador de vértices (vertex shader) no aplicaba ningún color específico a los vértices. Entre éste y el fragmento sombreado que asigna el color blanco fijo a cada pixel, todo el cuadrado se renderizó como blanco sólido.</p> + +<p>Vamos a suponer que queremos desplegar un gradiente donde cada una de las esquinas tiene diferente color: rojo, azul, verde, y blanco. La primera tarea es establecer estos colores en los cuatro vértices. Para hacer esto, primero necesitamos crear una matriz de colores de vértices, después la guardaremos dentro del buffer WebGL. Podemos realizarlo agregando el siguiente código a nuestra función initBuffers(): </p> + +<pre class="brush: js"> var colors = [ + 1.0, 1.0, 1.0, 1.0, // blanco + 1.0, 0.0, 0.0, 1.0, // rojo + 0.0, 1.0, 0.0, 1.0, // verde + 0.0, 0.0, 1.0, 1.0 // azul + ]; + + squareVerticesColorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); +} +</pre> + +<p>El código comienza por crear una matriz JavaScript que contenga cuatro vectores de 4 valores, para cada uno de los colores del vértice. Entonces se reserva un nuevo buffer WebGL para almacenar esos colores y la matriz se convierte en floats (Números de tipo flotante) y se almacena dentro del buffer.</p> + +<p>Para designar los colores a utilizar, el vertex shader necesita ser actualizado para extraer el color apropiado del buffer de color:</p> + +<pre class="brush: html"> <script id="shader-vs" type="x-shader/x-vertex"> + attribute vec3 aVertexPosition; + attribute vec4 aVertexColor; + + uniform mat4 uMVMatrix; + uniform mat4 uPMatrix; + + varying lowp vec4 vColor; + + void main(void) { + gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); + vColor = aVertexColor; + } + </script> +</pre> + +<p>La diferencia principal aquí es que, por cada vértice, vamos a establecer su color usando <code>varying</code> en el fragmento de sombreado.</p> + +<h2 id="Coloreando_los_fragments">Coloreando los fragments</h2> + +<p>Anteriormente utilizábamos el fragment shader como un actualizador:</p> + +<pre class="brush: html"> <script id="shader-fs" type="x-shader/x-fragment"> + void main(void) { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + } + </script> +</pre> + +<p>Según vayamos tomando el color interpolado para cada pixel, nosotros simplemente necesitamos cambiar esto para obtener el valor de la variable vColor:</p> + +<pre class="brush: html"> <script id="shader-fs" type="x-shader/x-fragment"> + varying lowp vec4 vColor; + + void main(void) { + gl_FragColor = vColor; + } + </script> +</pre> + +<p>Es un cambio simple; cada fragmento simplemente recibe el color interpolado basado en su posición relativa a los vértices, en lugar que de un valor establecido.</p> + +<h2 id="Dibujando_usando_los_colores">Dibujando usando los colores</h2> + +<p>Como siguiente, es necesario agregar código hacia la rutina <code>initShaders() esto para inicializar el atributo de color para el shader program:</code></p> + +<pre class="brush: js"> vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor"); + gl.enableVertexAttribArray(vertexColorAttribute); +</pre> + +<p>Then, drawScene() puede ser revisado para que utilice dichos colores cuando dibuje el cuadrado:</p> + +<p>gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesColorBuffer); gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);</p> + +<p>{{EmbedGHLiveSample('webgl-examples/tutorial/sample3/index.html', 670, 510) }}</p> + +<p><a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial/sample3">Ver el código completo</a> | <a href="http://mdn.github.io/webgl-examples/tutorial/sample3/">Abrir demostración en una nueva página</a></p> + +<p>{{PreviousNext("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context", "Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL")}}</p> diff --git a/files/es/web/api/webgl_api/tutorial/wtilizando_texturas_en_webgl/index.html b/files/es/web/api/webgl_api/tutorial/wtilizando_texturas_en_webgl/index.html new file mode 100644 index 0000000000..9d2be2d61b --- /dev/null +++ b/files/es/web/api/webgl_api/tutorial/wtilizando_texturas_en_webgl/index.html @@ -0,0 +1,209 @@ +--- +title: Utilizando texturas en WebGL +slug: Web/API/WebGL_API/Tutorial/Wtilizando_texturas_en_WebGL +tags: + - Texturas + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL +--- +<p>{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL", "Web/API/WebGL_API/Tutorial/Lighting_in_WebGL")}}</p> + +<p>Ahora que nuestro programa de prueba tiene un cubo, asignemos una textura en lugar de tener sus caras de un color solido.</p> + +<h2 id="Cargando_texturas">Cargando texturas</h2> + +<p>La primera cosa que debemos hacer es añadir el codigo para cargar nuestra textura. en nuestro caso, estaremos usando una unica textura, asignada en las seis caras de nuestro cubo rotador, pero la misma tecnica puede ser utilizada para cualquier cantidad de texturas.</p> + +<div class="note"><strong>Note:</strong> Es importante señalar que la carga de texturas sigue <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS">reglas de dominio-cruzado</a>; Es decir, sólo puede cargar texturas de sitios para los que su contenido tiene aprobación de CORS. Vea las texturas entre dominios a continuación para más detalles.</div> + +<p>El codigo que carga la textura se ve como esto:</p> + +<pre class="brush: js">function initTextures() { + cubeTexture = gl.createTexture(); + cubeImage = new Image(); + cubeImage.onload = function() { handleTextureLoaded(cubeImage, cubeTexture); } + cubeImage.src = 'cubetexture.png'; +} + +function handleTextureLoaded(image, texture) { + 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_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); + gl.generateMipmap(gl.TEXTURE_2D); + gl.bindTexture(gl.TEXTURE_2D, null); +} +</pre> + +<p><code><font face="Open Sans, Arial, sans-serif">La rutina </font>initTextures()</code> comienza por crear el GL texture cubeTexture llamando la rutina GL {{domxref("WebGLRenderingContext.createTexture()", "createTexture()")}}. Para cargar la textura desde un archivo de imagen, este luego crea un Objeto Imagen y carga en él el archivo de imagen que deseamos utilizar como nuestra textura. La rutina <code>handleTextureLoaded()</code> corre cuando la textura ha terminado de cargar.</p> + +<p>Para realmente crear la textura, especificamos que la nueva textura es la textura actual en la que queremos operar vinculándola a gl.TEXTURE_2D. Despues de esto, la imagen cargada es pasada a {{domxref("WebGLRenderingContext.texImage2D()", "texImage2D()")}} para escribir la informacion de la imagen en la textura.</p> + +<div class="note"><strong>Nota: El alto y hancho de las texturas deben, en la mayoría de las circunstancias, ser una potencia de dos píxeles (es decir, 1, 2, 4, 8, 16, etc.) en cada dimensión. Para la excepción, vea la sección: <a href="https://developer.mozilla.org/en-US/docs/Web/WebGL/Using_textures_in_WebGL#Non_power-of-two_textures">"Texturas no potencia de dos"</a>, a continuación.</strong></div> + +<p>Las siguientes dos líneas setean el filtrado para la textura; Esto controla cómo se filtra la imagen mientras se escala. En este caso estamos usando linear filtering cuando escala la imagen, y mipmap cuando se hace mas pequeña. Entonces el mipmap es generado llamando {{domxref("WebGLRenderingContext.generateMipMap()", "generateMipMap()")}}, Y terminamos diciéndole a WebGL que hemos terminado de manipular la textura vinculando null a gl.TEXTURE_2D.</p> + +<h3 id="Texturas_no_potencia-de-dos">Texturas no potencia-de-dos</h3> + +<p>Generalmente hablando, Utilizar texturas cuyos lados son una potencia de dos es ideal. Están almacenadas eficientemente en la memoria de video y no están restringidas en cómo podrían ser utilizadas. Las texturas creadas por el artista deben ser escaladas hacia arriba o hacia abajo a una potencia cercana a dos y, realmente, debería haber sido creada en potencia-de-dos para empezar. Cada lado debe ser: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024 ó 2048 píxeles. Muchos dispositivos, pero no todos, pueden soportar 4096 píxeles; Algunos pueden soportar 8192 e incluso más.</p> + +<p>Ocasionalmente, es difícil utilizar texturas en potencia-de-dos dada una circunstancia especifica. Si la fuente es alguna tercera parte, A menudo los mejores resultados vienen de modificar las imágenes usando canvas HTML5 en tamaños de potencia-de-dos antes de que se pasen a WebGL; Las coordenadas UV también pueden requerir ajuste si el estiramiento es notorio.</p> + +<p>Pero, Si tiene que tener una textura no-potencia-de-dos (NPOT = no-power-of-two), WebGL incluye un limitado soporte nativo. Las texturas NPOT son en su mayoría útiles si las dimensiones de la textura debe ser la misma resolución que otra cosa, como la resolución de tu monitor, o si no vale la pena molestarse por las sugerencias anteriores. Resumiendo: estas texturas no se pueden usar con mipmapping y no deben repetirse (tile o wrap).</p> + +<p>Un ejemplo de una textura es tilear una imagen de unos ladrillos para cubrir una pared de ladrillos.</p> + +<p>Mipmapping y "UV tiling" pueden ser desactivados utilizando {{domxref("WebGLRenderingContext.texParameter()", "texParameteri()")}} y cuando creas tu textura utilizando {{domxref("WebGLRenderingContext.bindTexture()", "bindTexture()")}}. Ésto permitirá las texturas NPOT a expensas de mipmapping, UV wrapping, UV tiling, y tu control sobre cómo el dispositivo procederá a manejar tu textura.</p> + +<pre class="brush: js">// gl.NEAREST is also allowed, instead of gl.LINEAR, as neither mipmap. +gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); +// Prevents s-coordinate wrapping (repeating). +gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); +// Prevents t-coordinate wrapping (repeating). +gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);</pre> + +<p>Una vez más, con estos parámetros, los dispositivos compatibles con WebGL aceptarán automáticamente cualquier resolución para esa textura (hasta sus dimensiones máximas). Sin realizar la configuración anterior, WebGL requiere que todas las muestras de texturas NPOT fallen al devolver el color "negro sólido": rgba (0,0,0,1).</p> + +<h2 id="Mapeando_la_textura_en_las_caras">Mapeando la textura en las caras</h2> + +<p>A este punto, la textura esta cargada y lista para usar. pero antes de utilizarla, Necesitamos asignar el mapeo de las coordenadas de textura a los vértices de las caras de nuestro cubo. Esto reemplaza todo el código previamente existente para configurar colores para cada una de las caras del cubo en initBuffers().</p> + +<pre class="brush: js">cubeVerticesTextureCoordBuffer = gl.createBuffer(); +gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); + +var textureCoordinates = [ + // Front + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + // Back + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + // Top + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + // Bottom + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + // Right + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0, + // Left + 0.0, 0.0, + 1.0, 0.0, + 1.0, 1.0, + 0.0, 1.0 +]; + +gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), + gl.STATIC_DRAW); +</pre> + +<p>Primeramente, este codigo crea un GL buffer en el cual almacenaremos las coordenadas de la textura para cada cara, luego enlazamos ese buffer como el array en el cual escribiremos.</p> + +<p>El array textureCoordinates define las coordenadas de textura correspondientes a cada vértice de cada cara. Tenga en cuenta que las coordenadas de textura van de 0,0 a 1,0; Las dimensiones de las texturas se normalizan a un rango de 0,0 a 1,0 independientemente de su tamaño real, con el propósito de mapeo de textura.</p> + +<p>Una vez que hemos seteado la matriz de mapeo de textura, pasamos la matriz al búfer, de modo que GL tiene esos datos listos para su uso.</p> + +<h2 id="Actualizando_los_shaders">Actualizando los shaders</h2> + +<p>El shader -- y el código que inicializa los shaders -- también necesita ser actualizado para utilizar la textura en vez de un color solido.</p> + +<p>Primero, echemos un vistazo a un cambio muy sencillo que se necesita en initShaders():</p> + +<pre class="brush: js">textureCoordAttribute = gl.getAttribLocation(shaderProgram, 'aTextureCoord'); +gl.enableVertexAttribArray(textureCoordAttribute); +gl.vertexAttribPointer(texCoordAttribute, 2, gl.FLOAT, false, 0, 0); +</pre> + +<p>Esto reemplaza el código que setea el atributo "vertex color" (color del vertice) con uno que contiene la coordenada de textura para cada vértice.</p> + +<h3 id="El_vertex_shader">El vertex shader</h3> + +<p>A continuación, necesitamos reemplazar el "vertex shader" de modo que en lugar de buscar datos de color, busque los datos de coordenadas de textura.</p> + +<pre class="brush: html"><script id="shader-vs" type="x-shader/x-vertex"> + attribute vec3 aVertexPosition; + attribute vec2 aTextureCoord; + + uniform mat4 uMVMatrix; + uniform mat4 uPMatrix; + + varying highp vec2 vTextureCoord; + + void main(void) { + gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); + vTextureCoord = aTextureCoord; + } +</script> +</pre> + +<p>El cambio clave aquí es que en lugar de buscar el color del vértice (vertex color), estamos estableciendo las coordenadas de textura; Esto indicará la ubicación dentro de la textura correspondiente al vértice.</p> + +<h3 id="El_fragment_shader">El fragment shader</h3> + +<p>El fragment shader también debe actualizarse:</p> + +<pre class="brush: html"><script id="shader-fs" type="x-shader/x-fragment"> + varying highp vec2 vTextureCoord; + + uniform sampler2D uSampler; + + void main(void) { + gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)); + } +</script> +</pre> + +<p>En lugar de asignar un valor de color al fragment color, el fragment color se calcula recolectando el texel (es decir, el píxel dentro de la textura) que el muestreador dice que se corresponde mejor con la posición del fragment.</p> + +<h2 id="Dibujando_el_cubo_texturado">Dibujando el cubo texturado</h2> + +<p>El cambio a la función drawScene() es simple (excepto que por razones de claridad, he eliminado el código que hace que el cubo se traslade a través del espacio mientras se anima, en vez de eso, solo gira).</p> + +<p>El código para mapear colores a la textura se ha ido, sustituido por esto:</p> + +<pre class="brush: js">gl.activeTexture(gl.TEXTURE0); +gl.bindTexture(gl.TEXTURE_2D, cubeTexture); +gl.uniform1i(gl.getUniformLocation(shaderProgram, 'uSampler'), 0); +</pre> + +<p>GL proporciona 32 registros de textura; La primera de ellas es gl.TEXTURE0. Vincularemos nuestra textura previamente cargada a ese registro, a continuación, establecremos el shader sampler uSampler (especificado en el shader) para utilizar esa textura.</p> + +<p>En este punto, el cubo giratorio debe estar listo.</p> + +<p>{{EmbedGHLiveSample('webgl-examples/tutorial/sample6/index.html', 670, 510) }}</p> + +<p><a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial/sample6">Ver el código completo</a> | <a href="http://mdn.github.io/webgl-examples/tutorial/sample6/">Abrir esta demo en una nueva pestaña</a></p> + +<h2 id="Texturas_entre_dominios">Texturas entre dominios</h2> + +<p>La carga de texturas WebGL esta sujeta a controles de acceso entre dominios. Para que su contenido cargue una textura de otro dominio, La aprobacion CORS debe ser obtenida. Ver <a href="/en-US/docs/Web/HTTP/Access_control_CORS">control de acceso HTTP</a> para mas detalles sobre CORS.</p> + +<p>Ver este articulo <a class="external" href="http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/">hacks.mozilla.org</a> para una explicacion de como usar imágenes CORS-approved como texturas WebGL , con un <a class="external" href="http://people.mozilla.org/~bjacob/webgltexture-cors-js.html">ejemplo auto-contenido</a>.</p> + +<div class="note"> +<p><strong>Nota: </strong>El soporte CORS para texturas WebGL y el atributo crossOrigin para elementos de imagen se implementan en {{Gecko ("8.0")}}.</p> +</div> + +<p>Canvas 2D contaminados (Solo lectura) no pueden ser utilizados como texturas WebGL. una 2D {{ HTMLElement("canvas") }} se convierte en contaminada, por ejemplo, cuando una imagen de dominio cruzado (cross-domain) es dibujada en el.</p> + +<div class="note"> +<p><strong>Nota: </strong>El soporte de CORS para Canvas 2D drawImage se implementa en {{Gecko ("9.0")}}. Esto significa que el uso de una imagen de dominio cruzado con aprobación de CORS ya no pinta el lienzo 2D, por lo que el lienzo 2D sigue siendo utilizable como fuente de una textura WebGL. </p> +</div> + +<div class="note"> +<p><strong>Nota:</strong> El soporte de CORS para videos de dominio cruzado y el atributo de crossorigin para elementos {{HTMLElement("video")}} se implementa en {{Gecko ("12.0")}}.</p> +</div> + +<p>{{PreviousNext("Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL", "Web/API/WebGL_API/Tutorial/Lighting_in_WebGL")}}</p> |