Skip to content

Commit 7ab6021

Browse files
committed
Fix some skeletal meshes being incorrectly offset if they're scaled
1 parent ad708fa commit 7ab6021

File tree

2 files changed

+209
-7
lines changed

2 files changed

+209
-7
lines changed

Src/D3D9Render_mesh_processing.cpp

Lines changed: 208 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ static inline void calcEnvMapping(FRenderVert& vert, const DirectX::XMMATRIX& sc
9090
vert.V = (XMVectorGetY(envNorm) + 1.0) * 0.5 * 256.0;
9191
}
9292

93+
#if !UNDYING
9394
void UD3D9RenderDevice::renderMeshActor(FSceneNode* frame, AActor* actor, RenderList& renderList, SpecialCoord* specialCoord) {
9495
#ifdef UTGLR_DEBUG_SHOW_CALL_COUNTS
9596
{
@@ -230,15 +231,9 @@ void UD3D9RenderDevice::renderMeshActor(FSceneNode* frame, AActor* actor, Render
230231
#endif // UTGLR_NO_LODMESH
231232
{
232233
isLod = false;
233-
#if UNDYING
234-
numVerts = mesh->FrameVerts(actor);
235-
samples = New<FVector>(GMem, numVerts);
236-
mesh->GetFrame(samples, sizeof(samples[0]), GMath.UnitCoords, actor, frame);
237-
#else
238234
numVerts = mesh->FrameVerts;
239235
samples = New<FVector>(GMem, numVerts);
240236
mesh->GetFrame(samples, sizeof(samples[0]), GMath.UnitCoords, actor);
241-
#endif
242237
numTris = mesh->Tris.Num();
243238
}
244239

@@ -462,7 +457,214 @@ void UD3D9RenderDevice::renderMeshActor(FSceneNode* frame, AActor* actor, Render
462457

463458
unguard;
464459
}
460+
#else
461+
462+
void UD3D9RenderDevice::renderMeshActor(FSceneNode* frame, AActor* actor, RenderList& renderList, SpecialCoord* specialCoord) {
463+
#ifdef UTGLR_DEBUG_SHOW_CALL_COUNTS
464+
{
465+
static int si;
466+
dout << L"utd3d9r: renderMeshActor = " << si++ << std::endl;
467+
}
468+
#endif
469+
using namespace DirectX;
470+
guard(UD3D9RenderDevice::renderMeshActor);
471+
UMesh* mesh = actor->Mesh;
472+
if (!mesh)
473+
return;
474+
475+
//dout << "rendering actor " << actor->GetName() << std::endl;
476+
XMMATRIX actorMatrix = XMMatrixIdentity();
477+
478+
mesh->SetResolution(actor, -1);
479+
TRefArray<FMeshTri> tris = mesh->GetTris(actor);
480+
INT numVerts = mesh->FrameVerts(actor);
481+
482+
// The old switcheroo, trick the game to not transform the mesh verts to object position
483+
FVector origLoc = actor->Location;
484+
FVector origPrePiv = actor->PrePivot;
485+
FRotator origRot = actor->Rotation;
486+
FLOAT origScale = actor->DrawScale;
487+
actor->Location = FVector(0, 0, 0);
488+
actor->PrePivot = FVector(0, 0, 0);
489+
actor->Rotation = FRotator(0, 0, 0);
490+
USkelMesh* skelMesh = Cast<USkelMesh>(actor->Mesh);
491+
if (skelMesh) {
492+
// Don't exactly know what this is doing / why it works but it took 3 weeks to figure out 💀
493+
// The mesh has some kind of pre-scale offset that itself gets scaled with the DrawScale
494+
// eg. groundskeeper is offset in Z ~ 3.75 and 3.5714 before scale of 1.05, this gets me that number.
495+
FPlace offsetScaled = skelMesh->ToActor(actor);
496+
actor->DrawScale = 1.0f;
497+
FPlace offsetIdentity = skelMesh->ToActor(actor);
498+
XMMATRIX matLoc = XMMatrixTranslationFromVector(FVecToDXVec(offsetScaled.Pos - offsetIdentity.Pos));
499+
actorMatrix *= matLoc;
500+
}
501+
actor->DrawScale = 1.0f;
502+
503+
FVector* samples = New<FVector>(GMem, numVerts);
504+
mesh->GetFrame(samples, sizeof(samples[0]), GMath.UnitCoords, actor, frame);
505+
INT numTris = tris.Num();
506+
507+
actor->Location = origLoc;
508+
actor->PrePivot = origPrePiv;
509+
actor->Rotation = origRot;
510+
actor->DrawScale = origScale;
511+
512+
bool renderAsParticles = actor->bParticles;
513+
if (!renderAsParticles) {
514+
XMMATRIX matScale = XMMatrixScaling(actor->DrawScale, actor->DrawScale, actor->DrawScale);
515+
actorMatrix *= matScale;
516+
}
517+
if (specialCoord && specialCoord->enabled) {
518+
actorMatrix *= FCoordToDXMat(specialCoord->coord);
519+
actorMatrix *= FCoordToDXMat(specialCoord->baseCoord);
520+
}
521+
else {
522+
XMMATRIX matLoc = XMMatrixTranslationFromVector(FVecToDXVec(actor->Location + actor->PrePivot));
523+
XMMATRIX matRot = FRotToDXRotMat(actor->Rotation);
524+
actorMatrix *= matRot;
525+
actorMatrix *= matLoc;
526+
}
527+
528+
FTime currentTime = frame->Viewport->CurrentTime;
529+
DWORD baseFlags = getBasePolyFlags(actor);
530+
531+
if (renderAsParticles) {
532+
FLOAT lux = Clamp(actor->ScaleGlow * 0.5f + actor->AmbientGlow / 256.f, 0.f, 1.f);
533+
FPlane color = FVector(lux, lux, lux);
534+
if (GIsEditor && (baseFlags & PF_Selected)) {
535+
color = color * 0.4 + FVector(0.0, 0.6, 0.0);
536+
}
537+
UTexture* tex = actor->Texture->Get(currentTime);
538+
for (INT i = 0; i < numVerts; i++) {
539+
FVector& sample = samples[i];
540+
if (tex) {
541+
542+
// Transform the local-space point into world-space
543+
XMVECTOR xpoint = FVecToDXVec(sample);
544+
xpoint = XMVector3Transform(xpoint, actorMatrix);
545+
FVector point = DXVecToFVec(xpoint);
546+
547+
FTextureInfo texInfo;
548+
tex->Lock(texInfo, currentTime, -1, this);
549+
renderSpriteGeo(frame, point, actor->DrawScale, texInfo, baseFlags, color);
550+
tex->Unlock(texInfo);
551+
}
552+
}
553+
return;
554+
}
555+
556+
UniqueValueArray<UTexture*> textures(mesh->Textures.Num());
557+
UTexture* envTex = nullptr;
558+
559+
// Lock all mesh textures
560+
for (int i = 0; i < mesh->Textures.Num(); i++) {
561+
UTexture* tex = mesh->GetTexture(i, actor);
562+
if (!tex && actor->Texture) {
563+
tex = actor->Texture;
564+
}
565+
else if (!tex) {
566+
continue;
567+
}
568+
tex = tex->Get(currentTime);
569+
textures.insert(i, tex);
570+
envTex = tex;
571+
}
572+
if (actor->Texture) {
573+
envTex = actor->Texture;
574+
}
575+
else if (actor->Region.Zone && actor->Region.Zone->EnvironmentMap) {
576+
envTex = actor->Region.Zone->EnvironmentMap;
577+
}
578+
else if (actor->Level->EnvironmentMap) {
579+
envTex = actor->Level->EnvironmentMap;
580+
}
581+
if (!envTex) {
582+
return;
583+
}
584+
585+
bool fatten = actor->Fatness != 128;
586+
FLOAT fatness = (actor->Fatness / 16.0) - 8.0;
587+
588+
FVector* normals = NewZeroed<FVector>(GMem, numVerts);
589+
590+
// Calculate normals
591+
// Already zeroed on new
592+
for (int i = 0; i < numTris; i++) {
593+
int sampleIdx[3];
594+
const FMeshTri& tri = tris(i);
595+
for (int j = 0; j < 3; j++) {
596+
sampleIdx[j] = tri.iVertex[j];
597+
}
598+
FVector fNorm = (samples[sampleIdx[1]] - samples[sampleIdx[0]]) ^ (samples[sampleIdx[2]] - samples[sampleIdx[0]]);
599+
for (int j = 0; j < 3; j++) {
600+
normals[sampleIdx[j]] += fNorm;
601+
}
602+
}
603+
for (int i = 0; i < numVerts; i++) {
604+
XMVECTOR normal = FVecToDXVec(normals[i]);
605+
normal = XMVector3Normalize(normal);
606+
normals[i] = DXVecToFVec(normal);
607+
}
608+
609+
XMMATRIX screenSpaceMat = actorMatrix * FCoordToDXMat(frame->Uncoords);
610+
611+
ActorRenderData& renderData = renderList.emplace_back();
612+
renderData.actorMatrix = ToD3DMATRIX(actorMatrix);
613+
SurfKeyBucketVector<UTexture*, FRenderVert>& surfaceBuckets = renderData.surfaceBuckets;
614+
surfaceBuckets.reserve(numTris);
465615

616+
int vertMaxCount = numTris * 3;
617+
// Process all triangles on the mesh
618+
for (INT i = 0; i < numTris; i++) {
619+
INT sampleIdx[3];
620+
DWORD polyFlags;
621+
INT texIdx;
622+
FMeshUV triUV[3];
623+
const FMeshTri& tri = tris(i);
624+
for (int j = 0; j < 3; j++) {
625+
sampleIdx[j] = tri.iVertex[j];
626+
triUV[j] = tri.Tex[j];
627+
}
628+
texIdx = tri.TextureIndex;
629+
polyFlags = tri.PolyFlags;
630+
631+
polyFlags |= baseFlags;
632+
633+
bool environMapped = polyFlags & PF_Environment;
634+
UTexture** tex = textures.at(texIdx);
635+
if (environMapped || tex == nullptr) {
636+
tex = &envTex;
637+
}
638+
float scaleU = (*tex)->Scale * (*tex)->USize / 256.0;
639+
float scaleV = (*tex)->Scale * (*tex)->VSize / 256.0;
640+
641+
// Sort triangles into surface/flag groups
642+
std::vector<FRenderVert>& pointsVec = surfaceBuckets.get(*tex, polyFlags);
643+
pointsVec.reserve(vertMaxCount);
644+
for (INT j = 0; j < 3; j++) {
645+
FRenderVert& vert = pointsVec.emplace_back();
646+
FVector pos = samples[sampleIdx[j]];
647+
const FVector& norm = normals[sampleIdx[j]];
648+
if (fatten) {
649+
pos += norm * fatness;
650+
}
651+
vert.pos = pos;
652+
vert.norm = norm;
653+
vert.U = triUV[j].U;
654+
vert.V = triUV[j].V;
655+
656+
// Calculate the environment UV mapping
657+
if (environMapped) {
658+
calcEnvMapping(vert, screenSpaceMat, frame);
659+
}
660+
vert.U *= scaleU;
661+
vert.V *= scaleV;
662+
}
663+
}
664+
665+
unguard;
666+
}
667+
#endif
466668

467669
#if UNREAL_GOLD_OLDUNREAL
468670
void UD3D9RenderDevice::renderStaticMeshActor(FSceneNode* frame, AActor* actor, RenderList& renderList, SpecialCoord* specialCoord) {

0 commit comments

Comments
 (0)