Skip to content
Snippets Groups Projects
Commit 1e67c0d8 authored by David Gilbert's avatar David Gilbert :bug:
Browse files

Initial separation

parents
No related branches found
No related tags found
No related merge requests found
Pipeline #350009 failed
Showing
with 728 additions and 0 deletions
---
Language: Cpp
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignOperands: false
AlignTrailingComments: false
AlwaysBreakTemplateDeclarations: Yes
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: true
BeforeWhile: true
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBraces: Custom
BreakConstructorInitializers: AfterColon
ColumnLimit: 120
SortIncludes: false
PointerAlignment: Left
IndentCaseBlocks: true
IndentWidth: 4
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
SpacesInAngles: false
TabWidth: 4
UseTab: Always
...
# Visual Studio 2015 user specific files
.vs/
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
*.ipa
# These project files can be generated by the engine
*.xcodeproj
*.xcworkspace
*.sln
*.suo
*.opensdf
*.sdf
*.VC.db
*.VC.opendb
# Precompiled Assets
SourceArt/**/*.png
SourceArt/**/*.tga
# Binary Files
Binaries/*
Plugins/*/Binaries/*
# Builds
Build/*
# Whitelist PakBlacklist-<BuildConfiguration>.txt files
!Build/*/
Build/*/**
!Build/*/PakBlacklist*.txt
# Don't ignore icon files in Build
!Build/**/*.ico
# Built data for maps
*_BuiltData.uasset
# Configuration files generated by the Editor
Saved/*
# Compiled source files for the engine to use
Intermediate/*
Plugins/*/Intermediate/*
# Cache files for the editor to use
DerivedDataCache/*
\ No newline at end of file
#-------------------------------------------------------------------------------
# Copyright (c) 2022 RWTH Aachen University, Germany,
# Virtual Reality & Immersive Visualisation Group.
#-------------------------------------------------------------------------------
# The include file can be change to either be removed or reference a specific commit.
include:
- project: '${UNREAL_CI_PROJECT}'
ref: master
file: '/shared_scripts.yml'
# In this file you are able to configure your plugins pipeline.
# If you want to customize something, either overwrite things that are defined in the shared_scripts repository,
# or remove the "extends" and write your own scripts
#
# If you want your pipeline to run on every commit, just remove the "only" blocks. Keep in mind, that a build
# can take some time.
#
# If you want to alter the unreal-building process two variables are defined for either changing the CLIENT_CONFIG or
# for adding EXTRA_ARGS to the building process
#
# For the generate stage, you can specify needed dependencies in GEN_DEPENDENCIES with [Branch@PluginFolder] as key
# Example:
#
# Generate_Project:
# only: ['web', 'schedules']
# extends: .Generate_Project_
# variables:
# GEN_TEMPLATE_REPO: "https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/unrealprojecttemplate.git"
# GEN_TEMPLATE_BRANCH: "4.26"
# GEN_DEPENDENCIES: "(
# [4.26@RWTHVRToolkit]='https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/Plugins/rwth-vr-toolkit.git'
# [4.26@UniversalLogging]='https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/Plugins/universallogging.git'
# )"
#
# You can uncomment the deploy lines to deploy your project to the CAVE/VRDev. This only makes sense, if your plugin works
# with a generated project.
variables:
UNREAL_VERSION: "5.3"
stages:
- analyze
- generate
- build
- deploy
clang-format:
image: registry.git-ce.rwth-aachen.de/vr-vis/vr-group/unreal-development/plugins/rwth-vr-toolkit/alpine-analyze:latest
tags:
- docker-executor
- linux
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
variables:
GIT_STRATEGY: fetch
GIT_CHECKOUT: "true"
GIT_DEPTH: "2"
stage: analyze
allow_failure: false
script:
- clang-format --version
- git fetch --depth 1 origin $CI_MERGE_REQUEST_DIFF_BASE_SHA
- echo $CI_MERGE_REQUEST_DIFF_BASE_SHA
- linter_errors=$(unbuffer git-clang-format --commit "$CI_MERGE_REQUEST_DIFF_BASE_SHA" *.h *.cpp -q --diff | grep -v --color=always "no modified files to format" || true)
- echo "$linter_errors"
- if [ ! -z "$linter_errors" ]; then echo "Detected formatting issues; please fix"; exit 1; else echo "Formatting is correct"; exit 0; fi
Generate_Project:
rules:
- if: $CI_PIPELINE_SOURCE == "web"
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
extends: .Generate_Project_
variables:
RUN_SETUP: "false"
GEN_DEPENDENCIES: "(
[master@UnrealDTrackPlugin]='https://github.com/VRGroupRWTH/UnrealDTrackPlugin.git',
[dev/5.3@UnrealDTrackPlugin]='https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/rwth-vr-toolkit.git')"
Build_Windows:
rules:
- if: $CI_PIPELINE_SOURCE == "web"
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
extends: .Build_Windows_
tags:
- windows
- unreal
variables:
GIT_STRATEGY: none
GIT_CHECKOUT: "false"
# CLIENT_CONFIG: "Shipping"
CLIENT_CONFIG: "DebugGame"
needs:
- job: "Generate_Project"
artifacts: true
Build_Linux:
rules:
- if: $CI_PIPELINE_SOURCE == "web"
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
extends: .Build_Linux_
tags:
- linux
- unreal
- docker-executor
variables:
GIT_STRATEGY: none
GIT_CHECKOUT: "false"
# CLIENT_CONFIG: "Shipping"
CLIENT_CONFIG: "DebugGame"
needs:
- job: "Generate_Project"
artifacts: true
Deploy_Windows:
rules:
- if: $CI_PIPELINE_SOURCE == "web"
- if: $CI_PIPELINE_SOURCE == "schedule"
extends: .Deploy_VRDev_
needs:
- job: "Build_Windows"
artifacts: true
Deploy_CAVE:
rules:
- if: $CI_PIPELINE_SOURCE == "web"
- if: $CI_PIPELINE_SOURCE == "schedule"
extends: .Deploy_vrdemo_
needs:
- job: "Build_Linux"
artifacts: true
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
File added
LICENSE 0 → 100644
BSD 3-Clause License
Copyright (c) 2024, Virtual Reality & Immersive Visualization Group at RWTH Aachen University
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
# RWTH VR Toolkit
The **RWTH VR Toolkit** contains a collection of extensions which are used in many of our applications. It serves as a tool to implement virtual reality applications which work on desktop, HMD and room-mounted devices.
The contents of this plugin are constantly extended and improved to reflect changes in the Unreal nDisplay Plugin that we use to support our aixCAVE with Unreal.
[Check out the repository's wiki page for installation, usage and documentation](https://git-ce.rwth-aachen.de/vr-vis/VR-Group/unreal-development/plugins/rwth-vr-toolkit/-/wikis/home).
{
"FileVersion": 3,
"Version": 1,
"VersionName": "1.0",
"FriendlyName": "RWTH VR Cluster",
"Description": "",
"Category": "Other",
"CreatedBy": "",
"CreatedByURL": "",
"DocsURL": "",
"MarketplaceURL": "",
"SupportURL": "",
"CanContainContent": true,
"IsBetaVersion": false,
"Installed": false,
"EnabledByDefault": true,
"Modules": [
{
"Name": "RWTHVRCluster",
"Type": "Runtime",
"LoadingPhase": "Default",
"WhitelistPlatforms": [
"Win64",
"Linux"
]
}
],
"Plugins": [
{
"Name": "RWTHVRToolkit",
"Enabled": true
},
{
"Name": "nDisplay",
"Enabled": true,
"SupportedTargetPlatforms": [
"Win64",
"Linux"
]
},
{
"Name": "LiveLink",
"Enabled": true
},
{
"Name": "LiveLinkOvernDisplay",
"Enabled": true,
"SupportedTargetPlatforms": [
"Win64",
"Linux"
]
},
{
"Name": "DTrackPlugin",
"Enabled": true,
"SupportedTargetPlatforms": [
"Win64",
"Linux"
]
},
{
"Name": "EnhancedInput",
"Enabled": true
},
{
"Name": "Niagara",
"Enabled": true
},
{
"Name": "Switchboard",
"Enabled": true,
"SupportedTargetPlatforms": [
"Win64",
"Linux"
]
}
]
}
Resources/Icon128.png

4 KiB

#include "CAVEOverlay/CAVEOverlayController.h"
#include "CoreMinimal.h"
#include "EnhancedInputComponent.h"
#include "IDisplayCluster.h"
#include "MotionControllerComponent.h"
#include "Camera/CameraComponent.h"
#include "CAVEOverlay/DoorOverlayData.h"
#include "Cluster/DisplayClusterClusterEvent.h"
#include "Cluster/IDisplayClusterClusterManager.h"
#include "Components/StaticMeshComponent.h"
#include "Engine/CollisionProfile.h"
#include "Logging/StructuredLog.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "Pawn/RWTHVRPawn.h"
#include "Utility/RWTHVRUtilities.h"
DEFINE_LOG_CATEGORY(LogCAVEOverlay);
// Helper function to check if a string is contained within an array of strings, ignoring case.
bool ContainsFString(const TArray<FString>& Array, const FString& Entry)
{
for (FString Current_Entry : Array)
{
if (Current_Entry.Equals(Entry, ESearchCase::IgnoreCase))
return true;
}
return false;
}
UStaticMeshComponent* ACAVEOverlayController::CreateMeshComponent(const FName& Name, USceneComponent* Parent)
{
UStaticMeshComponent* Result = CreateDefaultSubobject<UStaticMeshComponent>(Name);
Result->SetupAttachment(Parent);
Result->SetVisibility(false);
Result->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
return Result;
}
// Sets default values
ACAVEOverlayController::ACAVEOverlayController()
{
// Set this actor to call Tick() every frame.
PrimaryActorTick.bCanEverTick = true;
bAllowTickBeforeBeginPlay = false;
// Creation of sub-components
Root = CreateDefaultSubobject<USceneComponent>("DefaultSceneRoot");
SetRootComponent(Root);
Tape = CreateMeshComponent("Tape", Root);
SignRightHand = CreateMeshComponent("SignRightHand", Root);
SignLeftHand = CreateMeshComponent("SignLeftHand", Root);
}
void ACAVEOverlayController::CycleDoorType()
{
DoorCurrentMode = static_cast<EDoorMode>((DoorCurrentMode + 1) % DOOR_NUM_MODES);
// Send out a cluster event to the whole cluster that the door mode has been changed
if (auto* const Manager = IDisplayCluster::Get().GetClusterMgr())
{
FDisplayClusterClusterEventJson cluster_event;
cluster_event.Name = "CAVEOverlay Change Door to " + DoorModeNames[DoorCurrentMode];
cluster_event.Type = "DoorChange";
cluster_event.Category = "CAVEOverlay";
cluster_event.Parameters.Add("NewDoorState", FString::FromInt(DoorCurrentMode));
Manager->EmitClusterEventJson(cluster_event, true);
}
}
void ACAVEOverlayController::HandleClusterEvent(const FDisplayClusterClusterEventJson& Event)
{
if (Event.Category.Equals("CAVEOverlay") && Event.Type.Equals("DoorChange") &&
Event.Parameters.Contains("NewDoorState"))
{
SetDoorMode(static_cast<EDoorMode>(FCString::Atoi(*Event.Parameters["NewDoorState"])));
}
}
void ACAVEOverlayController::SetDoorMode(const EDoorMode NewMode)
{
DoorCurrentMode = NewMode;
switch (DoorCurrentMode)
{
case EDoorMode::DOOR_DEBUG:
case EDoorMode::DOOR_PARTIALLY_OPEN:
DoorCurrentOpeningWidthAbsolute = DoorOpeningWidthAbsolute;
if (ScreenType == SCREEN_DOOR)
Overlay->BlackBox->SetRenderScale(FVector2D(0, 1));
if (ScreenType == SCREEN_DOOR_PARTIAL)
Overlay->BlackBox->SetRenderScale(FVector2D(DoorOpeningWidthRelative, 1));
if (ScreenType == SCREEN_PRIMARY)
Overlay->BlackBox->SetRenderScale(FVector2D(0, 1));
Overlay->BlackBox->SetVisibility(ESlateVisibility::Visible);
break;
case EDoorMode::DOOR_OPEN:
DoorCurrentOpeningWidthAbsolute = WallDistance * 2;
if (ScreenType == SCREEN_DOOR)
Overlay->BlackBox->SetRenderScale(FVector2D(1, 1));
if (ScreenType == SCREEN_DOOR_PARTIAL)
Overlay->BlackBox->SetRenderScale(FVector2D(1, 1));
if (ScreenType == SCREEN_PRIMARY)
Overlay->BlackBox->SetRenderScale(FVector2D(0, 1));
Overlay->BlackBox->SetVisibility(ESlateVisibility::Visible);
break;
case EDoorMode::DOOR_CLOSED:
DoorCurrentOpeningWidthAbsolute = 0;
if (ScreenType == SCREEN_DOOR)
Overlay->BlackBox->SetRenderScale(FVector2D(0, 1));
if (ScreenType == SCREEN_DOOR_PARTIAL)
Overlay->BlackBox->SetRenderScale(FVector2D(0, 1));
if (ScreenType == SCREEN_PRIMARY)
Overlay->BlackBox->SetRenderScale(FVector2D(0, 1));
Overlay->BlackBox->SetVisibility(ESlateVisibility::Hidden);
break;
default:;
}
// On the secondary nodes that are not the door, hide the overlay completely
// It might make more sense to just not add it there...
if (ScreenType == SCREEN_NORMAL)
Overlay->BlackBox->SetRenderScale(FVector2D(0, 1));
UE_LOGFMT(LogCAVEOverlay, Log, "Switched door state to {State}. New opening width is {Width}.",
*DoorModeNames[DoorCurrentMode], DoorCurrentOpeningWidthAbsolute);
// On the primary node, show which door mode is currently active.
if (ScreenType == SCREEN_PRIMARY)
{
Overlay->CornerText->SetText(FText::FromString(DoorModeNames[DoorCurrentMode]));
}
}
// Called when the game starts or when spawned
void ACAVEOverlayController::BeginPlay()
{
Super::BeginPlay();
// Don't do anything if we're a dedicated server. We shouldn't even exist there.
if (GetNetMode() == NM_DedicatedServer)
return;
// Currently, there is no support for multi-user systems in general, as we only depend on the local pawn.
// In a MU setting, the relevant pawn isn't our local one, but the primary node's pawn.
if (GetNetMode() != NM_Standalone)
return;
// This should return the respective client's local playercontroller or, if we're a listen server, our own PC.
auto* PC = GetWorld() ? GetWorld()->GetFirstPlayerController() : nullptr;
// it can happen that the PC is valid, but we have no player attached to it yet.
// Check for this - however, we should work around it by somehow getting notified when that happens.
// Not sure which place would be best...
const bool bValidPC = PC && PC->GetLocalPlayer();
if (!bValidPC || !URWTHVRUtilities::IsRoomMountedMode())
return;
// Input config
if (URWTHVRUtilities::IsPrimaryNode())
{
if (CycleDoorTypeInputAction == nullptr)
{
UE_LOGFMT(LogCAVEOverlay, Error, "Input action and mapping not set in CaveOverlayController!");
return;
}
UEnhancedInputComponent* Input = Cast<UEnhancedInputComponent>(PC->InputComponent);
Input->BindAction(CycleDoorTypeInputAction, ETriggerEvent::Triggered, this,
&ACAVEOverlayController::CycleDoorType);
}
// Bind the cluster events that manage the door state.
IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
if (ClusterManager && !ClusterEventListenerDelegate.IsBound())
{
ClusterEventListenerDelegate =
FOnClusterEventJsonListener::CreateUObject(this, &ACAVEOverlayController::HandleClusterEvent);
ClusterManager->AddClusterEventJsonListener(ClusterEventListenerDelegate);
}
// Determine the screen-type for later usage
if (IDisplayCluster::Get().GetClusterMgr()->GetNodeId().Equals(ScreenMain, ESearchCase::IgnoreCase))
{
ScreenType = SCREEN_PRIMARY;
}
else if (ContainsFString(ScreensDoor, IDisplayCluster::Get().GetClusterMgr()->GetNodeId()))
{
ScreenType = SCREEN_DOOR;
}
else if (ContainsFString(ScreensDoorPartial, IDisplayCluster::Get().GetClusterMgr()->GetNodeId()))
{
ScreenType = SCREEN_DOOR_PARTIAL;
}
else
{
ScreenType = SCREEN_NORMAL;
}
// Create and add widget to local playercontroller.
if (!OverlayClass)
{
UE_LOGFMT(LogCAVEOverlay, Error, "OverlayClass not set in CaveOverlayController!");
return;
}
Overlay = CreateWidget<UDoorOverlayData>(PC, OverlayClass);
Overlay->AddToViewport(0);
// Set the default door mode (partially open)
SetDoorMode(DoorCurrentMode);
// Set Text to "" until someone presses the key for the first time
Overlay->CornerText->SetText(FText::FromString(""));
// Get the pawn so we can have access to head and hand positions
VRPawn = Cast<ARWTHVRPawn>(PC->GetPawnOrSpectator());
if (VRPawn)
{
// we're good to go!
bInitialized = true;
}
else
{
UE_LOGFMT(LogCAVEOverlay, Error, "No VirtualRealityPawn found which we could attach to!");
}
// Create dynamic materials at runtime
TapeMaterialDynamic = Tape->CreateDynamicMaterialInstance(0);
RightSignMaterialDynamic = SignRightHand->CreateDynamicMaterialInstance(0);
LeftSignMaterialDynamic = SignLeftHand->CreateDynamicMaterialInstance(0);
UE_LOGFMT(LogCAVEOverlay, Display, "CaveOverlay Initialization was successfull.");
}
void ACAVEOverlayController::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
IDisplayClusterClusterManager* ClusterManager = IDisplayCluster::Get().GetClusterMgr();
if (ClusterManager && ClusterEventListenerDelegate.IsBound())
{
ClusterManager->RemoveClusterEventJsonListener(ClusterEventListenerDelegate);
}
Super::EndPlay(EndPlayReason);
}
double ACAVEOverlayController::CalculateOpacityFromPosition(const FVector& Position) const
{
// Calculate opacity value depending on how far we are from the walls. Further away == lower opacity,
// fully opaque when WallFadeDistance away from the wall. Could just use a lerp here..
return FMath::Max(
FMath::Clamp((FMath::Abs(Position.X) - (WallDistance - WallCloseDistance)) / WallFadeDistance, 0.0, 1.0),
FMath::Clamp((FMath::Abs(Position.Y) - (WallDistance - WallCloseDistance)) / WallFadeDistance, 0.0, 1.0));
}
bool ACAVEOverlayController::PositionInDoorOpening(const FVector& Position) const
{
// The position of the corner with 10cm of buffer. In negative direction because the door is in negative direction
// of the cave
const float CornerValue = -(WallDistance + 10);
// Check whether our X position is within the door zone. This zone starts 10cm further away from the wall
// than the WallCloseDistance, and ends 10cm outside of the wall (door). As the door is in negative X direction,
// the signs need to be negated.
const bool bXWithinDoor =
FMath::IsWithinInclusive(Position.X, CornerValue, -(WallDistance - WallCloseDistance - 10));
// Checks whether our Y position is between the lower corner with some overlap and
// the door corner (CornerValue + DoorCurrentOpeningWidthAbsolute)
const bool bYWithinDoor =
FMath::IsWithinInclusive(Position.Y, CornerValue, CornerValue + DoorCurrentOpeningWidthAbsolute);
return bXWithinDoor && bYWithinDoor;
}
void ACAVEOverlayController::SetSignsForHand(UStaticMeshComponent* Sign, const FVector& HandPosition,
UMaterialInstanceDynamic* HandMaterial) const
{
const bool bHandIsCloseToWall =
FMath::IsWithinInclusive(HandPosition.GetAbsMax(), WallDistance - WallCloseDistance, WallDistance);
if (bHandIsCloseToWall && !PositionInDoorOpening(HandPosition))
{
Sign->SetVisibility(true);
HandMaterial->SetScalarParameterValue("SignOpacity", CalculateOpacityFromPosition(HandPosition));
// Which wall are we closest to? This is the wall we project the sign onto
const bool bXWallCloser = FMath::Abs(HandPosition.X) > FMath::Abs(HandPosition.Y);
// Set the position towards the closest wall to the wall itself, keep the other positions
const double X = bXWallCloser ? FMath::Sign(HandPosition.X) * WallDistance : HandPosition.X;
const double Y = bXWallCloser ? HandPosition.Y : FMath::Sign(HandPosition.Y) * WallDistance;
const double Z = HandPosition.Z;
// Rotate the sign by 90° if we're on a side wall
const auto Rot = bXWallCloser ? FRotator(0, 0, 0) : FRotator(0, 90, 0);
const auto Pos = FVector(X, Y, Z);
Sign->SetRelativeLocationAndRotation(Pos, Rot);
}
else
{
Sign->SetVisibility(false);
}
}
void ACAVEOverlayController::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// If we're not yet initialized, do nothing. This shouldn't really happen as we only spawn on the cave anyway
if (!bInitialized)
{
return;
}
// Head/Tape Logic
const FVector HeadPosition = VRPawn->HeadCameraComponent->GetRelativeTransform().GetLocation();
const bool bHeadIsCloseToWall =
FMath::IsWithinInclusive(HeadPosition.GetAbsMax(), WallDistance - WallCloseDistance, WallDistance);
// Only show the tape when close to a wall and not within the door opening
if (bHeadIsCloseToWall && !PositionInDoorOpening(HeadPosition))
{
Tape->SetVisibility(true);
// Offset the tape in z direction to always be at head height
Tape->SetRelativeLocation(HeadPosition * FVector(0, 0, 1));
TapeMaterialDynamic->SetScalarParameterValue("BarrierOpacity", CalculateOpacityFromPosition(HeadPosition));
if (FMath::IsWithin(FVector2D(HeadPosition).GetAbsMax(), WallDistance - WallWarningDistance, WallDistance))
{
// in warning distance == red tape
TapeMaterialDynamic->SetVectorParameterValue("StripeColor", FVector(1, 0, 0));
}
else
{
// otherwise we're just yellow
TapeMaterialDynamic->SetVectorParameterValue("StripeColor", FVector(1, 1, 0));
}
}
else
{
Tape->SetVisibility(false);
}
// Hand Logic
const FVector RightPosition = VRPawn->RightHand->GetRelativeTransform().GetLocation();
const FVector LeftPosition = VRPawn->LeftHand->GetRelativeTransform().GetLocation();
// Set the position rotation, opacity, visibility of the hand warning signs.
SetSignsForHand(SignRightHand, RightPosition, RightSignMaterialDynamic);
SetSignsForHand(SignLeftHand, LeftPosition, LeftSignMaterialDynamic);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment