Friday, August 18, 2017

Teleport Arc Rumble

Teleport Arc Rumble


What I thought was going to be a 1 hour task turned into a deep dark black hole of hell.

I did not find a single example of someone successfully rumbling the Vive controller from C++.

I have code that should work but it does not and I am tired of fighting with it right now.

So... I went the opposite route and worked on calling a blueprint method (which I know works) from C++. That was an extreme pain as well.

If you construct a blueprint object via Spawn it will not call blue print methods.

I had to resort to dropping a blueprint actor (that subclassed a C++ class I created) into the scene and then find it once the game started. That gave me the ability to call blue print custom events.

Unreal fights me every inch of the way...

Thursday, August 17, 2017

Vive Teleport in C++ : Wrap Up

Vive Teleport in C++ : Wrap Up


I've finished the visual piece of the teleport. Here is a combined screen shot of failure and success:


Notice how the red teleport circle matches the normal of the plane it hits.

It is snappy, completely in C++ and does not rely on the overhead of the navigational mesh that comes with the Unreal example. It only relies on the teleport meshes I have on the screen.

My goal is to match the gold standard that is Valve's VR Room. That is the level of polish I want for my game. It looks simple and feels natural.

Hats off to Valve for pushing VR tech forward so that we can have a holodeck for the home.

Next is to actually teleport and polish my world generation logic.

Wednesday, August 16, 2017

Vive Teleporter in C++ : Part 3

Vive Teleporter in C++ : Part 3

I have the teleport arc working in C++

Problem is that it doesn't collide with anything on the screen, only the static nav mesh that came with the example. I left that under my world construction so I can teleport around with the old code. My goal is to get rid of it so I'm going to need to change this...

From what I understand, there are collision channels. I need to put all my non-plant meshes in a custom collision channel and use that for detection. Or... at least that is the theory.

I think I am going to have to rip this code out of unreal and customize it at some point but if I can avoid that for a while I will.

....

Tracing this arc only seems to work for static meshes predefined in the level.

The trace logic is a black box to me. It leaves me no choice but to copy all the tracing logic into a utility class I control and start figuring wtf is going on here.

Unreal has no end to the pain it puts me through.

...

I think I have this figured out. I created a utility class and moved these 2 methods into it:
Blueprint_PredictProjectilePath_ByObjectType and PredictProjectilePath

I then altered PredictProjectilePath to force a channel trace instead of ObjectType trace.

That hit every mesh on the screen.

I then added a tag to each mesh.

Next came collision. I switched ground and walls to complex collision on the mesh.

For the teleport areas, they are planes and Unreal's collision mesh didn't work. I had to add a collision mesh for the teleport planes. Once I did this, the channel trace found it and identified the teleport areas.

Now it is just a matter of clean up and moving onto adding an end point that matches Valve's VR implementation.

I am getting occasional stutter, but I think it is the log spewing out too much info.

Vive Teleporter in C++ : Part 2

Vive Teleporter in C++ : Part 2

Mapping controller buttons into code went very well.

Now onto the teleport arc. Here is the code in blueprint:

Everything is flowing in and out of that big blue-header box.

I found the method:
UGameplayStatics::Blueprint_PredictProjectilePath_ByObjectType

That thing takes in 16 parameters!

Who the hell names a method Blueprint_ ?

Fortunately we can see all of them on the screen but 1. Some of the parameters are output parameters. I actually have my code calling this method on teleport button press and getting 60 points back that appear to be along an arc. Now I just need to build a spline based on these points.

Since nobody on the planet seems to be calling this method from C++, let me help you:

UObject* WorldContextObject = GetWorld();

Location = RightMotionController->GetComponentLocation(); ForwardVector = RightMotionController->GetForwardVector();

// INPUT --------------------------
FVector StartPos = Location;
float Velocity = 900.0f;
FVector LaunchVelocity = UKismetMathLibrary::Multiply_VectorFloat(ForwardVector, Velocity);
bool bTracePath = true;
float ProjectileRadius = 0.0f;
TArray<TEnumAsByte<EObjectTypeQuery>> ObjectTypes;
ObjectTypes.Add(EObjectTypeQuery::ObjectTypeQuery1);
bool bTraceComplex = false;
const TArray<AActor*> ActorsToIgnore;
EDrawDebugTrace::Type DrawDebugType = EDrawDebugTrace::None;
float DrawDebugTime = 0.0;
float SimFrequency = 30.0;
float MaxSimTime = 2.0;
float OverrideGravityZ = 0.0;

// OUTPUT --------------------------
FHitResult OutHit;
TArray<FVector> OutPathPositions;
FVector OutLastTraceDestination;

bool HitSomething = UGameplayStatics::Blueprint_PredictProjectilePath_ByObjectType(
WorldContextObject,
OutHit,
OutPathPositions,
OutLastTraceDestination,
StartPos,
LaunchVelocity,
bTracePath,
ProjectileRadius,
ObjectTypes,
bTraceComplex,
ActorsToIgnore,
DrawDebugType,
DrawDebugTime,
SimFrequency,
MaxSimTime,
OverrideGravityZ
);

Tuesday, August 15, 2017

Vive Teleporter in C++

Vive Teleporter in C++


I've been programming a long time and I must admit the teleport blueprint example from Unreal is very intimidating. Converting this to C++ feels like a major task


It reminds me of an airplane cockpit:



Well... with anything big, you eat it one bite at a time.

The first bite was getting VIVE controllers into my game in C++. That was easier than I thought and covered in a prior post.

The second bite is firing off my C++ code when buttons are pressed.

This is a great article on doing this:
http://jonaskunze.com/accessing-htc-vive-controllers-from-c-in-ue4-4-13-and-4-14/

I don't want to break the existing teleport example in Unreal so I have to figure out which buttons are already mapped and use event names instead of the ones in that example. Eventually I will rename the event names to be generic but that will be a last step in the process.

I think this image is very helpful:

I compared the button mappings in my current DefaultInput.ini, to what that article listed. Here is what I have:

 Action Mappings:
  TeleportRight (RightTouchpadPress) = MotionController_Right_Thumbstick
  TeleportRight (RightTouchpadUp) = MotionController_Right_FaceButton1
  GrabLeft (LeftTrigger) = MotionController_Left_Trigger
  GrabRight (RightTrigger) = MotionController_Right_Trigger
  TeleportLeft (LeftTouchpadPress) = MotionController_Left_Thumbstick
  TeleportLeft (LeftTouchpadUp) = MotionController_Left_FaceButton1
  HMDTeleport

 Axis Mappings:
  TeleportDirectionUp = Gamepad_LeftY
  TeleportDirectionRight = Gamepad_LeftX
  MotionControllerThumbLeft_Y (LeftTouchpadY) = MotionController_Left_Thumbstick_Y
  MotionControllerThumbLeft_X (LeftTouchpadX) = MotionController_Left_Thumbstick_X
  MotionControllerThumbRight_Y (RightTouchpadY) = MotionController_Right_Thumbstick_Y
  MotionControllerThumbRight_X (RightTouchpadX) = MotionController_Right_Thumbstick_X

The name on the left is what the Unreal teleport example calls it.
The name in parens is what the article calls it.
The value on the right is the actual action/axis event.

To start with, I am going to use these and add methods for each of them in my Pawn code. It recommend a Character class. Character just extends Pawn and adds more human locomotion logic. If I need to, I will change my base class to Character, but for the moment I am sticking with Pawn.

This was a reddit post discussing Pawn vs Character for reference:
https://www.reddit.com/r/unrealengine/comments/2yo13c/a_question_on_the_acharacter_vs_apawn_conundrum/

Monday, August 14, 2017

How to set up Vive controllers in Unreal in C++

How to set up Vive controllers in Unreal in C++


I am going to show you exactly how to set up HTC Vive controllers in Unreal 4 using C++. 

This was a pain in the ass with snippets of code and information scattered everywhere. This may be easy for seasoned UE4 developers. For noobs like myself, it was not. The Blueprint hides things and does not explain how this is done in C++.



Prerequsite:

You need a custom game mode working you can write logic into its BeginPlay() method.

1. Import the Vive 3D controller into blender.


Steam\steamapps\common\SteamVR\resources\rendermodels\vr_controller_vive_1_5\
  vr_controller_vive_1_5.obj


2. Export the Vive 3D controller as fbx



3. Import the Vive 3D controller and 2 related textures


C:\Program Files (x86)\Steam\steamapps\common\SteamVR\resources\rendermodels\vr_controller_vive_1_5
   onepointfive_occ_bake.tga
   onepointfive_texture.png


