¿Cómo puedo dibujar un esquema en Unity3d?

13

Estoy tratando de resaltar un rectángulo de altura arbitraria. Pensé que la forma más fácil de hacer esto sería crear un objeto de juego de "caja" separado que delinee el rectángulo.

He intentado con MeshRenderer + Transparent Texture y LineRenderer para delinear los cuatro puntos del rectángulo. Tampoco son muy satisfactorios.

ingrese la descripción de la imagen aquí

(Representador de línea en el centro, cubo a escala a la derecha)

¿Cuál es la forma correcta de hacer esto? Estoy tratando de obtener algo como el rectángulo izquierdo: un perímetro simple de ancho fijo a través de cuatro puntos de mi elección.

Soñador cuervo
fuente

Respuestas:

8

Uso GUI.Box().

Si solo necesita un rectángulo 2D, la GUI es el camino a seguir. Cree un nuevo GUIStyle usando un rectángulo simple como textura (el interior del rectángulo debe ser transparente, por supuesto), configure su Bordervalor para que no se estire y llame GUI.Box(new Rect(...),"",myGuiStyle);.

Puede utilizar el Camera.WorldToScreenPointmétodo si desea delinear algo en coordenadas mundiales (es decir, 3D), solo recuerde que en las coordenadas mundiales de Unity y va de abajo hacia arriba, y en GUI y va de arriba hacia abajo.

Ejemplo de código:

void OnGUI()
{
    //top left point of rectangle
    Vector3 boxPosHiLeftWorld = new Vector3(0.5f, 12, 0);
    //bottom right point of rectangle
    Vector3 boxPosLowRightWorld = new Vector3(1.5f, 0, 0);

    Vector3 boxPosHiLeftCamera = Camera.main.WorldToScreenPoint(boxPosHiLeftWorld);
    Vector3 boxPosLowRightCamera = Camera.main.WorldToScreenPoint(boxPosLowRightWorld);

    float width = boxPosHiLeftCamera.x - boxPosLowRightCamera.x;
    float height = boxPosHiLeftCamera.y - boxPosLowRightCamera.y;


     GUI.Box(new Rect(boxPosHiLeftCamera.x, Screen.Height - boxPosHiLeftCamera.y, width, height),"", highlightBox);
}
No importa
fuente
A menos que me equivoque, ¿GUI.Box () siempre se dibujará sobre cualquier objeto en la escena? ¿Es posible tener un elemento GUI detrás o parcialmente detrás de un objeto de juego?
Raven Dreamer
Sí, la GUI siempre se dibuja después de otros objetos. Hay un truco que puedes usar para renderizar una cámara separada encima de la GUI, pero es un poco difícil de manejar.
importa
Esta respuesta me dio lo que necesitaba, pero la mantengo abierta por el momento con la esperanza de que haya una mejor manera de hacerlo en el caso general.
Raven Dreamer
Acepté su ejemplo de edición de código de adición y arreglé el error de GUI-y-al revés en él.
importa
1

A continuación se muestra un enfoque sin sombreador.

Piense en su cuadro 2D como nada más que cuatro líneas, donde cada línea se estira en una sola dimensión (las otras dos dimensiones son la sección transversal del borde). Esto es muy parecido a construir una caja en la vida real, en la que se juntan longitudes variables de madera que tienen el mismo tamaño de sección transversal.

Con eso en mente, puede diseñar un Componente, por ejemplo BoxBuilder, que cuando se adjunta a un GameObject, crea y administra cuatro GameObjects secundarios. Cada objeto de juego secundario es uno de los bordes de su caja, y puede ser simplemente un cubo 3D que se estira en una sola dimensión. Con una widthy heightdefinida BoxBuildernivel, se puede calcular la posición necesaria y la escala no uniforme de los cuatro bordes del niño. Será una gran cantidad de pos.x=w/2, pos.y=h/2, ..., scale.x=h, scale.y=w, etc tipo de código.

Aunque creo que solo está pidiendo 2-d, tenga en cuenta que esta misma idea se puede aplicar a cuadros 3d si es necesario, donde BoxBuilderahora debe crear y administrar 12 aristas secundarias, pero nuevamente solo escalando cada arista en una dimensión local.

