Ejemplo n.º 1
0
        private void LinkSkinningData(DRW1 draw_matrix_data, EVP1 envelope_data)
        {
            foreach (Shape shape in Shapes)
            {
                int vertex_index = 0;

                shape.VertexDescription.EnableAttribute(ShaderAttributeIds.SkinIndices);
                shape.VertexDescription.EnableAttribute(ShaderAttributeIds.SkinWeights);

                foreach (MatrixGroup group in shape.MatrixGroups)
                {
                    foreach (MeshVertexIndex vertex in group.Indices)
                    {
                        int draw_mat_index  = vertex.PosMtxIndex >= 0 ? group.MatrixDataTable.MatrixTable[vertex.PosMtxIndex] : 0;
                        int transform_index = draw_matrix_data.TransformIndexTable[draw_mat_index];

                        // If this vertex is influenced by mulltiple bones, we build vec4s containing the indices and weights
                        // for each bone that influences it.
                        if (draw_matrix_data.IsPartiallyWeighted[draw_mat_index])
                        {
                            EVP1.Envelope envelope = envelope_data.Envelopes[transform_index];

                            // Because we're using vec4s for the skinning data, any vertex with more than 4 bones influencing it
                            // is invalid to us. We're going to assume this never happens, but in the event that it does, this assert
                            // will tell us.
                            Trace.Assert(envelope.NumBones <= 4);

                            Vector4 indices = new Vector4(0, 0, 0, 0);
                            Vector4 weights = new Vector4(0, 0, 0, 0);

                            for (int i = 0; i < envelope.NumBones; i++)
                            {
                                indices[i] = envelope.BoneIndexes[i];
                                weights[i] = envelope.BoneWeights[i];
                            }

                            shape.VertexData.SkinIndices.Add(indices);
                            shape.VertexData.SkinWeights.Add(weights);
                        }
                        // If the vertex only has a single bone influencing it, we need to do some extra work. The vertex is stored in
                        // bone space instead of bind space. We need to transform the vertex into bind space so we can work with it more easily.
                        else
                        {
                            Vector4 pos_as_vec4 = new Vector4(shape.VertexData.Position[vertex_index], 1.0f);
                            shape.VertexData.Position[vertex_index] = Vector4.Transform(pos_as_vec4, envelope_data.InverseBindPose[transform_index].Inverted()).Xyz;

                            Vector4 nrm_as_vec4 = new Vector4(shape.VertexData.Normal[vertex_index], 0.0f);
                            Matrix4 nrm_mat     = envelope_data.InverseBindPose[transform_index];
                            nrm_mat.Transpose();

                            shape.VertexData.Normal[vertex_index] = Vector4.Transform(nrm_as_vec4, nrm_mat).Xyz;

                            shape.VertexData.SkinIndices.Add(new Vector4(transform_index, 0, 0, 0));
                            shape.VertexData.SkinWeights.Add(new Vector4(1, 0, 0, 0));
                        }

                        vertex_index++;
                    }
                }
            }
        }
