Announcement

Collapse
No announcement yet.

What happened to USkeletalMesh in UE 4.19?

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    What happened to USkeletalMesh in UE 4.19?

    I'm porting a plugin written for UE 4.16 to UE 4.19, and I've seen a lot of things have changed for the class USkeletalMesh (and other related classes).

    For example, in UE 4.16 I have:

    Code:
    FStaticLODModel* LodModel = new FStaticLODModel();
    SkeletalMesh->GetImportedResource()->LODModels.Add(LodModel);
    In UE 4.19 I can't see anymore FStaticLODModel, so I thought it has been replaced with FSkeletalMeshLODModel; also the method GetImportedResource() has disappeared in UE 4.19, and the most similar method I found is GetImportedModel().
    So the previous two rows may be replaced with:

    Code:
    FSkeletalMeshLODModel* LodModel = new FSkeletalMeshLODModel();
    SkeletalMesh->GetImportedModel()->LODModels.Add(LodModel);


    Another thing is, in UE 4.16 I have this piece of code:

    Code:
    LodModel->MultiSizeIndexContainer.CreateIndexBuffer(sizeof(uint16_t));
    LodModel->NumVertices = data->vertexCount;
    LodModel->NumTexCoords = 1;
    
    for (uint32_t index = 0; index < data->indexCount; index++)
    {
        LodModel->MultiSizeIndexContainer.GetIndexBuffer()->AddItem(data->indexBuffer[index]);
    }
    In UE 4.19 I can't find the field MultiSizeIndexContainer, but I find an IndexBuffer attribute, so I replaced this snippet with:

    Code:
    LodModel->NumVertices = data->vertexCount;
    LodModel->NumTexCoords = 1;
    
    for (uint32_t index = 0; index < data->indexCount; index++)
    {
        LodModel->IndexBuffer.Add(data->indexBuffer[index]);
    }


    The last thing (the most critical one) is this piece of code in UE 4.16:

    Code:
    const uint32 vert_flags = FStaticLODModel::EVertexFlags::None | FStaticLODModel::EVertexFlags::UseFullPrecisionUVs;
    LodModel->BuildVertexBuffers(vert_flags);
    
    SkeletalMesh->Skeleton = NewObject<USkeleton>();
    SkeletalMesh->Skeleton->MergeAllBonesToBoneTree(SkeletalMesh);
    SkeletalMesh->PostLoad();
    In UE 4.19 the method BuildVertexBuffers has disappeared, and I've found nothing to replace it... so I just wrote this:

    Code:
    SkeletalMesh->bUseFullPrecisionUVs = true;
    SkeletalMesh->bHasVertexColors = false;
    
    SkeletalMesh->Skeleton = NewObject<USkeleton>();
    SkeletalMesh->Skeleton->MergeAllBonesToBoneTree(SkeletalMesh);
    SkeletalMesh->PostLoad();


    It compiles correctly, but it randomly crashes when cycling on the SkeletalMesh's IndexBuffer, also whether I'm using the same meshes, so I think there is something I'm not replacing correctly...
    May someone help me to understand what has changed in UE 4.19 and how to correctly replace those snippets of code?
    Last edited by masmil1988; 03-27-2018, 06:57 AM.

    #2
    Quite frustrating that none of these structural changes are documented in the release notes. We do procedural mesh stuff with Skeletal meshes, and have to deal with the same changes that you are.

    Comment


      #3
      DanielW is there any documentation about these changes? Could Marcus Wassmer or anyone else involved in the changes please weight in? :-)

      Comment


        #4
        I'll try and give an overview of the USkeletalMesh changes in 4.19, what we did and why.

        The main idea here is that we want to move the SkeletalMesh render data into the Derived Data Cache (DDC) in a similar way to how StaticMesh works. This makes it much easier to make changes to the render buffer layout. To this end we split FSkeletalMeshResource (which was both the 'source' and the 'derived' data) into FSkeletalMeshModel (source data, only available in editor builds) and FSkeletalMeshRenderData (the actual data needed at runtime for rendering). For each LOD we now have a FSkeletalMeshLODModel (editor only data, within the FSkeletalMeshModel) and a FSkeletalMeshLODRenderData (derived render data, within the FSkeletalMeshRenderData). These are the replacement for the old, confusingly named FStaticLODModel. The derived data is transient - it is re-derived any time the source data changes.

        So when you are updating your code, the main question is - "is this runtime or editor time code". If you want to work on the source data in the editor, you need to work on FSkeletalMeshModel. If your code is supposed to run in cooked game builds, then you can only work with FSkeletalMeshRenderData. So for example, the mesh merging code all works with FSkeletalMeshRenderData because it has to work at runtime. All the editor code now operates on FSkeletalMeshModel, and triggers a rebuild of the derived data so you can see the results (you can see USkeletalMesh::PostEditChangeProperty calls InvalidateRenderData which updates the GUID on the source data and re-generates the derived data for rendering.

        I hope that helps!



        Lead Programmer - UE4 Animation/Physics/Audio Team - Epic Games
        Twitter: @EpicJamesG

        Comment


          #5
          One thing to check would be the c++ Transition guides rama posts in the forum every engine version...
          eg. https://forums.unrealengine.com/deve...ansition-guide
          https://www.casualdistractiongames.com

          Comment


            #6
            JamesG
            ​​​​​​​
            Originally posted by JamesG View Post
            I'll try and give an overview of the USkeletalMesh changes in 4.19, what we did and why.

            The main idea here is that we want to move the SkeletalMesh render data into the Derived Data Cache (DDC) in a similar way to how StaticMesh works. This makes it much easier to make changes to the render buffer layout. To this end we split FSkeletalMeshResource (which was both the 'source' and the 'derived' data) into FSkeletalMeshModel (source data, only available in editor builds) and FSkeletalMeshRenderData (the actual data needed at runtime for rendering). For each LOD we now have a FSkeletalMeshLODModel (editor only data, within the FSkeletalMeshModel) and a FSkeletalMeshLODRenderData (derived render data, within the FSkeletalMeshRenderData). These are the replacement for the old, confusingly named FStaticLODModel. The derived data is transient - it is re-derived any time the source data changes.

            So when you are updating your code, the main question is - "is this runtime or editor time code". If you want to work on the source data in the editor, you need to work on FSkeletalMeshModel. If your code is supposed to run in cooked game builds, then you can only work with FSkeletalMeshRenderData. So for example, the mesh merging code all works with FSkeletalMeshRenderData because it has to work at runtime. All the editor code now operates on FSkeletalMeshModel, and triggers a rebuild of the derived data so you can see the results (you can see USkeletalMesh::PostEditChangeProperty calls InvalidateRenderData which updates the GUID on the source data and re-generates the derived data for rendering.

            I hope that helps!
            This post has been very helpful. The reason of the change is clear and also the difference between editor and built behavior. We now have the plugin working in editor, but I cannot find some "equivalent" behaviour for the cooked game build.

            i.e.
            We have the following behaviour for the editor:

            Code:
            FSkeletalMeshLODModel* LodModel = new FSkeletalMeshLODModel();
            ...
            FSkelMeshSection LodMeshSection = LodModel->Sections[0];
            FSoftSkinVertex* DestVertex = LodMeshSection.SoftVertices.GetData();
            for (uint32_t VertIndex = 0; VertIndex < data->vertexCount; VertIndex++, SourceVertex++, DestVertex++)
            {
                DestVertex->Position = 100.0f * FVector(-SourceVertex->z, SourceVertex->x, SourceVertex->y);
            }
            For the cooked game we are missing something:
            Code:
            FSkeletalMeshLODRenderData* LodRenderData = new FSkeletalMeshLODRenderData();
            ...
            FSkelMeshRenderSection MeshSection = LodRenderData->RenderSections[0];
            // FSkelMeshRenderSection is missing a SoftVertices param; what to do?
            After adding all the vertexes to the mesh, we call the following method for the editor (which replace the old LodModel->BuildVertexBuffers()):
            Code:
            SkeletalMesh->PostEditChange();
            but that method is available only in the editor, what to do for the cooked game build?

            Many many thanks for your help!
            Last edited by masmil1988; 04-03-2018, 03:53 AM.

            Comment


              #7
              Like masmil1988, I had the idea of putting both editor/runtime meshes in the same function. I think the biggest drawbacks are:
              Editor: MultiSizeIndexContainer replaced by IndexBuffer == doesn't work very well (empty array)
              Editor: BuildVertexBuffers no longer there

              and with
              Runtime: TriangleSortSettings not in LodInfo
              Runtime: SoftVertices not in RenderMeshSection

              Not sure for PostEditChange();
              Usefulness of LodRender->BuildFromLODModel(LodModel,vert_flags) ? Why reconstruct runtime mesh with editor mesh??

              Anyway; here's the code now. //RUNTIME should be use during runtime instead of LodModel related functions. We should be able to claim victory soon!

              Code:
              void UOvrAvatar::LoadMesh(USkeletalMesh* SkeletalMesh, const ovrAvatarMeshAssetData* data)
              {
              UE_LOG(LogAvatars, Warning, TEXT("[Avatars] Loaded Mesh."));
              
              //NEW CODE FROM 4.19
              FSkeletalMeshLODModel* LodModel = new FSkeletalMeshLODModel();
              SkeletalMesh->GetImportedModel()->LODModels.Add(LodModel);
              FSkeletalMeshLODRenderData* LodRender = new FSkeletalMeshLODRenderData();
              SkeletalMesh->GetResourceForRendering()->LODRenderData.Add(LodRender);
              
              /* REPLACE OLD CODE FROM 4.18
              FStaticLODModel* LodModel = new FStaticLODModel();
              SkeletalMesh->GetImportedResource()->LODModels.Add(LodModel);
              */
              
              new(LodModel->Sections) FSkelMeshSection();
              LodModel->Sections[0].MaterialIndex = 0;
              LodModel->Sections[0].BaseIndex = 0;
              LodModel->Sections[0].NumTriangles = 0;
              
              //RUNTIME//new(LodRender->RenderSections) FSkelMeshRenderSection();
              //RUNTIME//LodRender->RenderSections[0].MaterialIndex = 0;
              //RUNTIME//LodRender->RenderSections[0].BaseIndex = 0;
              //RUNTIME//LodRender->RenderSections[0].NumTriangles = 0;
              
              SkeletalMesh->LODInfo.Add(FSkeletalMeshLODInfo());
              FSkeletalMeshLODInfo& LodInfo = SkeletalMesh->LODInfo[0];
              
              LodInfo.ScreenSize = 0.3f;
              LodInfo.LODHysteresis = 0.2f;
              /* REPLACE OLD CODE FROM 4.18
              LodInfo.TriangleSortSettings.Add(FTriangleSortSettings());
              */
              LodInfo.LODMaterialMap.Add(0);
              
              SkeletalMesh->Materials.Add(UMaterial::GetDefaultMaterial(MD_Surface));
              SkeletalMesh->RefSkeleton.Empty(data->skinnedBindPose.jointCount);
              /* REPLACE OLD CODE FROM 4.18
              SkeletalMesh->RefSkeleton.Allocate(data->skinnedBindPose.jointCount);
              */
              
              SkeletalMesh->bUseFullPrecisionUVs = true;
              SkeletalMesh->bHasBeenSimplified = false;
              SkeletalMesh->bHasVertexColors = false;
              
              for (uint32_t BoneIndex = 0; BoneIndex < data->skinnedBindPose.jointCount; BoneIndex++)
              {
              LodModel->RequiredBones.Add(BoneIndex);
              LodModel->ActiveBoneIndices.Add(BoneIndex);
              LodModel->Sections[0].BoneMap.Add(BoneIndex);
              
              //RUNTIME//LodRender->RequiredBones.Add(BoneIndex);
              //RUNTIME//LodRender->ActiveBoneIndices.Add(BoneIndex);
              //RUNTIME//LodRender->RenderSections[0].BoneMap.Add(BoneIndex);
              
              FString BoneString = data->skinnedBindPose.jointNames[BoneIndex];
              FName BoneName = FName(*BoneString);
              
              FTransform Transform = FTransform::Identity;
              OvrAvatarHelpers::ConvertTransform(data->skinnedBindPose.jointTransform[BoneIndex], Transform);
              
              FReferenceSkeletonModifier Modifier = FReferenceSkeletonModifier(SkeletalMesh->RefSkeleton, nullptr);
              Modifier.Add(FMeshBoneInfo(BoneName, BoneString, data->skinnedBindPose.jointParents[BoneIndex]), Transform);
              }
              
              check(data->indexCount % 3 == 0);
              check(data->vertexCount > 0);
              
              
              auto& MeshSection = LodModel->Sections[0];
              MeshSection.BaseIndex = 0;
              MeshSection.NumTriangles = data->indexCount / 3;
              MeshSection.BaseVertexIndex = 0;
              MeshSection.NumVertices = data->vertexCount;
              MeshSection.MaxBoneInfluences = 4;
              MeshSection.SoftVertices.SetNumUninitialized(data->vertexCount);
              
              //RUNTIME//auto& RenderMeshSection = LodRender->RenderSections[0];
              //RUNTIME//RenderMeshSection.BaseIndex = 0;
              //RUNTIME//RenderMeshSection.NumTriangles = data->indexCount / 3;
              //RUNTIME//RenderMeshSection.BaseVertexIndex = 0;
              //RUNTIME//RenderMeshSection.NumVertices = data->vertexCount;
              //RUNTIME//RenderMeshSection.MaxBoneInfluences = 4;
              
              const ovrAvatarMeshVertex* SourceVertex = data->vertexBuffer;
              const uint32_t NumBlendWeights = 4;
              
              FSoftSkinVertex* DestVertex = MeshSection.SoftVertices.GetData();
              
              FBox BoundBox = FBox();
              BoundBox.Init();
              
              for (uint32_t VertIndex = 0; VertIndex < data->vertexCount; VertIndex++, SourceVertex++, DestVertex++)
              {
              DestVertex->Position = 100.0f * FVector(-SourceVertex->z, SourceVertex->x, SourceVertex->y);
              
              BoundBox += DestVertex->Position;
              
              FVector n = FVector(-SourceVertex->nz, SourceVertex->nx, SourceVertex->ny);
              FVector t = FVector(-SourceVertex->tz, SourceVertex->tx, SourceVertex->ty);
              FVector bt = FVector::CrossProduct(t, n) * FMath::Sign(SourceVertex->tw);
              DestVertex->TangentX = FPackedNormal(t);
              DestVertex->TangentY = FPackedNormal(bt);
              DestVertex->TangentZ = FPackedNormal(n);
              DestVertex->UVs[0] = FVector2D(SourceVertex->u, SourceVertex->v);
              
              for (uint32_t BlendIndex = 0; BlendIndex < MAX_TOTAL_INFLUENCES; BlendIndex++)
              {
              DestVertex->InfluenceWeights[BlendIndex] = BlendIndex < NumBlendWeights ? (uint8_t)(255.0f*SourceVertex->blendWeights[BlendIndex]) : 0;
              DestVertex->InfluenceBones[BlendIndex] = BlendIndex < NumBlendWeights ? SourceVertex->blendIndices[BlendIndex] : 0;
              }
              }
              
              /* INITIALIZE/CREATE BUFFER LIKE IN 4.18???
              LodModel->MultiSizeIndexContainer.CreateIndexBuffer(sizeof(uint16_t));
              */
              LodModel->NumVertices = data->vertexCount;
              LodModel->NumTexCoords = 1;
              //RUNTIME//LodRender->MultiSizeIndexContainer.CreateIndexBuffer(sizeof(uint16_t));
              //RUNTIME//LodRender->GetNumVertices = data->vertexCount;
              //RUNTIME//LodRender->GetNumTexCoords = 1;
              
              for (uint32_t index = 0; index < data->indexCount; index++)
              {
              /* REPLACE OLD CODE FROM 4.18
              LodModel->MultiSizeIndexContainer.GetIndexBuffer()->AddItem(data->indexBuffer[index]);
              */
              LodModel->IndexBuffer.Add(data->indexBuffer[index]);
              //RUNTIME//LodRender->MultiSizeIndexContainer.GetIndexBuffer()->AddItem(data->indexBuffer[index]);
              }
              
              FBoxSphereBounds Bounds(BoundBox);
              Bounds = Bounds.ExpandBy(100000.0f);
              SkeletalMesh->SetImportedBounds(Bounds);
              
              /* REPLACE OLD CODE FROM 4.18
              const uint32 vert_flags = FStaticLODModel::EVertexFlags::None | FStaticLODModel::EVertexFlags::UseFullPrecisionUVs;
              //LodModel->BuildVertexBuffers(vert_flags);
              */
              uint32 vert_flags = ESkeletalMeshVertexFlags::None | ESkeletalMeshVertexFlags::UseFullPrecisionUVs;
              LodRender->BuildFromLODModel(LodModel,vert_flags);
              
              //SkeletalMesh->PostEditChange();
              SkeletalMesh->Skeleton = NewObject<USkeleton>();
              SkeletalMesh->Skeleton->MergeAllBonesToBoneTree(SkeletalMesh);
              SkeletalMesh->PostLoad();
              }
              Last edited by TheJamsh; 04-04-2018, 04:48 AM.

              Comment


                #8
                Oh please... not again. I was really hoping that if they ever change all the skeletal mesh code again, there would be a transition help with deprecation warnings etc. But there's absolutely NOTHING. It's not even mentioned in the version history. Now I have around 5000 lines of code dealing with procedural skeletal mesh analysis and manipulation at runtime that are basically one big error.

                Has anyone figured out yet where the section vertices have gone? I used to be able to get vertex data by accessing FStaticLODModel::Sections[x]::SoftVertices. But there are no vertices in FStaticLODRenderData::RenderSections[x].

                And I can't even test anything, because I need to fix 5000 lines of code before I can even compile my project - without any info / documentation on how to fix it. I need to create a new project with test code just to figure out what has been changed and what I can use instead of the old structures now. What a f*cking nightmare.

                For example, there is StaticVertexBuffer inside FSkeletalMeshLODRenderData. Maybe that is what I have to use now, if I want to access vertices for reading and/or modifying. Or maybe that buffer is just as empty as the index-buffer. I can't rewrite the entire code without even knowing if I'm on the right track. Wow... Thanks a lot. Might as well just dump my whole project.
                Last edited by MaxPower42; 03-30-2018, 04:06 PM.

                Comment


                  #9
                  Proteus (and everyone else)

                  Are you sure the index buffer is still empty in no-editor builds in 4.19 [edit: I just realised you were talking about the "model", not the "render data" - my index-array isn't empty though]? I remember this being the case in earlier versions, which is why I had to write code to store this data from editor-builds for every mesh and restore it on loading in no-editor-builds, so I could work with it there. However, I just built a test project from the 3rd Person Template and it looks like indices are now contained at runtime in the "RenderData". Can someone please confirm this? Maybe I just did something differently...

                  Also, as everyone probably knows already, the vertex-buffers are no longer kept for each section seperately and seperated into buffers for positions, weights, colors, so there are no FSoftVertices here anymore. I could be wrong, but the best way to update the model at runtime after making changes to the data is to simply call mesh->ReleaseResources() and mesh->InitResources() while suspending the render thread with FSuspendRenderThread to avoid rare crashes (because I think someone asked about this).

                  edit: Is it even a good time to port now or is it likely that more interface changes regarding skeletal meshes will be made in the near future? If that's the case, I would rather skip 4.19 and wait until everything is done than adjusting all my code more than once.
                  Last edited by MaxPower42; 04-02-2018, 12:38 AM.

                  Comment


                    #10
                    Ok, it's a pain, but I am trying to adjust most of my code to the new FSkeletalMeshRenderData. Since there are no FSoftSkinVertices here to work with anymore, I am now using

                    FSkeletalMeshLODRenderData::StaticVertexBuffers.PositionVertexBuffer
                    FSkeletalMeshLODRenderData::StaticVertexBuffers.StaticMeshVertexBuffer
                    FSkeletalMeshLODRenderData::StaticVertexBuffers.ColorVertexBuffer
                    FSkeletalMeshLODRenderData::SkinWeightVertexBuffer

                    for modifying skeletal meshes at runtime. I am still far from being able to compile my project without errors, and there's already a problem that doesn't seem solvable. All the buffers except the one for skin weights have an overloaded Init-function that takes an integer as parameter and sets the buffer size accordingly, so you can scale the vertex count up or down. For the skin weights there is no such overload. I need to dynamically add and remove RenderSections on meshes, and so I must be able to change the vertex count as well. What am I supposed to do?

                    Comment


                      #11
                      Originally posted by MaxPower42 View Post
                      Ok, it's a pain, but I am trying to adjust most of my code to the new FSkeletalMeshRenderData. Since there are no FSoftSkinVertices here to work with anymore, I am now using

                      FSkeletalMeshLODRenderData::StaticVertexBuffers.PositionVertexBuffer
                      FSkeletalMeshLODRenderData::StaticVertexBuffers.StaticMeshVertexBuffer
                      FSkeletalMeshLODRenderData::StaticVertexBuffers.ColorVertexBuffer
                      FSkeletalMeshLODRenderData::SkinWeightVertexBuffer

                      for modifying skeletal meshes at runtime. I am still far from being able to compile my project without errors, and there's already a problem that doesn't seem solvable. All the buffers except the one for skin weights have an overloaded Init-function that takes an integer as parameter and sets the buffer size accordingly, so you can scale the vertex count up or down. For the skin weights there is no such overload. I need to dynamically add and remove RenderSections on meshes, and so I must be able to change the vertex count as well. What am I supposed to do?
                      The class FSkinWeightVertexBuffer has not an Init method available for non-editor builds, but has an override of operator=, through which you can assign a TArray<TSkinWeightInfo<bool>> to the SkinWeightVertexBuffer's WeightData.
                      Last edited by masmil1988; 04-03-2018, 08:28 AM.

                      Comment


                        #12
                        I get a linker error for FSkinWeightVertexBuffer::AllocateData(void) called from FSkinWeightVertexBuffer:: operator=

                        The module should be engine, so I don't know what to do. So much trouble for nothing again with this update...
                        Last edited by MaxPower42; 04-03-2018, 12:39 PM.

                        Comment


                          #13
                          I wrote the following snippet for assigning the SkingWeightVertexBuffer weights:

                          Code:
                              TArray<TSkinWeightInfo<true>> InWeights;
                              InWeights.AddUninitialized(data->vertexCount);
                          
                              for (uint32_t VertIndex = 0; VertIndex < data->vertexCount; VertIndex++, SourceVertex++)
                              {
                                  FModelVertex ModelVertex;
                                  ModelVertex.Position = 100.0f * FVector(-SourceVertex->z, SourceVertex->x, SourceVertex->y);
                                  BoundBox += ModelVertex.Position;
                          
                                  FVector n = FVector(-SourceVertex->nz, SourceVertex->nx, SourceVertex->ny);
                                  FVector t = FVector(-SourceVertex->tz, SourceVertex->tx, SourceVertex->ty);
                                  FVector bt = FVector::CrossProduct(t, n) * FMath::Sign(SourceVertex->tw);
                                  ModelVertex.TangentX = FPackedNormal(t);
                                  ModelVertex.TangentZ = FPackedNormal(n);
                                  ModelVertex.TexCoord = FVector2D(SourceVertex->u, SourceVertex->v);
                          
                                  LodRenderData->StaticVertexBuffers.PositionVertexBuffer.VertexPosition(VertIndex) = ModelVertex.Position;
                                  LodRenderData->StaticVertexBuffers.StaticMeshVertexBuffer.SetVertexTangents(VertIndex, ModelVertex.TangentX, ModelVertex.GetTangentY(), ModelVertex.TangentZ);
                                  LodRenderData->StaticVertexBuffers.StaticMeshVertexBuffer.SetVertexUV(VertIndex, 0, ModelVertex.TexCoord);
                          
                                  for (uint32_t BlendIndex = 0; BlendIndex < MAX_TOTAL_INFLUENCES; BlendIndex++)
                                  {
                                      InWeights[VertIndex].InfluenceWeights[BlendIndex] = BlendIndex < NumBlendWeights ? (uint8_t)(255.0f*SourceVertex->blendWeights[BlendIndex]) : 0;
                                      InWeights[VertIndex].InfluenceBones[BlendIndex] = BlendIndex < NumBlendWeights ? SourceVertex->blendIndices[BlendIndex] : 0;
                                  }
                              }
                              LodRenderData->SkinWeightVertexBuffer.SetHasExtraBoneInfluences(true);
                              LodRenderData->SkinWeightVertexBuffer = InWeights;
                          I still miss something. I still have a crash in the non-editor build, on SkeletalMesh->PostLoad() ... A help, or a transition guide would be appreciated.
                          Last edited by masmil1988; 04-03-2018, 10:54 AM.

                          Comment


                            #14
                            The code so far (only for runtime - I guess that FSkeletalMeshLODRenderData is the way to go now).
                            linker error for FSkinWeightVertexBuffer::AllocateData(void) called from FSkinWeightVertexBuffer:: operator= still there.
                            We are making progress.

                            Code:
                            void UOvrAvatar::LoadMesh(USkeletalMesh* SkeletalMesh, const ovrAvatarMeshAssetData* data)
                            {
                            UE_LOG(LogAvatars, Warning, TEXT("[Avatars] Loaded Mesh."));
                            
                            /*EDITOR FSkeletalMeshLODModel* LodModel = new FSkeletalMeshLODModel();
                            SkeletalMesh->GetImportedModel()->LODModels.Add(LodModel);*/
                            FSkeletalMeshLODRenderData* LodRender = new FSkeletalMeshLODRenderData();
                            SkeletalMesh->GetResourceForRendering()->LODRenderData.Add(LodRender);
                            
                            /* REPLACE OLD CODE FROM 4.18
                            FStaticLODModel* LodModel = new FStaticLODModel();
                            SkeletalMesh->GetImportedResource()->LODModels.Add(LodModel);
                            */
                            
                            /*EDITOR new(LodModel->Sections) FSkelMeshSection();
                            LodModel->Sections[0].MaterialIndex = 0;
                            LodModel->Sections[0].BaseIndex = 0;
                            LodModel->Sections[0].NumTriangles = 0;*/
                            
                            new(LodRender->RenderSections) FSkelMeshRenderSection();
                            LodRender->RenderSections[0].MaterialIndex = 0;
                            LodRender->RenderSections[0].BaseIndex = 0;
                            LodRender->RenderSections[0].NumTriangles = 0;
                            
                            SkeletalMesh->LODInfo.Add(FSkeletalMeshLODInfo());
                            FSkeletalMeshLODInfo& LodInfo = SkeletalMesh->LODInfo[0];
                            
                            LodInfo.ScreenSize = 0.3f;
                            LodInfo.LODHysteresis = 0.2f;
                            /* REMOVED IN 4.19
                            LodInfo.TriangleSortSettings.Add(FTriangleSortSettings());
                            */
                            LodInfo.LODMaterialMap.Add(0);
                            
                            SkeletalMesh->Materials.Add(UMaterial::GetDefaultMaterial(MD_Surface));
                            SkeletalMesh->RefSkeleton.Empty(data->skinnedBindPose.jointCount);
                            /* REPLACE OLD CODE FROM 4.18
                            SkeletalMesh->RefSkeleton.Allocate(data->skinnedBindPose.jointCount);
                            */
                            
                            SkeletalMesh->bUseFullPrecisionUVs = true;
                            SkeletalMesh->bHasBeenSimplified = false;
                            SkeletalMesh->bHasVertexColors = false;
                            
                            for (uint32_t BoneIndex = 0; BoneIndex < data->skinnedBindPose.jointCount; BoneIndex++)
                            {
                            /*EDITOR LodModel->RequiredBones.Add(BoneIndex);
                            LodModel->ActiveBoneIndices.Add(BoneIndex);
                            LodModel->Sections[0].BoneMap.Add(BoneIndex);*/
                            
                            LodRender->RequiredBones.Add(BoneIndex);
                            LodRender->ActiveBoneIndices.Add(BoneIndex);
                            LodRender->RenderSections[0].BoneMap.Add(BoneIndex);
                            
                            FString BoneString = data->skinnedBindPose.jointNames[BoneIndex];
                            FName BoneName = FName(*BoneString);
                            
                            FTransform Transform = FTransform::Identity;
                            OvrAvatarHelpers::ConvertTransform(data->skinnedBindPose.jointTransform[BoneIndex], Transform);
                            
                            FReferenceSkeletonModifier Modifier = FReferenceSkeletonModifier(SkeletalMesh->RefSkeleton, nullptr);
                            Modifier.Add(FMeshBoneInfo(BoneName, BoneString, data->skinnedBindPose.jointParents[BoneIndex]), Transform);
                            }
                            
                            check(data->indexCount % 3 == 0);
                            check(data->vertexCount > 0);
                            
                            
                            /* EDITOR auto& MeshSection = LodModel->Sections[0];
                            MeshSection.BaseIndex = 0;
                            MeshSection.NumTriangles = data->indexCount / 3;
                            MeshSection.BaseVertexIndex = 0;
                            MeshSection.NumVertices = data->vertexCount;
                            MeshSection.MaxBoneInfluences = 4;
                            
                            MeshSection.SoftVertices.SetNumUninitialized(data->vertexCount);*/
                            
                            auto& RenderMeshSection = LodRender->RenderSections[0];
                            RenderMeshSection.BaseIndex = 0;
                            RenderMeshSection.NumTriangles = data->indexCount / 3;
                            RenderMeshSection.BaseVertexIndex = 0;
                            RenderMeshSection.NumVertices = data->vertexCount;
                            RenderMeshSection.MaxBoneInfluences = 4;
                            //REMOVED IN 4.19//RenderMeshSection.SoftVertices.SetNumUninitialized(data->vertexCount);
                            
                            const ovrAvatarMeshVertex* SourceVertex = data->vertexBuffer;
                            const uint32_t NumBlendWeights = 4;
                            
                            //EDITOR FSoftSkinVertex* DestVertex = MeshSection.SoftVertices.GetData();
                            
                            FBox BoundBox = FBox();
                            BoundBox.Init();
                            
                            /*EDITOR for (uint32_t VertIndex = 0; VertIndex < data->vertexCount; VertIndex++, SourceVertex++, DestVertex++)
                            {
                            DestVertex->Position = 100.0f * FVector(-SourceVertex->z, SourceVertex->x, SourceVertex->y);
                            
                            BoundBox += DestVertex->Position;
                            
                            FVector n = FVector(-SourceVertex->nz, SourceVertex->nx, SourceVertex->ny);
                            FVector t = FVector(-SourceVertex->tz, SourceVertex->tx, SourceVertex->ty);
                            FVector bt = FVector::CrossProduct(t, n) * FMath::Sign(SourceVertex->tw);
                            DestVertex->TangentX = FPackedNormal(t);
                            DestVertex->TangentY = FPackedNormal(bt);
                            DestVertex->TangentZ = FPackedNormal(n);
                            DestVertex->UVs[0] = FVector2D(SourceVertex->u, SourceVertex->v);
                            
                            for (uint32_t BlendIndex = 0; BlendIndex < MAX_TOTAL_INFLUENCES; BlendIndex++)
                            {
                            DestVertex->InfluenceWeights[BlendIndex] = BlendIndex < NumBlendWeights ? (uint8_t)(255.0f*SourceVertex->blendWeights[BlendIndex]) : 0;
                            DestVertex->InfluenceBones[BlendIndex] = BlendIndex < NumBlendWeights ? SourceVertex->blendIndices[BlendIndex] : 0;
                            }
                            }*/
                            
                            TArray<TSkinWeightInfo<true>> InWeights;
                            InWeights.AddUninitialized(data->vertexCount);
                            
                            for (uint32_t VertIndex = 0; VertIndex < data->vertexCount; VertIndex++, SourceVertex++)
                            {
                            FModelVertex ModelVertex;
                            ModelVertex.Position = 100.0f * FVector(-SourceVertex->z, SourceVertex->x, SourceVertex->y);
                            BoundBox += ModelVertex.Position;
                            
                            FVector n = FVector(-SourceVertex->nz, SourceVertex->nx, SourceVertex->ny);
                            FVector t = FVector(-SourceVertex->tz, SourceVertex->tx, SourceVertex->ty);
                            FVector bt = FVector::CrossProduct(t, n) * FMath::Sign(SourceVertex->tw);
                            ModelVertex.TangentX = FPackedNormal(t);
                            ModelVertex.TangentZ = FPackedNormal(n);
                            ModelVertex.TexCoord = FVector2D(SourceVertex->u, SourceVertex->v);
                            
                            LodRender->StaticVertexBuffers.PositionVertexBuffer.VertexPosition(VertIndex) = ModelVertex.Position;
                            LodRender->StaticVertexBuffers.StaticMeshVertexBuffer.SetVertexTangents(VertIndex, ModelVertex.TangentX, ModelVertex.GetTangentY(), ModelVertex.TangentZ);
                            LodRender->StaticVertexBuffers.StaticMeshVertexBuffer.SetVertexUV(VertIndex, 0, ModelVertex.TexCoord);
                            
                            for (uint32_t BlendIndex = 0; BlendIndex < MAX_TOTAL_INFLUENCES; BlendIndex++)
                            {
                            InWeights[VertIndex].InfluenceWeights[BlendIndex] = BlendIndex < NumBlendWeights ? (uint8_t)(255.0f*SourceVertex->blendWeights[BlendIndex]) : 0;
                            InWeights[VertIndex].InfluenceBones[BlendIndex] = BlendIndex < NumBlendWeights ? SourceVertex->blendIndices[BlendIndex] : 0;
                            }
                            }
                            LodRender->SkinWeightVertexBuffer.SetHasExtraBoneInfluences(true);
                            LodRender->SkinWeightVertexBuffer = InWeights;
                            
                            /* REMOVED IN 4.19
                            LodModel->MultiSizeIndexContainer.CreateIndexBuffer(sizeof(uint16_t));
                            */
                            /*EDITOR LodModel->NumVertices = data->vertexCount;
                            LodModel->NumTexCoords = 1;*/
                            
                            LodRender->MultiSizeIndexContainer.CreateIndexBuffer(sizeof(uint16_t));
                            LodRender->RenderSections[0].NumVertices = data->vertexCount;
                            //REMOVED IN 4.19 LodModel->NumTexCoords = 1;
                            
                            for (uint32_t index = 0; index < data->indexCount; index++)
                            {
                            
                            //EDITOR LodModel->IndexBuffer.Add(data->indexBuffer[index]);
                            LodRender->MultiSizeIndexContainer.GetIndexBuffer()->AddItem(data->indexBuffer[index]);
                            }
                            
                            FBoxSphereBounds Bounds(BoundBox);
                            Bounds = Bounds.ExpandBy(100000.0f);
                            SkeletalMesh->SetImportedBounds(Bounds);
                            
                            /* REPLACE OLD CODE FROM 4.18
                            const uint32 vert_flags = FStaticLODModel::EVertexFlags::None | FStaticLODModel::EVertexFlags::UseFullPrecisionUVs;
                            //LodModel->BuildVertexBuffers(vert_flags);
                            */
                            uint32 vert_flags = ESkeletalMeshVertexFlags::None | ESkeletalMeshVertexFlags::UseFullPrecisionUVs;
                            //NOT USED SINCE WE ARE ONLY RUNTIME?? LodRender->BuildFromLODModel(LodModel,vert_flags);
                            //INITRESSOURCES?? LodRender->InitResources(false, )
                            //RELEASE RESSOURCES ?? LodRender->ReleaseResources();
                            
                            
                            //POSTEDITCHANGES?? SkeletalMesh->PostEditChange();
                            SkeletalMesh->Skeleton = NewObject<USkeleton>();
                            SkeletalMesh->Skeleton->MergeAllBonesToBoneTree(SkeletalMesh);
                            SkeletalMesh->PostLoad();
                            }
                            Last edited by TheJamsh; 04-04-2018, 04:48 AM. Reason: added code tags

                            Comment


                              #15
                              I tried everything, but I can't fix the linker error for FSkinWeightVertexBuffer::AllocateData(void) when using the = operator. I don't know if this has something to do with the templated nature of the operator-function. Neither AllocateData() nor FSkinWeightVertexBuffer itself are templated, though. I even created a new project and copied my code over without any success. In my 4.19 test project the error has now appeared, too. This is so stupid... a dev statement would be nice before I go insane over some error that can't be fixed.

                              Comment

                              Working...
                              X