Unity에서 올바르게 선을 그리는 방법


27

더 공식적으로 언급 된 단일 지점에서 몇 줄을 그려야하는 게임을 진행하고 있습니다.

좌표 x, y를 가진 점 A가 주어지면 i 번째 줄의 좌표가 xi, yi라는 n 줄을 그립니다. Unity3D의 LineRenderer 기능을 사용하면 폴리 라인 만 렌더링하므로 특정 지점에서 둘 이상의 선을 그릴 수 없었습니다.

현재 라인을 성공적으로 렌더링하는 Debug.DrawLine () 메서드를 사용하고 있습니다. Unity 예제에 표시된 것처럼 GL.Begin ()을 사용해 보았지만 선이 그려지는 것을 볼 수 없습니다.

내 질문은 :이 작업을 수행하는 다른 방법이 있습니까? 그렇지 않은 경우 재생 모드에서 Debug.DrawLine ()으로 그리는 선을 어떻게 표시 할 수 있습니까? Gizmos.DrawLine ()을 사용할 수 있음을 보았지만 사용법을 잘 이해하지 못했습니다.

답변:


48

GL 라인 사용 :

GL API를 사용하여 선을 그리는 것이 좋습니다 . 화면에서 선 두께는 항상 1px이며 변경할 수있는 옵션이 없습니다. 그림자도 없습니다.

GL 메소드 호출은 즉시 실행되므로 카메라가 이미 렌더링 된 후에 호출해야합니다.

스크립트를 카메라에 연결하고 Camera.OnPostRender ()를 사용 하면 게임 창에서 렌더링하는 데 적합합니다. 편집기에 표시하려면 MonoBehaviour.OnDrawGizmos ()를 사용할 수 있습니다 .

GL API로 선을 그리는 기본 코드는 다음과 같습니다.

public Material lineMat = new Material("Shader \"Lines/Colored Blended\" {" + "SubShader { Pass { " + "    Blend SrcAlpha OneMinusSrcAlpha " + "    ZWrite Off Cull Off Fog { Mode Off } " + "    BindChannels {" + "      Bind \"vertex\", vertex Bind \"color\", color }" + "} } }");

void OnPostRender() {
    GL.Begin(GL.LINES);
    lineMat.SetPass(0);
    GL.Color(new Color(0f, 0f, 0f, 1f));
    GL.Vertex3(0f, 0f, 0f);
    GL.Vertex3(1f, 1f, 1f);
    GL.End();
}

다음은 주어진 모든 포인트를 메인 포인트에 연결하는 전체 스크립트입니다. 코드 주석에 올바르게 설정하기위한 지침과 진행 상황에 대한 지침이 있습니다.

연결선의 색상을 변경하는 데 문제가있는 경우 등의 정점 색상을 고려한 선 재질에 셰이더를 사용해야합니다 Unlit/Color.

using UnityEngine;
using System.Collections;

// Put this script on a Camera
public class DrawLines : MonoBehaviour {

    // Fill/drag these in from the editor

    // Choose the Unlit/Color shader in the Material Settings
    // You can change that color, to change the color of the connecting lines
    public Material lineMat;

    public GameObject mainPoint;
    public GameObject[] points;

    // Connect all of the `points` to the `mainPoint`
    void DrawConnectingLines() {
        if(mainPoint && points.Length > 0) {
            // Loop through each point to connect to the mainPoint
            foreach(GameObject point in points) {
                Vector3 mainPointPos = mainPoint.transform.position;
                Vector3 pointPos = point.transform.position;

                GL.Begin(GL.LINES);
                lineMat.SetPass(0);
                GL.Color(new Color(lineMat.color.r, lineMat.color.g, lineMat.color.b, lineMat.color.a));
                GL.Vertex3(mainPointPos.x, mainPointPos.y, mainPointPos.z);
                GL.Vertex3(pointPos.x, pointPos.y, pointPos.z);
                GL.End();
            }
        }
    }

    // To show the lines in the game window whne it is running
    void OnPostRender() {
        DrawConnectingLines();
    }

