анимированый кастомный персонаж

Программирование на Юнити.

анимированый кастомный персонаж

Сообщение lazykiller 20 июл 2011, 06:47

привет. изучаю юньку [unity 3D] параллельно с с# (c#) и 3dmax (max_sm) уже 2 месяца. есть продвижения, но в некоторых моментах полный затык. дело вот в чём, так как с кубиками играться не особо интересно выдрал модельки и анимацию из популярной стрелялки killingfloor. анимаций ~750 штук юнька ворочала в метаданных долго поэтому пришлось засунуть всё в бандл, отрезал анимашки при помощи скрипта из антареса (немного допилил для батча). всё красиво грузится за пару секунд модельки двигаются как надо. теперь захотелось модельки сделать сборными рукиногиголовабоди и дополнительный кастом да чтобы ещё и отстреливать можно было. и вот здесь то выходит несостыковка. прочитал http://unity3d.ru/distribution/viewtopic.php?f=87&t=2051&start=15#p21425 что можно сделать отдельно скелет с шаблоном и подключать к нему отдельные меши беря информацию по костям из шаблона. нарезал модельку подключаю, а её корёжит так что маманегорюй. пересчёт весов не помогает.
Синтаксис:
Используется csharp
using System;
using UnityEngine;

class CharacterCustomizationExt : MonoBehaviour
{

    public GameObject[] characterPartsList;
    public SkinnedMeshRenderer templateSkeleltalSource;

    /// <summary>
    /// Takes a target GameObject and an array of GameObjects. All skinned mesh renderers attached to any GameObject in the array are copied to the target GameObject.
    /// </summary>
    void Start()
    {
        GameObject character = this.gameObject;
        // Record start time for logging time spent
        float startTime = Time.realtimeSinceStartup;

       // Transform[] characterBones = CharacterBones(character, templateSkeleltalSource);

        // Step through all game objects in gameObjectsToCombine
        foreach (GameObject part in characterPartsList)
        {
            CharPartAdd(character, part);
        }

       
        // Log time spent
        Debug.Log("Combining game objects took " + (Time.realtimeSinceStartup - startTime) * 1000 + " ms");
    }


    public void CharPartAdd(GameObject character, GameObject part)
    {
       
        Mesh mesh = new Mesh();
        Material[] materials = new Material[0];

        if (part.GetComponent<SkinnedMeshRenderer>() != null)
        {
            mesh = (MeshCopy(part.GetComponent<SkinnedMeshRenderer>().sharedMesh));
            materials = part.GetComponent<SkinnedMeshRenderer>().sharedMaterials;

        }
        else
        {
            if (part.GetComponent<MeshFilter>() != null)
            {
                mesh = (MeshCopy(part.GetComponent<MeshFilter>().sharedMesh));
                materials = part.GetComponent<MeshRenderer>().sharedMaterials;
            }
            else
            {
                return;
            }
        }
       


        GameObject newPart = new GameObject();
        newPart.name = ("char_part_" + part.name);
        mesh.name = newPart.name;

        newPart.transform.rotation = part.transform.rotation;
        newPart.transform.localScale = part.transform.localScale;

        newPart.transform.position = character.transform.position;
        newPart.transform.parent = character.transform;


/*
        // if static object
        newPart.AddComponent<MeshFilter>();
        newPart.GetComponent<MeshFilter>().mesh = mesh;

        newPart.AddComponent<MeshRenderer>();
        newPart.GetComponent<MeshRenderer>().materials = materials;

*/


        // if animated character
        SkinnedMeshRenderer smr = newPart.AddComponent(typeof(SkinnedMeshRenderer))
          as SkinnedMeshRenderer;


        mesh.bindposes =  templateSkeleltalSource.sharedMesh.bindposes;//part.GetComponent<SkinnedMeshRenderer>().sharedMesh.bindposes;//
        smr.bones = CharacterBones(character, templateSkeleltalSource);//CharacterBones(character, part.GetComponent<SkinnedMeshRenderer>());//

        Debug.Log(smr.bones.Length);
        for (int i=0; i<smr.bones.Length; i++)
        {
         Debug.Log(i + " - " +smr.bones[i].name);
        }

/*
        BoneWeight[] weights = mesh.boneWeights;
        for (int i = 0; i < weights.Length; i++)
        {
            weights[i].boneIndex0 = weights[i].boneIndex0 % templateSkeleltalSource.bones.Length;
            weights[i].boneIndex1 = weights[i].boneIndex1 % templateSkeleltalSource.bones.Length;
            weights[i].boneIndex2 = weights[i].boneIndex2 % templateSkeleltalSource.bones.Length;
            weights[i].boneIndex3 = weights[i].boneIndex3 % templateSkeleltalSource.bones.Length;
        }
        mesh.boneWeights = weights;
*/
       

        smr.sharedMesh = mesh;
        smr.materials = materials;
    }

