반응형
절차적 메시로 정다각기둥, 원기둥 그리기에서 정점의 개수를 줄여보자.
ProceduralRegularPrismUpgrade.cs를 추가하고 ProceduralRegularPrism.cs를 복사한 후 코드를 수정한다.
옆면 생성 코드를 개선하면 된다.
밑면의 정점을 먼저 만들고 윗면의 정점을 추가한다.
그리고 해당 정점 2 * N개만 triangles에 배치한다. (이전 코드는 4 * N개였다.)
/* -------------------- 옆면 + 개선 -------------------- */
vIdx = 2 * polygon + 2;
for (int i = 1; i <= polygon; i++)
{
float angle = -i * (Mathf.PI * 2.0f) / polygon;
vertices[vIdx++]
= new Vector3(Mathf.Cos(angle) * size, -height / 2.0f, Mathf.Sin(angle) * size) + offset;
}
for (int i = 1; i <= polygon; i++)
{
float angle = -i * (Mathf.PI * 2.0f) / polygon;
vertices[vIdx++]
= new Vector3(Mathf.Cos(angle) * size, height / 2.0f, Mathf.Sin(angle) * size) + offset;
}
tIdx = 6 * polygon;
for (int i = 0; i < polygon - 1; i++)
{
triangles[tIdx++]= (2 * polygon + 2) + i + 0;
triangles[tIdx++]= (2 * polygon + 2) + i + 1;
triangles[tIdx++]= (2 * polygon + 2) + i + polygon;
triangles[tIdx++]= (2 * polygon + 2) + i + 1;
triangles[tIdx++]= (2 * polygon + 2) + i + 1 + polygon;
triangles[tIdx++]= (2 * polygon + 2) + i + polygon;
}
triangles[tIdx++] = (2 * polygon + 2) + polygon - 1;
triangles[tIdx++] = (2 * polygon + 2) + 0;
triangles[tIdx++] = (2 * polygon + 2) + polygon - 1 + polygon;
triangles[tIdx++] = (2 * polygon + 2) + 0;
triangles[tIdx++] = (2 * polygon + 2) + polygon;
triangles[tIdx++] = (2 * polygon + 2) + polygon - 1 + polygon;
개선된 코드로 게임을 실행해보자. (왼쪽이 Upgrade ver)
N이 작은 경우 정점이 부족하여 라이팅 연산이 제대로 되지 않는다.
하지만 N이 적절히 크다면 정점이 정보를 잘 공유하여 라이팅 연산을 잘 하게 된다.
즉, N이 클수록 옆면이 연속으로 붙어있게 되므로 정점을 줄이는 것이 성능 향상에 도움이 된다.
또한 정점이 적은 쪽이 더 부드럽다.
처음에는 정점이 부족해서 라이팅 연산이 잘 안되지만, N이 커질수록 큰 문제가 없다.
이전 정다각기둥과 개선된 정다각기둥을 비교해보자.
원기둥에 가까워질수록 두 오브젝트는 큰 차이가 없다.
따라서 N이 큰 경우라면 정점이 적은 것이 성능에 도움이 된다.
전체 코드는 다음과 같다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class ProceduralRegularPrismUpgrade : MonoBehaviour
{
public int polygon = 3;
public float size = 1.0f;
public float height = 1.0f;
public Vector3 offset = new Vector3(0, 0, 0);
Mesh mesh;
Vector3[] vertices;
int[] triangles;
public void makePolygon(int polygon)
{
setMeshData(size, polygon);
createProceduralMesh();
}
void OnValidate()
{
if (mesh == null) return;
if (size > 0 || offset.magnitude > 0 || polygon >= 3 || height > 0)
{
setMeshData(size, polygon);
createProceduralMesh();
}
}
void Start()
{
mesh = GetComponent<MeshFilter>().mesh;
setMeshData(size, polygon);
createProceduralMesh();
}
void setMeshData(float size, int polygon)
{
/* -------------------- 밑면 -------------------- */
vertices = new Vector3[(polygon + 1) + (polygon + 1) + (polygon * 4)];
vertices[0] = new Vector3(0, -height / 2.0f, 0) + offset;
for (int i = 1; i <= polygon; i++)
{
float angle = -i * (Mathf.PI * 2.0f) / polygon;
vertices[i]
= new Vector3(Mathf.Cos(angle) * size, -height / 2.0f, Mathf.Sin(angle) * size) + offset;
}
triangles = new int[(3 * polygon) + (3 * polygon) + (6 * polygon)];
for (int i = 0; i < polygon - 1; i++)
{
triangles[i * 3] = 0;
triangles[i * 3 + 1] = i + 2;
triangles[i * 3 + 2] = i + 1;
}
triangles[3 * polygon - 3] = 0;
triangles[3 * polygon - 2] = 1;
triangles[3 * polygon - 1] = polygon;
/* -------------------- 윗면 -------------------- */
int vIdx = polygon + 1;
vertices[vIdx++] = new Vector3(0, height / 2.0f, 0) + offset;
for (int i = 1; i <= polygon; i++)
{
float angle = -i * (Mathf.PI * 2.0f) / polygon;
vertices[vIdx++]
= new Vector3(Mathf.Cos(angle) * size, height / 2.0f, Mathf.Sin(angle) * size) + offset;
}
int tIdx = 3 * polygon;
for (int i = 0; i < polygon - 1; i++)
{
triangles[tIdx++] = polygon + 1;
triangles[tIdx++] = i + 1 + polygon + 1;
triangles[tIdx++] = i + 2 + polygon + 1;
}
triangles[tIdx++] = polygon + 1;
triangles[tIdx++] = polygon + polygon + 1;
triangles[tIdx++] = 1 + polygon + 1;
/* -------------------- 옆면 + 개선 -------------------- */
vIdx = 2 * polygon + 2;
for (int i = 1; i <= polygon; i++)
{
float angle = -i * (Mathf.PI * 2.0f) / polygon;
vertices[vIdx++]
= new Vector3(Mathf.Cos(angle) * size, -height / 2.0f, Mathf.Sin(angle) * size) + offset;
}
for (int i = 1; i <= polygon; i++)
{
float angle = -i * (Mathf.PI * 2.0f) / polygon;
vertices[vIdx++]
= new Vector3(Mathf.Cos(angle) * size, height / 2.0f, Mathf.Sin(angle) * size) + offset;
}
tIdx = 6 * polygon;
for (int i = 0; i < polygon - 1; i++)
{
triangles[tIdx++]= (2 * polygon + 2) + i + 0;
triangles[tIdx++]= (2 * polygon + 2) + i + 1;
triangles[tIdx++]= (2 * polygon + 2) + i + polygon;
triangles[tIdx++]= (2 * polygon + 2) + i + 1;
triangles[tIdx++]= (2 * polygon + 2) + i + 1 + polygon;
triangles[tIdx++]= (2 * polygon + 2) + i + polygon;
}
triangles[tIdx++] = (2 * polygon + 2) + polygon - 1;
triangles[tIdx++] = (2 * polygon + 2) + 0;
triangles[tIdx++] = (2 * polygon + 2) + polygon - 1 + polygon;
triangles[tIdx++] = (2 * polygon + 2) + 0;
triangles[tIdx++] = (2 * polygon + 2) + polygon;
triangles[tIdx++] = (2 * polygon + 2) + polygon - 1 + polygon;
Debug.Log("Upgrade : " + vIdx + " " + tIdx);
}
void createProceduralMesh()
{
mesh.Clear();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
Destroy(this.GetComponent<MeshCollider>());
this.gameObject.AddComponent<MeshCollider>();
}
}
참고 - PolygonController.cs를 빈 오브젝트에 추가하여 동시에 N 값을 변경하였다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PolygonController : MonoBehaviour
{
public GameObject pol1, pol2;
public int polygon;
ProceduralRegularPrism prp;
ProceduralRegularPrismUpgrade prpu;
void OnValidate()
{
if (prp == null) return;
if (polygon >= 3)
{
prp.makePolygon(polygon);
prpu.makePolygon(polygon);
}
}
void Start()
{
prp = pol1.GetComponent<ProceduralRegularPrism>();
prpu = pol2.GetComponent<ProceduralRegularPrismUpgrade>();
}
}
각 스크립트에는 아래 함수를 추가하였다.
public void makePolygon(int polygon)
{
setMeshData(size, polygon);
createProceduralMesh();
}
위의 실행결과는 아래의 unitypackage에서 확인 가능하다.
Unity Plus:
Unity Pro:
Unity 프리미엄 학습:
반응형
댓글