internal FSkelMeshSection(BinaryReader reader, FNameEntrySerialized[] name_map) { var flags = new FStripDataFlags(reader); material_index = reader.ReadUInt16(); base_index = reader.ReadUInt32(); num_triangles = reader.ReadUInt32(); var _recompute_tangent = reader.ReadUInt32() != 0; var _cast_shadow = reader.ReadUInt32() != 0; base_vertex_index = reader.ReadUInt32(); cloth_mapping_data = reader.ReadTArray(() => new FApexClothPhysToRenderVertData(reader)); bool HasClothData = cloth_mapping_data.Length > 0; bone_map = reader.ReadTArray(() => reader.ReadUInt16()); num_vertices = reader.ReadInt32(); max_bone_influences = reader.ReadInt32(); var _correspond_cloth_asset_index = reader.ReadInt16(); clothing_data = new FClothingSectionData(reader); var _vertex_buffer = new FDuplicatedVerticesBuffer(reader); disabled = reader.ReadUInt32() != 0; }
//public FStaticMeshVertexDataUV? uvs; public FStaticMeshVertexBuffer(BinaryReader reader) { high_precision_tangent_basis = false; var flags = new FStripDataFlags(reader); num_tex_coords = reader.ReadInt32(); num_vertices = reader.ReadInt32(); full_precision_uvs = reader.ReadInt32() != 0; high_precision_tangent_basis = reader.ReadInt32() != 0; if (!flags.server_data_stripped) { int ItemSize, ItemCount; uv = new FStaticMeshUVItem4[num_vertices]; // Tangents ItemSize = reader.ReadInt32(); ItemCount = reader.ReadInt32(); if (ItemCount != num_vertices) { throw new FileLoadException("Invalid item count/num_vertices at pos " + reader.BaseStream.Position); } var pos = reader.BaseStream.Position; for (int i = 0; i < num_vertices; i++) { uv[i].SerializeTangents(reader, high_precision_tangent_basis); } if (reader.BaseStream.Position - pos != ItemCount * ItemSize) { throw new FileLoadException("Didn't read static mesh uvs correctly at pos " + reader.BaseStream.Position); } // Texture coordinates ItemSize = reader.ReadInt32(); ItemCount = reader.ReadInt32(); if (ItemCount != num_vertices * num_tex_coords) { throw new FileLoadException("Invalid item count/num_vertices at pos " + reader.BaseStream.Position); } pos = reader.BaseStream.Position; for (int i = 0; i < num_vertices; i++) { uv[i].SerializeTexcoords(reader, num_tex_coords, full_precision_uvs); } if (reader.BaseStream.Position - pos != ItemCount * ItemSize) { throw new FileLoadException("Didn't read static mesh texcoords correctly at pos " + reader.BaseStream.Position); } } else { uv = null; } }
internal FStaticLODModel(BinaryReader reader, FNameEntrySerialized[] name_map, bool has_vertex_colors) { var flags = new FStripDataFlags(reader); Sections = reader.ReadTArray(() => new FSkelMeshSection(reader, name_map)); Indices = new FMultisizeIndexContainer(reader); ActiveBoneIndices = reader.ReadTArray(() => reader.ReadInt16()); RequiredBones = reader.ReadTArray(() => reader.ReadInt16()); if (flags.server_data_stripped || flags.class_data_stripped(2)) { throw new FileLoadException("Could not read FSkelMesh, no renderable data"); } var position_vertex_buffer = new FPositionVertexBuffer(reader); var static_mesh_vertex_buffer = new FStaticMeshVertexBuffer(reader); var skin_weight_vertex_buffer = new FSkinWeightVertexBuffer(reader); if (has_vertex_colors) { var colour_vertex_buffer = new FColorVertexBuffer(reader); } AdjacencyIndexBuffer = default; if (!flags.class_data_stripped(1)) { AdjacencyIndexBuffer = new FMultisizeIndexContainer(reader); } ClothVertexBuffer = default; if (HasClothData(Sections)) { ClothVertexBuffer = new FSkeletalMeshVertexClothBuffer(reader); } SkinWeightProfilesData = new FSkinWeightProfilesData(reader, name_map); VertexBufferGPUSkin = new FSkeletalMeshVertexBuffer(); VertexBufferGPUSkin.bUseFullPrecisionUVs = true; NumVertices = position_vertex_buffer.num_verts; NumTexCoords = static_mesh_vertex_buffer.num_tex_coords; VertexBufferGPUSkin.VertsFloat = new FGPUVert4Float[NumVertices]; for (int i = 0; i < NumVertices; i++) { var V = new FGPUVert4Float(); var SV = static_mesh_vertex_buffer.uv[i]; V.Pos = position_vertex_buffer.verts[i]; V.Infs = skin_weight_vertex_buffer.weights[i]; V.Normal = SV.Normal; // i mean, we're not using it for anything else, are we? V.UV = SV.UV; VertexBufferGPUSkin.VertsFloat[i] = V; } }
public FColorVertexBuffer(BinaryReader reader) { var flags = new FStripDataFlags(reader); stride = reader.ReadInt32(); num_verts = reader.ReadInt32(); colors = null; if (!flags.server_data_stripped && num_verts > 0) { var _element_size = reader.ReadInt32(); colors = reader.ReadTArray(() => new FColor(reader)); } }
public FSkinWeightVertexBuffer(BinaryReader reader) { var flags = new FStripDataFlags(reader); var bExtraBoneInfluences = reader.ReadInt32() != 0; var num_vertices = reader.ReadInt32(); if (flags.server_data_stripped) { weights = null; return; } var _element_size = reader.ReadInt32(); var num_influences = bExtraBoneInfluences ? 8 : 4; weights = reader.ReadTArray(() => new FSkinWeightInfo(reader, num_influences)); }
public FSkeletalMeshVertexClothBuffer(BinaryReader reader) { var flags = new FStripDataFlags(reader); if (!flags.server_data_stripped) { // umodel: https://github.com/gildor2/UModel/blob/9a1fe8c77d136f018ba18c9e5c445fdcc5f374ae/Unreal/UnMesh4.cpp#L924 // https://github.com/gildor2/UModel/blob/39c635c13d61616297fb3e47f33e3fc20259626e/Unreal/UnCoreSerialize.cpp#L320 // ue4: https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Runtime/Engine/Private/SkeletalMeshLODRenderData.cpp#L758 // https://github.com/EpicGames/UnrealEngine/blob/master/Engine/Source/Runtime/Engine/Public/Rendering/SkeletalMeshLODRenderData.h#L119 int elem_size = reader.ReadInt32(); // umodel has this, might want to actually serialize this like how ue4 has it int count = reader.ReadInt32(); reader.BaseStream.Seek(elem_size * count, SeekOrigin.Current); cloth_index_mapping = reader.ReadTArray(() => reader.ReadUInt64()); } cloth_index_mapping = null; }
internal USkeletalMesh(BinaryReader reader, FNameEntrySerialized[] name_map, FObjectImport[] import_map) { BaseObject = new UObject(reader, name_map, import_map, "SkeletalMesh", true); bool has_vertex_colors = false; foreach (var prop in BaseObject.properties) { if (prop.name == "bHasVertexColors" && prop.tag == FPropertyTagType.BoolProperty) { has_vertex_colors = (bool)prop.tag_data; } else if (prop.name == "LODInfo") { var data = ((UScriptArray)prop.tag_data).data; LODInfo = new FSkeletalMeshLODInfo[data.Length]; for (int i = 0; i < data.Length; i++) { var info = (UScriptStruct)data[i]; if (info.struct_name != "SkeletalMeshLODInfo") { throw new FileLoadException("Invalid lod info type"); } var props = ((FStructFallback)info.struct_type).properties; var newInfo = new FSkeletalMeshLODInfo(); foreach (var lodProp in props) { switch (lodProp.name) { case "DisplayFactor": newInfo.DisplayFactor = (float)lodProp.tag_data; break; case "LODHysteresis": newInfo.LODHysteresis = (float)lodProp.tag_data; break; case "LODMaterialMap": newInfo.LODMaterialMap = ((UScriptArray)lodProp.tag_data).data.Cast <int>().ToArray(); break; case "bEnableShadowCasting": newInfo.bEnableShadowCasting = ((UScriptArray)lodProp.tag_data).data.Cast <bool>().ToArray(); break; } } LODInfo[i] = newInfo; } } } var flags = new FStripDataFlags(reader); Bounds = new FBoxSphereBounds(reader); Materials = reader.ReadTArray(() => new FSkeletalMaterial(reader, name_map, import_map)); RefSkeleton = new FReferenceSkeleton(reader, name_map); if (!flags.editor_data_stripped) { Console.WriteLine("Editor data still present!"); } if (reader.ReadUInt32() == 0) { throw new FileLoadException("No cooked data"); } LODModels = reader.ReadTArray(() => new FStaticLODModel(reader, name_map, has_vertex_colors)); uint serialize_guid = reader.ReadUInt32(); MaterialAssets = new string[Materials.Length]; for (int i = 0; i < Materials.Length; i++) { if (Materials[i].Material.import == null) { continue; } for (int j = 0; j < import_map.Length; j++) { if (import_map[j].class_name != "MaterialInstanceConstant" && import_map[j].object_name.EndsWith(Materials[i].Material.import)) { MaterialAssets[i] = import_map[j].object_name; break; } } } }