    Mesh MeshCopy(Mesh fromMesh)
    {
        Mesh toMesh = new Mesh();

        Vector3[] newVertices = fromMesh.vertices;
        toMesh.vertices = newVertices;


        Vector2[] newUV = fromMesh.uv;
        toMesh.uv = newUV;


        int[] newTriangles = fromMesh.triangles;
        toMesh.triangles = newTriangles;


        Vector3[] newNormals = fromMesh.normals;
        toMesh.normals = newNormals;


        BoneWeight[] newBoneWeight = fromMesh.boneWeights;
        toMesh.boneWeights = newBoneWeight;


        Matrix4x4[] newBindposes = fromMesh.bindposes;
        toMesh.bindposes = newBindposes;    


      //  toMesh.RecalculateNormals();
      //  toMesh.RecalculateBounds();

        return toMesh;

    }


    Transform[] CharacterBones(GameObject character, SkinnedMeshRenderer templateSkeleltalSource)
    {
        Transform[] bones = new Transform[templateSkeleltalSource.bones.Length];
        // Step through all bones used by the original renderer
        for (int bone = 0; bone < templateSkeleltalSource.bones.Length; bone++)
        {
            Transform t = null;
            // Step through all transforms in the target game object
            foreach (Component c in character.GetComponentsInChildren(typeof(Transform)))
            {
                // Check if we have found the corresponding bone
                if (c.name == templateSkeleltalSource.bones[bone].name)
                {
                    t = c.transform;
                    break;
                }
            }

            // Throw an exception when we dont find a bone with the same name
            if (t == null) throw new Exception("Bone not found");
            // Add the bone we found to the array
            bones[bone] = t;
        }
        return bones;
    }
}



вся оказия случается вот здесь
Синтаксис:
Используется csharp
        mesh.bindposes =  templateSkeleltalSource.sharedMesh.bindposes;//part.GetComponent<SkinnedMeshRenderer>().sharedMesh.bindposes;//
        smr.bones = CharacterBones(character, templateSkeleltalSource);//CharacterBones(character, part.GetComponent<SkinnedMeshRenderer>());//

templateSkeleltalSource - общий шаблон
part.GetComponent<SkinnedMeshRenderer>() - данные о костях конкретного меша
Аватара пользователя
lazykiller
UNец
 
Сообщения: 17
Зарегистрирован: 18 июл 2011, 17:44

Re: анимированый кастомный персонаж

Сообщение Kristof 20 июл 2011, 10:47

Я четсно говоря в скриптах не силен, но у своей модели подключал через GetComponentsInChildren, изменял лицо тело и т.д
Возможно ты криво нарезал модель, а вообще есть бесплатный пример в Asset Store называется, Character Customization.
Есть еще отличный пример инвентаря с использованием GetComponentsInChildren
Демоhttps://dl.dropbox.com/u/6629353/AdvancedInventorySystem.html
Вот сам инвентарь (нарыл с РЛ Теам)
http://www.megaupload.com/?d=H2K1S51Y
Kristof
UNIт
 
Сообщения: 83
Зарегистрирован: 10 ноя 2009, 07:19

Re: анимированый кастомный персонаж

Сообщение lazykiller 20 июл 2011, 11:08

Character Customization уже смотрел. там все элементы заранее предустановлены просто скрываются ненужные. Я же хочу накидать список обЪектов в массив и чтобы они все навесились на скелет. в идеале стоит задача сделать рандомно генерящихся зомби из кучи частей тел.
нарезка правильная, её моделер со стажем делал всё работает если брать информацию из своего скинедмеша, а если брать кости из шаблонного скинедмеша где вся модель целиком то запчасти плывут при анимации.
и кажется нашёл в чём причина при экспорте из маха (max_sm) (или при импорте в юньку [unity 3D] ) по частям кости с нулевым весом отсекаются из скина, соответственно при загрузке костей они получаются с другими индексами. возможно это влияет.
Аватара пользователя
lazykiller
UNец
 
Сообщения: 17
Зарегистрирован: 18 июл 2011, 17:44

Re: анимированый кастомный персонаж

Сообщение lazykiller 20 июл 2011, 11:14

Kristof, спасибо за дему инвентаря похоже то что нужно. буду разбираться дальше.
Аватара пользователя
lazykiller
UNец
 
Сообщения: 17
Зарегистрирован: 18 июл 2011, 17:44

Re: анимированый кастомный персонаж

Сообщение Kristof 20 июл 2011, 11:20

НУ скорее всего, даже логично, если ты экспортиш коски отдельно, и части тела отдельно без коскей, то получится полная лажа:)
Обычно при нарезке модели для игр, каждая часть тела идет со скелетом, и уже в процессе игры можешь из этих частей делать сборную салянку.
Kristof
UNIт
 
Сообщения: 83
Зарегистрирован: 10 ноя 2009, 07:19

Re: анимированый кастомный персонаж