Ejemplo n.º 2
0
        public void Render(Matrix4 viewMatrix, Matrix4 projectionMatrix, Matrix4 modelMatrix)
        {
            m_viewMatrix  = viewMatrix;
            m_projMatrix  = projectionMatrix;
            m_modelMatrix = modelMatrix;

            IList <SkeletonJoint> boneList = (m_currentBoneAnimation != null) ? JNT1Tag.AnimatedJoints : JNT1Tag.BindJoints;

            Matrix4[] boneTransforms = new Matrix4[boneList.Count];
            ApplyBonePositionsToAnimationTransforms(boneList, boneTransforms);

            // Assume that all bone animations constantly invalidate the skinning.
            if (m_currentBoneAnimation != null)
            {
                m_skinningInvalid = true;
            }

            // We'll only transform the position and normal vertices if skinning has been invalidated.
            if (m_skinningInvalid)
            {
                foreach (var shape in SHP1Tag.Shapes)
                {
                    var transformedPositions = new List <Vector3>(shape.VertexData.Position.Count);
                    var transformedNormals   = new List <Vector3>(shape.VertexData.Normal.Count);
                    //List<WLinearColor> colorOverride = new List<WLinearColor>();

                    for (int i = 0; i < shape.VertexData.Position.Count; i++)
                    {
                        // This is relative to the vertex's original packet's matrix table.
                        ushort posMtxIndex = (ushort)(shape.VertexData.PositionMatrixIndexes[i]);

                        // We need to calculate which packet data table that is.
                        int originalPacketIndex = 0;
                        for (int p = 0; p < shape.MatrixDataTable.Count; p++)
                        {
                            if (i >= shape.MatrixDataTable[p].FirstRelevantVertexIndex && i < shape.MatrixDataTable[p].LastRelevantVertexIndex)
                            {
                                originalPacketIndex = p; break;
                            }
                        }

                        // Now that we know which packet this vertex belongs to, we can get the index from it.
                        // If the Matrix Table index is 0xFFFF then it means "use previous", and we have to
                        // continue backwards until it is no longer 0xFFFF.
                        ushort matrixTableIndex;
                        do
                        {
                            matrixTableIndex = shape.MatrixDataTable[originalPacketIndex].MatrixTable[posMtxIndex];
                            originalPacketIndex--;
                        } while (matrixTableIndex == 0xFFFF);

                        bool   isPartiallyWeighted = DRW1Tag.IsPartiallyWeighted[matrixTableIndex];
                        ushort indexFromDRW1       = DRW1Tag.TransformIndexTable[matrixTableIndex];

                        Matrix4 finalMatrix = Matrix4.Zero;
                        if (isPartiallyWeighted)
                        {
                            EVP1.Envelope envelope = EVP1Tag.Envelopes[indexFromDRW1];
                            for (int b = 0; b < envelope.NumBones; b++)
                            {
                                Matrix4 sm1 = EVP1Tag.InverseBindPose[envelope.BoneIndexes[b]];
                                Matrix4 sm2 = boneTransforms[envelope.BoneIndexes[b]];

                                finalMatrix = finalMatrix + Matrix4.Mult(Matrix4.Mult(sm1, sm2), envelope.BoneWeights[b]);
                            }
                        }
                        else
                        {
                            // If the vertex is not weighted then we use a 1:1 movement with the bone matrix.
                            finalMatrix = boneTransforms[indexFromDRW1];
                        }

                        // Multiply the data from the model file by the finalMatrix to put it in the correct (skinned) position
                        transformedPositions.Add(Vector3.Transform(shape.VertexData.Position[i], finalMatrix));

                        if (shape.VertexData.Normal.Count > 0)
                        {
                            Vector3 transformedNormal = Vector3.TransformNormal(shape.VertexData.Normal[i], finalMatrix);
                            transformedNormals.Add(transformedNormal);
                        }

                        //colorOverride.Add(isPartiallyWeighted ? WLinearColor.Black : WLinearColor.White);
                    }

                    // Re-upload to the GPU.
                    shape.OverrideVertPos = transformedPositions;
                    //shape.VertexData.Color0 = colorOverride;
                    if (transformedNormals.Count > 0)
                    {
                        shape.OverrideNormals = transformedNormals;
                    }
                    shape.UploadBuffersToGPU(true);
                }

                m_skinningInvalid = false;
            }

            //if (WInput.GetKeyDown(System.Windows.Input.Key.O))
            //    m_shapeIndex--;
            //if (WInput.GetKeyUp(System.Windows.Input.Key.P))
            //    m_shapeIndex++;

            m_shapeIndex = WMath.Clamp(m_shapeIndex, 0, SHP1Tag.ShapeCount - 1);

            RenderMeshRecursive(INF1Tag.HierarchyRoot);

            // We're going to restore some semblance of state after rendering ourselves, as models often modify weird and arbitrary GX values.
            GL.Enable(EnableCap.Blend);
            GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
            GL.Enable(EnableCap.CullFace);
            GL.CullFace(CullFaceMode.Back);
            GL.Enable(EnableCap.DepthTest);
            GL.DepthMask(true);
            GL.Enable(EnableCap.Dither);
        }