PatoMaestro
fuente
Funcionable, pero MUY complicado.
importa
Si tuviera que hacerlo de esta manera, simplemente usaría renderizadores de 4 líneas ...
Raven Dreamer
Sin embargo, esto maneja adecuadamente la profundidad.
DuckMaestro
1

Una manera simple es usar un sombreador con dos pases: el primer pase usa el sombreador de vértices para escalar un poco el objeto y usa el sombreador de píxeles para colorearlo con un color sólido que coincida con el color que desea que tenga el contorno, y entonces el segundo Pase hace la representación regular.

UBSophung
fuente
¿Podría dar un código de ejemplo para explicar mejor a qué se refiere?
Raven Dreamer
Esto solo funcionaría para objetos convexos (como un rectángulo) cuyo origen está en su centro geométrico.
rootlocus
1

Tuve el mismo problema al crear un esquema, excepto que necesitaba crear el "trazo" para un cubo 3D, y encontré una nueva forma de hacerlo que no he visto en ningún otro lugar en línea.

En la imagen de abajo hay dos formas con contornos. El de la derecha es un cubo construido con LineRenderer, que construye caras planas que siempre giran hacia el usuario. Encontré este método super glitchy, con "golpes" aleatorios que imitaban los triángulos que componen la cara.

El de la izquierda es mi "innovación" con 12 cubos delgados que construyen lo que parece un contorno. Para cambiar el tamaño del "trazo" en el contorno, necesito aumentar / disminuir los tamaños de dos lados de cada uno de los 12 cubos delgados. Esto también funcionaría para esquemas 2D. ¡Solo aplica un material para cambiar el color y listo!

dos esquemas diferentes

En esta imagen puedes ver un detalle de la estructura de este cubo. Todo esto podría crearse en tiempo de ejecución, pero lo hice a mano y lo usé como prefabricado.

detalle

ow3n
fuente
0

Actualmente estoy enfrentando el mismo problema, y ​​mi solución es exactamente lo que sugirieron DuckMaestro y Raven Dreamer: tener un script que cree 4 objetos secundarios en tiempo de ejecución, cada uno de los cuales representa un lado del borde y adjuntar renderizadores de línea a cada uno.

En mi caso, necesitaba cambiar constantemente el tamaño del borde para mantenerlo alrededor de mi objeto (una malla de texto [que usa un renderizador de malla] para un campo de texto personalizado), así que cada actualización que hice esto:


float width = Mathf.Max(renderer.bounds.size.x + paddingX * 2, minWidth);      
float x = renderer.bounds.center.x - width / 2;
float height = renderer.bounds.size.y + paddingY * 2;
float y = renderer.bounds.center.y - height / 2;

AlterBorder(0, new Vector3(x - thickness / 2, y, 0), new Vector3(x + width + thickness / 2, y, 0)); //Bottom edge going left to right
AlterBorder(1, new Vector3(x + width, y + thickness / 2, 0), new Vector3(x + width, y + height - thickness / 2, 0)); //Right edge going bottom to top
AlterBorder(2, new Vector3(x + width + thickness / 2, y + height, 0), new Vector3(x - thickness / 2, y + height, 0)); //Top edge going right to left
AlterBorder(3, new Vector3(x, y + height - thickness / 2, 0), new Vector3(x, y + thickness / 2, 0)); //Left edge going top to bottom

AlterBorder() simplemente accede al renderizador de línea apropiado (especificado por el primer parámetro) y establece su inicio y fin en el primer y segundo vector respectivamente.

Tenga en cuenta que utilicé renderercomo referencia para el tamaño, pero obviamente puede usar cualquier rectángulo, siempre que x, y sea la esquina superior izquierda.

Por lo que puedo decir, esto funciona muy bien, se ve muy bien en el juego porque puedo mover fácilmente mi objeto bordeado en los 3 ejes (incluso rotarlo, y dado que los renderizadores de línea siempre miran hacia la cámara, no se ve raro), y es No es difícil de implementar.

romano
fuente