Сообщение seaman 20 июл 2011, 11:31

Как то я не понял. Я решил, что у Вас проблема в CombinedMesh частей. Во всяком случае по ссылке, приведенной в первом посте, рассматривается именно это. Сделать перса из частей, подгружаемых на лету достаточно просто. Вот объединить эти части в единую сетку гораздо сложнее.

ЗЫ: Еще замечание по экспорту. Юнити не работает с двурутовыми объектами. Т.е. если у Вас в сцене скелет и какая-то часть персонажа заскиненная на этот скелет, то Юнити при импорте добавляет еще один объект, который делает рутовым и к скелету, и к части персонажа. Это нормально работает в большинстве случаев. Однако, если Вы при этом экспортируете анимации на чистом скелете - корень у сцены один, и Юнити ничего не добавит. Иерархия будет другой, по сравнению с первым случаем - анимации экспортированные таким образом будут воспроизводиться не верно. Выход - добавьте в сцену со скелетом дамми. Тогда в сцене опять будет два рута - Юнити добавит свой - все будет работать. Ну или экспортируйте и анимации с какой-нибудь частью персонажа - не с чистым скелетом.
seaman
Адепт
 
Сообщения: 8352
Зарегистрирован: 24 янв 2011, 12:32
Откуда: Самара

Re: анимированый кастомный персонаж

Сообщение gnoblin 20 июл 2011, 11:40

Комбайнить скинедмеш грамотно из частей не такая простая задача.

Много гемороя :D.
skypeid: madkust
Мои крайние проекты:
Убойный Хоккей
Cube Day Z (альфа)
Аватара пользователя
gnoblin
Адепт
 
Сообщения: 4633
Зарегистрирован: 08 окт 2008, 17:23
Откуда: Минск, Беларусь
Skype: madkust
  • Сайт

Re: анимированый кастомный персонаж

Сообщение lazykiller 20 июл 2011, 11:50

seaman, спасибо за подсказки. с анимацией был долгий путь в неделю, сначала чтобы уменьшить размер файла поменял перса на дамми, а потом и от скелета избавился спасибо Neodrop'у за функцию отрезание анимации в Антаресе. в примере по ссылке часть комбайнится из чистых мешей и на неё навешиваются кости из шаблона. вот Я и думаю, что можно сделать один скелет с описанием костей и биндинг поз, а части тела подгружать чистыми мешами.
по поводу сетки в моём случае части будут уже в нужных позициях, а так можно навешивать их на заранее подготовленные именованные дамми
Аватара пользователя
lazykiller
UNец
 
Сообщения: 17
Зарегистрирован: 18 июл 2011, 17:44

Re: анимированый кастомный персонаж

Сообщение gnoblin 24 июл 2011, 15:00

lazykiller писал(а):Character Customization уже смотрел. там все элементы заранее предустановлены просто скрываются ненужные.


неправда, там подгружаются из бандлей нужные части :)
skypeid: madkust
Мои крайние проекты:
Убойный Хоккей
Cube Day Z (альфа)
Аватара пользователя
gnoblin
Адепт
 
Сообщения: 4633
Зарегистрирован: 08 окт 2008, 17:23
Откуда: Минск, Беларусь
Skype: madkust
  • Сайт

Re: анимированый кастомный персонаж

Сообщение lazykiller 24 июл 2011, 22:40

gnoblin, а ведь и правда, то что нужно было у меня под носом. ну и ладно зато разобрался с вертексами и прочими базовыми 3дмодельностями. теперь нужно, чтобы куски отваливались рэгдольно. нерэгдольно просто меняю скинедмеш на обычный, вроде даже по Вашему скрипту. если кости отламывать то полики тянутся. кто-нибудь потерю конечностей делал? у меня уже мысли делать второй скелет и на него потеряную конечность переписывать :-\
Аватара пользователя
lazykiller
UNец
 
Сообщения: 17
Зарегистрирован: 18 июл 2011, 17:44

Re: анимированый кастомный персонаж

Сообщение gnoblin 24 июл 2011, 23:21

что куски отваливались рэгдольно - надо как-то модульно моделить конечности
skypeid: madkust
Мои крайние проекты:
Убойный Хоккей
Cube Day Z (альфа)
Аватара пользователя
gnoblin
Адепт
 
Сообщения: 4633
Зарегистрирован: 08 окт 2008, 17:23
Откуда: Минск, Беларусь
Skype: madkust
  • Сайт

Re: анимированый кастомный персонаж

Сообщение lazykiller 25 июл 2011, 09:19

да Я так и делаю, для опробы пока кусоков 7 штук потом на каждую кость планирую. главное расчленяемость чтобы была по методу рэгдола )
У вас нет доступа для просмотра вложений в этом сообщении.
Аватара пользователя
lazykiller
UNец
 
Сообщения: 17
Зарегистрирован: 18 июл 2011, 17:44


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 11