    // To show the lines in the editor
    void OnDrawGizmos() {
        DrawConnectingLines();
    }
}

그림자에 대한 추가 참고 : 나는 지오메트리 셰이더가 그림자를 만들하지만 GL 호출 즉시 실행하기 때문에, 그들은 정상적인 렌더링 파이프 라인에없는 및 사용 탐구 AutoLight.cgincLighting.cginc픽업되지 않습니다 ShadowCaster패스를.


그림자와 반지름이있는 선

선 두께를 변경하고 사실적인 그림자를 원할 경우. 원통 메쉬를 사용하여 높이를 조정하십시오.

다음은 각 점을 메인 점에 연결하기 위해 실린더를 만드는 스크립트입니다. 빈 게임 오브젝트에 놓고 매개 변수를 채우십시오. 추가 연결 개체를 모두 보유합니다.

using UnityEngine;
using System.Collections;

public class ConnectPointsWithCylinderMesh : MonoBehaviour {

    // Material used for the connecting lines
    public Material lineMat;

    public float radius = 0.05f;

    // Connect all of the `points` to the `mainPoint`
    public GameObject mainPoint;
    public GameObject[] points;

    // Fill in this with the default Unity Cylinder mesh
    // We will account for the cylinder pivot/origin being in the middle.
    public Mesh cylinderMesh;


    GameObject[] ringGameObjects;

    // Use this for initialization
    void Start () {
        this.ringGameObjects = new GameObject[points.Length];
        //this.connectingRings = new ProceduralRing[points.Length];
        for(int i = 0; i < points.Length; i++) {
            // Make a gameobject that we will put the ring on
            // And then put it as a child on the gameobject that has this Command and Control script
            this.ringGameObjects[i] = new GameObject();
            this.ringGameObjects[i].name = "Connecting ring #" + i;
            this.ringGameObjects[i].transform.parent = this.gameObject.transform;

            // We make a offset gameobject to counteract the default cylindermesh pivot/origin being in the middle
            GameObject ringOffsetCylinderMeshObject = new GameObject();
            ringOffsetCylinderMeshObject.transform.parent = this.ringGameObjects[i].transform;

            // Offset the cylinder so that the pivot/origin is at the bottom in relation to the outer ring gameobject.
            ringOffsetCylinderMeshObject.transform.localPosition = new Vector3(0f, 1f, 0f);
            // Set the radius
            ringOffsetCylinderMeshObject.transform.localScale = new Vector3(radius, 1f, radius);

            // Create the the Mesh and renderer to show the connecting ring
            MeshFilter ringMesh = ringOffsetCylinderMeshObject.AddComponent<MeshFilter>();
            ringMesh.mesh = this.cylinderMesh;

            MeshRenderer ringRenderer = ringOffsetCylinderMeshObject.AddComponent<MeshRenderer>();
            ringRenderer.material = lineMat;

        }
    }

    // Update is called once per frame
    void Update () {
        for(int i = 0; i < points.Length; i++) {
            // Move the ring to the point
            this.ringGameObjects[i].transform.position = this.points[i].transform.position;

            // Match the scale to the distance
            float cylinderDistance = 0.5f*Vector3.Distance(this.points[i].transform.position, this.mainPoint.transform.position);
            this.ringGameObjects[i].transform.localScale = new Vector3(this.ringGameObjects[i].transform.localScale.x, cylinderDistance, this.ringGameObjects[i].transform.localScale.z);

            // Make the cylinder look at the main point.
            // Since the cylinder is pointing up(y) and the forward is z, we need to offset by 90 degrees.
            this.ringGameObjects[i].transform.LookAt(this.mainPoint.transform, Vector3.up);
            this.ringGameObjects[i].transform.rotation *= Quaternion.Euler(90, 0, 0);
        }
    }
}


2
Booo, 선에는 그림자가 없습니다. : p
MichaelHouse

좋은 답변입니다. 나는 당신이 나를 위해 무엇을 가지고 있는지 검사하고 있습니다. 세부 사항에 대해 많이 감사드립니다. 나는 성공하지 않고 이와 비슷한 것을했습니다. 나는 어디에서 잘못되었는지 알기 위해 당신의 모범을 잘 살펴볼 것입니다. 감사합니다!
Christo