4. Build a material. I tweaked it to use a custom wood material


I assume you know how to make a material...


5. Set the material on the 3D controller


This is pretty straight forward...


6. Add HeadMountedDisplay to PublicDependencyModuleNames in your GameName.build.cs file
PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "Foliage", "InputCore", "HeadMountedDisplay" });


7. Create a C++ Pawn using UE4


This is pretty straight forward...


8. Add 3 UPROPERTY Variables to the pawn class:


UPROPERTY(EditAnywhere)
USceneComponent* OurVisibleComponent;

UPROPERTY(EditDefaultsOnly)
class UMotionControllerComponent* LeftMotionController;

UPROPERTY(EditDefaultsOnly)
class UMotionControllerComponent* RightMotionController;


9. Flesh out the Pawn constructor


// Set the player to be represented by this pawn
AutoPossessPlayer = EAutoReceiveInput::Player0;
RootComponent = CreateDefaultSubobject<USceneComponent>(TEXT("RootComponent"));

LeftMotionController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("LeftMotionController"));
LeftMotionController->Hand = EControllerHand::Left;
LeftMotionController->SetupAttachment(RootComponent);
RightMotionController = CreateDefaultSubobject<UMotionControllerComponent>(TEXT("RightMotionController"));
RightMotionController->Hand = EControllerHand::Right;
RightMotionController->SetupAttachment(RootComponent);

UCameraComponent* OurCamera = CreateDefaultSubobject<UCameraComponent>(TEXT("PlayerCameraComponent"));
OurCamera->SetupAttachment(RootComponent);

// TODO: Add SteamVRChaperone bounds
// TODO: Set Tracking Origin to floor for Vive

BaseEyeHeight = 0.0f;


10. Flesh out the Pawn BeginPlay


FTransform SpawnTransform = FTransform(FRotator(0.0f, 90.0f, 0.0f), FVector(0.f, 0.f, 0.f), FVector(0.120f, 0.120f, 0.120f));
// AGeneratedActor sets the mesh and material in its constructor
AGeneratedActor* LeftControllerActor = GetWorld()->SpawnActor<AGeneratedActor>(AGeneratedActor::StaticClass(), SpawnTransform);
LeftControllerActor->AttachToComponent(LeftMotionController, FAttachmentTransformRules::KeepRelativeTransform);

SpawnTransform = FTransform(FRotator(0.0f, 90.0f, 0.0f), FVector(0.f, 0.f, 0.f), FVector(0.120f, 0.120f, 0.120f));
AGeneratedActor* RightControllerActor = GetWorld()->SpawnActor<AGeneratedActor>(AGeneratedActor::StaticClass(), SpawnTransform);
RightControllerActor->AttachToComponent(RightMotionController, FAttachmentTransformRules::KeepRelativeTransform);


11. Spawn the Pawn in the GameMode BeginPlay()


FTransform SpawnTransform = FTransform(FRotator(0.0f, 0.0f, 0.0f), FVector(400.f, 550.f, 105.f), FVector(1.0f, 1.0f, 1.0f));
ASeanPawn* MyPawn = GetWorld()->SpawnActor<ASeanPawn>(ASeanStepPawn::StaticClass(), SpawnTransform);


12. Voila


I know I didn't cover the creation of an Actor with a Mesh. This is pretty straight forward thing. If you have constructed any meshes in C++, you should know how to do this.
I had to adjust rotation and scale of the model until it felt right. You will need to do the same.

Unreal 4 Tips

Unreal 4 C++ Tips


Are you starting a new game with Unreal 4? Are you looking to write it in C++?

Let me help by giving you some tips that I've learned over the last few months.


1. Get used to the Unreal engine blowing up. A lot.

If you do anything wrong, the engine will blow up. It won't pop up and error and gracefully move on. It will explode with a stack trace (if you are lucky). This is normal behavior. I've never done C++ game development before, so maybe this is normal, but it is not normal for production code in business applications (which is my day job). In business applications you wrap exceptions with a catch and gracefully move around an issue.

Because it blows up a lot, you need to be used to building from Visual Studio. Get in a habit of compiling there.


2. If your class is intended to live in the engine, you MUST extend one of their classes and make each of your variables a UPROPERTY. 

If you do not it WILL garbage collect your variables and you will slowly go out of your mind. It took me days to figure out wtf was going on and a few more days of converting my code to extend UObject and pray the fix worked (and it did).

class YEGAME_API UMyClass : public UObject {
  GENERATED_BODY()
public:
  UPROPERTY()
  UAnotherClass* MyObject;
}


3. Any class that extend one of their classes is under the control of the Unreal Engine. 

You cannot construct it. This is so they can track instances of it for memory management and garbage collection. Get used to this syntax. It is your lifeblood for creating objects:

UGameTime* CurrentGameTime = NewObject<UGameTime>();

This means everything is a memory pointer. I'm ok with that. At least it is consistent.


4. The name of a mesh and material must be fully pathed in the constructor of an Actor.

AGeneratedActor::AGeneratedActor(const class FObjectInitializer& PCIP) : Super(PCIP) {
  ...
  static ConstructorHelpers::FObjectFinder<UStaticMesh> StaticMesh(TEXT("StaticMesh'/Game/StarterContent/Props/SM_Rock.SM_Rock'"));
  ...
  static ConstructorHelpers::FObjectFinder<UMaterial> Material(TEXT("Material'/Game/StarterContent/Props/Materials/M_Rock.M_Rock'"));


5. You CAN tell the Actor constructor what mesh/material you want via a singleton. 

I will leave it to you to sort that out, but that is a huge hint to get around their frustrating Actor construction API.


6. Foliage materials must have this damn check mark checked: "Used with Instanced Static Meshes"

I probably wasted a week on that one thing.


7. Foliage cannot handle transparent materials

Makes sense I guess. BTW, transparency is the enemy of fluid performance. If you have a lot of transparency on screen, you will get stutter. You should use it VERY sparingly.


8. Lighting of Foliage Meshes is the same for all instances. 

This can be weird and I do not use it for ground.


9. The coordinate system for Unreal is Y over and X up. 

This is called a Left Handed coordinate system and bears no resemblance to mathematical coordinate systems that are X over and Y up. Blender uses the correct coordinate system. Blender gets a cookie. Unreal? They do not get a cookie.

From everything I've read on it, it is Microsoft's fault. DirectX operates this way because it was originally for flight simulators which are traditionally Left Coordinate systems.

I don't care what your excuse is, Y over and X up is pure insanity. There is no excuse for this. It is X over, Y up and Z in the 3rd dimension. Kinda like a tabs versus spaces argument (tabs are correct btw...). If you are putting objects on the screen via C++ code, you need to know this upfront.


10. Unreal cannot handle nested variables

You cannot do this: TArray<TArray>

I guess this is hard to implement. Java, C++ Structs and Ruby can do it. I use nested containers all the time. I don't quite understand this quirk.

There is a way around this. You create a class that has your second container on it as a UPROPERTY. I do this in my game and it works like a champ.


11. What is up with these damn macros?

I'm talking about these:
DECLARE_LOG_CATEGORY_EXTERN(YeLogName, Log, All);
UCLASS()
GENERATED_BODY()
UPROPERTY()

You probably know this, but your code is pre-processed into a new class before compilation. All those "myclass.generated.h" are the result of this. They are found in the intermediate folder.

When writing a new class, you can include the "generated.h" header even though it doesn't exist.

Expect nothing to highlight correctly in Visual Studio until everything compiles. Even then, Visual Studio is often confused.

If you code works, that is the true test.


12. Logging is painful

OMG is it annoying. Each class must have its own logger and everything must be converted perfectly for it to log.

If you pass the wrong type, the log may show a variable from a prior log that was for that type. That drove me crazy for a while. Also, don't forget to * your FString variable when logging it.

This is a great page on logging:
https://wiki.unrealengine.com/Logs,_Printing_Messages_To_Yourself_During_Runtime

13. And finally, never give up and never surrender.

You want to make a C++ game for Unreal? Well, its gonna suck. Hard. But... it doesn't suck as hard as writing a game engine from scratch. Now that I've got a lot of C++ code in place, I encounter a lot fewer explosions or surprises.

I like to think as Unreal as my team of engineers adding new features for me. It is painful to get started but they are a large team working for you. They have given you their entire code base to look through.

Hopefully this helps someone. If I knew all of this, it would have save me weeks of pain and suffering.