Advertisement
  1. Code
  2. Effects

Crear un efecto de distorsión retro CRT utilizando el desplazamiento RGB

Scroll to top
Read Time: 16 min

Spanish (Español) translation by Esther (you can also view the original English article)

En este tutorial aprenderás a separar los tres canales de color de una imagen para crear un efecto de desplazamiento RGB. También te mostraré algunos trucos gráficos para imitar una antigua pantalla CRT.


Avance del resultado final

Este es un ejemplo del efecto que vamos a crear:

Lo principal de este tutorial va a ser el efecto de cambio de RGB, pero también demostraré cómo crear las líneas de escaneo CRT, el ruido y los gráficos de la barra de balanceo.


Paso 1: Sobre las imágenes RGB

Todas las imágenes de la pantalla del ordenador se muestran con los colores rojo, azul y verde. Al mezclar estos tres colores en distintas cantidades, el ordenador puede crear los demás colores del espectro.

RGB Color ChannelsRGB Color ChannelsRGB Color Channels

Si los tres canales de color no se alinean correctamente, la imagen no se compondrá correctamente, y empezarás a ver los bordes de los canales individuales 'sangrando' por los lados de la imagen.

Misaligned Color ChannelsMisaligned Color ChannelsMisaligned Color Channels

Esto es exactamente lo que vamos a hacer en este tutorial; separar una imagen en sus tres canales de color y luego transformar cada uno individualmente para crear un efecto de distorsión. ¡Vamos a ello!

(Puedes aprender mucho más sobre cómo funciona el color RGB en Wikipedia).


Paso 2: Crear una pantalla de título

Tendrás que crear un gráfico al que aplicar el efecto. Yo elegí crear una pantalla de título de videojuego, pero puedes hacer cualquier tipo de gráfico que quieras.

Crea un nuevo Clip de Película llamado 'titleScreen' y pon tu pantalla de título (u otros gráficos) dentro.

Creo que algo de temática retro es lo que mejor funciona con este efecto, ya que me recuerda a una vieja pantalla de recreativa que funciona mal. Creé mi pantalla de título con una fuente llamada Commodore 64 Pixeled. Añadí un filtro Glow al texto para darle ese aspecto de CRT manchado y soplado.

Glow Filter on TextGlow Filter on TextGlow Filter on Text

Una vez que estés satisfecho con tu diseño, añade el MovieClip titleScreen al escenario y dale el nombre de instancia 'titleScreen'.

titleScreen InstancetitleScreen InstancetitleScreen Instance

Paso 3: Crear la clase RGBShift

Crea un nuevo archivo Actionscript llamado 'RGBShift.as'. Guarda este archivo en el mismo directorio que tu archivo principal de Flash. Añade este código para crear el shell de la clase:

1
package {
2
3
	import flash.display.DisplayObject;
4
	import flash.display.Sprite;
5
	import flash.display.BitmapData;
6
	import flash.display.Bitmap;
7
	import flash.display.BitmapDataChannel;
8
	import flash.display.BlendMode;
9
	import flash.events.Event;
10
	import flash.geom.Point;
11
12
	public class RGBShift extends Sprite {
13
14
		private var _centerX:Number;
15
		private var _centerY:Number;
16
17
		// CONSTRUCTOR

18
		public function RGBShift(dObj:DisplayObject) {
19
20
21
        }
22
23
24
	}
25
26
}

Nota del editor: ¿Aún no se siente cómodo con la codificación basada en la clase? Consulta este consejo rápido para ayudarte a empezar.

Este código no hace realmente nada todavía. Las primeras 10 líneas más o menos importan todas las clases adicionales que vamos a necesitar. Tengo dos variables privadas llamadas '_centerX' y '_centerY' (uso los guiones bajos para significar variables privadas). Estas dos variables contendrán las coordenadas x e y del centro de nuestro gráfico.

Observa que la función constructora (vacía por ahora) acepta un DisplayObject. Esto nos permitirá usar cualquier tipo de DisplayObject con este efecto (MovieClip, Sprite, Bitmap, etc.) Vamos a usar el MovieClip titleScreen del escenario, pero el hecho de que la clase acepte cualquier DisplayObject la mantiene flexible para usos posteriores.


Paso 4: Añadir la función createBMD

Hicimos nuestra clase flexible permitiéndole aceptar cualquier DisplayObject, pero en realidad vamos a necesitar un objeto BitmapData para hacer el efecto de cambio de RGB. Vamos a crear una función que pueda crear BitmapData a partir de un DisplayObject.

