Skip to content

Instantly share code, notes, and snippets.

@LJH960101
Created March 20, 2019 09:56
Show Gist options
  • Select an option

  • Save LJH960101/1063aabbd6d9a3ee18c99c4936867afc to your computer and use it in GitHub Desktop.

Select an option

Save LJH960101/1063aabbd6d9a3ee18c99c4936867afc to your computer and use it in GitHub Desktop.
엔진심화 2차 과제2
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
struct FMeshData
{
public List<Vector3> vertices;
public List<int> triangles;
public List<Vector2> uvs;
}
class Quad
{
public FMeshData meshData;
public static int SizeOfVertex()
{
return 4;
}
public static int SizeOfIndex()
{
return 6;
}
public static Quad CreateQuad(Vector3 center, Vector3 rotation, Vector2 uvLeftDown, Vector2 uvRightTop, float size = 5f, bool isReverse = false)
{
Quad quad = new Quad();
quad.meshData = new FMeshData();
quad.meshData.vertices = new List<Vector3>();
quad.meshData.triangles = new List<int>();
quad.meshData.uvs = new List<Vector2>();
// 중심이 0,0,0인 벡터 만들기
quad.meshData.vertices.Add(new Vector3(-size / 2, -size / 2, 0f));
quad.meshData.vertices.Add(new Vector3(-size / 2, size / 2, 0f));
quad.meshData.vertices.Add(new Vector3(size / 2, size / 2, 0f));
quad.meshData.vertices.Add(new Vector3(size / 2, -size / 2, 0f));
// uv 만들기
quad.meshData.uvs = new List<Vector2>();
quad.meshData.uvs.Add(new Vector2(uvLeftDown.x, uvLeftDown.y));
quad.meshData.uvs.Add(new Vector2(uvLeftDown.x, uvRightTop.y));
quad.meshData.uvs.Add(new Vector2(uvRightTop.x, uvRightTop.y));
quad.meshData.uvs.Add(new Vector2(uvRightTop.x, uvLeftDown.y));
// 벡터 회전하기
Matrix4x4 rotateMatrix = Matrix4x4.Rotate(Quaternion.Euler(rotation));
for (int i = 0; i < 4; ++i)
{
quad.meshData.vertices[i] = rotateMatrix * quad.meshData.vertices[i];
}
// 회전한 벡터 움직이기
for (int i = 0; i < 4; ++i)
{
quad.meshData.vertices[i] = center + quad.meshData.vertices[i];
}
if (isReverse)
{
quad.meshData.triangles.Add(0);
quad.meshData.triangles.Add(1);
quad.meshData.triangles.Add(2);
quad.meshData.triangles.Add(2);
quad.meshData.triangles.Add(3);
quad.meshData.triangles.Add(0);
}
else
{
quad.meshData.triangles.Add(0);
quad.meshData.triangles.Add(2);
quad.meshData.triangles.Add(1);
quad.meshData.triangles.Add(2);
quad.meshData.triangles.Add(0);
quad.meshData.triangles.Add(3);
}
return quad;
}
};
class Cube
{
public FMeshData meshData;
public static int SizeOfVertex()
{
return Quad.SizeOfVertex() * 6;
}
public static int SizeOfIndex()
{
return Quad.SizeOfIndex() * 6;
}
/* Parameters :
V3: Center, front, back, left, right, top, bottom
V2,V2: front, back, left, right, top, bottom
Vector3: scale
*/
public static Cube CreateCube(Vector3 center,
Vector2 uvLeftDown_front, Vector2 uvRightTop_front,
Vector2 uvLeftDown_back, Vector2 uvRightTop_back,
Vector2 uvLeftDown_left, Vector2 uvRightTop_left,
Vector2 uvLeftDown_right, Vector2 uvRightTop_right,
Vector2 uvLeftDown_top, Vector2 uvRightTop_top,
Vector2 uvLeftDown_bottom, Vector2 uvRightTop_bottom,
Vector3 scale)
{
Cube cube = new Cube();
cube.meshData = new FMeshData();
cube.meshData.vertices = new List<Vector3>();
cube.meshData.triangles = new List<int>();
cube.meshData.uvs = new List<Vector2>();
for (int k = 0; k < 6; ++k)
{
Quad quad;
switch (k)
{
case 0: // 정면
quad = Quad.CreateQuad(new Vector3(0f, 0f, -0.5f), Vector3.zero, uvLeftDown_front, uvRightTop_front, 1f, true);
break;
case 1: // 후면
quad = Quad.CreateQuad(new Vector3(0f, 0f, 0.5f), Vector3.zero, uvLeftDown_back, uvRightTop_back, 1f);
break;
case 2: // 좌
quad = Quad.CreateQuad(new Vector3(-0.5f, 0f, 0f), new Vector3(0.0f, -90.0f, 0.0f), uvLeftDown_left, uvRightTop_left, 1f);
break;
case 3: // 우
quad = Quad.CreateQuad(new Vector3(0.5f, 0f, 0f), new Vector3(0.0f, 90.0f, 0.0f), uvLeftDown_right, uvRightTop_right, 1f);
break;
case 4: // 상단
quad = Quad.CreateQuad(new Vector3(0f, 0.5f, 0f), new Vector3(-90.0f, 0.0f, 0.0f), uvLeftDown_top, uvRightTop_top, 1f);
break;
case 5: // 하단
quad = Quad.CreateQuad(new Vector3(0f, -0.5f, 0f), new Vector3(90.0f, 0.0f, 0.0f), uvLeftDown_bottom, uvRightTop_bottom, 1f);
break;
default:
Debug.Log("잘못된 K");
throw new System.Exception();
}
// 위치 * 이동 변환 행렬
Matrix4x4 scaleAndTranslateMatrix = Matrix4x4.Scale(scale) * Matrix4x4.Translate(center);
for (int i = 0; i < quad.meshData.vertices.Count; ++i)
{
// 버텍스 위치를 스케일, 센터에 맞춰준다.
quad.meshData.vertices[i] = scaleAndTranslateMatrix.MultiplyPoint3x4(quad.meshData.vertices[i]);
}
for (int i = 0; i < quad.meshData.triangles.Count; ++i)
{
quad.meshData.triangles[i] = quad.meshData.triangles[i] + k * 4;
}
cube.meshData.triangles.AddRange(quad.meshData.triangles);
cube.meshData.vertices.AddRange(quad.meshData.vertices);
cube.meshData.uvs.AddRange(quad.meshData.uvs);
}
return cube;
}
};
[ExecuteInEditMode]
public class MinecraftCharacter : MonoBehaviour
{
List<Transform> bones = null;
Dictionary<string, int> boneNames = null;
List<Matrix4x4> bindposes = null;
List<BoneWeight> boneWeights = null;
private int GetBonesIndexByName(string name)
{
if (!boneNames.ContainsKey(name))
{
Debug.Log("Not exsit bone!! : " + name);
return -1;
}
return boneNames[name];
}
// 본을 입력 받는다. 루트는 본으로 받지 않음.
private static List<Transform> GetBones(Transform root)
{
List<Transform> transforms = new List<Transform>();
int childCount = root.childCount;
for (int i = 0; i < childCount; ++i)
{
List<Transform> childTransforms = _GetBones(root.GetChild(i));
transforms.AddRange(childTransforms);
}
return transforms;
}
// 본을 제귀로 찾아내는 함수.
private static List<Transform> _GetBones(Transform root)
{
List<Transform> transforms = new List<Transform>();
int childCount = root.childCount;
transforms.Add(root);
for (int i = 0; i < childCount; ++i)
{
List<Transform> childTransforms = _GetBones(root.GetChild(i));
transforms.AddRange(childTransforms);
}
return transforms;
}
private List<BoneWeight> CreateBoneWeight(int verticesCount, string boneName)
{
List<BoneWeight> newBoneWeights = new List<BoneWeight>();
BoneWeight boneWight = new BoneWeight()
{
boneIndex0 = GetBonesIndexByName(boneName),
weight0 = 1.0f
};
for (int j_vertic = 0; j_vertic < verticesCount; ++j_vertic)
{
newBoneWeights.Add(boneWight);
}
return newBoneWeights;
}
private void Awake()
{
Mesh m = new Mesh();
List<Vector3> vertices = new List<Vector3>();
List<Vector2> uvs = new List<Vector2>();
List<int> triangles = new List<int>();
boneWeights = new List<BoneWeight>();
bindposes = new List<Matrix4x4>();
bones = GetBones(transform.GetChild(0));
boneNames = new Dictionary<string, int>();
// 본이름 - 인덱스 사전을 만든다.
for (int i = 0; i < bones.Count; ++i)
{
boneNames[bones[i].name] = i;
}
// 바인드 포스를 셋팅한다.
for (int i = 0; i < bones.Count; ++i)
{
bindposes.Add(bones[i].worldToLocalMatrix * transform.localToWorldMatrix);
}
const float pixel4 = 0.0625f;
const float pixel8 = 0.125f;
const float pixel12 = 0.1875f;
const float pixel16 = 0.25f;
for (int i_part = 0; i_part < 6; ++i_part)
{
Cube cube = new Cube();
switch (i_part)
{
case 0: // head
cube = Cube.CreateCube(new Vector3(0.0f, 1.25f, 0.0f),
new Vector2(0.125f, 0.75f), new Vector2(0.25f, 0.875f),
new Vector2(0.375f, 0.75f), new Vector2(0.5f, 0.875f),
new Vector2(0.25f, 0.75f), new Vector2(0.375f, 0.875f),
new Vector2(0f, 0.75f), new Vector2(0.125f, 0.875f),
new Vector2(0.125f, 0.875f), new Vector2(0.25f, 1f),
new Vector2(0.25f, 0.875f), new Vector2(0.375f, 1f),
new Vector3(1f, 1f, 0.5f));
boneWeights.AddRange(CreateBoneWeight(Cube.SizeOfVertex(), "Head"));
break;
case 1: // body
cube = Cube.CreateCube(new Vector3(0.0f, 0.0f, 0.0f),
new Vector2(0.3125f, 0.5f), new Vector2(0.3125f + pixel8, 0.5f + pixel12),
new Vector2(0.3125f + pixel8, 0.5f), new Vector2(0.5f + pixel8, 0.6875f),
new Vector2(0.5625f, 0.5f), new Vector2(0.5625f + pixel4, 0.5f + pixel12),
new Vector2(pixel16, 0.5f), new Vector2(pixel16 + pixel4, 0.5f + pixel12),
new Vector2(0.3125f, 0.6875f), new Vector2(0.3125f + 0.125f, 0.75f),
new Vector2(0.3125f + pixel8, 0.6875f), new Vector2(0.3125f + pixel8 + 0.125f, 0.75f),
new Vector3(1.0f, 1.5f, 0.5f));
boneWeights.AddRange(CreateBoneWeight(Cube.SizeOfVertex(), "Body"));
break;
case 2: // left arm
cube = Cube.CreateCube(new Vector3(-1.5f, 0.0f, 0.0f),
new Vector2(0.5f + pixel4, 0f), new Vector2(0.5f + pixel4 * 2, pixel12),
new Vector2(0.5f + pixel4 * 3, 0f), new Vector2(0.5f + pixel4 * 4, pixel12),
new Vector2(0.5f + pixel4 * 2, 0f), new Vector2(0.5f + pixel4 * 3, pixel12),
new Vector2(0.5f, 0f), new Vector2(0.5f + pixel4, pixel12),
new Vector2(0.5625f + pixel4, pixel12), new Vector2(0.5625f + pixel4 * 2, pixel12 + pixel4),
new Vector2(0.625f, pixel12), new Vector2(0.625f + pixel4, pixel12 + pixel4),
new Vector3(0.5f, 1.5f, 0.5f));
boneWeights.AddRange(CreateBoneWeight(Cube.SizeOfVertex(), "Left Arm"));
break;
case 3: // right arm
cube = Cube.CreateCube(new Vector3(1.5f, 0.0f, 0.0f),
new Vector2(0.6875f, 0.5f), new Vector2(0.6875f + pixel4, 0.5f + pixel12),
new Vector2(0.6875f + pixel4 * 2, 0.5f), new Vector2(0.6875f + pixel4 * 3, 0.5f + pixel12),
new Vector2(0.6875f + pixel4, 0.5f), new Vector2(0.6875f + pixel4 * 2, 0.5f + pixel12),
new Vector2(0.6875f - pixel4, 0.5f), new Vector2(0.6875f, 0.5f + pixel12),
new Vector2(0.6875f + pixel4, 0.6875f), new Vector2(0.6875f + pixel4 * 2, 0.6875f + pixel4),
new Vector2(0.6875f + pixel4, 0.5f + pixel12), new Vector2(0.6875f + pixel4 * 2, 0.5f + pixel12 + pixel4),
new Vector3(0.5f, 1.5f, 0.5f));
boneWeights.AddRange(CreateBoneWeight(Cube.SizeOfVertex(), "Right Arm"));
break;
case 4: // left leg
cube = Cube.CreateCube(new Vector3(-0.5f, -1.0f, 0.0f),
new Vector2(0.25f + pixel4, 0f), new Vector2(0.25f + pixel4 * 2, 0f + pixel12),
new Vector2(0.25f + pixel4 * 3, 0f), new Vector2(0.25f + pixel4 * 4, 0f + pixel12),
new Vector2(0.25f + pixel4 * 2, 0f), new Vector2(0.25f + +pixel4 * 3, 0f + pixel12),
new Vector2(0.25f, 0f), new Vector2(0.25f + pixel4, 0f + pixel12),
new Vector2(0.3125f, pixel12), new Vector2(0.3125f + pixel4, pixel12 + pixel4),
new Vector2(0.3125f + pixel4, pixel12), new Vector2(0.3125f + pixel4 * 2, pixel12 + pixel4),
new Vector3(0.5f, 1.5f, 0.5f));
boneWeights.AddRange(CreateBoneWeight(Cube.SizeOfVertex(), "Left Leg"));
break;
case 5: // right leg
cube = Cube.CreateCube(new Vector3(0.5f, -1.0f, 0.0f),
new Vector2(pixel4, 0.5f), new Vector2(pixel4 * 2, 0.5f + pixel12),
new Vector2(pixel4 * 3, 0.5f), new Vector2(pixel4 * 4, 0.5f + pixel12),
new Vector2(pixel4 * 2, 0.5f), new Vector2(pixel4 * 3, 0.5f + pixel12),
new Vector2(0.0f, 0.5f), new Vector2(pixel4, 0.5f + pixel12),
new Vector2(pixel4, 0.6875f), new Vector2(pixel4 * 2, 0.6875f + pixel4),
new Vector2(pixel4 * 2, 0.6875f), new Vector2(pixel4 * 3, 0.6875f + pixel4),
new Vector3(0.5f, 1.5f, 0.5f));
boneWeights.AddRange(CreateBoneWeight(Cube.SizeOfVertex(), "Right Leg"));
break;
default:
Debug.Log("Bad parts value!!!");
throw new System.Exception();
}
// 인덱스를 큐브 버텍스 갯수를 고려하여 더해준다.
for (int j_index = 0; j_index < cube.meshData.triangles.Count; ++j_index)
{
cube.meshData.triangles[j_index] = cube.meshData.triangles[j_index] + i_part * Cube.SizeOfVertex();
}
vertices.AddRange(cube.meshData.vertices);
uvs.AddRange(cube.meshData.uvs);
triangles.AddRange(cube.meshData.triangles);
}
m.vertices = vertices.ToArray();
m.triangles = triangles.ToArray();
m.boneWeights = boneWeights.ToArray();
m.bindposes = bindposes.ToArray();
m.uv = uvs.ToArray();
SkinnedMeshRenderer smr = GetComponent<SkinnedMeshRenderer>();
smr.bones = bones.ToArray();
smr.sharedMesh = m;
smr.quality = SkinQuality.Bone2;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment