x

Search in
Sort by:

Question Status:

Search help

  • Simple searches use one or more words. Separate the words with spaces (cat dog) to search cat,dog or both. Separate the words with plus signs (cat +dog) to search for items that may contain cat but must contain dog.
  • You can further refine your search on the search results page, where you can search by keywords, author, topic. These can be combined with each other. Examples
    • cat dog --matches anything with cat,dog or both
    • cat +dog --searches for cat +dog where dog is a mandatory term
    • cat -dog -- searches for cat excluding any result containing dog
    • [cats] —will restrict your search to results with topic named "cats"
    • [cats] [dogs] —will restrict your search to results with both topics, "cats", and "dogs"

Custom Mesh FOV

In UDK, the UDKSkeletalMesh had an FOV option whereby we could set a custom FOV that the mesh would be rendered at. Is there such an option in UE4? I don't see it in the properties of my skeletalmeshcomponents for my blueprint. Does it have to be done by code? Does it exist at all?

Product Version: Not Selected
Tags:
more ▼

asked Apr 06 '14 at 06:58 PM in Blueprint Scripting

avatar image

gregdumb
23 4 7 10

avatar image gregdumb Apr 07 '14 at 09:19 PM

Sooo... I guess this isn't possible yet? I can't find info on it anywhere. :(

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

3 answers: sort voted first

Yes, Shadowriver was right. Indeed override GetRenderMatrix of USkeletalMeshComponent should work. The following code is the code which I was developed for our game. Please notice I used magic number 1920/1080 which is our game resolution. Feel free change it to whatever fit to your game.

     APlayerController* playerController = GetWorld()->GetFirstPlayerController();
     if (playerController)
     {
         ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(playerController->Player);
 
         if (LocalPlayer != NULL && LocalPlayer->ViewportClient != NULL && LocalPlayer->ViewportClient->Viewport != NULL)
         {
             FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
                 LocalPlayer->ViewportClient->Viewport,
                 GetWorld()->Scene,
                 LocalPlayer->ViewportClient->EngineShowFlags)
                 .SetRealtimeUpdate(true));
 
             FVector ViewLocation;
             FRotator ViewRotation;
             FSceneView* SceneView = LocalPlayer->CalcSceneView(&ViewFamily, ViewLocation, ViewRotation, LocalPlayer->ViewportClient->Viewport);
 
             float MinZ = SceneView->NearClippingDistance;
             float MaxZ = MinZ;
 
             // Avoid zero ViewFOV's which cause divide by zero's in projection matrix
             float MatrixFOV = FMath::Max(0.001f, WeaponFOV) * (float)PI / 360.0f;
 
             FMatrix projMatrix = FReversedZPerspectiveMatrix(
                     MatrixFOV,
                     MatrixFOV,
                     1.0f,
                     1920.0f / 1080.0f,
                     MinZ,
                     MaxZ
                     );
 
             FScaleMatrix ClipSpaceFixScale(FVector(1.0f, 1.0f, 1.0f - 0.0f));
             FTranslationMatrix ClipSpaceFixTranslate(FVector(0.0f, 0.0f, 0.0f));
             projMatrix =  projMatrix * ClipSpaceFixScale * ClipSpaceFixTranslate;
 
             FMatrix adjustedViewProjectMatrix = SceneView->ViewMatrices.ViewMatrix * projMatrix;
             FMatrix inverseOldViewProjectMatrix = SceneView->InvViewProjectionMatrix;
             FMatrix adjTransform = ComponentToWorld.ToMatrixWithScale() * adjustedViewProjectMatrix * inverseOldViewProjectMatrix;
 
             return adjTransform;
         }
         else
         {
             return Super::GetRenderMatrix();
         }
     }
     else
     {
         return Super::GetRenderMatrix();
     }


more ▼

answered Mar 29 '15 at 10:22 AM

avatar image

frankmli
271 6 10 17

avatar image staticvoidlol Apr 13 '15 at 01:35 PM

Awesome stuff!

Just had to do a small check to ensure that "SceneView" is not null - seems that for a few frames at startup, it will be null (depending on when you spawn your meshes). Otherwise, works perfectly (even with attachments/sockets).

Thanks very much for sharing.

avatar image frankmli Apr 14 '15 at 06:55 AM

Thanks a lot for pointing out a potential risk.

avatar image staticvoidlol Sep 14 '15 at 07:29 AM

Hi frankmli,

It seems that in 4.9 this is unfortunately causing a crash.

