public void OptimizeBones()
        {
            // Для всех вершин мержу веса костей в одно значение если есть 2 (и более) одинаковые кости в вершине
            // далее нормализирую веса в каждой вершине. Индексы костей при этом сортируются в порядке возрастания (в конце идут неиспользуемые кости с индексом и весом 0)

            var indexedWeights = new Dictionary <byte, float>();

            foreach (var mesh in Meshes)
            {
                foreach (var vertex in mesh.Vertices)
                {
                    int i;

                    indexedWeights.Clear();
                    for (i = 0; i < 4; i++)
                    {
                        indexedWeights[vertex.BoneIndexes[i]] = 0f;
                    }

                    for (i = 0; i < 4; i++)
                    {
                        indexedWeights[vertex.BoneIndexes[i]] += vertex.BoneWeights[i];
                    }

                    var newIndexes = new ByteVec4();
                    var newWeights = new Vec4();

                    i = 0;
                    foreach (var indexedWeight in indexedWeights.OrderBy(x => x.Key))
                    {
                        newIndexes[i] = indexedWeight.Key;
                        newWeights[i] = indexedWeight.Value;
                        i++;
                    }

                    newWeights.NormalizeSum();

                    vertex.BoneIndexes = newIndexes;
                    vertex.BoneWeights = newWeights;
                }
            }

            // Перестраиваем массив костей, удаляя пустые костаи и заменяя старые индексы в вершинах на новые
            // ToDo: сделать это, но только сейчас есть проблема с поиском индексов, которые ссылаются на эти кости.
            // проблема в том что отсюда надо знать какие меши ссылаются на эти кости. Сейчас уже есть основной меш + аттачменты.
            // сначало нужно сделать систему при которой скелет будет знать какие мешы к нему привязаны а потом уже делать эту оптимизацию
            // дальше еще есть проблема что индексы кости просто в разных объектах могут висеть (в Wh* классах точно они есть), надо убедиться что их дальше использования не будет.
            // Все исползования должны быть только по ссылке на WowBone.
        }
Beispiel #2
0
 public void PostRenderCommand(Vector position, float z_orther, float rotate, Vector scale, HalfVector anchor, ByteVec4 color, bool vertical_flip, bool horizon_flip) => PostRenderCommand(position, z_orther, _bound, rotate, scale, anchor, color, vertical_flip, horizon_flip);
Beispiel #3
0
        public WowObject BuildFromCharacterWhModel(WhModel whCharacterModel)
        {
            // ToDo: Смотреть как работает, Wow.Model.draw,
            // по сути в зависимости от алгоритма отрисовки идет и алгоритм построения объектов для дальнейшей отрисовки (то что тут происодит)

            // Сам перс

            var characterObject = new WowObject();

            // Добавляем MainMesh
            characterObject.Meshes.Add(MakeMeshFromWhModel(whCharacterModel));

            characterObject.Bones = MakeBoneHierarchyFromWhModel(whCharacterModel);
            characterObject.OptimizeBones();
            TranslateBonePositionsFromGlobalToLocal(characterObject);

            // Рога

            if (whCharacterModel.HornsModel != null)
            {
                AddAdditionalMeshToCharacterObject(characterObject, whCharacterModel.HornsModel);
            }

            // Маунт

            if (whCharacterModel.Mount != null)
            {
                // ToDo: хз че тут  делать, создать его вообще отдельно?

                //var mountObject = new WowObject()
                //{
                //    Parent = characterObject
                //};

                //// MainMesh (не факт что я вообще тут правильно делаю, т.к. еще не тестил)
                //mountObject.Meshes.Add(MakeMeshFromWhModel(whCharacterModel.Mount));

                //characterObject.Children.Add(mountObject);
            }

            // Итемы

            foreach (var whItemInSlot in whCharacterModel.Items)
            {
                var whItem = whItemInSlot.Value;

                if (whItem?.Models == null)
                {
                    continue;
                }

                foreach (var whItemModel in whItem.Models)
                {
                    if (whItemModel?.Model == null)
                    {
                        continue;
                    }

                    if (whItemModel.Bone > -1 && whItemModel.Bone < whCharacterModel.Bones.Length)
                    {
                        var itemPosition = Vec3.Scale(Vec3.ConvertPositionFromWh(whItemModel.Attachment.Position), _scale);

                        var itemObject = new WowObject()
                        {
                            Parent         = characterObject,
                            GlobalPosition = itemPosition,
                        };

                        // MainMesh - по сути он использоваться будет тлолько в AttachedWowObjects кости
                        itemObject.Meshes.Add(MakeMeshFromWhModel(whItemModel.Model));

                        // Если у итема есть кость, к которой можно прикрепиться
                        if (itemObject.Parent != null && whItemModel.Attachment.Bone >= 0)
                        {
                            var parentAttachmentBone   = itemObject.Parent.Bones[whItemModel.Attachment.Bone];
                            var whParentAttachmentBone = whItemModel.Model.Parent.Bones[whItemModel.Attachment.Bone];

                            // записываем объект этого итема в кость, к которой крепимся(у родительского объекта)
                            parentAttachmentBone.AttachedWowObjects.Add(itemObject);

                            // меняем данные о костях в вершинах так итема так, чтобы при привязке к скелету родителя этот итем двигался вместе с костью
                            // (при этом в иерархии объектов он не будет в ноде кости, а будет на том же уровне что и родительский объект, к скелету которого мы привязываем итем)

                            itemObject.MainMesh.ApplyTransform(
                                whParentAttachmentBone.LastUpdatedTranslation,
                                whParentAttachmentBone.LastUpdatedRotation,
                                whParentAttachmentBone.LastUpdatedScale);

                            var eachVertexItemBoneIndexes = new ByteVec4((byte)parentAttachmentBone.Index, 0, 0, 0);
                            var eachVertexItemBoneWeights = new Vec4(1, 0, 0, 0);

                            foreach (var vertex in itemObject.MainMesh.Vertices)
                            {
                                vertex.BoneIndexes = eachVertexItemBoneIndexes;
                                vertex.BoneWeights = eachVertexItemBoneWeights;
                            }
                        }

                        if (whItem.Visual?.Models != null && whItemModel.Model.Loaded)
                        {
                            foreach (var visual in whItem.Visual.Models)
                            {
                                if (visual != null)
                                {
                                    var visualPosition = Vec3.Scale(Vec3.ConvertPositionFromWh(visual.Attachment.Position), _scale);

                                    var visualObject = new WowObject()
                                    {
                                        Parent         = characterObject,
                                        GlobalPosition = visualPosition
                                    };

                                    // MainMesh (не факт что я вообще тут правильно делаю, т.к. еще не тестил)
                                    visualObject.Meshes.Add(MakeMeshFromWhModel(visual.Model));
                                }
                            }
                        }
                    }
                    else if (whItemModel.Bone == -1)
                    {
                        AddAdditionalMeshToCharacterObject(characterObject, whItemModel.Model);
                    }
                }
            }

            foreach (var collection in whCharacterModel.CollectionModels.Values)
            {
                if (collection == null)
                {
                    continue;
                }

                AddAdditionalMeshToCharacterObject(characterObject, collection);
            }

            return(characterObject);
        }
