Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Programmable camera distortion #3039

Merged
merged 15 commits into from
Dec 17, 2020
3 changes: 2 additions & 1 deletion AirLib/include/api/RpcLibClientBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,14 +103,15 @@ class RpcLibClientBase {
CollisionInfo simGetCollisionInfo(const std::string& vehicle_name = "") const;

CameraInfo simGetCameraInfo(const std::string& camera_name, const std::string& vehicle_name = "") const;
void simSetDistortionParam(const std::string& camera_name, const std::string& param_name, float value, const std::string& vehicle_name = "");
std::vector<float> simGetDistortionParams(const std::string& camera_name, const std::string& vehicle_name = "");
void simSetCameraPose(const std::string& camera_name, const Pose& pose, const std::string& vehicle_name = "");
void simSetCameraFov(const std::string& camera_name, float fov_degrees, const std::string& vehicle_name = "");
// This is a backwards-compatibility wrapper over simSetCameraPose, and can be removed in future major releases
void simSetCameraOrientation(const std::string& camera_name, const Quaternionr& orientation, const std::string& vehicle_name = "");

msr::airlib::Kinematics::State simGetGroundTruthKinematics(const std::string& vehicle_name = "") const;
msr::airlib::Environment::State simGetGroundTruthEnvironment(const std::string& vehicle_name = "") const;

std::vector<std::string> simSwapTextures(const std::string& tags, int tex_id = 0, int component_id = 0, int material_id = 0);

// Recording APIs
Expand Down
2 changes: 2 additions & 0 deletions AirLib/include/api/VehicleSimApiBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ class VehicleSimApiBase : public msr::airlib::UpdatableObject {
virtual CameraInfo getCameraInfo(const std::string& camera_name) const = 0;
virtual void setCameraPose(const std::string& camera_name, const Pose& pose) = 0;
virtual void setCameraFoV(const std::string& camera_name, float fov_degrees) = 0;
virtual void setDistortionParam(const std::string& camera_name, const std::string& param_name, float value) = 0;
virtual std::vector<float> getDistortionParams(const std::string& camera_name) = 0;

virtual CollisionInfo getCollisionInfo() const = 0;
virtual int getRemoteControlID() const = 0; //which RC to use, 0 is first one, -1 means disable RC (use keyborad)
Expand Down
1 change: 0 additions & 1 deletion AirLib/include/api/WorldSimApiBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ class WorldSimApiBase {
virtual bool setObjectPose(const std::string& object_name, const Pose& pose, bool teleport) = 0;
virtual bool runConsoleCommand(const std::string& command) = 0;
virtual bool setObjectScale(const std::string& object_name, const Vector3r& scale) = 0;

virtual std::unique_ptr<std::vector<std::string>> swapTextures(const std::string& tag, int tex_id = 0, int component_id = 0, int material_id = 0) = 0;
virtual vector<MeshPositionVertexBuffersResponse> getMeshPositionVertexBuffers() const = 0;

Expand Down
10 changes: 10 additions & 0 deletions AirLib/src/api/RpcLibClientBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,16 @@ void RpcLibClientBase::simSetCameraFov(const std::string& camera_name, float fov
pimpl_->client.call("simSetCameraFov", camera_name, fov_degrees, vehicle_name);
}

void RpcLibClientBase::simSetDistortionParam(const std::string& camera_name, const std::string& param_name, float value, const std::string& vehicle_name)
{
pimpl_->client.call("simSetDistortionParam", camera_name, param_name, value, vehicle_name);
}

std::vector<float> RpcLibClientBase::simGetDistortionParams(const std::string& camera_name, const std::string& vehicle_name)
{
return pimpl_->client.call("simGetDistortionParams", camera_name, vehicle_name).as<std::vector<float>>();
}

msr::airlib::Kinematics::State RpcLibClientBase::simGetGroundTruthKinematics(const std::string& vehicle_name) const
{
return pimpl_->client.call("simGetGroundTruthKinematics", vehicle_name).as<RpcLibAdapatorsBase::KinematicsState>().to();
Expand Down
8 changes: 8 additions & 0 deletions AirLib/src/api/RpcLibServerBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,14 @@ RpcLibServerBase::RpcLibServerBase(ApiProvider* api_provider, const std::string&
return RpcLibAdapatorsBase::CameraInfo(camera_info);
});

pimpl_->server.bind("simSetDistortionParam", [&](const std::string& camera_name, const std::string& param_name, float value, const std::string& vehicle_name) -> void {
getVehicleSimApi(vehicle_name)->setDistortionParam(camera_name, param_name, value);
});

pimpl_->server.bind("simGetDistortionParams", [&](const std::string& camera_name, const std::string& vehicle_name) -> std::vector<float> {
return getVehicleSimApi(vehicle_name)->getDistortionParams(camera_name);
});

pimpl_->server.bind("simSetCameraPose", [&](const std::string& camera_name, const RpcLibAdapatorsBase::Pose& pose,
const std::string& vehicle_name) -> void {
getVehicleSimApi(vehicle_name)->setCameraPose(camera_name, pose.to());
Expand Down
40 changes: 40 additions & 0 deletions PythonClient/airsim/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,46 @@ def simGetCameraInfo(self, camera_name, vehicle_name = ''):
# TODO: below str() conversion is only needed for legacy reason and should be removed in future
return CameraInfo.from_msgpack(self.client.call('simGetCameraInfo', str(camera_name), vehicle_name))

def simGetDistortionParams(self, camera_name, vehicle_name = ''):
"""
Get camera distortion parameters

Args:
camera_name (str): Name of the camera, for backwards compatibility, ID numbers such as 0,1,etc. can also be used
vehicle_name (str, optional): Vehicle which the camera is associated with

Returns:
List (float): List of distortion parameter values corresponding to K1, K2, K3, P1, P2 respectively.
"""

return self.client.call('simGetDistortionParams', str(camera_name), vehicle_name)

def simSetDistortionParams(self, camera_name, distortion_params, vehicle_name = ''):
"""
Set camera distortion parameters

Args:
camera_name (str): Name of the camera, for backwards compatibility, ID numbers such as 0,1,etc. can also be used
distortion_params (dict): Dictionary of distortion param names and corresponding values
{"K1": 0.0, "K2": 0.0, "K3": 0.0, "P1": 0.0, "P2": 0.0}
vehicle_name (str, optional): Vehicle which the camera is associated with
"""

for param_name, value in distortion_params.items():
self.client.call('simSetDistortionParam', str(camera_name), param_name, value, vehicle_name)

def simSetDistortionParam(self, camera_name, param_name, value, vehicle_name = ''):
"""
Set single camera distortion parameter

Args:
camera_name (str): Name of the camera, for backwards compatibility, ID numbers such as 0,1,etc. can also be used
param_name (str): Name of distortion parameter
value (float): Value of distortion parameter
vehicle_name (str, optional): Vehicle which the camera is associated with
"""
self.client.call('simSetDistortionParam', str(camera_name), param_name, value, vehicle_name)

def simSetCameraPose(self, camera_name, pose, vehicle_name = ''):
"""
- Control the pose of a selected camera
Expand Down
Binary file not shown.
Binary file not shown.
76 changes: 54 additions & 22 deletions Unreal/Plugins/AirSim/Source/PIPCamera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "Camera/CameraComponent.h"
#include "Engine/TextureRenderTarget2D.h"
#include "Engine/World.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "ImageUtils.h"

#include <string>
Expand All @@ -23,6 +22,16 @@ APIPCamera::APIPCamera()
UAirBlueprintLib::LogMessageString("Cannot create noise material for the PIPCamera",
"", LogDebugLevel::Failure);

static ConstructorHelpers::FObjectFinder<UMaterial> dist_mat_finder(TEXT("Material'/AirSim/HUDAssets/CameraDistortion.CameraDistortion'"));
if (dist_mat_finder.Succeeded())
{
distortion_material_static_ = dist_mat_finder.Object;
distortion_param_collection_ = Cast<UMaterialParameterCollection>(StaticLoadObject(UMaterialParameterCollection::StaticClass(), NULL, TEXT("'/AirSim/HUDAssets/DistortionParams.DistortionParams'")));
}
else
UAirBlueprintLib::LogMessageString("Cannot create distortion material for the PIPCamera",
"", LogDebugLevel::Failure);

PrimaryActorTick.bCanEverTick = true;

image_type_to_pixel_format_map_.Add(0, EPixelFormat::PF_B8G8R8A8);
Expand All @@ -33,6 +42,7 @@ APIPCamera::APIPCamera()
image_type_to_pixel_format_map_.Add(5, EPixelFormat::PF_B8G8R8A8);
image_type_to_pixel_format_map_.Add(6, EPixelFormat::PF_B8G8R8A8);
image_type_to_pixel_format_map_.Add(7, EPixelFormat::PF_B8G8R8A8);

}

void APIPCamera::PostInitializeComponents()
Expand Down Expand Up @@ -66,6 +76,7 @@ void APIPCamera::BeginPlay()
Super::BeginPlay();

noise_materials_.AddZeroed(imageTypeCount() + 1);
distortion_materials_.AddZeroed(imageTypeCount() + 1);

//by default all image types are disabled
camera_type_enabled_.assign(imageTypeCount(), false);
Expand All @@ -82,6 +93,9 @@ void APIPCamera::BeginPlay()
gimbal_stabilization_ = 0;
gimbald_rotator_ = this->GetActorRotation();
this->SetActorTickEnabled(false);

if (distortion_param_collection_)
distortion_param_instance_ = this->GetWorld()->GetParameterCollectionInstance(distortion_param_collection_);
}

msr::airlib::ProjectionMatrix APIPCamera::getProjectionMatrix(const APIPCamera::ImageType image_type) const
Expand Down Expand Up @@ -208,6 +222,18 @@ void APIPCamera::EndPlay(const EEndPlayReason::Type EndPlayReason)
noise_material_static_ = nullptr;
noise_materials_.Empty();

if (distortion_materials_.Num()) {
for (unsigned int image_type = 0; image_type < imageTypeCount(); ++image_type) {
if (distortion_materials_[image_type + 1])
captures_[image_type]->PostProcessSettings.RemoveBlendable(distortion_materials_[image_type + 1]);
}
if (distortion_materials_[0])
camera_->PostProcessSettings.RemoveBlendable(distortion_materials_[0]);
}

distortion_material_static_ = nullptr;
distortion_materials_.Empty();

for (unsigned int image_type = 0; image_type < imageTypeCount(); ++image_type) {
//use final color for all calculations
captures_[image_type] = nullptr;
Expand Down Expand Up @@ -312,12 +338,12 @@ void APIPCamera::setupCameraFromSettings(const APIPCamera::CameraSetting& camera
false);
break;
}

setDistortionMaterial(image_type, captures_[image_type], captures_[image_type]->PostProcessSettings);
setNoiseMaterial(image_type, captures_[image_type], captures_[image_type]->PostProcessSettings, noise_setting);
}
else { //camera component
updateCameraSetting(camera_, capture_setting, ned_transform);

setDistortionMaterial(image_type, camera_, camera_->PostProcessSettings);
setNoiseMaterial(image_type, camera_, camera_->PostProcessSettings, noise_setting);
}
}
Expand Down Expand Up @@ -423,30 +449,36 @@ void APIPCamera::updateCameraPostProcessingSetting(FPostProcessSettings& obj, co
}
}

void APIPCamera::setDistortionMaterial(int image_type, UObject* outer, FPostProcessSettings& obj)
{
UMaterialInstanceDynamic* distortion_material = UMaterialInstanceDynamic::Create(distortion_material_static_, outer);
distortion_materials_[image_type + 1] = distortion_material;
obj.AddBlendable(distortion_material, 1.0f);
}

void APIPCamera::setNoiseMaterial(int image_type, UObject* outer, FPostProcessSettings& obj, const NoiseSetting& settings)
{
if (!settings.Enabled)
return;

UMaterialInstanceDynamic* noise_material_ = UMaterialInstanceDynamic::Create(noise_material_static_, outer);
noise_materials_[image_type + 1] = noise_material_;


noise_material_->SetScalarParameterValue("HorzWaveStrength", settings.HorzWaveStrength);
noise_material_->SetScalarParameterValue("RandSpeed", settings.RandSpeed);
noise_material_->SetScalarParameterValue("RandSize", settings.RandSize);
noise_material_->SetScalarParameterValue("RandDensity", settings.RandDensity);
noise_material_->SetScalarParameterValue("RandContrib", settings.RandContrib);
noise_material_->SetScalarParameterValue("HorzWaveContrib", settings.HorzWaveContrib);
noise_material_->SetScalarParameterValue("HorzWaveVertSize", settings.HorzWaveVertSize);
noise_material_->SetScalarParameterValue("HorzWaveScreenSize", settings.HorzWaveScreenSize);
noise_material_->SetScalarParameterValue("HorzNoiseLinesContrib", settings.HorzNoiseLinesContrib);
noise_material_->SetScalarParameterValue("HorzNoiseLinesDensityY", settings.HorzNoiseLinesDensityY);
noise_material_->SetScalarParameterValue("HorzNoiseLinesDensityXY", settings.HorzNoiseLinesDensityXY);
noise_material_->SetScalarParameterValue("HorzDistortionStrength", settings.HorzDistortionStrength);
noise_material_->SetScalarParameterValue("HorzDistortionContrib", settings.HorzDistortionContrib);

obj.AddBlendable(noise_material_, 1.0f);
UMaterialInstanceDynamic* noise_material = UMaterialInstanceDynamic::Create(noise_material_static_, outer);
noise_materials_[image_type + 1] = noise_material;

noise_material->SetScalarParameterValue("HorzWaveStrength", settings.HorzWaveStrength);
noise_material->SetScalarParameterValue("RandSpeed", settings.RandSpeed);
noise_material->SetScalarParameterValue("RandSize", settings.RandSize);
noise_material->SetScalarParameterValue("RandDensity", settings.RandDensity);
noise_material->SetScalarParameterValue("RandContrib", settings.RandContrib);
noise_material->SetScalarParameterValue("HorzWaveContrib", settings.HorzWaveContrib);
noise_material->SetScalarParameterValue("HorzWaveVertSize", settings.HorzWaveVertSize);
noise_material->SetScalarParameterValue("HorzWaveScreenSize", settings.HorzWaveScreenSize);
noise_material->SetScalarParameterValue("HorzNoiseLinesContrib", settings.HorzNoiseLinesContrib);
noise_material->SetScalarParameterValue("HorzNoiseLinesDensityY", settings.HorzNoiseLinesDensityY);
noise_material->SetScalarParameterValue("HorzNoiseLinesDensityXY", settings.HorzNoiseLinesDensityXY);
noise_material->SetScalarParameterValue("HorzDistortionStrength", settings.HorzDistortionStrength);
noise_material->SetScalarParameterValue("HorzDistortionContrib", settings.HorzDistortionContrib);

obj.AddBlendable(noise_material, 1.0f);
}

void APIPCamera::enableCaptureComponent(const APIPCamera::ImageType type, bool is_enabled)
Expand Down
9 changes: 9 additions & 0 deletions Unreal/Plugins/AirSim/Source/PIPCamera.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
#include "common/AirSimSettings.hpp"
#include "NedTransform.h"

#include "Materials/MaterialParameterCollection.h"
#include "Materials/MaterialParameterCollectionInstance.h"
#include "Materials/MaterialInstanceDynamic.h"
#include "PIPCamera.generated.h"


Expand Down Expand Up @@ -51,6 +54,9 @@ class AIRSIM_API APIPCamera : public ACameraActor
UTextureRenderTarget2D* getRenderTarget(const ImageType type, bool if_active);

msr::airlib::Pose getPose() const;

UPROPERTY() UMaterialParameterCollection* distortion_param_collection_;
UPROPERTY() UMaterialParameterCollectionInstance* distortion_param_instance_;

private: //members
UPROPERTY() TArray<USceneCaptureComponent2D*> captures_;
Expand All @@ -60,7 +66,9 @@ class AIRSIM_API APIPCamera : public ACameraActor
//TMap<int, UMaterialInstanceDynamic*> noise_materials_;
//below is needed because TMap doesn't work with UPROPERTY, but we do have -ve index
UPROPERTY() TArray<UMaterialInstanceDynamic*> noise_materials_;
UPROPERTY() TArray<UMaterialInstanceDynamic*> distortion_materials_;
UPROPERTY() UMaterial* noise_material_static_;
UPROPERTY() UMaterial* distortion_material_static_;

std::vector<bool> camera_type_enabled_;
FRotator gimbald_rotator_;
Expand All @@ -79,6 +87,7 @@ class AIRSIM_API APIPCamera : public ACameraActor
bool auto_format, const EPixelFormat& pixel_format, const CaptureSetting& setting, const NedTransform& ned_transform,
bool force_linear_gamma);
void setNoiseMaterial(int image_type, UObject* outer, FPostProcessSettings& obj, const NoiseSetting& settings);
void setDistortionMaterial(int image_type, UObject* outer, FPostProcessSettings& obj);
static void updateCameraPostProcessingSetting(FPostProcessSettings& obj, const CaptureSetting& setting);
static void updateCameraSetting(UCameraComponent* camera, const CaptureSetting& setting, const NedTransform& ned_transform);
};
24 changes: 24 additions & 0 deletions Unreal/Plugins/AirSim/Source/PawnSimApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "NedTransform.h"
#include "common/EarthUtils.hpp"

#include "Materials/MaterialParameterCollectionInstance.h"
#include "DrawDebugHelpers.h"

PawnSimApi::PawnSimApi(const Params& params)
Expand Down Expand Up @@ -426,6 +427,29 @@ void PawnSimApi::setCameraFoV(const std::string& camera_name, float fov_degrees)
}, true);
}

void PawnSimApi::setDistortionParam(const std::string& camera_name, const std::string& param_name, float value)
{
UAirBlueprintLib::RunCommandOnGameThread([this, camera_name, param_name, value]() {
APIPCamera* camera = getCamera(camera_name);
camera->distortion_param_instance_->SetScalarParameterValue(FName(param_name.c_str()), value);
}, true);
}

std::vector<float> PawnSimApi::getDistortionParams(const std::string& camera_name)
{
std::vector<float> param_values(5, 0.0);
UAirBlueprintLib::RunCommandOnGameThread([this, camera_name, &param_values]() {
APIPCamera* camera = getCamera(camera_name);
camera->distortion_param_instance_->GetScalarParameterValue(FName(TEXT("K1")), param_values[0]);
camera->distortion_param_instance_->GetScalarParameterValue(FName(TEXT("K2")), param_values[1]);
camera->distortion_param_instance_->GetScalarParameterValue(FName(TEXT("K3")), param_values[2]);
camera->distortion_param_instance_->GetScalarParameterValue(FName(TEXT("P1")), param_values[3]);
camera->distortion_param_instance_->GetScalarParameterValue(FName(TEXT("P2")), param_values[4]);
}, true);

return param_values;
}

//parameters in NED frame
PawnSimApi::Pose PawnSimApi::getPose() const
{
Expand Down
3 changes: 3 additions & 0 deletions Unreal/Plugins/AirSim/Source/PawnSimApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ class PawnSimApi : public msr::airlib::VehicleSimApiBase {
virtual msr::airlib::CameraInfo getCameraInfo(const std::string& camera_name) const override;
virtual void setCameraPose(const std::string& camera_name, const Pose& pose) override;
virtual void setCameraFoV(const std::string& camera_name, float fov_degrees) override;
virtual void setDistortionParam(const std::string& camera_name, const std::string& param_name, float value) override;
virtual std::vector<float> getDistortionParams(const std::string& camera_name) override;

virtual CollisionInfo getCollisionInfo() const override;
virtual int getRemoteControlID() const override;
virtual msr::airlib::RCData getRCData() const override;
Expand Down
5 changes: 2 additions & 3 deletions Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ ASimModeBase::ASimModeBase()

}
else
loading_screen_widget_ = nullptr;

loading_screen_widget_ = nullptr;
}

void ASimModeBase::toggleLoadingScreen(bool is_visible)
Expand Down Expand Up @@ -201,7 +200,7 @@ void ASimModeBase::initializeTimeOfDay()
sky_sphere_ = sky_spheres[0];
static const FName sun_prop_name(TEXT("Directional light actor"));
auto* p = sky_sphere_class_->FindPropertyByName(sun_prop_name);
UObjectProperty* sun_prop = Cast<UObjectProperty>(p);
FObjectProperty* sun_prop = Cast<UObjectProperty>(p);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change breaks UE 4.24, which is okay IMO, just need to update docs to 4.25
It still produces warnings on 4.25, so it should be fixed completely like
FObjectProperty* sun_prop = CastField<FObjectProperty>(p)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I will revert this, because officially we still wish to support older UE versions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, that's also good, however I think the latest PRs like the segmentation one and even this has asset modifications which were done on 4.25 I assume, and wouldn't work in 4.24. Need to test all this though
While trying to maintain compatibility with 4.24, it might be good to update the docs to recommend 4.25, since some features could stop working on 4.24 and also raise support questions. Currently docs say 4.22 is supported, which I'm pretty sure is not the case

UObject* sun_obj = sun_prop->GetObjectPropertyValue_InContainer(sky_sphere_);
sun_ = Cast<ADirectionalLight>(sun_obj);
if (sun_)
Expand Down
2 changes: 0 additions & 2 deletions Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
#include "PawnSimApi.h"
#include "common/StateReporterWrapper.hpp"
#include "LoadingScreenWidget.h"

#include "SimModeBase.generated.h"

DECLARE_DYNAMIC_MULTICAST_DELEGATE(FLevelLoaded);
Expand Down Expand Up @@ -124,7 +123,6 @@ class AIRSIM_API ASimModeBase : public AActor

protected:
int record_tick_count;

UPROPERTY() UClass* pip_camera_class;
UPROPERTY() UParticleSystem* collision_display_template;

Expand Down