Computer Graphics/HumanGL

HumanGL - 3. 사람 그리기

surkim 2024. 10. 17. 17:03

이제 상자의 스케일을 조정하고, 몸의 각 파트를 계층적으로 나누어 사람을 그려주었다. 하위 단계의 값들은 상위 단계의 값을 계승하며, 각 파트는 부모의 상대 좌표를 기반으로 계산된다. 이렇게 계층 구조로 설정된 방식은 게임 엔진의 트리 구조와 비슷하게 동작한다.

Human 초기화

먼저 사람의 각 신체 부위를 초기화하는 작업부터 시작했다. 몸통을 중심으로 머리, 팔, 다리 등 모든 부위를 트리 구조로 정리해주었다. 각 파트는 위치(translate), 회전(rotate), 크기(scale), 색상(color) 정보를 가지며, 이 값들은 계층적으로 상위 값을 계승한다.

void Human::Init() {
    m_body = {sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(1.0f, 1.0f, 0.3f), sglm::vec3(1.0f, 0.0f, 0.0f)};

    // body 자식
    m_head = {sglm::vec3(0.0f, 0.75f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(0.5f, 0.5f, 1.0f), sglm::vec3(0.767f, 0.634f, 0.591f)};

    m_leftUpperArm = {sglm::vec3(-0.65f, 0.15f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(0.3f, 0.7f, 1.0f), sglm::vec3(1.0f, 0.0f, 0.0f)};
    m_rightUpperArm = {sglm::vec3(0.65f, 0.15f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(0.3f, 0.7f, 1.0f), sglm::vec3(1.0f, 0.0f, 0.0f)};

    m_leftLowerArm = {sglm::vec3(0.0f, -0.7f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(1.0f, 1.0f, 1.0f), sglm::vec3(0.767f, 0.634f, 0.591f)};
    m_rightLowerArm = {sglm::vec3(0.0f, -0.7f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(1.0f, 1.0f, 1.0f), sglm::vec3(0.767f, 0.634f, 0.591f)};

    m_leftUpperLeg = {sglm::vec3(-0.25f, -0.875f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(0.45f, 0.75f, 1.0f), sglm::vec3(0.0f, 0.0f, 1.0f)};
    m_rightUpperLeg = {sglm::vec3(0.25f, -0.875f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(0.45f, 0.75f, 1.0f), sglm::vec3(0.0f, 0.0f, 1.0f)};

    m_leftLowerLeg = {sglm::vec3(0.0f, -0.75f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(1.0f, 1.0f, 1.0f), sglm::vec3(0.767f, 0.634f, 0.591f)};
    m_rightLowerLeg = {sglm::vec3(0.0f, -0.75f, 0.0f), sglm::vec3(0.0f, 0.0f, 0.0f), sglm::vec3(1.0f, 1.0f, 1.0f), sglm::vec3(0.767f, 0.634f, 0.591f)};

    // 노드 트리 구조 설정
    Node head = {&m_head, {}};
    Node leftLowerArm = {&m_leftLowerArm, {}};
    Node rightLowerArm = {&m_rightLowerArm, {}};
    Node leftLowerLeg = {&m_leftLowerLeg, {}};
    Node rightLowerLeg = {&m_rightLowerLeg, {}};

    Node leftUpperArm = {&m_leftUpperArm, {leftLowerArm}};
    Node rightUpperArm = {&m_rightUpperArm, {rightLowerArm}};
    Node leftUpperLeg = {&m_leftUpperLeg, {leftLowerLeg}};
    Node rightUpperLeg = {&m_rightUpperLeg, {rightLowerLeg}};

    // body를 루트로 하는 트리 구조 완성
    m_root = {&m_body, {head, leftUpperArm, rightUpperArm, leftUpperLeg, rightUpperLeg}};
}

이 초기화 과정에서는 신체 각 부위를 정의하고, 계층적인 트리 구조로 설정해주었다. 몸통을 루트 노드로 설정하고, 그 아래에 머리, 팔, 다리 등을 연결했다. 이제 이 구조를 기반으로 각 부위를 쉽게 제어할 수 있게 되었다.

Human 그리기

Draw 함수에서는 트리 구조로 설정된 사람의 각 부위를 계층적으로 그려준다. 이때 DrawNode 함수는 부모의 변환 값을 자식에게 전달하면서 재귀적으로 그리기 작업을 수행한다.

void Human::Draw(const Mesh* mesh, const Program* program, const Transform& transform) const {
    DrawNode(m_root, mesh, program, transform);
}

void Human::DrawNode(const Node& node, const Mesh* mesh, const Program* program, const Transform& transform) const {
    sglm::mat4 translateModel = sglm::mat4(1.0f);
    sglm::mat4 rotateModel = sglm::mat4(1.0f);
    sglm::mat4 scaleModel = sglm::mat4(1.0f);

    translateModel = sglm::translate(translateModel, node.part->translate);
    translateModel = transform.translateModel * translateModel;
    rotateModel = sglm::rotate(rotateModel, sglm::radians(node.part->rotate.x), sglm::vec3(1.0f, 0.0f, 0.0f));
    rotateModel = sglm::rotate(rotateModel, sglm::radians(node.part->rotate.y), sglm::vec3(0.0f, 1.0f, 0.0f));
    rotateModel = sglm::rotate(rotateModel, sglm::radians(node.part->rotate.z), sglm::vec3(0.0f, 0.0f, 1.0f));
    rotateModel = transform.rotateModel * rotateModel;
    scaleModel = sglm::scale(scaleModel, node.part->scale);
    scaleModel = transform.scaleModel * scaleModel;

    sglm::mat4 newTransform = transform.projection * transform.view * translateModel * rotateModel * scaleModel;
    program->Use();
    program->SetUniform("objectColor", sglm::vec4(node.part->color.x, node.part->color.y, node.part->color.z, 1.0f));
    program->SetUniform("transform", newTransform);
    mesh->Draw(program);

    Transform childTransform = {transform.projection, transform.view, translateModel, rotateModel,

 scaleModel};
    for (const auto& child : node.children) {
        DrawNode(child, mesh, program, childTransform);
    }
}

이 함수는 각 신체 부위에 대해 translate, rotate, scale을 적용한 후, 트랜스폼 행렬을 통해 그려준다. 자식 노드로 내려갈 때마다 부모의 트랜스폼 값을 이어받아 그리기 때문에, 계층적으로 정확한 위치에 각 부위가 그려진다.


이렇게 해서 사람의 신체를 계층적으로 설정하고 그리는 작업을 완료했다. 초기화와 그리기 함수가 갖춰졌으니, 이후에는 이 구조를 활용해 다양한 움직임과 애니메이션을 추가할 것이다.