Beispiel #4
0
        public void PostRenderCommand(Vector position, float z_other, Vector bound, float rotate, Vector scale, HalfVector anchor, ByteVec4 color, bool vertical_flip, bool horizon_flip)
        {
            /*-----------------CURRENT VERSION------------------ -
             *   anchor(Hlaf)	    color(byte)         modelMatrix
             *   vec2(2)		        vec4(4)             Matrix3x2(6)
             */

            var is_xflip = Math.Sign(scale.X);
            var is_yflip = Math.Sign(scale.Y);

            //adjust scale transform which value is negative
            horizon_flip  = horizon_flip | (is_xflip < 0);
            vertical_flip = vertical_flip | (is_yflip < 0);
            float scalex = is_xflip * scale.X * bound.X;
            float scaley = is_yflip * scale.Y * bound.Y;

            //Create ModelMatrix
            float cosa = (float)Math.Cos(rotate);
            float sina = (float)Math.Sin(rotate);

            Matrix3x2 model = Matrix3x2.Zero;

            model.Row0.X = cosa * scalex;
            model.Row0.Y = -sina * scalex;
            model.Row1.X = sina * scaley;
            model.Row1.Y = cosa * scaley;

            model.Row2.X = position.X - RenderKernel.SB_WIDTH / 2f;
            model.Row2.Y = -position.Y + RenderKernel.SB_HEIGHT / 2f;

            unsafe
            {
                //Anchor write
                fixed(byte *ptr = &PostData[_currentPostBaseIndex])
                {
                    //anchor
                    int *hpv = (int *)(ptr + 0);

                    *hpv = *(int *)&anchor;

                    //color
                    int *ip = (int *)(ptr + 4);

                    *ip = *(int *)&color;

                    //flip write
                    Half *hp = (Half *)(ptr + 8);

                    hp[0] = horizon_flip ? HalfNegativeOne : HalfOne;
                    hp[1] = vertical_flip ? HalfNegativeOne : HalfOne;

                    var copyLen = 2 * 3 * sizeof(float);
                    var basePtr = (byte *)&model.Row0.X;

                    for (int i = 0; i < copyLen; i++)
                    {
                        ptr[i + 12] = *(basePtr + i);
                    }
                }
            }

            CurrentPostCount++;
            _currentPostBaseIndex += _VertexSize;
            if (CurrentPostCount >= Capacity)
            {
                FlushDraw();
            }
        }