Creando un Sistema de Portales Dimensiones con Render Textures en Unity 🌌
Descubre cómo implementar portales dimensionales realistas en Unity, utilizando Render Textures para mostrar el contenido de otra ubicación. Este tutorial te guiará paso a paso, desde la configuración de las cámaras hasta la creación de shaders personalizados para efectos visuales inmersivos.
¡Hola, aventureros de Unity! 👋 ¿Alguna vez has soñado con crear esos impresionantes portales que transportan al jugador a otras dimensiones, como en juegos clásicos como Portal o Antichamber? ¡Hoy haremos realidad ese sueño! En este tutorial, aprenderemos a construir un sistema de portales dimensionales utilizando una técnica muy potente de Unity: las Render Textures.
Este sistema no solo te permitirá ver a través del portal como si fuera una ventana a otra escena o área, sino que también sentará las bases para futuras interacciones de teletransporte. ¡Prepárate para expandir tu conocimiento de Unity!
🚀 ¿Qué aprenderemos hoy?
En este tutorial, cubriremos los siguientes puntos clave:
- Entender qué son las Render Textures y cómo funcionan.
- Configurar cámaras auxiliares para capturar la vista de la 'otra dimensión'.
- Crear y aplicar materiales con Render Textures a nuestros objetos de portal.
- Optimizar el rendimiento y resolver problemas comunes.
- Mejorar la inmersión con efectos visuales básicos para los portales.
🛠️ Requisitos Previos
Antes de empezar, asegúrate de tener lo siguiente:
- Unity Hub y una versión de Unity instalada.
- Un nuevo proyecto de Unity (preferiblemente URP si quieres los mejores resultados gráficos, pero el estándar también funciona).
- Un entorno 3D básico con algunos objetos para poder ver los efectos del portal.
🖼️ Paso 1: Entendiendo las Render Textures
Las Render Textures son activos especiales en Unity que actúan como texturas a las que una cámara puede renderizar directamente. En lugar de dibujar la vista de la cámara en la pantalla principal del juego, la dibuja en esta textura. Luego, puedes usar esta textura en un material para mostrarla en cualquier superficie 3D.
Imagina que tienes una cámara grabando un programa de televisión y, en lugar de transmitirlo, lo muestra en una pantalla dentro del propio programa. ¡Eso es una Render Texture en esencia!
Propiedades Clave de una Render Texture:
| Propiedad | Descripción | Valores Típicos |
|---|---|---|
| Size | Resolución de la textura (ancho x alto). Mayor resolución, mejor calidad, más rendimiento. | 1024x1024, 2048x2048 |
| Color Format | Formato de color de los píxeles. RGB24, ARGB32 son comunes. | ARGB32 |
| Depth Buffer | Profundidad de bits para el búfer de profundidad. Necesario para 3D. | 16 bit, 24 bit (recomendado para 3D) |
| Filter Mode | Cómo se interpola la textura al escalarse. | Bilinear, Trilinear |
| Wrap Mode | Cómo se comporta la textura si las coordenadas UV van más allá de [0,1]. | Repeat, Clamp |
🌐 Paso 2: Configurando el Escenario y los Portales
Para empezar, necesitamos un par de objetos que actúen como nuestros portales y dos ubicaciones distintas para enlazar.
-
Crea la Estructura Base:
- Crea una escena sencilla con dos habitaciones o áreas separadas. Puedes usar cubos para paredes y suelos.
- En cada habitación, coloca algunos objetos distintivos (cubos de colores, esferas) para que sea fácil distinguir una de otra.
-
Crea los Objetos del Portal:
- En cada una de las dos áreas, crea un
Quad(GameObject -> 3D Object -> Quad). Estos serán nuestros portales. Renómbralos aPortalAyPortalB. - Asegúrate de que los quads estén mirando hacia el interior de la habitación, de modo que cuando el jugador se acerque, vea la 'ventana' al otro lado.
- Ajusta la escala y posición para que parezcan entradas razonables.
- En cada una de las dos áreas, crea un
📸 Paso 3: Las Cámaras Auxiliares y Render Textures
Ahora viene la magia: una cámara por cada portal que renderizará la vista del otro lado.
3.1. Creando las Render Textures
- En la ventana
Project, crea una nueva carpeta llamadaRenderTextures. - Haz clic derecho en
RenderTextures->Create->Render Texture. - Crea dos:
PortalARenderTextureyPortalBRenderTexture. - Selecciona cada Render Texture y en el Inspector, ajusta:
- Size:
1024 x 1024(o2048 x 2048para mayor calidad, pero prueba con 1024 primero). - Depth Buffer:
24 bit.
- Size:
3.2. Configurando las Cámaras de Portal
Vamos a necesitar una cámara para cada portal.
-
Crea dos nuevas cámaras:
PortalACamerayPortalBCamera(GameObject -> Camera). -
Configura
PortalACamera:- Selecciónala. En el Inspector, para
Target Texture, arrastraPortalBRenderTexture. - Esto significa que
PortalACameracapturará lo que ve y lo dibujará en la textura paraPortalB. Sí, lo lees bien: la cámara del portal A mira la vista que se mostrará en el portal B. ¡Es un reflejo! - Ajusta
Clear FlagsaSolid Colory elBackgrounda negro o a un color que encaje con tu ambiente. - Desmarca
HDRsi no lo necesitas, y marcaOpaque Texturesi usas URP. - Ajusta el
Field of View(FOV) para que coincida con el FOV de tu cámara principal (jugador), generalmente 60. - Asegúrate de que la cámara no renderice la misma capa que tu portal para evitar recursión infinita (por ahora, esto lo manejaremos más adelante).
- Selecciónala. En el Inspector, para
-
Configura
PortalBCamera:- Selecciónala. En el Inspector, para
Target Texture, arrastraPortalARenderTexture. - Aplica las mismas configuraciones generales (Clear Flags, Background, FOV) que para
PortalACamera.
- Selecciónala. En el Inspector, para
🎨 Paso 4: Creando Materiales y Asignándolos a los Portales
Ahora necesitamos materiales para nuestros quads que usen estas Render Textures.
-
Crea una nueva carpeta llamada
Materials. -
Crea dos materiales:
PortalAMaterialyPortalBMaterial(Create -> Material). -
Configura
PortalAMaterial:- Selecciónalo. En el Inspector, para la propiedad
Albedo(oBase Mapen URP), arrastraPortalARenderTexture. - Cambia el
Rendering ModeaFadeoTransparentsi quieres un efecto translúcido. - Arrastra
PortalAMaterialalQuadllamadoPortalAen tu escena.
- Selecciónalo. En el Inspector, para la propiedad
-
Configura
PortalBMaterial:- Selecciónalo. En el Inspector, para la propiedad
Albedo(oBase Mapen URP), arrastraPortalBRenderTexture. - Aplica las mismas configuraciones de
Rendering Mode. - Arrastra
PortalBMaterialalQuadllamadoPortalBen tu escena.
- Selecciónalo. En el Inspector, para la propiedad
¡En este punto, deberías ver que tus quads ahora muestran una imagen! Puede que no sea la correcta todavía, ¡pero es un progreso!
📐 Paso 5: Posicionamiento Dinámico de las Cámaras de Portal
El truco para los portales realistas es que la cámara que renderiza para un portal siempre debe estar en la posición relativa correcta al otro portal. Esto lo haremos con un script C#.
-
Crea una nueva carpeta
Scriptsy crea un script C# llamadoPortalCamera. -
Abre
PortalCamera.csy pega el siguiente código:
using UnityEngine;
public class PortalCamera : MonoBehaviour
{
public Transform playerCamera;
public Transform portalA;
public Transform portalB;
void LateUpdate()
{
if (playerCamera == null || portalA == null || portalB == null)
{
Debug.LogWarning("Asigna playerCamera, portalA y portalB en el inspector del script PortalCamera.");
return;
}
// Calcular la posición y rotación del jugador en el espacio del Portal A
Vector3 playerOffsetFromPortalA = playerCamera.position - portalA.position;
Quaternion playerRotationFromPortalA = Quaternion.Inverse(portalA.rotation) * playerCamera.rotation;
// Reflejar esa posición y rotación en el espacio del Portal B
// (Ajuste de la rotación para que mire en la dirección correcta)
Vector3 newCameraPosition = portalB.position + Quaternion.Euler(0, 180, 0) * (portalB.rotation * playerOffsetFromPortalA);
Quaternion newCameraRotation = portalB.rotation * Quaternion.Euler(0, 180, 0) * playerRotationFromPortalA;
// Asignar la nueva posición y rotación a la cámara del portal (esta cámara)
transform.position = newCameraPosition;
transform.rotation = newCameraRotation;
}
}
-
Asigna el script:
- Arrastra el script
PortalCameraaPortalACameray aPortalBCamera. - Para
PortalACamera(que renderiza paraPortalB): en el Inspector, arrastra tuMain Camera(la cámara del jugador) al campoPlayer Camera,PortalAal campoPortalA, yPortalBal campoPortalB. - Para
PortalBCamera(que renderiza paraPortalA): en el Inspector, arrastra tuMain Cameraal campoPlayer Camera,PortalBal campoPortalA, yPortalAal campoPortalB. ¡Cuidado con el orden aquí! La cámara del portal debe saber qué portal es el suyo (elportalAen el script) y cuál es el otro (portalBen el script) para el cálculo.
⚠️ Advertencia: La lógica en `PortalCamera` asume que el `portalA` es el portal que la cámara *actual* está emulando, y `portalB` es el portal *destino*. Asegúrate de asignar correctamente las referencias en el Inspector para cada cámara auxiliar. - Arrastra el script
¿Por qué usamos `LateUpdate()`?
Cuando actualizamos la cámara del portal en `LateUpdate()`, nos aseguramos de que la cámara del jugador ya haya terminado de moverse en `Update()`. Esto garantiza que los cálculos de posición y rotación sean lo más precisos posible con respecto a la posición final del jugador en el frame actual.✨ Paso 6: Añadiendo un Shader Básico para un Efecto de Portal
Un simple material Standard puede funcionar, pero para un efecto más convincente, un shader personalizado puede hacer maravillas. Vamos a crear un shader URP (o Standard si no usas URP) que solo muestre la textura y permita cierta transparencia.
6.1. Creando un Shader Gráfico (Shader Graph - URP)
Si usas URP, Shader Graph es la forma más sencilla.
-
En la carpeta
Materials, haz clic derecho ->Create->Shader Graph->URP->Unlit Graph(oPBR Graphsi quieres reflejos). -
Renombra a
PortalShaderGraph. -
Abre el Shader Graph.
- Crea un nodo
Texture 2D Assety arrastra tuRender Texture(por ejemplo,PortalARenderTexture) a él. - Conecta la salida
RGBAdel nodoTexture 2D Assetal nodoBase Color(oColoren Unlit). - Si quieres transparencia, cambia
SurfaceaTransparenten las propiedades delGraph Inspector(PestañaGraph Settings). Conecta la salidaAlphaa la entradaAlphadel nodoFragment. - Guarda el Asset. ¡Ya tienes tu shader!
- Crea un nodo
-
Crea nuevos materiales (por ejemplo,
PortalA_ShaderMaterial) y asigna estePortalShaderGraph. -
Asigna la
Render Texturecorrecta (e.g.PortalARenderTexture) a la propiedad de textura que el shader exponga (si la expusiste como propiedad).
6.2. Shader Básico Códificado (Fallback para Standard RP o si prefieres código)
Si no usas URP o prefieres código, puedes usar un shader básico.
- En la carpeta
Materials, haz clic derecho ->Create->Shader->Standard Surface Shader. - Renombra a
PortalSurfaceShader. - Abre el archivo
.shadery modifícalo para que se parezca a esto (ejemplo simplificado de unlit transparente):
Shader "Custom/PortalSurfaceShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_Color ("Color", Color) = (1,1,1,1)
}
SubShader
{
Tags { "RenderType"="Transparent" "Queue"="Transparent" }
LOD 100
Blend SrcAlpha OneMinusSrcAlpha
Cull Off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _Color;
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv) * _Color;
return col;
}
ENDCG
}
}
}
- Crea nuevos materiales que usen este shader y asigna la
Render Textureapropiada a la propiedad_MainTex.
🔄 Paso 7: Teletransporte del Jugador (Opcional pero recomendado)
Para que los portales sean realmente funcionales, el jugador debe poder atravesarlos. Esto implica teletransportar al jugador cuando cruza la superficie del portal.
-
Crea un nuevo script C# llamado
PortalTeleporter. -
Abre
PortalTeleporter.csy pega el siguiente código:
using UnityEngine;
public class PortalTeleporter : MonoBehaviour
{
public Transform player;
public Transform receiver;
private bool playerIsOverlapping = false;
void Start()
{
// Asegurarse de que el objeto del portal tiene un Collider marcado como Trigger
Collider portalCollider = GetComponent<Collider>();
if (portalCollider == null || !portalCollider.isTrigger)
{
Debug.LogWarning("El objeto Portal debe tener un Collider con 'Is Trigger' activado.");
// Añadir un BoxCollider si no existe y configurarlo como trigger
if (portalCollider == null)
{
portalCollider = gameObject.AddComponent<BoxCollider>();
}
portalCollider.isTrigger = true;
}
}
void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Player"))
{
playerIsOverlapping = true;
}
}
void OnTriggerExit(Collider other)
{
if (other.CompareTag("Player"))
{
playerIsOverlapping = false;
}
}
void Update()
{
if (playerIsOverlapping)
{
if (player == null || receiver == null)
{
Debug.LogWarning("Asigna player y receiver en el inspector del script PortalTeleporter.");
return;
}
// Obtener la dirección en la que el portal está mirando (adelante)
Vector3 portalForward = transform.forward;
// Comprobar si el jugador ha cruzado el umbral del portal
// Si el producto punto es negativo, significa que el jugador cruzó el plano del portal
float dotProduct = Vector3.Dot(player.position - transform.position, portalForward);
if (dotProduct < 0f)
{
// Calcular la rotación para alinear el jugador con el portal de destino
Quaternion portalToPortalRotation = Quaternion.FromToRotation(transform.forward, -receiver.forward);
float angularDifference = Quaternion.Angle(transform.rotation, receiver.rotation);
Quaternion rotationDifference = Quaternion.Euler(0, angularDifference, 0);
Vector3 positionOffsetFromPortal = player.position - transform.position;
positionOffsetFromPortal = portalToPortalRotation * positionOffsetFromPortal;
player.position = receiver.position + positionOffsetFromPortal;
// Aplicar la rotación del portal al jugador
// Esto asegura que el jugador mire en la dirección correcta después del teletransporte
player.rotation = portalToPortalRotation * player.rotation;
playerIsOverlapping = false; // Reset para evitar teletransporte múltiple
}
}
}
}
- Configura el teletransporte:
- Asegúrate de que tu
Player(o el objeto que representa al jugador, por ejemplo, el padre de laMain Camera) tenga unTagllamadoPlayer. - Añade el script
PortalTeleportera los objetosPortalAyPortalB. - Para
PortalA:- Arrastra tu
Playeral campoPlayer. - Arrastra
PortalBal campoReceiver.
- Arrastra tu
- Para
PortalB:- Arrastra tu
Playeral campoPlayer. - Arrastra
PortalAal campoReceiver.
- Arrastra tu
- Asegúrate de que ambos
Quadde los portales tengan unBox Collidermarcado comoIs Trigger.
- Asegúrate de que tu
📈 Paso 8: Optimizaciones y Consideraciones Avanzadas
Crear portales con Render Textures puede ser exigente para el rendimiento. Aquí hay algunas formas de optimizar:
- Resolución de la Render Texture: Cuanto menor sea la resolución, menor será la carga. Experimenta con diferentes tamaños para encontrar un equilibrio entre calidad y rendimiento.
- Culling Masks de las Cámaras: En la
PortalACamerayPortalBCamera, en la propiedadCulling Mask, desactiva las capas que no necesitas renderizar (por ejemplo, la capa del jugador, la propia geometría del portal). Esto reduce lo que la cámara tiene que dibujar. - Renderizado Condicional: Desactiva las cámaras del portal cuando el jugador no las esté mirando, o cuando estén muy lejos. Puedes usar
OnBecameVisible()yOnBecameInvisible()en un script adjunto a los portales, o cálculos de distancia y frustum. - Desactivación de Componentes Innecesarios: Las cámaras de portal no necesitan componentes como
Audio ListeneroFlare Layer.
🐛 Resolución de Problemas Comunes
- El portal está negro/vacío:
- Asegúrate de que la
Target Texturede la cámara del portal esté asignada correctamente a laRender Texture. - Verifica que el material del portal esté usando la
Render Texturecorrecta en suAlbedo(oBase Map). - Asegúrate de que los objetos a través del portal no estén en una capa que haya sido excluida por el
Culling Maskde la cámara del portal. - Comprueba que el
Near Clip Planede la cámara del portal no sea demasiado grande, cortando lo que debería verse.
- Asegúrate de que la
- El portal muestra la misma escena (recursión):
- Asegúrate de que el objeto
Quaddel portal no esté en una capa que esté siendo renderizada por la cámara del portal. Crea una nueva capa llamadaPortalGeopara los quads y desactívala en elCulling Maskde las cámaras del portal.
- Asegúrate de que el objeto
- El teletransporte no funciona:
- Verifica que el
Playertenga el tagPlayer. - Asegúrate de que los quads del portal tienen un
Box Collidermarcado comoIs Trigger. - Comprueba que las referencias
playeryreceiverestén asignadas correctamente en el scriptPortalTeleporterde cada portal. - Asegúrate de que el
playertenga unRigidbodysi estás usando colisiones físicas para tu controlador de personaje, o unCharacterControllercon el cualOnTriggerEnterfuncione.
- Verifica que el
🎉 ¡Conclusión y Próximos Pasos!
¡Felicidades! 🎉 Has construido un sistema de portales dimensionales funcional en Unity. Esto es solo el principio. Puedes expandir este sistema de muchas maneras:
- Efectos visuales avanzados: Añade animaciones, partículas, distorsión de la imagen o shaders más complejos para hacer los portales más mágicos.
- Audio espacial: Haz que el sonido del otro lado del portal sea audible y se adapte a la distancia.
- Teletransporte con
CharacterController: Adapta el scriptPortalTeleporterpara trabajar con elCharacterControllerde Unity para movimientos de jugador más robustos. - Portal unidireccional: Modifica el script para que solo se pueda pasar en una dirección.
- Más de dos portales: Implementa una lógica que permita conectar múltiples portales dinámicamente.
La técnica de Render Textures es increíblemente versátil y se utiliza en muchos otros contextos, como espejos, visores de cámaras de seguridad, o incluso mini-mapas dinámicos. ¡Sigue experimentando!
Tutoriales relacionados
- Creando un Sistema de Inventario Modular en Unity para RPGs y Juegos de Aventuraintermediate25 min
- Controlador de Personaje en Primera Persona: Construyendo desde Cero en Unity 🚶♂️ FPS Essentialsintermediate18 min
- Creando un Sistema de Diálogos Ramificados en Unity 🗣️ RPGs y Aventuras Narrativasintermediate25 min
Comentarios (0)
Aún no hay comentarios. ¡Sé el primero!