FOS Mirror
Versión 1.0.1 · requiere FOS Essentials Core 1.0.0 o posterior
Enciende y apaga los espejos — por distancia, por botón, por interacción — desde un único gestor central, con ajustes predefinidos de calidad y una estimación indicativa del coste. Requiere FOS Essentials Core 1.0.0.
Los espejos son lo primero que hunde la tasa de fotogramas de un mundo de VRChat. Este pack no los abarata: nada puede hacerlo. Los vuelve controlados: apagados por defecto, encendidos solo donde y cuando alguien lo ha pedido de verdad.
Puesta en marcha
Sección titulada «Puesta en marcha»- Crea un GameObject vacío y añade FOS Essentials > Mirror > Mirror Manager.
- Pulsa Scan the scene. Cada espejo de VRChat recibe un
FOSMirrorTarget, se conectan su componente de espejo y su gestor, y se rellena la lista del gestor. - Elige el Mode: exclusivo, o cada espejo independiente.
- Añade un control donde un jugador deba poder conmutar un espejo: Mirror Control (UI Button) o Mirror Control (Interact).
Vuelve a lanzar el escaneo tras añadir espejos. Los objetivos existentes nunca se sobrescriben: cualquier ajuste manual sobrevive.
Componentes
Sección titulada «Componentes»| Componente | Función |
|---|---|
FOSMirrorManager |
Uno por escena. Posee el bucle, la prueba de distancia y el modo exclusivo. |
FOSMirrorTarget |
Uno por espejo. Guarda ajustes y el estado encendido/apagado — ningún trabajo por fotograma. |
FOSMirrorButton |
Conmuta un espejo desde un Button de interfaz. Conecta el OnClick por ti. |
FOSMirrorInteract |
Conmuta un espejo cuando un jugador usa el objeto que lo lleva. |
El pack no declara deliberadamente ningún inspector propio para
VRC_MirrorReflection. Unity solo acepta uno por tipo y VRWorldToolkit ya trae el suyo.
Aquí todo pasa por el componente FOS, de modo que ambas herramientas siguen funcionando en
paralelo.
Qué se conmuta realmente
Sección titulada «Qué se conmuta realmente»El componente VRC_MirrorReflection, mediante su .enabled — nunca el GameObject.
SetActive(false) reejecutaría todos los OnEnable de la jerarquía, Udon incluido, lo que
puede reiniciar el estado de scripts sin relación. Además ocultaría el propio objeto
espejo, cuando un espejo suele ser un marco decorado que debe seguir visible al apagarse.
Los Extra components y los Extra colliders se conmutan con él.
Colliderno deriva deBehaviour: deriva directamente deComponent, con su propia propiedadenabled. Por eso los colliders tienen su propia lista.
Nunca metas en esa lista el collider que sirve para volver a encender un espejo: se desactivaría junto con él y el espejo ya no podría encenderse nunca más. El inspector del objetivo señala ese caso como error.
Qué aspecto tiene un espejo apagado
Sección titulada «Qué aspecto tiene un espejo apagado»Desactivar el componente de espejo detiene el reflejo, pero la superficie se sigue dibujando, y un shader de espejo sin nada que reflejar pinta negro puro. Un espejo apagado es por tanto un rectángulo negro, salvo que digas otra cosa.
Dos campos del objetivo deciden el aspecto:
| Mirror surface | Off material | Resultado |
|---|---|---|
| vacío | — | El rectángulo negro. No se toca nada. |
| puesto | vacío | La superficie se oculta. Su draw call desaparece también. |
| puesto | puesto | La superficie cambia a ese material: cristal oscuro, panel esmerilado, placa pintada. |
El escaneo rellena Mirror surface con el renderer que está en el espejo, así que ocultar es el comportamiento por defecto. Vuelve a escanear una escena antigua para aprovecharlo, o usa el botón Use the mirror’s renderer del inspector del objetivo.
El pack incluye un material de apagado listo, Materials/FOSMirrorOff.mat: una placa
oscura y brillante. Usa el shader Standard de Unity, elegido para que el material no
dependa de nada ajeno a Unity. En Quest, cambia su shader por uno móvil como
VRChat/Mobile/Standard Lite, o simplemente deja Off material vacío: ocultar la
superficie no cuesta nada y no necesita ningún material.
El cambio escribe renderer.material, nunca sharedMaterial: escribir sharedMaterial en
ejecución modifica el asset de material en disco, lo que en ClientSim dejaría el
material del espejo sobrescrito para siempre en tu proyecto.
Rendererderiva deComponent, no deBehaviour, y lleva su propia propiedadenabled: la misma razón por la que los colliders tienen su propia lista.
El material «encendido» se captura del renderer al arrancar el mundo. No dejes el material de apagado asignado al renderer en la escena: se capturaría como aspecto del espejo y el reflejo no volvería nunca. El inspector señala ese caso como error.
Esto vale también para el culling por distancia, que suele ser lo que quieres: un espejo fuera de alcance pierde a la vez su reflejo y su superficie.
Las dos mitades del estado de un espejo
Sección titulada «Las dos mitades del estado de un espejo»Un espejo solo se dibuja si ambas son ciertas:
| Mitad | Propietario | Lo fija |
|---|---|---|
| Estado manual — ¿alguien lo quiere encendido? | El objetivo | Botón, interacción, startsOn |
| Alcance — ¿está el jugador bastante cerca? | El gestor | Prueba de distancia, presupuesto por fotograma |
Un espejo que el jugador ha apagado sigue apagado por mucho que se acerque. El alcance nunca enciende un espejo por sí solo: solo deja volver al que ya está encendido.
La distancia
Sección titulada «La distancia»La misma lógica que FOS UI Culling: distancias al cuadrado, dos umbrales, comprobaciones por turnos y una escritura solo cuando el estado cambia de verdad.
| Opción | Efecto |
|---|---|
| Default distance | Metros por debajo de los cuales un espejo puede dibujarse, salvo sobrescritura del objetivo. |
| Show distance (objetivo) | Sobrescritura por espejo. -1 significa «heredar el valor del gestor». |
| Distance reference (objetivo) | Punto desde el que se mide. Vacío significa el propio espejo. |
| Hysteresis | Metros adicionales antes de volver a apagar. |
| Checks per frame | Cuántos espejos se comprueban por fotograma. 2 por defecto. |
El inspector del objetivo deletrea el resultado — «Effective distance: 12 m (inherited
from the manager)» — para que nunca tengas que recordar qué significa -1.
Las distancias se leen una sola vez en Start. Cambiar una en ejecución exige llamar a
RefreshTargets() en el gestor.
Un espejo que el jugador acaba de encender se mide de inmediato en lugar de esperar su turno: plantarse ante un espejo que tarda cuatro fotogramas en aparecer se siente roto.
Los modos
Sección titulada «Los modos»| Modo | Comportamiento |
|---|---|
| Free | Cada espejo es independiente. Nada impide que un jugador los encienda todos. |
| Exclusive | Encender uno apaga todos los demás. |
El modo exclusivo es el ajuste más eficaz de este pack, porque el segundo factor de coste de un mundo es cuántos espejos se dibujan a la vez, y ese número lo decide, si no, el primer curioso que pase.
También se aplica al arrancar: si varios espejos están configurados para empezar encendidos, solo lo hace el primero, y el inspector del gestor lo indica.
Alcance de la conmutación, espejo a espejo
Sección titulada «Alcance de la conmutación, espejo a espejo»| Alcance | Red | Quién paga |
|---|---|---|
| Local | Ninguna | Solo el jugador que lo conmutó |
| Synchronized | [UdonSynced], sincronización manual |
Todos en la instancia |
Local es el valor por defecto, y es el adecuado para un espejo público: quien quiera comprobar su avatar tiene uno, y nadie más lo paga.
Synchronized es para un espejo que forma parte del mundo: un escenario de baile, un
vestuario compartido. La propiedad se toma antes de escribir la variable, y el estado se
reconstruye para quienes llegan después desde OnDeserialization.
Un
SendCustomNetworkEventno se repite para quienes llegan tarde. Por eso el estado vive en una variable sincronizada y no en un evento.
Como el estado se guarda en el objetivo, ambos alcances se mezclan sin problema en una misma escena. En modo exclusivo, ten presente lo que implica mezclarlos: apagar un espejo local solo lo apaga para ti.
La sincronización manual está limitada a aproximadamente una serialización por segundo y por comportamiento. Encender un espejo sincronizado en modo exclusivo escribe también en los demás espejos sincronizados, así que evita volver sincronizados una docena de espejos cuando solo uno lo necesita.
La calidad
Sección titulada «La calidad»Se exponen en el objetivo dos ajustes del espejo de VRChat: las capas reflejadas y la desactivación de luces por píxel.
| Ajuste | Capas reflejadas |
|---|---|
| Untouched (por defecto) | No se aplica nada; el espejo conserva sus propios ajustes. |
| Players only | Player + MirrorReflection — los avatares sobre el skybox. |
| Players and world | Default + Player + Environment + MirrorReflection. |
| World only | Default + Environment. Ningún avatar se dibuja dos veces. |
| Nothing | Una máscara vacía. El espejo dibuja un reflejo en blanco. |
| Custom | Lo que fijes a mano en Reflected layers. |
El ajuste se resuelve en el campo Reflected layers en cuanto lo eliges, así que la
máscara que ves es la que se aplicará. El gestor la escribe en el espejo en Start; el
inspector del objetivo también ofrece Apply to the mirror now para escribirla desde el
editor, algo útil cuando quieres que las comprobaciones de VRWorldToolkit la vean.
Untouched existe porque una herramienta nunca debe sobrescribir en silencio ajustes hechos
a mano. No se escribe nada hasta que eliges un ajuste.
El inspector avisa de los errores clásicos: la máscara por defecto sin tocar, UiMenu
reflejado, PlayerLocal reflejado, y los jugadores reflejados sin la capa
MirrorReflection, lo que hace que se vean entre ellos pero no a sí mismos.
La estimación de coste
Sección titulada «La estimación de coste»Los inspectores del objetivo y del gestor muestran una nota indicativa sobre 100. Es una estimación ponderada, no una medición, y se construye en este orden:
-
Las capas reflejadas, factor dominante. Un espejo dibuja la escena por segunda vez — dos veces en RV. Lo que cuesta es por tanto lo que vuelve a dibujar. Reflejar avatares duplica el elemento más pesado de una instancia poblada, y ese elemento crece con el número de jugadores, no con el mundo. Un espejo de «solo mundo» cuesta una fracción del mismo espejo reflejando jugadores, a igual tamaño y posición.
-
Cuántos espejos pueden dibujarse a la vez. Dos espejos encendidos son dos pasadas de render extra; entre ellos no se comparte nada. El modo exclusivo elimina este factor de raíz, así que la nota de la escena toma el peor espejo en lugar de la suma.
-
La cobertura de pantalla, la última y con poco peso. VRChat dibuja un espejo en una textura dimensionada por la resolución del visor, no por el espejo: un espejo grande no cuesta mecánicamente más que uno pequeño. El tamaño cuenta de forma indirecta: un espejo grande se ve desde más lejos, se llena de avatares más a menudo y se descarta por distancia con menos eficacia.
Usa la nota para comparar dos ajustes de un mismo mundo. No es una cifra absoluta y no sustituye a un análisis de rendimiento.
El gizmo
Sección titulada «El gizmo»Seleccionar un espejo dibuja su plano, una flecha a lo largo de la cara reflectante y una cruz roja sobre el dorso. Un espejo es un objeto plano: nada en la vista de escena distingue uno bien colocado de otro girado 180°, y normalmente te enteras dentro del juego, plantado ante un rectángulo negro.
La normal se lee del mesh, no se adivina del transform, así que sigue siendo correcta sea cual sea el mesh que use el espejo.
El gizmo vive en un script de editor con [DrawGizmo]. Deliberadamente no es un
OnDrawGizmos dentro del comportamiento de Udon: Udon nunca llama a ese método, y UdonSharp
tendría que compilarlo igualmente, junto con Gizmos y Handles, que no están expuestos.
Scripting
Sección titulada «Scripting»Todos los puntos de entrada públicos son sin parámetros, así que cualquier script puede
alcanzarlos con SendCustomEvent:
| Llamada | En | Efecto |
|---|---|---|
FOSRequestToggle() |
FOSMirrorTarget |
Invierte el espejo |
FOSRequestOn() / FOSRequestOff() |
FOSMirrorTarget |
Fuerza un estado |
TriggerMirror() |
FOSMirrorButton / FOSMirrorInteract |
Ejecuta la acción del control |
FOSTurnAllOff() |
FOSMirrorManager |
Botón de pánico: apaga todos los espejos |
RefreshTargets() |
FOSMirrorManager |
Reconstruye las cachés tras un cambio de escena |
El cableado OnClick que necesita un botón de interfaz es
SendCustomEvent("TriggerMirror") sobre el UdonBehaviour del control. Acertarlo a mano
implica apuntar al UdonBehaviour y no al componente visible, y escribir el nombre del evento
sin erratas: una errata no lanza ningún error, el botón simplemente no hace nada. El
inspector lo conecta con un clic y te dice si ya lo está.
Notas y límites
Sección titulada «Notas y límites»- Un gestor por escena. Varios gestores se pelearían por los mismos espejos; el inspector lo señala como error.
- Los espejos heredados se omiten. Solo el componente de espejo del SDK3 está expuesto a Udon. El escaneo los cuenta y te lo dice.
- Los espejos creados en ejecución no se recogen automáticamente. Rellena
targetsy llama aRefreshTargets(). - Un espejo sin gestor no se puede conmutar. El escaneo se lo asigna; el inspector del objetivo lo indica cuando falta.
- Quest y PC se comportan igual aquí: no hay código específico de plataforma, ni podría haberlo, porque Udon se compila una sola vez para ambas.
