0
\$\begingroup\$

I created a custom actor, placed it on my scene and selected it.

When I press "F" to focus on it, the camera zoom back very far from the scene, probably because I didn't implement the method supposed to return the bounding box of my actor.

How can I do that?

Update

I implemented a custom component which delegates all drawing functions to an internal ULineBatchComponent member. I unregistered this ULineBatchComponent member. The custom component is not even attached to the actor root component.

But its bounding box is still taken into account when focusing on the actor.

UPBLineBatchComponent.h

UCLASS()
class UPBLineBatchComponent : public UObject
{
    GENERATED_UCLASS_BODY()
public:
    virtual FBoxSphereBounds CalcBounds(const FTransform& LocalToWorld) const;
    void SetTransform(const FTransform &Transform);
    virtual void DrawLine(...);
    virtual void DrawPoint(...);
    void Flush();
    ULineBatchComponent* LineBatchComponent;
    FBox LocalBounds;
};

UPBLineBatchComponent.cpp

UPBLineBatchComponent::UPBLineBatchComponent( const FObjectInitializer& ObjectInitializer )
        : Super( ObjectInitializer )
{
    LineBatchComponent = CreateDefaultSubobject<ULineBatchComponent>(TEXT("LineBatcher"));
    LineBatchComponent->UnregisterComponent();
    LocalBounds = FBox(0);
    LineBatchComponent->Bounds = FBoxSphereBounds(EForceInit::ForceInitToZero);
}

FBoxSphereBounds UPBLineBatchComponent::CalcBounds(const FTransform& LocalToWorld) const
{
    LineBatchComponent->Bounds = FBoxSphereBounds(LocalBounds.TransformBy(LocalToWorld));
    return FBoxSphereBounds(LocalBounds.TransformBy(LocalToWorld));
}

void UPBLineBatchComponent::SetTransform(const FTransform& Transform)
{
    LocalBounds = LocalBounds.TransformBy(Transform);
    LineBatchComponent->Bounds = FBoxSphereBounds(LocalBounds);

    bool bDirty = false;
    for (FBatchedLine& Line : LineBatchComponent->BatchedLines)
    {
        Line.Start = Transform.TransformPosition(Line.Start);
        Line.End = Transform.TransformPosition(Line.End);
        bDirty = true;
    }

    for (FBatchedPoint& Point : LineBatchComponent->BatchedPoints)
    {
        Point.Position = Transform.TransformPosition(Point.Position);
        bDirty = true;
    }

    for (FBatchedMesh& Mesh : LineBatchComponent->BatchedMeshes)
    {
        for (FVector& Vert : Mesh.MeshVerts)
        {
            Vert = Transform.TransformPosition(Vert);
            bDirty = true;
        }
    }

    if (bDirty)
    {
        LineBatchComponent->MarkRenderStateDirty();
    }
}

void UPBLineBatchComponent::DrawLine(const FVector &Start, const FVector &End, const FLinearColor &Color, uint8 DepthPriority, float Thickness, float LifeTime)
{
    LineBatchComponent->DrawLine(Start, End, Color, DepthPriority, Thickness, LifeTime);
    LocalBounds += Start;
    LocalBounds += End;
    LineBatchComponent->Bounds = FBoxSphereBounds(LocalBounds);
}

void UPBLineBatchComponent::DrawPoint(const FVector &Position, const FLinearColor &Color, float PointSize, uint8 DepthPriority, float LifeTime)
{
    LineBatchComponent->DrawPoint(Position, Color, PointSize, DepthPriority, LifeTime);
    LocalBounds += Position;
    LineBatchComponent->Bounds = FBoxSphereBounds(LocalBounds);
}

void UPBLineBatchComponent::Flush()
{
    LineBatchComponent->Flush();
    LocalBounds = FBox(0);
    LineBatchComponent->Bounds = FBoxSphereBounds(EForceInit::ForceInitToZero);
}

Update 2

If I use

LineBatchComponent = NewObject<ULineBatchComponent>();

instead of

LineBatchComponent = CreateDefaultSubobject<ULineBatchComponent>(TEXT("LineBatcher"));

I can focus properly on the actor, but I can't see the lines anymore.

\$\endgroup\$
2
\$\begingroup\$

I've never experienced the problem you're describing with any custom actor types. You shouldn't need to do anything explicitly, or implement any methods, yourself.

The "focus" command is handled in EditorServer.cpp (the link requires access to Epic's private Unreal Engine GitHub, which can be obtained by registering an account with Epic); specifically UEditorEngine::MoveViewportCamerasToActor.

This method computes a bounding box for the viewable region based on the bounding boxes of the individual selected actors and their components.

Based on your problem description, it is likely that your actor, or one of its components, has an improperly initialized or overly-large bounding box assigned. The other possibility would be that your actor has no components, and is configured such that all other code paths computing the bounding box are skipped (certain types of actors, et cetera), resulting in a zero box.

However the subsequent call that actually focuses the viewport on a box will early-out if given a zero box, so it's quite likely the case is the first one: one of your actor's components has an overly-large or malformed non-zero bounding box.

\$\endgroup\$
  • \$\begingroup\$ Yes, I didn't investigate it yet, but I think one of my component returns a huge bounding box. I strongly suspects UBatchLineComponent. I will check this. \$\endgroup\$ – arthur.sw Mar 22 '16 at 17:26
  • \$\begingroup\$ Yes UBatchLineComponent::CalcBounds() (implementation here) returns the biggest bounds possible. And I can't find any way to fix that. I tried to make my custom UBatchLineComponent by extending it, but I get link errors. \$\endgroup\$ – arthur.sw Mar 23 '16 at 11:44
  • 1
    \$\begingroup\$ Another option might be to unregister the component, as the bounding box computation skips unregistered components. \$\endgroup\$ – Josh Mar 23 '16 at 16:34
  • \$\begingroup\$ It still does not work, I edited my question. \$\endgroup\$ – arthur.sw Mar 24 '16 at 11:16
  • \$\begingroup\$ Did you put a breakpoint on the MoveViewportCamerasToActor function and see where it goes wrong? \$\endgroup\$ – Josh Mar 24 '16 at 13:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.