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"

[C++] Scaling an UStaticMeshComponent causes collision to stop working

I have got a UStaticMeshComponent which I rotate and scale non uniformly, in order to have a cylinder which connects two points. After scaling, checking for collision with LineTraceSingleByChannel returns no hit results. Before scaling, everything works fine, i.e. I get a valid hit result. All this is in the standalone executable, not the editor.

How do I preserve collision (or recreate it) after scaling a static mesh?

I use the following code to create the component:

 UStaticMeshComponent* AWireActor::createCylinder(FVector startPosition, FVector endPosition)
 {
     UStaticMeshComponent *cylinder = NewObject<UStaticMeshComponent>(this);
     cylinder->RegisterComponent();
     cylinder->AttachTo(RootComponent);
     cylinder->SetMobility(EComponentMobility::Movable);
 
     // Make the wire sleeker (scale start and end size down) and center it, since the mesh has it's oirigin on the side, not the center.
     cylinder->SetRelativeScale3D(FVector(0.1f, 0.1f, 1.0f));
     // roatate to match start and end
     alignCylinder(startPosition, endPosition, cylinder);
 
     UStaticMesh* meshToUse = Cast<UStaticMesh>(StaticLoadObject(UStaticMesh::StaticClass(), nullptr,
         TEXT("StaticMesh'/Game/StarterContent/Shapes/Shape_Cylinder.Shape_Cylinder'")));
     cylinder->SetStaticMesh(meshToUse);
     cylinder->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
     cylinder->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Block);
     // cylinder->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic);
 
     cylinder->SetMaterial(0, cylinderMaterial);
 
     return cylinder;
 }

This code is used to move the cylinder to the correct position:

 void AWireActor::alignCylinder(FVector start, FVector end, UStaticMeshComponent *cylinder)
 {
     // rotate by 90° around X-axis to correct for the cylinder being aligned on the Z instead of the X axis.
     cylinder->SetWorldRotation(FRotator(90.0f, 0.0f, 0.0f));
     // add the rotation of the vector between start and end to align the cylinder with it.
     cylinder->AddWorldRotation((end - start).Rotation());
 
     // place the cylinder in the end location, since it's pivot is in there.
     cylinder->SetWorldLocation(end);
 
     // scale the cylinder up to properly reach both ends.
     FVector min, max;
     cylinder->GetLocalBounds(min, max);
     
     float zScale = ((start - end).Size() / max.Size());
     cylinder->SetRelativeScale3D(FVector(0.1f, 0.1f, zScale));
 }

Wierdly enough this (buggy) scaling code does not break collision. However it doesn't always scale the component correctly, so it's not usable:

 void AWireActor::alignCylinder(FVector start, FVector end, UStaticMeshComponent *cylinder)
 {
     // rotate by 90° around X-axis to correct for the cylinder being aligned on the Z instead of the X axis.
     cylinder->SetWorldRotation(FRotator(90.0f, 0.0f, 0.0f));
     // add the rotation of the vector between start and end to align the cylinder with it.
     cylinder->AddWorldRotation((end - start).Rotation());
 
     // place the cylinder in the end location, since it's pivot is in there.
     cylinder->SetWorldLocation(end);
     // scale the cylinder up to properly reach both ends.
     float radius = 0.0f, halfHeight = 0.0f;
     cylinder->CalcBoundingCylinder(radius, halfHeight);
     float zScale = ((start - end).Size() / (halfHeight * 2.0f));
     cylinder->SetRelativeScale3D(FVector(0.1f, 0.1f, zScale));
     GEngine->AddOnScreenDebugMessage(-1, LOG_TIME, FColor::Green, FString("Scaled to ") + FString::SanitizeFloat(zScale)
         + FString("Height is ") + FString::SanitizeFloat(halfHeight));
 }

A similar problem has been presented here, however there's no solution: https://answers.unrealengine.com/questions/166286/problems-with-collision-when-non-uniformly-scaling.html

Previously I used splines to create these wires, however they always had the same collision issue as described here, hence I abandoned them in favour of regular static meshes. Could this be a similar issue?

Product Version: UE 4.9
Tags:
more ▼

asked Mar 11 '16 at 03:10 PM in C++ Programming

avatar image

MarvinG
1 1 2 3

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

1 answer: sort voted first

Found the solution: When a scene component is scaled to zer in one dimension, the collision model vanishes while the mesh remains visible. If I check whether zScale is zero before executing cylinder->SetRelativeScale3D(FVector(0.1f, 0.1f, zScale)); the issue is avoided.

more ▼

answered Mar 14 '16 at 11:41 AM

avatar image

MarvinG
1 1 2 3

(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