OnPostRender를 사용하지 않고이 작업을 수행 할 수 있습니까?
Christo

모노 동작에서 파생되지 않은 사용자 정의 클래스에서 수행해야하므로 OnPostRender 메서드가 없습니다.
Christo

1
GL.Color ()에 어떤 색을 넣었는지 또는 전혀 호출하는지 여부는 중요하지 않습니다. 선의 색은 재질의 색을 유지합니다. 내 선 재질이 현재 셰이더 Unlit / Color를 사용하고 있습니다.
Erhannis 2016

5

큐브를 통한 그림자와 반지름이있는 선

의 오프가는 @ MadLittleMod의 대답은 여기, 큐브를 기반으로 라인 (사용하여 다른 버전 : 12 트리스를 대신 실린더 기초 라인 (의) : 80 트리스 ) :

using UnityEngine;
using System.Collections;

public class ConnectPointsWithCubeMesh : MonoBehaviour 
{

    // Material used for the connecting lines
    public Material lineMat;

    public float radius = 0.05f;

    // Connect all of the `points` to the `mainPoint`
    public GameObject mainPoint;
    public GameObject[] points;

    // Fill in this with the default Unity Cube mesh
    // We will account for the cube pivot/origin being in the middle.
    public Mesh cubeMesh;


    GameObject[] ringGameObjects;

    // Use this for initialization
    void Start() 
    {
        this.ringGameObjects = new GameObject[points.Length];
        //this.connectingRings = new ProceduralRing[points.Length];
        for(int i = 0; i < points.Length; i++) {
            // Make a gameobject that we will put the ring on
            // And then put it as a child on the gameobject that has this Command and Control script
            this.ringGameObjects[i] = new GameObject();
            this.ringGameObjects[i].name = "Connecting ring #" + i;
            this.ringGameObjects[i].transform.parent = this.gameObject.transform;

            // We make a offset gameobject to counteract the default cubemesh pivot/origin being in the middle
            GameObject ringOffsetCubeMeshObject = new GameObject();
            ringOffsetCubeMeshObject.transform.parent = this.ringGameObjects[i].transform;

            // Offset the cube so that the pivot/origin is at the bottom in relation to the outer ring     gameobject.
            ringOffsetCubeMeshObject.transform.localPosition = new Vector3(0f, 1f, 0f);
            // Set the radius
            ringOffsetCubeMeshObject.transform.localScale = new Vector3(radius, 1f, radius);

            // Create the the Mesh and renderer to show the connecting ring
            MeshFilter ringMesh = ringOffsetCubeMeshObject.AddComponent<MeshFilter>();
            ringMesh.mesh = this.cubeMesh;

            MeshRenderer ringRenderer = ringOffsetCubeMeshObject.AddComponent<MeshRenderer>();
            ringRenderer.material = lineMat;

        }
    }

    // Update is called once per frame
    void Update() 
    {
        for(int i = 0; i < points.Length; i++) {
            // Move the ring to the point
            this.ringGameObjects[i].transform.position = this.points[i].transform.position;

            this.ringGameObjects[i].transform.position = 0.5f * (this.points[i].transform.position + this.mainPoint.transform.position);
            var delta = this.points[i].transform.position - this.mainPoint.transform.position;
            this.ringGameObjects[i].transform.position += delta;

            // Match the scale to the distance
            float cubeDistance = Vector3.Distance(this.points[i].transform.position, this.mainPoint.transform.position);
            this.ringGameObjects[i].transform.localScale = new Vector3(this.ringGameObjects[i].transform.localScale.x, cubeDistance, this.ringGameObjects[i].transform.localScale.z);

            // Make the cube look at the main point.
            // Since the cube is pointing up(y) and the forward is z, we need to offset by 90 degrees.
            this.ringGameObjects[i].transform.LookAt(this.mainPoint.transform, Vector3.up);
            this.ringGameObjects[i].transform.rotation *= Quaternion.Euler(90, 0, 0);
        }
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.