Añade esta función a tu clase RGBShift justo debajo del constructor:

1
private function createBMD(dObj:DisplayObject):BitmapData {
2
	// create a new BitmapData object the size of our DisplayObject
3
	var bmd:BitmapData = new BitmapData(dObj.width, dObj.height,
4
										true, 0xFF000000);
5
	
6
	// draw the display object to the bitmap data
7
	bmd.draw(dObj);
8
9
	return bmd;
10
}

Echa un vistazo a lo que hace esta función. La primera línea utiliza la anchura y la altura del DisplayObject para crear un nuevo objeto BitmapData transparente del mismo tamaño que el DisplayObject. A continuación, dibuja el DisplayObject en el BitmapData. Por último, devuelve el BitmapData a la persona que lo ha llamado.


Paso 5: Añadir la función createRGB

Aquí es donde tiene lugar la separación real de los colores. Añade esta función a tu clase:

1
private function createRGB(dObj:DisplayObject):Array {
2
	 var bmd:BitmapData = createBMD(dObj); // create bitmapData from the display object
3
	
4
	// create a new bitmap data object for each color channel
5
	var r:BitmapData = new BitmapData(bmd.width, bmd.height, true, 0xFF000000);
6
	var g:BitmapData = new BitmapData(bmd.width, bmd.height, true, 0xFF000000);
7
	var b:BitmapData = new BitmapData(bmd.width, bmd.height, true, 0xFF000000);
8
9
	// copy the data from each channel into the corresponding bitmap data
10
	r.copyChannel(bmd, bmd.rect, new Point(),
11
					BitmapDataChannel.RED, BitmapDataChannel.RED);
12
	g.copyChannel(bmd, bmd.rect, new Point(),
13
					BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
14
	b.copyChannel(bmd, bmd.rect, new Point(),
15
					BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
16
	
17
	// return an array with the bitmap data for the 3 color channels
18
	return [r, g, b];
19
}

Esta función también acepta un DisplayObject. Luego lo pasa a la función createBMD() que escribimos en el paso anterior, que lo convierte en BitmapData. A continuación creamos tres nuevos objetos BitmapData transparentes; uno para cada color. Los creamos con el mismo tamaño que nuestros BitmapData de origen (del DisplayObject).

A continuación, utilizamos el método copyChannel() de BitmapData para copiar un único canal de color del BitmapData de origen en cada uno de los tres nuevos objetos BitmapData.

La última línea simplemente devuelve los tres nuevos objetos BitmapData envueltos en un array.


Paso 6: Utilizar la función createRGB en el constructor

Ahora que tenemos nuestras clases createBMD y createRGB trabajando juntas, vamos a ponerlas en práctica. Añade esto como primera línea de código en la función constructora de la clase RGBShift:

1
var rgbBMD:Array = createRGB(dObj);

Esta línea solo pasa el DisplayObject a la función createRGB(). createRGB() utiliza la función createBMD() para convertirlo en BitmapData y luego lo separa en tres objetos BitmapData separados (uno para cada canal). Finalmente devuelve el array de esos tres objetos a nuestro array local rgbBMD. ¿Tiene sentido? Sí.


Paso 7: Crear mapas de bits a partir de los canales RGB

Ahora tenemos un array de tres objetos BitmapData. Necesitamos crear un Bitmap a partir de cada uno para poder mostrarlos en la pantalla. Añade este bucle for a la función constructora de RGBShift justo debajo de la última línea que hemos añadido:

Nota del editor: Disculpen las molestias, pero esta parte de ActionScript hace que FireFox se desborde. Siéntete libre de descargarlo aquí.

La mayor parte de esto es bastante simple. Echemos un vistazo.

  • Con cada objeto BitmapData en nuestro array rgbBMD estamos creando un nuevo Bitmap.
  • Ponemos el suavizado en true para poder escalar y rotar sin que se pixele. (línea 23)
  • A continuación creamos un Sprite contenedor y añadimos el nuevo Bitmap a la lista de visualización del contenedor. (líneas 25 y 26)
  • Ahora finalmente empezamos a usar las variables _centerX y _centerY. Establecemos cada una en el centro del Bitmap dividiendo el ancho y el alto por la mitad.
  • Usamos este punto central para desplazar el Bitmap dentro del Sprite contenedor, y luego para desplazar el Sprite contenedor en el escenario. Explicaré por qué en el siguiente paso.
  • Finalmente añadimos el Sprite contenedor al escenario (recuerda que hay un contenedor para cada uno de nuestros tres canales de color).

Paso 8: ¿Por qué utilizar el Sprite contenedor?

Podrías crear este efecto sin el Sprite contenedor simplemente añadiendo los Bitmaps directamente al escenario. Me gusta envolverlos en un contenedor porque hace más fácil controlar el punto de transformación cuando haces cosas como escalar y rotar.

Normalmente, cuando se realiza una escala o una rotación en un objeto se transforma desde el punto de origen (0,0) de ese objeto. Eso es raramente lo que quiero que ocurra. Normalmente quiero que las transformaciones se apliquen desde el centro del objeto.

Fíjate que en la última sección fijamos la x y la y de los Bitmaps a la mitad negativa de la anchura y la altura. Esto coloca el Bitmap para que su punto central esté en 0,0 en el Sprite contenedor. Si realizamos alguna transformación en el Sprite contenedor se transformará desde 0,0 del contenedor, que es ahora el centro de nuestro Bitmap.

El único problema es que ahora solo es visible la esquina inferior de nuestro Bitmap, por lo que establezco el Sprite contenedor x y y a la mitad de la altura y anchura del Bitmap para que todo vuelva a su posición correcta.

Container Sprite OffsetContainer Sprite OffsetContainer Sprite Offset

Paso 9: Clase RGBShift

Aquí está la clase de RGBShift hasta este punto en caso de que te hayas perdido por el camino:

Nota del editor: Una vez más, tendrás que descargar el AS aquí. Disculpen las molestias.


Paso 10: Crear la clase documental principal

Así pues, tenemos nuestra clase RGBShift, pero ¿cómo la utilizamos? Comience por crear un nuevo archivo Actionscript llamado Main.as, y luego agregue este código:

1
package {
2
	
3
	import flash.display.MovieClip;
4
	
5
	public class Main extends MovieClip {
6
	
7
		public function Main() {
8
			
9
			var rgb = new RGBShift(titleScreen); // create a new RGBShift from the titleScreen

10
			removeChild(titleScreen); // remove the original title screen from the stage

11
			
12
			// add it to the stage

13
			addChild(rgb);
14
			
15
		}
16
	}
17
18
}

Aquí estamos creando una nueva instancia de la clase RGBShift y pasándole el MovieClip titleScreen del escenario. Ya no necesitamos ese MovieClip, así que lo eliminamos del escenario y añadimos la nueva instancia de RGBShift en su lugar.

Ahora solo tenemos que vincular esta clase a nuestro documento Flash. Vuelve a Flash y establece la clase del documento como 'Main'.

Set the Document Class

Paso 11: Prueba

Ahora deberías poder probar tu archivo Flash (Control -> Probar Película) sin obtener ningún error o advertencia.

First TestFirst TestFirst Test

Hmm, eso no parece del todo correcto, ¿verdad?

Lo que ocurre aquí es que hemos superpuesto los tres canales de color, pero no están combinando y mezclando los colores, por lo que solo vemos la capa superior (azul). Vamos a arreglar eso ahora.


Paso 12: Cambiar el modo de fusión

Para conseguir que los canales de color se mezclen correctamente tenemos que cambiar su BlendMode a SCREEN. Sin embargo, solo queremos cambiar el modo de fusión de la segunda y tercera capa. Dejaremos la primera capa (inferior) normal y mezclaremos las otras dos capas en ella.

Añade este código al bucle for de la función constructora de la clase RGBShift:

1
if(i>0) {
2
	// set SCREEN blend mode for the 2nd and 3rd images
3
	bmp.blendMode = BlendMode.SCREEN;
4
}

Esto comprueba que la imagen actual no es la primera imagen (0) y luego establece la propiedad blendMode a SCREEN.


Paso 13: Volver a probar

Vuelve a probar tu película y deberías ver algo idéntico a tu MovieClip de titleScreen.

Successful TestSuccessful TestSuccessful Test

Sé lo que estás pensando: "Es mucho trabajo para recrear el mismo gráfico que ya existía".

Pero ahora el gráfico está formado por tres objetos que podemos transformar individualmente para crear nuestra distorsión. Así que deja de quejarte y continuemos...


Paso 14: Descarga de la Biblioteca Tweener

Vamos a utilizar la biblioteca Tweener para hacer nuestra animación. Descárgala aquí si aún no la tienes.

Para utilizar Tweener, coloca la carpeta principal 'caurina' en el mismo directorio que su archivo Flash y añade esta declaración de importación en la parte superior de la clase RGBShift:

1
import caurina.transitions.Tweener;

Paso 15: Añadir el archivo randRange

Utilizo esta función randRange como una forma fácil de generar enteros aleatorios dentro de un rango dado. Podrías simplemente añadir esta función a la clase RGBShift, pero yo uso esta función tan a menudo que me gusta mantenerla en un archivo separado, para que sea más fácil de compartir entre diferentes proyectos.

Crea un nuevo archivo Actionscript llamado 'randRange.as' en la misma carpeta que tu archivo Flash principal. Añade este código:

1
package {
2
	// returns a random number between specified range (inclusive)

3
	public function randRange(min:int, max:int):int {
4
	    var randomNum:int = Math.floor(Math.random() * (max - min + 1)) + min;
5
	    return randomNum;
6
	}
7
}

Como puedes ver, es solo una función envuelta en una declaración de paquete. Ahora podemos utilizar esta función como si fuera una parte de nuestra clase.

(Para más información sobre cómo funciona esta función, consulta el Consejo Rápido de Carlos).


Paso 16: Añadir la función distort()

Aquí es donde ocurre la magia. Añade esta función a la clase RGBShift:

1
private function distort(img:Sprite):void {
2
	Tweener.addTween(img, {
3
			y: randRange(_centerY-3, _centerY+3),	// randomize y shift
4
			time:randRange(1,2) /10, 		// randomize time
5
			alpha: randRange(8,10) /10,		// randomize alpha
6
			transition:"easeInOutSine",
7
			
8
			onComplete:distort, 			// when finished start the distortion again
9
			onCompleteParams:[img]
10
			}
11
	);
12
}

Vamos a ejecutar esta función distort() en cada uno de nuestros canales de color por separado para crear el efecto de distorsión.

La función acepta un Sprite (uno de nuestros contenedores de canales de color). Luego inicia una animación Tweener en el canal usando un valor Y aleatorio (entre -3 y 3), y una duración aleatoria (entre 1 y 2 segundos). Esto hará que cada canal se desplace hacia arriba y hacia abajo en diferentes cantidades a diferentes velocidades.

Fíjate que estoy usando la variable _centerY aquí de nuevo para compensar el valor Y. También interpolamos a un valor alfa aleatorio (entre 0,8 y 1) para hacer que cada canal parpadee un poco. Cuando la interpolación termina, usamos la propiedad onComplete para llamar de nuevo a la misma función distort(). Usando onCompleteParams le enviamos el mismo canal de color Sprite. Esto hace que la función de distorsión se repita una y otra vez en cada uno de nuestros canales de color.

¿Ves, qué te dije...? ¡Magia!

Para iniciar este bucle de distorsión necesitamos llamarlo una vez en cada uno de nuestros Sprites de canal de color. Añade esta línea al final del bucle for en la función constructora de RGBShift:

1
distort(container);  // start the bitmap distortion

Paso 17: Experimentar

Ahora deberías poder probar tu película y ver el efecto de distorsión en acción.

Personalmente, me gusta el sutil desplazamiento en Y que tenemos aquí, pero puedes hacer un montón de cosas locas con la distorsión ahora que tenemos los canales animados por separado.

Para experimentar con la distorsión, basta con modificar las propiedades y los valores en la llamada del interpolador en la función de distorsión. Consulta la documentación del Tweener para ver la lista completa de propiedades interpolables.

Aquí hay un ejemplo de una distorsión severa que he creado simplemente añadiendo algunas propiedades más a la llamada del Tweener:

Mira la función distort() que creó el efecto:

1
private function distort(img:Sprite):void {
2
	Tweener.addTween(img, {
3
			y: randRange(_centerY-3, _centerY+3), 	// ranomize y shift
4
			x: randRange(_centerX-10, _centerX+10),
5
			time:randRange(1,2) /10, 		// randomize time
6
			scaleX: randRange(9,11)/10,		// randimize x scale
7
8
			alpha: randRange(5,10) /10,		// randomize alpha
9
			transition:"easeInOutSine",
10
			
11
			onComplete:distort, 			// when finished start the distortion again
12
			onCompleteParams:[img]
13
			}
14
	);
15
}

Paso 18: Mejorar el aspecto de la CRT

Puedes parar aquí si quieres. La separación RGB y la distorsión deberían funcionar en este punto.

Para mejorar el efecto CRT creo que debemos añadir algunos elementos gráficos más. En los próximos pasos añadiremos líneas de escaneo, una barra negra rodante, algo de estática y un reflejo brillante.


Paso 19: Añadir las líneas de exploración

Crea un nuevo MovieClip en el escenario llamado 'líneas'. Dentro del MovieClip dibuja una línea horizontal de 1 pixel que abarque todo el ancho de tu película. Establece el color del trazo en negro con un 40% de alfa.

Ahora copia y pega esta línea una y otra vez, moviéndola 2 píxeles hacia abajo cada vez, hasta que tengas líneas que cubran toda la altura de tu película. El efecto que quieres es una línea de 1 píxel, y luego un espacio de 1 píxel antes de la siguiente línea.

Scan LinesScan LinesScan Lines

Paso 20: Añadir la barra de rodillos

Ahora añadiremos la barra negra rodante. Crea un nuevo MovieClip llamado 'bar'. Dentro, dibuja un rectángulo negro sólido que abarque todo el ancho de tu película. Hazlo de unos 40 píxeles de alto. Establece el estilo de color del MovieClip como Alfa al 30%.

Bar MovieClipBar MovieClipBar MovieClip

Paso 21: Animar la barra rodante

Crea un nuevo MovieClip llamado 'animatingBar' y coloca tu clip de barra dentro. Crea una animación de movimiento corto de la barra moviéndose desde la parte superior de tu película hasta la parte inferior. Esta animación hará un bucle para darnos el efecto de barra rodante.

Coloca el clip AnimatingBar en el escenario. Selecciónelo y añada un filtro de desenfoque. Desvincula los ajustes de desenfoque X e Y y establece el Desenfoque Y en 20 y el Desenfoque X en 0.

Establece el modo de fusión en Superposición. Esto es similar al modo de fusión de pantalla que usamos antes, pero no es exactamente lo mismo.

AnimatingBar Blur FilterAnimatingBar Blur FilterAnimatingBar Blur Filter

Paso 22: Crear la imagen estática

Crea un nuevo archivo de Photoshop del mismo tamaño que tu película. Rellena la capa de fondo con gris neutro (#808080). Elige Filtro > Ruido > Añadir Ruido... Ajuste el filtro al 100%, Gaussiano, Monocromático.

Noise Filter SettingsNoise Filter SettingsNoise Filter Settings

Guarda la imagen como 'noise.jpg'. Si no tienes Photoshop, puedes obtener mi 'noise.jpg' del archivo zip de la fuente.


Paso 23: Animar la estática

Importa la imagen noise.jpg a tu archivo flash. Crea un nuevo MovieClip llamado 'noise' y añade la imagen a él. Crea un nuevo fotograma clave en el cuadro 2 (F6) y gira la imagen 180 grados. Crea otro fotograma clave en el fotograma 3 y voltea la imagen horizontalmente (Modificar > Transformar > Voltear horizontal). Crea un cuarto fotograma clave en el fotograma 4 y de nuevo gira la imagen 180 grados. Ahora tenemos una animación de 4 fotogramas de estática parpadeante.

También puedes generar este efecto de ruido usando ActionScript, pero eso está fuera del alcance de este tutorial.

Animating Noise

Paso 24: Añadir el reflejo

Crea un nuevo MovieClip en el escenario llamado 'shine'. Dentro de él dibuja un óvalo grande que se extienda hasta la mitad de la parte superior de tu película. Selecciona la parte superior del óvalo y elimínala.

Create Shine OvalCreate Shine OvalCreate Shine Oval

Cambia el relleno a un gradiente lineal y ajústalo para que se mezcle desde el blanco 20% alfa en la parte superior hasta el blanco 5% alfa en la parte inferior. Agarra la parte superior de la forma y súbela un poco para darle una ligera curva.

Color the OvalColor the OvalColor the Oval

Paso 25: Fijar las capas de los elementos

Si pruebas tu película ahora no verás ninguno de los nuevos gráficos que acabamos de añadir porque las capas RGB se están añadiendo encima de todo. Para arreglar esto ve a la clase Principal y cambia esta línea:

1
addChild(rgb);

A esto:

1
addChildAt(rgb, 0);

Esto añade el objeto RGBShift en el nivel más bajo de la lista de visualización, por debajo de todos los demás gráficos.


Conclusión

Este tutorial pretende ser un punto de partida, no una solución final. Ahora que tienes los canales RGB separados y animados individualmente hay un montón de cosas diferentes que puedes hacer con esta técnica. El efecto quedaría muy bien si se combinara con la técnica de distorsión estática de mi anterior tutorial.

Como siempre, publica un comentario y hazme saber tu opinión. ¡Buena suerte!

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.