It happens around line 16 (where the SceneView is created). It first failed on an assertion which checked that the Times were set (I got around that by retrieving the World Time, Delta Time and Game Time from GetWorld() and setting these on the construction params. However it crashes at a later stage as well and I'm struggling to fix it.

So I suppose my question is whether you've managed to get this working in 4.9 yet?

In any case, I'll keep bashing my head against it and hope I figure it out eventually.

Also thanks very much again for sharing this!

Cheers.

avatar image frankmli Sep 14 '15 at 12:19 PM

Hi, Staticvoidlol

We don't have such issue at all here. Here are the screenshot from our game which running at version UE4.9. As what you described in your message, it seems line 8-12 might be issue which constructing messed viewFamily.

Good luck.

Cheers, Frank

alt text

avatar image staticvoidlol Sep 14 '15 at 08:35 PM

Hi Frank,

Thanks very much for getting back to me.

Interesting that it works perfectly for you.

It seems mine is only crashing when running the game standalone (not PIE), and it crashes on GetShadowIndex() in the class TConsoleVariableData (as shown in the screen shot).

I honestly have no idea what this function is supposed to be doing other than checking that it's happening on the main game thread

Have you checked that yours works fine in non-editor runtime?

Cheers!

alt text

capture.png (87.9 kB)
avatar image frankmli Sep 15 '15 at 02:32 AM

I got this here too in debug build. Hope I can find what wrong it is.

Frank

avatar image frankmli Sep 15 '15 at 04:26 AM

basically what it means is in GetRenderMatrix which is called in render thread invokes function LocalPlayer->CalcSceneView which should be only called in game thread. It is the issue. I need a way to get same information through render thread friendly function.

avatar image staticvoidlol Sep 15 '15 at 10:09 AM

Ah ok, I suppose that makes sense. Thanks for checking it out.

avatar image frankmli Sep 15 '15 at 02:08 PM

The fixed version is in another answer!!

(comments are locked)
10|2000 characters needed characters left
Viewable by all users

Thanks staticvoidlol for point out the issue. The last code I wrote which invoke a game thread function in render thread. The following code is my latest fix. Although it looks clumsy about calculating project/view matrix for viewport, it works perfectly here.

 FMatrix CustomFOVMeshComponent::GetRenderMatrix() const
 {
     //Get camera perspectiveMatrix
     APlayerController* playerController = GetWorld()->GetFirstPlayerController();
     if (playerController)
     {
         ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(playerController->Player);
 
         if (LocalPlayer != NULL && LocalPlayer->ViewportClient != NULL && LocalPlayer->ViewportClient->Viewport != NULL)
         {
             FSceneViewFamilyContext ViewFamily(FSceneViewFamily::ConstructionValues(
                 LocalPlayer->ViewportClient->Viewport,
                 GetWorld()->Scene,
                 LocalPlayer->ViewportClient->EngineShowFlags)
                 .SetWorldTimes(0.0f, 0.0f, 0.0f)
                 .SetRealtimeUpdate(false));
 
             FVector ViewLocation;
             FRotator ViewRotation;
 
             float MinZ = 3.0f;
             float MaxZ = MinZ;
 
             // Avoid zero ViewFOV's which cause divide by zero's in projection matrix
             float MatrixFOV = FMath::Max(0.001f, WeaponFOV) * (float)PI / 360.0f;
 
             FMatrix projMatrix = FReversedZPerspectiveMatrix(
                     MatrixFOV,
                     MatrixFOV,
                     1.0f,
                     LocalPlayer->Size.X * LocalPlayer->ViewportClient->Viewport->GetSizeXY().X / (LocalPlayer->Size.Y * LocalPlayer->ViewportClient->Viewport->GetSizeXY().Y),
                     MinZ,
                     MaxZ
                     );
 
             FScaleMatrix ClipSpaceFixScale(FVector(1.0f, 1.0f, 1.0f - 0.0f));
             FTranslationMatrix ClipSpaceFixTranslate(FVector(0.0f, 0.0f, 0.0f));
             projMatrix =  projMatrix * ClipSpaceFixScale * ClipSpaceFixTranslate;
 
             FMatrix viewMatrix;
             FMatrix invViewProjectionMatrix;
 
             GetViewMatrices(viewMatrix, invViewProjectionMatrix);
 
             FMatrix adjustedViewProjectMatrix = viewMatrix * projMatrix;
             FMatrix inverseOldViewProjectMatrix = invViewProjectionMatrix;
             FMatrix adjTransform = ComponentToWorld.ToMatrixWithScale() * adjustedViewProjectMatrix * inverseOldViewProjectMatrix;
 
             return adjTransform;
         }
         else
         {
             return Super::GetRenderMatrix();
         }
     }
     else
     {
         return Super::GetRenderMatrix();
     }
 }
 
 void CustomFOVMeshComponent::GetViewMatrices(FMatrix& viewMatrix, FMatrix& invViewProjectionMatrix) const
 {
     APlayerController* playerController = GetWorld()->GetFirstPlayerController();
     ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(playerController->Player);
 
     //Get View Origin
     FVector ViewOrigin;
     FRotator ViewRotation;
     playerController->GetPlayerViewPoint(/*out*/ ViewOrigin, /*out*/ ViewRotation);
 
     FMatrix ViewRotationMatrix = FInverseRotationMatrix(ViewRotation) * FMatrix(
         FPlane(0, 0, 1, 0),
         FPlane(1, 0, 0, 0),
         FPlane(0, 1, 0, 0),
         FPlane(0, 0, 0, 1));
 
     if (!ViewRotationMatrix.GetOrigin().IsNearlyZero(0.0f))
     {
         ViewOrigin += ViewRotationMatrix.InverseTransformPosition(FVector::ZeroVector);
         ViewRotationMatrix = ViewRotationMatrix.RemoveTranslation();
     }
 
     // Calculate view matrix
     viewMatrix = FTranslationMatrix(-ViewOrigin) * ViewRotationMatrix;
 
     // Calculate project matrix
     int32 X = FMath::TruncToInt(LocalPlayer->Origin.X * LocalPlayer->ViewportClient->Viewport->GetSizeXY().X);
     int32 Y = FMath::TruncToInt(LocalPlayer->Origin.Y * LocalPlayer->ViewportClient->Viewport->GetSizeXY().Y);
     uint32 SizeX = FMath::TruncToInt(LocalPlayer->Size.X * LocalPlayer->ViewportClient->Viewport->GetSizeXY().X);
     uint32 SizeY = FMath::TruncToInt(LocalPlayer->Size.Y * LocalPlayer->ViewportClient->Viewport->GetSizeXY().Y);
 
     FIntRect UnconstrainedRectangle = FIntRect(X, Y, X + SizeX, Y + SizeY);
 
     FSceneViewProjectionData ProjectionData;
     ProjectionData.SetViewRectangle(UnconstrainedRectangle);
 
     FMinimalViewInfo OutViewInfo;
 
     if (playerController->PlayerCameraManager != NULL)
     {
         OutViewInfo = playerController->PlayerCameraManager->CameraCache.POV;
         OutViewInfo.FOV = playerController->PlayerCameraManager->GetFOVAngle();
         playerController->GetPlayerViewPoint(/*out*/ OutViewInfo.Location, /*out*/ OutViewInfo.Rotation);
     }
     else
     {
         playerController->GetPlayerViewPoint(/*out*/ OutViewInfo.Location, /*out*/ OutViewInfo.Rotation);
     }
 
     FMinimalViewInfo::CalculateProjectionMatrixGivenView(OutViewInfo, LocalPlayer->AspectRatioAxisConstraint, LocalPlayer->ViewportClient->Viewport, /*inout*/ ProjectionData);
 
     FMatrix ProjMatrix = ProjectionData.ProjectionMatrix;
 
     FViewMatrices ViewMatrices;
     ViewMatrices.ViewMatrix = viewMatrix;
     ViewMatrices.ProjMatrix = ProjMatrix;
     invViewProjectionMatrix = ViewMatrices.GetInvViewProjMatrix();
 }
more ▼

answered Sep 15 '15 at 02:07 PM

avatar image

frankmli
271 6 10 17

avatar image staticvoidlol Sep 17 '15 at 04:29 PM

Hi Frank,

Again, I must say that I appreciate your effort and kindness in sharing this immensely! It is much appreciated - if there is anywhere I can donate to your project (or if you'd like to put this on the marketplace I'd buy it in an instant) please let me know.

However, I am having a bit of trouble with this new version - you can see the problem in this video.

It seems that my mesh now doesn't follow my character properly - it seems to be always positioned between my character and the world origin. I would suspect that there are some values getting pulled through as zero where it shouldn't be. This is purely a hunch as it seems to point to a Vector(0,0,0) (which is the world origin) affecting the transforms.

Do you have any idea what might be causing this behaviour? I've looked through each line of the code best I can, but I'm a bit lost here as I can't find anything that is zero where it obviously shouldn't be.

If you have some time to look at this I would be very grateful.

Thanks very much!

avatar image frankmli Sep 18 '15 at 12:58 AM

Hi,

I don't have such issue here. If the mesh is always in the world origin, set a break point at line 47, check ComponentToWorld.ToMatrixWithScale() if the world matrix still keep the translation.

avatar image staticvoidlol Sep 19 '15 at 10:36 AM

Hi Frank,

Thanks very much for having a look.

It seems that ComponentToWorld does keep the translation correctly (it's equal to the location of the mesh).

I'm getting the following values at the end of the "GetViewMatrices()" function:

Does anything look off to you?

viewmatrices.jpg (220.0 kB)
avatar image frankmli Sep 23 '15 at 05:00 AM

Hi,

This might be the problem alt text

It seems you simply get the view point location and rotation from current actor location and rotation. Basically, you need to fill out the information with the camera which viewport is rendered from. Hope it is helpful

mightbetheissue.jpg (528.7 kB)
avatar image staticvoidlol Sep 24 '15 at 10:44 AM

Hi Frank,

Thanks very much for having a look - unfortunately that is not the issue (the weapon's location and rotation is set exactly equal to the camera's). I get the same behaviour with a direct copy paste of your original code.

The code shown in my screenshot is just part of me going through each line and checking if I find any obvious zeroes.

I get the following when using the exact code you pasted (except for a hardcoded WeaponFOV of 100).

Viewmatrices

viewmatrices2.png (37.5 kB)
avatar image frankmli Sep 24 '15 at 01:18 PM

Hi,

Sorry, it is very hard to tell from my end. As long as you understand the theory behind code, you have to go through the code line by line to find out the reason on you own. Good luck. :)

Frank

avatar image staticvoidlol Sep 27 '15 at 02:41 PM

Thanks in any case for having a look Frank.

I've managed to (sort of) fix the problem on my side. I've reverted to the first solution and moved the CalcScene view from the GetRenderMatrix() to the TickComponent() function (moved from render to game thread) and I then store the required matrices on the component for when GetRenderMatrix() needs them. There does seem to be some delay using this method, as I assume the Render and Game threads don't tick exactly at the same rate. In any case, code below:

Attaching code via file.

fov.txt (2.3 kB)
avatar image staticvoidlol Oct 01 '15 at 07:46 PM

Phheeeeeeeeew, finally I've found the problem!

Ok, so I debugged through every value of every line of code of the original as well as the newest one, and the problem was simply this line in the newer version:

 float MinZ = 3.0f;

This line defines the near clipping plane. I changed this to 5 and now everything is perfectly fine.

Again, Frank, thanks a million for sharing your code. It is much appreciated!

avatar image Anders Holmquist Apr 12 '17 at 03:17 PM

I recently tried this code in 4.15, I wanted to do a quick test with mesh-specific FOV. In case somebody wants a more up-to-date version, here are some things I had to change:

MinZ should be your NearClippingDistance as staticvoidlol mentioned, but yours might not be 5, so make sure it's correct.

The members used in FViewMatrices are now private, and there's no real use to go through that class at all, so I replaced the final math in GetViewMatrices with:

 FMatrix ProjMatrix = ProjectionData.ProjectionMatrix;
 FMatrix InvProjectionMatrix = ProjMatrix.Inverse(); 
 FMatrix InvViewMatrix = FTranslationMatrix(-viewMatrix.GetOrigin()) * viewMatrix.RemoveTranslation().GetTransposed();
 invViewProjectionMatrix = InvProjectionMatrix * InvViewMatrix;
(comments are locked)
10|2000 characters needed characters left
Viewable by all users

I could not find anything related to FOV and SkeletalMesh in API refrence so i guess not.

I know that all classes that starts with UDK and are part of UDKBase are not really part of UE3 framework those some special things made for UDK, so most likely UE4 didn't inherited it. It's most likely implementable but extra requires C++ coding and override of USkeletalMeshComponent

more ▼

answered Apr 07 '14 at 10:48 PM

avatar image

Shadowriver
35.9k 928 169 1105

avatar image gregdumb Apr 07 '14 at 11:35 PM

Alright, thanks for the reply. I don't think I'm skilled enough to implement it myself unfortunately, so I guess I'll have to do without :(

avatar image elliotek Dec 16 '14 at 05:23 PM

I would need it too. Pretty handy when you have a weapon/Cockpit to display in the foreground...

(comments are locked)
10|2000 characters needed characters left
Viewable by all users
Your answer
toggle preview:

Up to 5 attachments (including images) can be used with a maximum of 5.2 MB each and 5.2 MB total.

Follow this question

Once you sign in you will be able to subscribe for any updates here

Answers to this question