diff --git a/.gitignore b/.gitignore index 7e8fafbc1..8d07dbbfe 100644 --- a/.gitignore +++ b/.gitignore @@ -402,3 +402,8 @@ PythonClient/docs/_build /Unreal/Environments/BlocksComp/ docker/LinuxBlocks/* /cosys-airsim-data-scripts/ +CLAUDE.md +*.claude +*.idea +Unreal/Environments/Blocks/Automation_Blocks.slnx +Unreal/Environments/Blocks/Blocks.slnx diff --git a/AirLib/include/common/AirSimSettings.hpp b/AirLib/include/common/AirSimSettings.hpp index a588aaf89..8eb1777d7 100644 --- a/AirLib/include/common/AirSimSettings.hpp +++ b/AirLib/include/common/AirSimSettings.hpp @@ -1837,6 +1837,8 @@ namespace airlib const std::string& simmode_name) { + unused(simmode_name); // no longer used for per-sensor-type gating, kept for call-site compatibility + // NOTE: Increase type if number of sensors goes above 8 uint8_t present_sensors_bitmask = 0; @@ -1852,15 +1854,11 @@ namespace airlib auto sensor_type = Utils::toEnum(child.getInt("SensorType", 0)); auto enabled = child.getBool("Enabled", false); - if (simmode_name == kSimModeTypeMultirotor && sensor_type == SensorBase::SensorType::GPULidar && enabled) { - throw std::invalid_argument(std::string("GPULiDAR sensor from MultiRotor vehicle as this combination is not supported. Please remove or disable.")); - }else{ - sensors[key] = createSensorSetting(sensor_type, key, enabled); - initializeSensorSetting(sensors[key].get(), child); + sensors[key] = createSensorSetting(sensor_type, key, enabled); + initializeSensorSetting(sensors[key].get(), child); - // Mark sensor types already added - present_sensors_bitmask |= 1U << Utils::toNumeric(sensor_type); - } + // Mark sensor types already added + present_sensors_bitmask |= 1U << Utils::toNumeric(sensor_type); } } diff --git a/AirLib/include/sensors/lidar/GPULidarSimpleParams.hpp b/AirLib/include/sensors/lidar/GPULidarSimpleParams.hpp index 29b2b6d50..95bd22a94 100755 --- a/AirLib/include/sensors/lidar/GPULidarSimpleParams.hpp +++ b/AirLib/include/sensors/lidar/GPULidarSimpleParams.hpp @@ -48,6 +48,8 @@ namespace msr { uint draw_mode = 0; // 0 = no coloring, 1 = instance segmentation, 2 = material, 3 = impact angle, 4 = intensity bool draw_sensor = false; // Draw the physical sensor in the world on the vehicle with a 3d colored axis + bool async_capture_mode = false; + real_T update_frequency = 10; // Frequency to update the sensor at in Hz real_T startup_delay = 1; // Delay until sensor is enabled in seconds @@ -57,6 +59,7 @@ namespace msr { void initializeFromSettings(const AirSimSettings::GPULidarSetting& settings) { std::string simmode_name = AirSimSettings::singleton().simmode_name; + async_capture_mode = (simmode_name == AirSimSettings::kSimModeTypeMultirotor); const auto& settings_json = settings.settings; diff --git a/CHANGELOG.md b/CHANGELOG.md index ce44caf28..22dabe81a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ -### Development (version 3.4) +### July 2026 (version 3.4) +* The latest available stable Unreal Engine version that is now targeted for release is 5.8. This means the previous 5.5 branch will no longer be receive updates or be actively maintained. +* Removed prebuild versions of 5.2.1 LTS version. This branch is still updated and maintained but has to be used from source. +* Added unique index to each object name in the annotation system to avoid duplicate name overrides. +* Added support with annotation system for (instanced) skeletal nanite meshes. +* Updated annotation system to add both actor and component tags to the annotation system for checking if both exist instead of old behaviour where actor tags took priority and component tags would be ignored if both existed. +* Updated annotation system to stop printing everything to log. +* Updated default camera to use auto-focus. Manual focus still available through API. +* Updated Docker tutorial to work better for recent Unreal versions. +* Updated Matlab Toolbox for new toolbox project file structure. +* Updated Linux installation from source to more easily target against the Clang shipped with Unreal Engine itself. +* Updated documentation pages to Material theme of MkDocs for better navigation and readibility. * Fixed duplicate indexes for annotation system causing meshes to not show up in annotation masks. +* Fixed several edge-cases and crashes in annotation system. +* Fixed GPU LiDAR crashing on Multirotor vehicles by dispatching its scene capture/readback asynchronously to the game thread. GPU LiDAR + Multirotor is allowed in settings.json again as a result. +* Fixed common crash on ending play. +* Fixed incorrect TF-coordinate system for cameras for ROS2 node. +* Fixed incorrect TF hierarchy order to world->odom->vehicle->sensors for ROS2 node. +* Fixed ROS2 header imports to support newer ROS2 distros such as Jazzy. + ### April 2025 (version 3.3) * The latest available stable Unreal Engine version that is now targeted for release is 5.5. This means 5.4 will no longer be actively maintained. @@ -58,7 +76,7 @@ * Updated to be compatible with Unreal 5.3. * Note that 5.3 breaks debug rendering! Disable it to avoid issues in editor. [Fixed in 5.4](https://issues.unrealengine.com/issue/UE-199454) * Note that 5.3 and higher requires _r.DetailMode 2_ console command or scalability settings to be set to Epic to avoid issues with rendering the RGB scene camera sensor. More info [here](docs/unreal_custenv.md#unreal-scene-camera-bug). -* Updated [ROS2 wrapper](docs/ros_cplusplus.md) to support Cosys-AirSim features and fix several issues: +* Updated [ROS2 wrapper](docs/ros2.md) to support Cosys-AirSim features and fix several issues: * Added support for annotation cameras. * Added support for GPU-Lidar and Echos sensors. * Added support for ground truth labels of Lidar sensor. diff --git a/Matlab/.gitattributes b/Matlab/.gitattributes new file mode 100644 index 000000000..78150916e --- /dev/null +++ b/Matlab/.gitattributes @@ -0,0 +1,33 @@ +* text=auto + +*.fig binary +*.mat binary +*.mdl binary diff merge=mlAutoMerge +*.mdlp binary +*.mex* binary +*.mlapp binary +*.mldatx binary merge=mlAutoMerge +*.mlproj binary +*.mlx binary +*.p binary +*.plprj binary +*.sbproj binary +*.sfx binary +*.sldd binary +*.slreqx binary merge=mlAutoMerge +*.slmx binary merge=mlAutoMerge +*.sltx binary +*.slxc binary +*.slx binary merge=mlAutoMerge +*.slxp binary + +## MATLAB Project metadata files use LF line endings +/resources/project/**/*.xml text eol=lf + +## Other common binary file types +*.docx binary +*.exe binary +*.jpg binary +*.pdf binary +*.png binary +*.xlsx binary diff --git a/Matlab/.gitignore b/Matlab/.gitignore new file mode 100644 index 000000000..aac549e77 --- /dev/null +++ b/Matlab/.gitignore @@ -0,0 +1,40 @@ +# Autosave files +*.asv +*.m~ +*.autosave +*.slx.r* +*.mdl.r* + +# Derived content-obscured files +*.p + +# Compiled MEX files +*.mex* + +# Packaged app and toolbox files +*.mlappinstall +*.mltbx + +# Deployable archives +*.ctf + +# Generated helpsearch folders +helpsearch*/ + +# Code generation folders +slprj/ +sccprj/ +codegen/ + +# Cache files +*.slxc + +# Cloud based storage dotfile +.MATLABDriveTag + +# buildtool cache folder +.buildtool/ + +# SimBiology backup files +*.sbproj.backup +*.sbproj.bak diff --git a/Matlab/Cosys-AirSim Matlab API Client.prj b/Matlab/Cosys-AirSim Matlab API Client.prj deleted file mode 100644 index ceb292153..000000000 --- a/Matlab/Cosys-AirSim Matlab API Client.prj +++ /dev/null @@ -1,154 +0,0 @@ - - - Cosys-AirSim Matlab API Client - Wouter Jansen - wouter.jansen@uantwerpen.be - Cosys-Lab, University of Antwerp - This a client implementation of the RPC API for Matlab for the Cosys-AirSim simulation framework. - This a client implementation of the RPC API for Matlab for the Cosys-AirSim simulation framework. A main class AirSimClient is available which implements all API calls. -Do note that at this point not all functions have been tested and most function documentation was auto-generated. This is still a WIP client. - D:\BigProjects\Cosys-AirSim-Public\promo\thumbnail_matlab.png - 3.3.0.0 - ${PROJECT_ROOT}\Cosys-AirSim Matlab API Client.mltbx - - Aerospace Toolbox - Computer Vision Toolbox - Signal Processing Toolbox - - - 108 - 96 - 8 - - - 24.2 - 24.2 - 24.2 - - - 3a9ac55d-69ef-4d53-9167-e1958860a717 - - true - <?xml version="1.0" encoding="utf-8"?> -<examples> - <exampleCategory name="Matlab"> - <example name="example" type="html"> - <file type="source">/html/example.html</file> - <file type="main">/example.m</file> - <file type="thumbnail">/html/example.png</file> - <file type="image">/html/example_01.png</file> - <file type="image">/html/example_02.png</file> - <file type="image">/html/example_03.png</file> - <file type="image">/html/example_04.png</file> - <file type="image">/html/example_05.png</file> - <file type="image">/html/example_06.png</file> - <file type="image">/html/example_07.png</file> - </example> - </exampleCategory> -</examples> - - - - ${PROJECT_ROOT}\info.xml - ${PROJECT_ROOT}\doc\GettingStarted.mlx - - - false - - - - - - false - true - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${PROJECT_ROOT} - - - ${PROJECT_ROOT}\AirSimCameraTypes.m - ${PROJECT_ROOT}\AirSimClient.m - ${PROJECT_ROOT}\AirSimDrivetrainTypes.m - ${PROJECT_ROOT}\AirSimGenerateColorMap.m - ${PROJECT_ROOT}\AirSimWeather.m - ${PROJECT_ROOT}\colormap.csv - ${PROJECT_ROOT}\demos.xml - ${PROJECT_ROOT}\doc - ${PROJECT_ROOT}\example.m - ${PROJECT_ROOT}\example_twodrones.m - ${PROJECT_ROOT}\help - ${PROJECT_ROOT}\html - ${PROJECT_ROOT}\info.xml - - - - - - D:\BigProjects\Cosys-AirSim-Public\Matlab\Cosys-AirSim Matlab API Client.mltbx - - - - C:\Program Files\MATLAB\R2024b - - - - - - true - - - - - false - false - true - false - false - false - false - false - 10.0 - false - true - win64 - true - - - \ No newline at end of file diff --git a/Matlab/Cosys-AirSimMatlabAPIClient.prj b/Matlab/Cosys-AirSimMatlabAPIClient.prj new file mode 100644 index 000000000..6b95f9812 --- /dev/null +++ b/Matlab/Cosys-AirSimMatlabAPIClient.prj @@ -0,0 +1,2 @@ + + diff --git a/Matlab/README.md b/Matlab/README.md new file mode 100644 index 000000000..5074050fa --- /dev/null +++ b/Matlab/README.md @@ -0,0 +1,368 @@ + +# Cosys\-AirSim Matlab Client + +This a client implementation of the RPC API for Matlab for the Cosys\-AirSim simulation framework. A main class AirSimClient is available which implements all API calls. + + +Do note that at this point not all functions have been tested and most function documentation was auto\-generated. This is still a WIP client. + +## Dependencies +- MATLAB 2024a or higher with the associated supported Python version, 3.7 or higher with the Cosys\-AirSim python module. +- Computer Vision, Aerospace, Signal Processing Toolboxes + +You can install the Cosys\-AirSim Python client from pip (not from matlab console but with terminal/powershell/bash): + +```matlab +pip install cosysairsim +``` +## Usage +#### **Configure Python for MATLAB** + +First you need to correctly link your installed Python installation to MATLAB, as by default this isn't always the latest version of Python 3 you installed. You can verify which Python is linked by running: + +```matlab +pe = pyenv; +pe.Version +``` + +If this is not a version that you which to use you can alter this manually. Do note that you need to do this everytime before using the client! Once Python is loaded in matlab, you need to restart MATLAB first before changing it. Therefore, running the commands above will likely mean requiring a restart of MATLAB. + + +For Windows you can run for example: + +```matlab +pyenv('Version','your.version') +``` + +With *'your.version'* indicating the *'major.minor'* version number of you Python release, for example *'3.6'.* + + +On linux you need to refer to the path of your Python 3 installation,, for example: + +```matlab +pyenv('Version',"/usr/bin/python3") +``` + +You can also link to specific Python versions by altering the path. + + +Some more information can be found [here](). + +#### **Initial setup** + +When starting with this wrapper, first try to make a connection to the Cosys\-AirSim simulation. + +```matlab +vehicle_name = "airsimvehicle"; +airSimClient = AirSimClient(IsDrone=false, IP="127.0.0.1", port=41451); +``` + +Now the client object can be used to run API methods from. All functions have some help text written for more information on them. + +## Example + +This example works well with the default [example settings](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/docs/settings_example.json) found in the docs folder op the Cosys\-AirSim repository. + + +This example will: + +- Connect to AirSim +- Get/set vehicle pose +- Get instance segmentation groundtruth table +- Get object pose(s) +- Get sensor data (imu, echo (active/passive), (gpu)LiDAR, camera (info, rgb, depth, segmentation, annotation)) + +Do note that the AirSim matlab client has almost all API functions available but not all are listed in this test script. For a full list see the source code fo the AirSimClient class. + + +Do note the test script requires next to the toolboxes listed above in the Prerequisites the following Matlab toolboxes: + +- Lidar Toolbox +- Navigation Toolbox +- Robotics System Toolbox +- ROS Toolbox +- UAV Toolbox +#### Setup connection +```matlab + +%Define client +vehicle_name = "airsimvehicle"; +airSimClient = AirSimClient(IsDrone=false, IP="127.0.0.1", port=41451); + +``` +#### Groundtruth labels +```matlab +% Get groundtruth look-up-table of all objects and their instance +% segmentation colors for the cameras and GPU LiDAR +groundtruthLUT = airSimClient.getInstanceSegmentationLUT(); + +``` +#### Get some poses +```matlab +% All poses are right handed coordinate system X Y Z and +% orientations are defined as quaternions W X Y Z. + +% Get poses of all objects in the scene, this takes a while for large +% scene so it is in comment by default +poses = airSimClient.getAllObjectPoses(false, false); + +% Get vehicle pose +vehiclePoseLocal = airSimClient.getVehiclePose(vehicle_name); +vehiclePoseWorld = airSimClient.getObjectPose(vehicle_name, false); + +% Choose the object to get the pose from (this one is in the Blocks env) +chosenObject = "Cylinder3"; + +% Get its pose +objectPoseLocal = airSimClient.getObjectPose(chosenObject, true); +objectPoseWorld = airSimClient.getObjectPose(chosenObject, false); + +figure; +subplot(1, 2, 1); +plotTransforms([vehiclePoseLocal.position; objectPoseLocal.position], [vehiclePoseLocal.orientation; objectPoseLocal.orientation], FrameLabel=["Vehicle"; chosenObject], AxisLabels="on") +axis equal; +grid on; +xlabel("X (m)") +ylabel("Y (m)") +zlabel("Z (m)") +title("Local Plot") + +subplot(1, 2, 2); +plotTransforms([vehiclePoseWorld.position; objectPoseWorld.position], [vehiclePoseWorld.orientation; objectPoseWorld.orientation], FrameLabel=["Vehicle"; chosenObject], AxisLabels="on") + +axis equal; +grid on; +xlabel("X (m)") +ylabel("Y (m)") +zlabel("Z (m)") +title("World Plot") +drawnow + +% Set vehicle pose +airSimClient.setVehiclePose(airSimClient.getVehiclePose(vehicle_name).position + [1 1 0], airSimClient.getVehiclePose(vehicle_name).orientation, true, vehicle_name) +``` + +![figure_0.png](README_media/figure_0.png) + + +#### IMU sensor Data +```matlab + +imuSensorName = "imu"; +[imuData, imuTimestamp] = airSimClient.getIMUData(imuSensorName, vehicle_name) + +``` +#### Echo sensor data +```matlab +% Example plots passive echo pointcloud +% and its reflection directions as 3D quivers + +echoSensorName = "echo"; +enablePassive = true; +[activePointCloud, activeData, passivePointCloud, passiveData , echoTimestamp, echoSensorPose] = airSimClient.getEchoData(echoSensorName, enablePassive, vehicle_name); + +figure; +subplot(1, 2, 1); +if ~isempty(activePointCloud) + pcshow(activePointCloud, color="X", MarkerSize=50); +else + pcshow(pointCloud([0, 0, 0])); +end +title('Active Echo Sensor Pointcloud') +xlabel("X (m)") +ylabel("Y (m)") +zlabel("Z (m)") +xlim([0 10]) +ylim([-10 10]) +zlim([-10 10]) + +subplot(1, 2, 2); +if ~isempty(passivePointCloud) + pcshow(passivePointCloud, color="X", MarkerSize=50); + hold on; + quiver3(passivePointCloud.Location(:, 1), passivePointCloud.Location(:, 2), passivePointCloud.Location(:, 3),... + passivePointCloud.Normal(:, 1), passivePointCloud.Normal(:, 2), passivePointCloud.Normal(:, 3), 2); + hold off +else + pcshow(pointCloud([0, 0, 0])); +end +title('Passive Echo Sensor Pointcloud') +xlabel("X (m)") +ylabel("Y (m)") +zlabel("Z (m)") +xlim([0 10]) +ylim([-10 10]) +zlim([-10 10]) +drawnow +``` + +![figure_1.png](README_media/figure_1.png) + + +#### LiDAR sensor data +```matlab +% Example plots lidar pointcloud and getting the groundtruth labels +``` + +![figure_2.png](README_media/figure_2.png) + +```matlab + +lidarSensorName = "lidar"; +enableLabels = true; +[lidarPointCloud, lidarLabels, LidarTimestamp, LidarSensorPose] = airSimClient.getLidarData(lidarSensorName, enableLabels, vehicle_name); + +figure; +if ~isempty(lidarPointCloud) + pcshow(lidarPointCloud, MarkerSize=50); +else + pcshow(pointCloud([0, 0, 0])); +end +title('LiDAR Pointcloud') +xlabel("X (m)") +ylabel("Y (m)") +zlabel("Z (m)") +xlim([0 10]) +ylim([-10 10]) +zlim([-10 10]) +drawnow + +``` +#### GPU LiDAR sensor data +```matlab +% Example plots GPU lidar pointcloud with its RGB segmentation colors + +gpuLidarSensorName = "gpulidar"; +enableLabels = true; +[gpuLidarPointCloud, gpuLidarTimestamp, gpuLidarSensorPose] = airSimClient.getGPULidarData(gpuLidarSensorName, vehicle_name); + +figure; +if ~isempty(gpuLidarPointCloud) + pcshow(gpuLidarPointCloud, MarkerSize=50); +else + pcshow(pointCloud([0, 0, 0])); +end +title('GPU-Accelerated LiDAR Pointcloud') +xlabel("X (m)") +ylabel("Y (m)") +zlabel("Z (m)") +xlim([0 10]) +ylim([-10 10]) +zlim([-10 10]) +drawnow +``` + +![figure_3.png](README_media/figure_3.png) + + +#### Cameras +```matlab + +%% Get camera info +cameraSensorName = "frontcamera"; +[intrinsics, cameraSensorPose] = airSimClient.getCameraInfo(cameraSensorName, vehicle_name); + +%% Get single camera images +% Get images sequentially + +cameraSensorName = "front_center"; +[rgbImage, rgbCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Scene, vehicle_name); +[segmentationImage, segmentationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Segmentation,vehicle_name); +[depthImage, depthCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.DepthPlanar,vehicle_name); +figure; +subplot(3, 1, 1); +imshow(rgbImage) +title("RGB Camera Image") +subplot(3, 1, 2); +imshow(segmentationImage) +title("Segmentation Camera Image") +subplot(3, 1, 3); +imshow(depthImage ./ max(max(depthImage)).* 255, gray) +title("Depth Camera Image") +drawnow + +``` + +![figure_4.png](README_media/figure_4.png) + +```matlab + +%% Get synced camera images +% By combining the image requests they will be synced +% and taken in the same frame + +cameraSensorName = "front_center"; +[images, cameraIimestamp] = airSimClient.getCameraImages(cameraSensorName, ... + [AirSimCameraTypes.Scene, AirSimCameraTypes.Segmentation, AirSimCameraTypes.DepthPlanar], ... + vehicle_name, ["", "", ""]); +figure; +subplot(3, 1, 1); +imshow(images{1}) +title("Synced RGB Camera Image") +subplot(3, 1, 2); +imshow(images{2}) +title("Synced Segmentation Camera Image") +subplot(3, 1, 3); +imshow(images{3} ./ max(max(images{3})).* 255, gray) +title("Synced Depth Camera Image") +drawnow +``` + +![figure_5.png](README_media/figure_5.png) +## Example Two Drones + +This example works well with the settings file as in the comments below: + +``` +{ + "SeeDocsAt": "https://cosys-lab.github.io/settings/", + "SettingsVersion": 2, + "ClockSpeed": 1, + "LocalHostIp": "127.0.0.1", + "ApiServerPort": 41451, + "RpcEnabled": true, + "SimMode": "Multirotor", + "Vehicles": { + "Drone1": { + "VehicleType": "SimpleFlight", + "AllowAPIAlways": true, + "X": 0, + "Y": 0, + "Z": 0, + "Yaw": 0 + }, + "Drone2": { + "VehicleType": "SimpleFlight", + "AllowAPIAlways": true, + "X": 5, + "Y": 0, + "Z": 0, + "Yaw": 0 + } + } +} +``` +```matlab +airSimClient = AirSimClient(IsDrone=true, IP="127.0.0.1", port=41451); + +airSimClient.setEnableApiControl("Drone1"); +airSimClient.setEnableApiControl("Drone2"); + +airSimClient.setEnableDroneArm("Drone1"); +airSimClient.setEnableDroneArm("Drone2"); + +airSimClient.takeoffAsync("Drone1", 20, true); +airSimClient.takeoffAsync("Drone2", 20, false); + +airSimClient.moveToPositionAsync(10, 10, -5, 5, 3e+38, AirSimDrivetrainTypes.MaxDegreeOfFreedom, true, 0, -1, 1, "Drone1", true); +airSimClient.moveToPositionAsync(10, 14, -5, 5, 3e+38, AirSimDrivetrainTypes.MaxDegreeOfFreedom, true, 0, -1, 1, "Drone2", true); + +airSimClient.landAsync("Drone1", 60, true); +airSimClient.landAsync("Drone2", 60, false); + +airSimClient.setDisableDroneArm("Drone1"); +airSimClient.setDisableDroneArm("Drone2"); + +airSimClient.setDisableApiControl("Drone1"); +airSimClient.setDisableApiControl("Drone2"); +``` diff --git a/Matlab/README_media/figure_0.png b/Matlab/README_media/figure_0.png new file mode 100644 index 000000000..635732c52 Binary files /dev/null and b/Matlab/README_media/figure_0.png differ diff --git a/Matlab/README_media/figure_1.png b/Matlab/README_media/figure_1.png new file mode 100644 index 000000000..f06ff6c92 Binary files /dev/null and b/Matlab/README_media/figure_1.png differ diff --git a/Matlab/README_media/figure_2.png b/Matlab/README_media/figure_2.png new file mode 100644 index 000000000..d0522b1b0 Binary files /dev/null and b/Matlab/README_media/figure_2.png differ diff --git a/Matlab/README_media/figure_3.png b/Matlab/README_media/figure_3.png new file mode 100644 index 000000000..7e733c877 Binary files /dev/null and b/Matlab/README_media/figure_3.png differ diff --git a/Matlab/README_media/figure_4.png b/Matlab/README_media/figure_4.png new file mode 100644 index 000000000..67df2298d Binary files /dev/null and b/Matlab/README_media/figure_4.png differ diff --git a/Matlab/README_media/figure_5.png b/Matlab/README_media/figure_5.png new file mode 100644 index 000000000..6bcb8757c Binary files /dev/null and b/Matlab/README_media/figure_5.png differ diff --git a/Matlab/buildfile.m b/Matlab/buildfile.m new file mode 100644 index 000000000..1276e861c --- /dev/null +++ b/Matlab/buildfile.m @@ -0,0 +1,149 @@ +function plan = buildfile + import matlab.buildtool.tasks.CleanTask + import matlab.buildtool.tasks.CodeIssuesTask + + % Create a plan from the task functions + plan = buildplan(localfunctions); + + % Define the "clean" Task + plan("clean") = matlab.buildtool.tasks.CleanTask; + + % Define the "check" task + sourceFolder = files(plan, "toolbox"); + plan("check") = matlab.buildtool.tasks.CodeIssuesTask(sourceFolder,... + IncludeSubfolders = true); + + plan.DefaultTasks = ["clean" "check" "generatedocs" "release"]; + + % Make the "release" task dependent on the others + plan("release").Dependencies = ["check" "generatedocs"]; + plan("release").Outputs = "release\Cosys-AirSim Matlab API Client.mltbx"; +end + +function releaseTask(~) + % Create an MLTBX package + releaseFolderName = "release"; + % Create a release and put it in the release directory + opts = matlab.addons.toolbox.ToolboxOptions("Cosys-AirSimMatlabAPIClient.prj"); + + % By default, the packaging GUI restricts the name of the getting started guide, so we fix that here. + opts.ToolboxGettingStartedGuide = fullfile("toolbox", "doc", "gettingStarted.mlx"); + + % GitHub releases don't allow spaces, so replace spaces with underscores + opts.OutputFile = fullfile(releaseFolderName, "Cosys-AirSim Matlab API Client.mltbx"); + + % Create the release directory, if needed + if ~exist(releaseFolderName,"dir") + mkdir(releaseFolderName) + end + matlab.addons.toolbox.packageToolbox(opts); +end + +function generatedocsTask(~) + % Generate markdown readme + + mdfile = export("toolbox/doc/GettingStarted.mlx", "README.md", Format="markdown"); + + % Clean up the README.md file + cleanupReadme("README.md"); + + % Generate HTML pages + htmldir = "toolbox\doc\html"; + if ~exist(htmldir, 'dir') + mkdir(htmldir) + end + mdfile = export("toolbox/doc/GettingStarted.mlx", "toolbox/doc/html/GettingStarted.html", Format="html"); +end + +function cleanupReadme(filename) + % Read the file + fileContent = fileread(filename); + lines = splitlines(fileContent); + + % Find and remove TOC section (between and ) + inToc = false; + linesToKeep = true(size(lines)); + + for i = 1:length(lines) + if contains(lines{i}, '') + inToc = true; + linesToKeep(i) = false; + elseif contains(lines{i}, '') + inToc = false; + linesToKeep(i) = false; + elseif inToc + linesToKeep(i) = false; + end + end + + lines = lines(linesToKeep); + + % Remove lines containing problematic links + % 1. Lines with MATLAB-specific anchor links like [text](#H_xxxx) + % 2. For lines with links to .mlx/.m files, remove only sentences with those links + linesToKeep = true(size(lines)); + + for i = 1:length(lines) + line = lines{i}; + % Check for MATLAB anchor links pattern: [text](#H_xxxx) or [text](#TMP_xxxx) + if ~isempty(regexp(line, '\[.*?\]\(#[HT]_[a-zA-Z0-9]+\)', 'once')) + linesToKeep(i) = false; + continue; + end + + % Check for links to .mlx or .m files + if contains(line, '.mlx)') || contains(line, '.m)') + % Split line into sentences (split by period followed by space or end of string) + sentences = regexp(line, '[^.]*\.(?:\s|$)', 'match'); + + % If no sentences found (no periods), check the whole line + if isempty(sentences) + sentences = {line}; + end + + cleanSentences = {}; + for j = 1:length(sentences) + sentence = sentences{j}; + % Keep sentence only if it doesn't contain .mlx or .m links + if ~contains(sentence, '.mlx)') && ~contains(sentence, '.m)') + cleanSentences{end+1} = sentence; + end + end + + % Reconstruct the line if there are any clean sentences + if ~isempty(cleanSentences) + lines{i} = strjoin(cleanSentences, ''); + % Trim any extra whitespace + lines{i} = strtrim(lines{i}); + else + % If all sentences had problematic links, mark line for removal + linesToKeep(i) = false; + end + end + end + + lines = lines(linesToKeep); + + % Downgrade heading levels (except the first main title) + % MATLAB exports title as #, but we want to keep first heading as # and downgrade all others + firstHeadingFound = false; + for i = 1:length(lines) + line = lines{i}; + % Check if line is a markdown heading (starts with #) + if ~isempty(line) && line(1) == '#' + if ~firstHeadingFound + % Keep the first heading as-is (the main title) + firstHeadingFound = true; + else + % Downgrade all subsequent headings by one level (add one more #) + lines{i} = ['#' line]; + end + end + end + + % Write the cleaned content back to file + fileContent = strjoin(lines, newline); + fid = fopen(filename, 'w', 'n', 'UTF-8'); + fwrite(fid, fileContent, 'char'); + fclose(fid); +end \ No newline at end of file diff --git a/Matlab/demos.xml b/Matlab/demos.xml deleted file mode 100644 index 705f45655..000000000 --- a/Matlab/demos.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - Cosys-AirSim Matlab API Client - toolbox - HelpIcon.DEMOS - - This a client implementation of the RPC API for Matlab for the Cosys-AirSim simulation framework. A main class AirSimClient is available which implements all API calls. -Do note that at this point not all functions have been tested and most function documentation was auto-generated. This is still a WIP client. - - - - - other - example - html/example.html - - - \ No newline at end of file diff --git a/Matlab/doc/GettingStarted.mlx b/Matlab/doc/GettingStarted.mlx deleted file mode 100644 index cf9fd00d1..000000000 Binary files a/Matlab/doc/GettingStarted.mlx and /dev/null differ diff --git a/Matlab/help/help.html b/Matlab/help/help.html deleted file mode 100644 index 08cde9635..000000000 --- a/Matlab/help/help.html +++ /dev/null @@ -1,309 +0,0 @@ - -Cosys-AirSim Matlab Client

Cosys-AirSim Matlab Client

This a client implementation of the RPC API for Matlab for the Cosys-AirSim simulation framework. A main class AirSimClient is available which implements all API calls.
Do note that at this point not all functions have been tested and most function documentation was auto-generated. This is still a WIP client.

Dependencies

  • MATLAB 2024a or higher with the associated supported Python version, 3.7 or higher with the Cosys-AirSim python module.
  • Computer Vision, Aerospace, Signal Processing Toolboxes

Usage

Configure Python for MATLAB

First you need to correctly link your installed Python installation to MATLAB, as by default this isn't always the latest version of Python 3 you installed. You can verify which Python is linked by running:
pe = pyenv;
pe.Version
If this is not a version that you which to use you can alter this manually. Do note that you need to do this everytime before using the clioent! Once Python is loaded in matlab, you need to restart MATLAB first before changing it. Therefore, running the commands above will likely mean requiring a restart of MATLAB.
For Windows you can run for example:
pyenv('Version','your.version')
With 'your.version' indicating the 'major.minor' version number of you Python release, for example '3.6'.
On linux you need to refer to the path of your Python 3 installation,, for example:
pyenv('Version',"/usr/bin/python3")
You can also link to specific Python versions by altering the path.
Some more information can be found here.

Initial setup

When starting with this wrapper, first try to make a connection to the Cosys-AirSim simulation.
vehicle_name = "airsimvehicle";
airSimClient = AirSimClient(IsDrone=false, ApiControl=false, IP="127.0.0.1", port=41451, vehicleName=vehicle_name);
Now the client object can be used to run API methods from. All functions have some help text written for more information on them.

Example

This example will:
  • Connect to AirSim
  • Get/set vehicle pose
  • Get instance segmentation groundtruth table
  • Get object pose(s)
  • Get sensor data (imu, echo (active/passive), (gpu)LiDAR, camera (info, rgb, depth, segmentation, annotation))
Do note that the AirSim matlab client has almost all API functions available but not all are listed in this test script. For a full list see the source code fo the AirSimClient class.
Do note the test script requires next to the toolboxes listed above in the Prerequisites the following Matlab toolboxes:
  • Lidar Toolbox
  • Navigation Toolbox
  • Robotics System Toolbox
  • ROS Toolbox
  • UAV Toolbox

Setup connection

 
%Define client
vehicle_name = "airsimvehicle";
airSimClient = AirSimClient(IsDrone=false, ApiControl=false, IP="127.0.0.1", port=41451, vehicleName=vehicle_name);
 

Groundtruth labels

% Get groundtruth look-up-table of all objects and their instance
% segmentation colors for the cameras and GPU LiDAR
groundtruthLUT = airSimClient.getInstanceSegmentationLUT();
 

Get some poses

% All poses are right handed coordinate system X Y Z and
% orientations are defined as quaternions W X Y Z.
 
% Get poses of all objects in the scene, this takes a while for large
% scene so it is in comment by default
poses = airSimClient.getAllObjectPoses(false, false);
 
% Get vehicle pose
vehiclePoseLocal = airSimClient.getVehiclePose();
vehiclePoseWorld = airSimClient.getObjectPose(vehicle_name, false);
 
% Get an random object pose or choose if you know the name of one
useChosenObject = false;
chosenObject = "Cylinder3";
 
if useChosenObject
finalName = chosenObject;
else
randomIndex = randi(size(groundtruthLUT, 1), 1);
randomName = groundtruthLUT.name(randomIndex);
finalName = randomName;
end
 
objectPoseLocal = airSimClient.getObjectPose(finalName, true);
objectPoseWorld = airSimClient.getObjectPose(finalName, false);
 
figure;
subplot(1, 2, 1);
plotTransforms([vehiclePoseLocal.position; objectPoseLocal.position], [vehiclePoseLocal.orientation; objectPoseLocal.orientation], FrameLabel=["Vehicle"; finalName], AxisLabels="on")
axis equal;
grid on;
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
title("Local Plot")
 
subplot(1, 2, 2);
plotTransforms([vehiclePoseWorld.position; objectPoseWorld.position], [vehiclePoseWorld.orientation; objectPoseWorld.orientation], FrameLabel=["Vehicle"; finalName], AxisLabels="on")
 
axis equal;
grid on;
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
title("World Plot")
drawnow
 
%% Set vehicle pose
airSimClient.setVehiclePose(airSimClient.getVehiclePose().position + [1 1 0], airSimClient.getVehiclePose().orientation)
 

IMU sensor Data

 
imuSensorName = "imu";
[imuData, imuTimestamp] = airSimClient.getIMUData(imuSensorName);
 

Echo sensor data

% Example plots passive echo pointcloud
% and its reflection directions as 3D quivers
 
echoSensorName = "echo";
enablePassive = true;
[activePointCloud, activeData, passivePointCloud, passiveData , echoTimestamp, echoSensorPose] = airSimClient.getEchoData(echoSensorName, enablePassive);
 
figure;
subplot(1, 2, 1);
if ~isempty(activePointCloud)
pcshow(activePointCloud, color="X", MarkerSize=50);
else
pcshow(pointCloud([0, 0, 0]));
end
title('Active Echo Sensor Pointcloud')
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
xlim([0 10])
ylim([-10 10])
zlim([-10 10])
 
subplot(1, 2, 2);
if ~isempty(passivePointCloud)
pcshow(passivePointCloud, color="X", MarkerSize=50);
hold on;
quiver3(passivePointCloud.Location(:, 1), passivePointCloud.Location(:, 2), passivePointCloud.Location(:, 3),...
passivePointCloud.Normal(:, 1), passivePointCloud.Normal(:, 2), passivePointCloud.Normal(:, 3), 2);
hold off
else
pcshow(pointCloud([0, 0, 0]));
end
title('Passive Echo Sensor Pointcloud')
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
xlim([0 10])
ylim([-10 10])
zlim([-10 10])
drawnow
 

LiDAR sensor data

% Example plots lidar pointcloud and getting the groundtruth labels
 
lidarSensorName = "lidar";
enableLabels = true;
[lidarPointCloud, lidarLabels, LidarTimestamp, LidarSensorPose] = airSimClient.getLidarData(lidarSensorName, enableLabels);
 
figure;
if ~isempty(lidarPointCloud)
pcshow(lidarPointCloud, MarkerSize=50);
else
pcshow(pointCloud([0, 0, 0]));
end
title('LiDAR Pointcloud')
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
xlim([0 10])
ylim([-10 10])
zlim([-10 10])
drawnow
 

GPU LiDAR sensor data

% Example plots GPU lidar pointcloud with its RGB segmentation colors
 
gpuLidarSensorName = "gpulidar";
enableLabels = true;
[gpuLidarPointCloud, gpuLidarTimestamp, gpuLidarSensorPose] = airSimClient.getGPULidarData(gpuLidarSensorName);
 
figure;
if ~isempty(gpuLidarPointCloud)
pcshow(gpuLidarPointCloud, MarkerSize=50);
else
pcshow(pointCloud([0, 0, 0]));
end
title('GPU-Accelerated LiDAR Pointcloud')
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
xlim([0 10])
ylim([-10 10])
zlim([-10 10])
drawnow
 

Cameras

 
%% Get camera info
cameraSensorName = "frontcamera";
[intrinsics, cameraSensorPose] = airSimClient.getCameraInfo(cameraSensorName);
 
%% Get single camera images
% Get images sequentially
 
cameraSensorName = "front_center";
[rgbImage, rgbCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Scene);
[segmentationImage, segmentationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Segmentation);
[depthImage, depthCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.DepthPlanar);
[annotationImage, annotationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Annotation, "TextureTestDirect");
figure;
subplot(4, 1, 1);
imshow(rgbImage)
title("RGB Camera Image")
subplot(4, 1, 2);
imshow(segmentationImage)
title("Segmentation Camera Image")
subplot(4, 1, 3);
imshow(depthImage ./ max(max(depthImage)).* 255, gray)
title("Depth Camera Image")
subplot(4, 1, 4);
imshow(annotationImage)
title("Annotation Camera Image")
drawnow
 
%% Get synced camera images
% By combining the image requests they will be synced
% and taken in the same frame
 
cameraSensorName = "front_center";
[images, cameraIimestamp] = airSimClient.getCameraImages(cameraSensorName, ...
[AirSimCameraTypes.Scene, AirSimCameraTypes.Segmentation, AirSimCameraTypes.DepthPlanar, AirSimCameraTypes.Annotation], ...
["", "", "", "GreyscaleTest"]);
figure;
subplot(4, 1, 1);
imshow(images{1})
title("Synced RGB Camera Image")
subplot(4, 1, 2);
imshow(images{2})
title("Synced Segmentation Camera Image")
subplot(4, 1, 3);
imshow(images{3} ./ max(max(images{3})).* 255, gray)
title("Synced Depth Camera Image")
subplot(4, 1, 4);
imshow(images{4})
title("Synced Annotation Camera Image")
drawnow
 
-
- -
\ No newline at end of file diff --git a/Matlab/help/helptoc.xml b/Matlab/help/helptoc.xml deleted file mode 100644 index 403949a97..000000000 --- a/Matlab/help/helptoc.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - Documentation - - \ No newline at end of file diff --git a/Matlab/html/example.html b/Matlab/html/example.html deleted file mode 100644 index ffe7279c9..000000000 --- a/Matlab/html/example.html +++ /dev/null @@ -1,549 +0,0 @@ - - - - - -Example - - - - - - - -
-

Example

- -

This example works well with the default example settings found in the docs folder op the repository.

-

This example will: -Connect to AirSim -Get/set vehicle pose -Get instance segmentation groundtruth table -Get object pose(s) -Get sensor data (imu, echo (active/passive), (gpu)LiDAR, camera (info, rgb, depth, segmentation, annotation))

-

Do note that the AirSim matlab client has almost all API functions available but not all are listed in this test script. For a full list see the source code fo the AirSimClient class.

-

Do note the test script requires next to the toolboxes listed in the Prerequisites the following Matlab toolboxes: -Lidar Toolbox -Navigation Toolbox -Robotics System Toolbox -ROS Toolbox -UAV Toolbox

- -

Contents

-
- -
-

Setup connection

-
-%Define client
-vehicle_name = "airsimvehicle";
-airSimClient = AirSimClient(IsDrone=false, IP="127.0.0.1", port=41451);
-
-

Groundtruth labels

-

Get groundtruth look-up-table of all objects and their instance segmentation colors for the cameras and GPU LiDAR

-
groundtruthLUT = airSimClient.getInstanceSegmentationLUT();
-
-

Get some poses

-

All poses are right handed coordinate system X Y Z and orientations are defined as quaternions W X Y Z.

-
-% Get poses of all objects in the scene, this takes a while for large
-% scene so it is in comment by default
-poses = airSimClient.getAllObjectPoses(false, false);
-
-% Get vehicle pose
-vehiclePoseLocal = airSimClient.getVehiclePose(vehicle_name);
-vehiclePoseWorld = airSimClient.getObjectPose(vehicle_name, false);
-
-% Choose the object to get the pose from (this one is in the Blocks env)
-chosenObject = "Cylinder3";
-
-% Get its pose
-objectPoseLocal = airSimClient.getObjectPose(chosenObject, true);
-objectPoseWorld = airSimClient.getObjectPose(chosenObject, false);
-
-figure;
-subplot(1, 2, 1);
-plotTransforms([vehiclePoseLocal.position; objectPoseLocal.position], [vehiclePoseLocal.orientation; objectPoseLocal.orientation], FrameLabel=["Vehicle"; finalName], AxisLabels="on")
-axis equal;
-grid on;
-xlabel("X (m)")
-ylabel("Y (m)")
-zlabel("Z (m)")
-title("Local Plot")
-
-subplot(1, 2, 2);
-plotTransforms([vehiclePoseWorld.position; objectPoseWorld.position], [vehiclePoseWorld.orientation; objectPoseWorld.orientation], FrameLabel=["Vehicle"; finalName], AxisLabels="on")
-
-axis equal;
-grid on;
-xlabel("X (m)")
-ylabel("Y (m)")
-zlabel("Z (m)")
-title("World Plot")
-drawnow
-
-% Set vehicle pose
-airSimClient.setVehiclePose(airSimClient.getVehiclePose(vehicle_name).position + [1 1 0], airSimClient.getVehiclePose(vehicle_name).orientation, false, vehicle_name)
-
-

IMU sensor Data

-
imuSensorName = "imu";
-[imuData, imuTimestamp] = airSimClient.getIMUData(imuSensorName, vehicle_name)
-
-
-imuData = 
-
-  struct with fields:
-
-           orientation: [1.0000 5.9864e-05 -0.0029 0.0012]
-       angularVelocity: [0 0 0]
-    linearAcceleration: [0.0560 -0.0012 9.8065]
-
-
-imuTimestamp =
-
-   1.7278e+09
-
-
-

Echo sensor data

-

Example plots passive echo pointcloud and its reflection directions as 3D quivers

-
echoSensorName = "echo";
-enablePassive = true;
-[activePointCloud, activeData, passivePointCloud, passiveData , echoTimestamp, echoSensorPose] = airSimClient.getEchoData(echoSensorName, enablePassive, vehicle_name);
-
-figure;
-subplot(1, 2, 1);
-if ~isempty(activePointCloud)
-    pcshow(activePointCloud, color="X", MarkerSize=50);
-else
-    pcshow(pointCloud([0, 0, 0]));
-end
-title('Active Echo Sensor Pointcloud')
-xlabel("X (m)")
-ylabel("Y (m)")
-zlabel("Z (m)")
-xlim([0 10])
-ylim([-10 10])
-zlim([-10 10])
-
-subplot(1, 2, 2);
-if ~isempty(passivePointCloud)
-    pcshow(passivePointCloud, color="X", MarkerSize=50);
-    hold on;
-    quiver3(passivePointCloud.Location(:, 1), passivePointCloud.Location(:, 2), passivePointCloud.Location(:, 3),...
-        passivePointCloud.Normal(:, 1), passivePointCloud.Normal(:, 2), passivePointCloud.Normal(:, 3), 2);
-    hold off
-else
-    pcshow(pointCloud([0, 0, 0]));
-end
-title('Passive Echo Sensor Pointcloud')
-xlabel("X (m)")
-ylabel("Y (m)")
-zlabel("Z (m)")
-xlim([0 10])
-ylim([-10 10])
-zlim([-10 10])
-drawnow
-
-

LiDAR sensor data

-

Example plots lidar pointcloud and getting the groundtruth labels

-
lidarSensorName = "lidar";
-enableLabels = true;
-[lidarPointCloud, lidarLabels, LidarTimestamp, LidarSensorPose] = airSimClient.getLidarData(lidarSensorName, enableLabels, vehicle_name);
-
-figure;
-if ~isempty(lidarPointCloud)
-    pcshow(lidarPointCloud, MarkerSize=50);
-else
-    pcshow(pointCloud([0, 0, 0]));
-end
-title('LiDAR Pointcloud')
-xlabel("X (m)")
-ylabel("Y (m)")
-zlabel("Z (m)")
-xlim([0 10])
-ylim([-10 10])
-zlim([-10 10])
-drawnow
-
-

GPU LiDAR sensor data

-

Example plots GPU lidar pointcloud with its RGB segmentation colors

-
gpuLidarSensorName = "gpulidar";
-enableLabels = true;
-[gpuLidarPointCloud, gpuLidarTimestamp, gpuLidarSensorPose] = airSimClient.getGPULidarData(gpuLidarSensorName, vehicle_name);
-
-figure;
-if ~isempty(gpuLidarPointCloud)
-    pcshow(gpuLidarPointCloud, MarkerSize=50);
-else
-    pcshow(pointCloud([0, 0, 0]));
-end
-title('GPU-Accelerated LiDAR Pointcloud')
-xlabel("X (m)")
-ylabel("Y (m)")
-zlabel("Z (m)")
-xlim([0 10])
-ylim([-10 10])
-zlim([-10 10])
-drawnow
-
-

Get camera info

-
cameraSensorName = "frontcamera";
-[intrinsics, cameraSensorPose] = airSimClient.getCameraInfo(cameraSensorName, vehicle_name);
-
-

Get single camera images

-

Get images sequentially

-
cameraSensorName = "front_center";
-[rgbImage, rgbCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Scene, vehicle_name);
-[segmentationImage, segmentationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Segmentation,vehicle_name);
-[depthImage, depthCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.DepthPlanar,vehicle_name);
-[annotationImage, annotationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Annotation, vehicle_name, "TextureTestDirect");
-figure;
-subplot(4, 1, 1);
-imshow(rgbImage)
-title("RGB Camera Image")
-subplot(4, 1, 2);
-imshow(segmentationImage)
-title("Segmentation Camera Image")
-subplot(4, 1, 3);
-imshow(depthImage ./ max(max(depthImage)).* 255, gray)
-title("Depth Camera Image")
-subplot(4, 1, 4);
-imshow(annotationImage)
-title("Annotation Camera Image")
-drawnow
-
-

Get synced camera images

-

By combining the image requests they will be synced and taken in the same frame

-
cameraSensorName = "front_center";
-[images, cameraIimestamp] = airSimClient.getCameraImages(cameraSensorName, ...
-                                                         [AirSimCameraTypes.Scene, AirSimCameraTypes.Segmentation, AirSimCameraTypes.DepthPlanar, AirSimCameraTypes.Annotation], ...
-                                                         vehicle_name, ["", "", "", "TextureTestDirect"]);
-figure;
-subplot(4, 1, 1);
-imshow(images{1})
-title("Synced RGB Camera Image")
-subplot(4, 1, 2);
-imshow(images{2})
-title("Synced Segmentation Camera Image")
-subplot(4, 1, 3);
-imshow(images{3} ./ max(max(images{3})).* 255, gray)
-title("Synced Depth Camera Image")
-subplot(4, 1, 4);
-imshow(images{4})
-title("Synced Annotation Camera Image")
-drawnow
-
-
Exception "java.lang.ClassNotFoundException: com/intellij/openapi/editor/RawText"while constructing DataFlavor for: application/x-java-jvm-local-objectref; class=com.intellij.openapi.editor.RawText
-Exception "java.lang.ClassNotFoundException: com/intellij/openapi/editor/RawText"while constructing DataFlavor for: application/x-java-jvm-local-objectref; class=com.intellij.openapi.editor.RawText
-
- -
- - - diff --git a/Matlab/html/example.png b/Matlab/html/example.png deleted file mode 100644 index ce03a5c33..000000000 Binary files a/Matlab/html/example.png and /dev/null differ diff --git a/Matlab/html/example_01.png b/Matlab/html/example_01.png deleted file mode 100644 index 509bcc8a8..000000000 Binary files a/Matlab/html/example_01.png and /dev/null differ diff --git a/Matlab/html/example_02.png b/Matlab/html/example_02.png deleted file mode 100644 index 756e6f093..000000000 Binary files a/Matlab/html/example_02.png and /dev/null differ diff --git a/Matlab/html/example_03.png b/Matlab/html/example_03.png deleted file mode 100644 index 03b251db8..000000000 Binary files a/Matlab/html/example_03.png and /dev/null differ diff --git a/Matlab/html/example_04.png b/Matlab/html/example_04.png deleted file mode 100644 index 54e80c8b1..000000000 Binary files a/Matlab/html/example_04.png and /dev/null differ diff --git a/Matlab/html/example_05.png b/Matlab/html/example_05.png deleted file mode 100644 index 03b7fb546..000000000 Binary files a/Matlab/html/example_05.png and /dev/null differ diff --git a/Matlab/html/example_06.png b/Matlab/html/example_06.png deleted file mode 100644 index 79c421344..000000000 Binary files a/Matlab/html/example_06.png and /dev/null differ diff --git a/Matlab/html/example_07.png b/Matlab/html/example_07.png deleted file mode 100644 index 786df8cbf..000000000 Binary files a/Matlab/html/example_07.png and /dev/null differ diff --git a/Matlab/Cosys-AirSim Matlab API Client.mltbx b/Matlab/release/Cosys-AirSim Matlab API Client.mltbx similarity index 96% rename from Matlab/Cosys-AirSim Matlab API Client.mltbx rename to Matlab/release/Cosys-AirSim Matlab API Client.mltbx index 6d69cf091..68b627ce7 100644 Binary files a/Matlab/Cosys-AirSim Matlab API Client.mltbx and b/Matlab/release/Cosys-AirSim Matlab API Client.mltbx differ diff --git a/Matlab/resources/project/2GpRyGDE8y_vvldl2K6-wfxxx0A/ZcWluXWWhTIbmWY8Dp35Sbw1RPQd.xml b/Matlab/resources/project/2GpRyGDE8y_vvldl2K6-wfxxx0A/ZcWluXWWhTIbmWY8Dp35Sbw1RPQd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/2GpRyGDE8y_vvldl2K6-wfxxx0A/ZcWluXWWhTIbmWY8Dp35Sbw1RPQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/2GpRyGDE8y_vvldl2K6-wfxxx0A/ZcWluXWWhTIbmWY8Dp35Sbw1RPQp.xml b/Matlab/resources/project/2GpRyGDE8y_vvldl2K6-wfxxx0A/ZcWluXWWhTIbmWY8Dp35Sbw1RPQp.xml new file mode 100644 index 000000000..01cb34e67 --- /dev/null +++ b/Matlab/resources/project/2GpRyGDE8y_vvldl2K6-wfxxx0A/ZcWluXWWhTIbmWY8Dp35Sbw1RPQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/BcjR4IfmSbVmxA6PYIiSTaxuVhMd.xml b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/BcjR4IfmSbVmxA6PYIiSTaxuVhMd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/BcjR4IfmSbVmxA6PYIiSTaxuVhMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/BcjR4IfmSbVmxA6PYIiSTaxuVhMp.xml b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/BcjR4IfmSbVmxA6PYIiSTaxuVhMp.xml new file mode 100644 index 000000000..01cb34e67 --- /dev/null +++ b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/BcjR4IfmSbVmxA6PYIiSTaxuVhMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/Zc_DNtJFvmdErN8IgMCYg6oZr5cd.xml b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/Zc_DNtJFvmdErN8IgMCYg6oZr5cd.xml new file mode 100644 index 000000000..99772b421 --- /dev/null +++ b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/Zc_DNtJFvmdErN8IgMCYg6oZr5cd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/Zc_DNtJFvmdErN8IgMCYg6oZr5cp.xml b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/Zc_DNtJFvmdErN8IgMCYg6oZr5cp.xml new file mode 100644 index 000000000..a97001b4a --- /dev/null +++ b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/Zc_DNtJFvmdErN8IgMCYg6oZr5cp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/ogWBynQRt1CbNj-ur86DmjSIGjMd.xml b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/ogWBynQRt1CbNj-ur86DmjSIGjMd.xml new file mode 100644 index 000000000..99772b421 --- /dev/null +++ b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/ogWBynQRt1CbNj-ur86DmjSIGjMd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/ogWBynQRt1CbNj-ur86DmjSIGjMp.xml b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/ogWBynQRt1CbNj-ur86DmjSIGjMp.xml new file mode 100644 index 000000000..5f134fc9c --- /dev/null +++ b/Matlab/resources/project/BYqQwXE0h8PX1pP5w0Coa5hMhtI/ogWBynQRt1CbNj-ur86DmjSIGjMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/-XuwkRLUzaRVPuWpmq98j_hwwjQd.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/-XuwkRLUzaRVPuWpmq98j_hwwjQd.xml new file mode 100644 index 000000000..99772b421 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/-XuwkRLUzaRVPuWpmq98j_hwwjQd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/-XuwkRLUzaRVPuWpmq98j_hwwjQp.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/-XuwkRLUzaRVPuWpmq98j_hwwjQp.xml new file mode 100644 index 000000000..aefc090b3 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/-XuwkRLUzaRVPuWpmq98j_hwwjQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/4il5A8e_hVPFAFwQW-mPEwuLfbQd.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/4il5A8e_hVPFAFwQW-mPEwuLfbQd.xml new file mode 100644 index 000000000..243370a7d --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/4il5A8e_hVPFAFwQW-mPEwuLfbQd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/4il5A8e_hVPFAFwQW-mPEwuLfbQp.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/4il5A8e_hVPFAFwQW-mPEwuLfbQp.xml new file mode 100644 index 000000000..025e7c0db --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/4il5A8e_hVPFAFwQW-mPEwuLfbQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/BYqQwXE0h8PX1pP5w0Coa5hMhtId.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/BYqQwXE0h8PX1pP5w0Coa5hMhtId.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/BYqQwXE0h8PX1pP5w0Coa5hMhtId.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/BYqQwXE0h8PX1pP5w0Coa5hMhtIp.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/BYqQwXE0h8PX1pP5w0Coa5hMhtIp.xml new file mode 100644 index 000000000..597dd163e --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/BYqQwXE0h8PX1pP5w0Coa5hMhtIp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/Fzc1FYnoELvZyuVca5dOrMCSPzAd.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/Fzc1FYnoELvZyuVca5dOrMCSPzAd.xml new file mode 100644 index 000000000..99772b421 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/Fzc1FYnoELvZyuVca5dOrMCSPzAd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/Fzc1FYnoELvZyuVca5dOrMCSPzAp.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/Fzc1FYnoELvZyuVca5dOrMCSPzAp.xml new file mode 100644 index 000000000..aad53d253 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/Fzc1FYnoELvZyuVca5dOrMCSPzAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/PiVxCdyBv25hm58SVzc4G_H6gzYd.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/PiVxCdyBv25hm58SVzc4G_H6gzYd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/PiVxCdyBv25hm58SVzc4G_H6gzYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/PiVxCdyBv25hm58SVzc4G_H6gzYp.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/PiVxCdyBv25hm58SVzc4G_H6gzYp.xml new file mode 100644 index 000000000..212332164 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/PiVxCdyBv25hm58SVzc4G_H6gzYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/co519NwO1ytUNdt1oSEab5W5S9Ud.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/co519NwO1ytUNdt1oSEab5W5S9Ud.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/co519NwO1ytUNdt1oSEab5W5S9Ud.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/co519NwO1ytUNdt1oSEab5W5S9Up.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/co519NwO1ytUNdt1oSEab5W5S9Up.xml new file mode 100644 index 000000000..01cb34e67 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/co519NwO1ytUNdt1oSEab5W5S9Up.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/eBn1bXHzSOlRI4DhozkvabaHhY4d.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/eBn1bXHzSOlRI4DhozkvabaHhY4d.xml new file mode 100644 index 000000000..99772b421 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/eBn1bXHzSOlRI4DhozkvabaHhY4d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/eBn1bXHzSOlRI4DhozkvabaHhY4p.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/eBn1bXHzSOlRI4DhozkvabaHhY4p.xml new file mode 100644 index 000000000..5f831ec40 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/eBn1bXHzSOlRI4DhozkvabaHhY4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/emugXUPK0naI8heZauzQsZEoGj4d.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/emugXUPK0naI8heZauzQsZEoGj4d.xml new file mode 100644 index 000000000..99772b421 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/emugXUPK0naI8heZauzQsZEoGj4d.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/emugXUPK0naI8heZauzQsZEoGj4p.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/emugXUPK0naI8heZauzQsZEoGj4p.xml new file mode 100644 index 000000000..974561e0d --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/emugXUPK0naI8heZauzQsZEoGj4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/j8uRpoP2wt7jVsMB3rwydJ9IVLMd.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/j8uRpoP2wt7jVsMB3rwydJ9IVLMd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/j8uRpoP2wt7jVsMB3rwydJ9IVLMd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/j8uRpoP2wt7jVsMB3rwydJ9IVLMp.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/j8uRpoP2wt7jVsMB3rwydJ9IVLMp.xml new file mode 100644 index 000000000..83ab938d5 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/j8uRpoP2wt7jVsMB3rwydJ9IVLMp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/jLZTG_juXEDB0Agn0V5Gm2Ok-5wd.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/jLZTG_juXEDB0Agn0V5Gm2Ok-5wd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/jLZTG_juXEDB0Agn0V5Gm2Ok-5wd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/jLZTG_juXEDB0Agn0V5Gm2Ok-5wp.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/jLZTG_juXEDB0Agn0V5Gm2Ok-5wp.xml new file mode 100644 index 000000000..097f70807 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/jLZTG_juXEDB0Agn0V5Gm2Ok-5wp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/wLXxHi0kcqiflvVqRxucbuyokXUd.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/wLXxHi0kcqiflvVqRxucbuyokXUd.xml new file mode 100644 index 000000000..99772b421 --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/wLXxHi0kcqiflvVqRxucbuyokXUd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/wLXxHi0kcqiflvVqRxucbuyokXUp.xml b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/wLXxHi0kcqiflvVqRxucbuyokXUp.xml new file mode 100644 index 000000000..b7f08876a --- /dev/null +++ b/Matlab/resources/project/CFKaf7YKwHdsPPwvW_vnk4ozl3Q/wLXxHi0kcqiflvVqRxucbuyokXUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/EN__FUPr3azx4fPdqeZTnLdGh48d.xml b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/EN__FUPr3azx4fPdqeZTnLdGh48d.xml new file mode 100644 index 000000000..a918fda69 --- /dev/null +++ b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/EN__FUPr3azx4fPdqeZTnLdGh48d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/EN__FUPr3azx4fPdqeZTnLdGh48p.xml b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/EN__FUPr3azx4fPdqeZTnLdGh48p.xml new file mode 100644 index 000000000..a0990236d --- /dev/null +++ b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/EN__FUPr3azx4fPdqeZTnLdGh48p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/m7v2-JqJoYIPIW_MnjpP2JKMTSod.xml b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/m7v2-JqJoYIPIW_MnjpP2JKMTSod.xml new file mode 100644 index 000000000..3e076293c --- /dev/null +++ b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/m7v2-JqJoYIPIW_MnjpP2JKMTSod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/m7v2-JqJoYIPIW_MnjpP2JKMTSop.xml b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/m7v2-JqJoYIPIW_MnjpP2JKMTSop.xml new file mode 100644 index 000000000..5c0b38e8c --- /dev/null +++ b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/m7v2-JqJoYIPIW_MnjpP2JKMTSop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/np1LwI4S9X0W-92q6pU0Em0Mf6Ad.xml b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/np1LwI4S9X0W-92q6pU0Em0Mf6Ad.xml new file mode 100644 index 000000000..cdddfcf57 --- /dev/null +++ b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/np1LwI4S9X0W-92q6pU0Em0Mf6Ad.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/np1LwI4S9X0W-92q6pU0Em0Mf6Ap.xml b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/np1LwI4S9X0W-92q6pU0Em0Mf6Ap.xml new file mode 100644 index 000000000..95d5576ab --- /dev/null +++ b/Matlab/resources/project/EEtUlUb-dLAdf0KpMVivaUlztwA/np1LwI4S9X0W-92q6pU0Em0Mf6Ap.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/83iDtJ8FXiSGDPZwaQku-uJuCx0d.xml b/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/83iDtJ8FXiSGDPZwaQku-uJuCx0d.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/83iDtJ8FXiSGDPZwaQku-uJuCx0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/83iDtJ8FXiSGDPZwaQku-uJuCx0p.xml b/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/83iDtJ8FXiSGDPZwaQku-uJuCx0p.xml new file mode 100644 index 000000000..01cb34e67 --- /dev/null +++ b/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/83iDtJ8FXiSGDPZwaQku-uJuCx0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/B1rB-40lxfwYCyJSbpXOTqcXJ5cd.xml b/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/B1rB-40lxfwYCyJSbpXOTqcXJ5cd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/B1rB-40lxfwYCyJSbpXOTqcXJ5cd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/B1rB-40lxfwYCyJSbpXOTqcXJ5cp.xml b/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/B1rB-40lxfwYCyJSbpXOTqcXJ5cp.xml new file mode 100644 index 000000000..2195e9d2c --- /dev/null +++ b/Matlab/resources/project/FVIFMHuse2VWlFgbqX2S_OQzxiU/B1rB-40lxfwYCyJSbpXOTqcXJ5cp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/2XlP1cLgb8QgQBrr0z3zq_kmurEd.xml b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/2XlP1cLgb8QgQBrr0z3zq_kmurEd.xml new file mode 100644 index 000000000..8f602f11b --- /dev/null +++ b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/2XlP1cLgb8QgQBrr0z3zq_kmurEd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/2XlP1cLgb8QgQBrr0z3zq_kmurEp.xml b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/2XlP1cLgb8QgQBrr0z3zq_kmurEp.xml new file mode 100644 index 000000000..f51d5aba5 --- /dev/null +++ b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/2XlP1cLgb8QgQBrr0z3zq_kmurEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/Mc3dms-Rejc-SFnzfpwvfvav6H4d.xml b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/Mc3dms-Rejc-SFnzfpwvfvav6H4d.xml new file mode 100644 index 000000000..79316c3e8 --- /dev/null +++ b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/Mc3dms-Rejc-SFnzfpwvfvav6H4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/Mc3dms-Rejc-SFnzfpwvfvav6H4p.xml b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/Mc3dms-Rejc-SFnzfpwvfvav6H4p.xml new file mode 100644 index 000000000..8935b7994 --- /dev/null +++ b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/Mc3dms-Rejc-SFnzfpwvfvav6H4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/RiyXzo1Mamt5SCJ73bqMCvwz60gd.xml b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/RiyXzo1Mamt5SCJ73bqMCvwz60gd.xml new file mode 100644 index 000000000..7688e416a --- /dev/null +++ b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/RiyXzo1Mamt5SCJ73bqMCvwz60gd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/RiyXzo1Mamt5SCJ73bqMCvwz60gp.xml b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/RiyXzo1Mamt5SCJ73bqMCvwz60gp.xml new file mode 100644 index 000000000..71d5c454d --- /dev/null +++ b/Matlab/resources/project/GrwGVM3WRxpNAyCBDmU4hNqxUOw/RiyXzo1Mamt5SCJ73bqMCvwz60gp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4d.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4d.xml new file mode 100644 index 000000000..6d1c43c94 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4p.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4p.xml new file mode 100644 index 000000000..e993c77c1 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/2kj09UetkV_lru3gvSPXnY6-nM4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml new file mode 100644 index 000000000..d47011f6a --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml new file mode 100644 index 000000000..91b0acc5e --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/KKyDJtbdIBOlaeHmIZd5VX6vqx8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml new file mode 100644 index 000000000..6c16a34c5 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml new file mode 100644 index 000000000..76301e1b2 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/QWNDYJD5mGW1bWYvPx9DtKnxzw4p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Id.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Id.xml new file mode 100644 index 000000000..e228479e6 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Id.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Ip.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Ip.xml new file mode 100644 index 000000000..958c22f23 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/R1RggVhA72agIvELiuhWPRS8F0Ip.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZod.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZod.xml new file mode 100644 index 000000000..b5689bd02 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZod.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZop.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZop.xml new file mode 100644 index 000000000..ffb1fe82a --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/aEHSZBIY-yve10yGis12Zr5DLZop.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencd.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencd.xml new file mode 100644 index 000000000..646977e18 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencp.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencp.xml new file mode 100644 index 000000000..2e052d92e --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/j4xwF_j8iFTVayUMfxLgMnTbencp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml new file mode 100644 index 000000000..c67e56767 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml new file mode 100644 index 000000000..880a24543 --- /dev/null +++ b/Matlab/resources/project/NjSPEMsIuLUyIpr2u1Js5bVPsOs/r8LR4nLmg9ai3oHrW1r_-KocQzkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/Project.xml b/Matlab/resources/project/Project.xml new file mode 100644 index 000000000..62d05aa9a --- /dev/null +++ b/Matlab/resources/project/Project.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/amwE3LmoG--0pRWluRol6WgE4ZY/lmBC8LfYX7EpuYL-T1EededA118d.xml b/Matlab/resources/project/amwE3LmoG--0pRWluRol6WgE4ZY/lmBC8LfYX7EpuYL-T1EededA118d.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/amwE3LmoG--0pRWluRol6WgE4ZY/lmBC8LfYX7EpuYL-T1EededA118d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/amwE3LmoG--0pRWluRol6WgE4ZY/lmBC8LfYX7EpuYL-T1EededA118p.xml b/Matlab/resources/project/amwE3LmoG--0pRWluRol6WgE4ZY/lmBC8LfYX7EpuYL-T1EededA118p.xml new file mode 100644 index 000000000..01cb34e67 --- /dev/null +++ b/Matlab/resources/project/amwE3LmoG--0pRWluRol6WgE4ZY/lmBC8LfYX7EpuYL-T1EededA118p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/GrwGVM3WRxpNAyCBDmU4hNqxUOwd.xml b/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/GrwGVM3WRxpNAyCBDmU4hNqxUOwd.xml new file mode 100644 index 000000000..d09c1be48 --- /dev/null +++ b/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/GrwGVM3WRxpNAyCBDmU4hNqxUOwd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/GrwGVM3WRxpNAyCBDmU4hNqxUOwp.xml b/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/GrwGVM3WRxpNAyCBDmU4hNqxUOwp.xml new file mode 100644 index 000000000..111cde4ec --- /dev/null +++ b/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/GrwGVM3WRxpNAyCBDmU4hNqxUOwp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml b/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml new file mode 100644 index 000000000..5de8c3e00 --- /dev/null +++ b/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml b/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml new file mode 100644 index 000000000..642c7d719 --- /dev/null +++ b/Matlab/resources/project/fjRQtWiSIy7hIlj-Kmk87M7s21k/NjSPEMsIuLUyIpr2u1Js5bVPsOsp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/XTHxbo--gimgNRchYy4CQ2U_YGYd.xml b/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/XTHxbo--gimgNRchYy4CQ2U_YGYd.xml new file mode 100644 index 000000000..856110fcc --- /dev/null +++ b/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/XTHxbo--gimgNRchYy4CQ2U_YGYd.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/XTHxbo--gimgNRchYy4CQ2U_YGYp.xml b/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/XTHxbo--gimgNRchYy4CQ2U_YGYp.xml new file mode 100644 index 000000000..ff14cfe5e --- /dev/null +++ b/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/XTHxbo--gimgNRchYy4CQ2U_YGYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/x4k7alMTwdsYHz1U_oI_m_nEErkd.xml b/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/x4k7alMTwdsYHz1U_oI_m_nEErkd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/x4k7alMTwdsYHz1U_oI_m_nEErkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/x4k7alMTwdsYHz1U_oI_m_nEErkp.xml b/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/x4k7alMTwdsYHz1U_oI_m_nEErkp.xml new file mode 100644 index 000000000..01cb34e67 --- /dev/null +++ b/Matlab/resources/project/j8uRpoP2wt7jVsMB3rwydJ9IVLM/x4k7alMTwdsYHz1U_oI_m_nEErkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/YbTZHLvE3Laj1TfsEIDULy9TLHEd.xml b/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/YbTZHLvE3Laj1TfsEIDULy9TLHEd.xml new file mode 100644 index 000000000..30e591127 --- /dev/null +++ b/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/YbTZHLvE3Laj1TfsEIDULy9TLHEd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/YbTZHLvE3Laj1TfsEIDULy9TLHEp.xml b/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/YbTZHLvE3Laj1TfsEIDULy9TLHEp.xml new file mode 100644 index 000000000..b1034f4d4 --- /dev/null +++ b/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/YbTZHLvE3Laj1TfsEIDULy9TLHEp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/tXw9xNycuLrBgipwxmb43VTl9W0d.xml b/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/tXw9xNycuLrBgipwxmb43VTl9W0d.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/tXw9xNycuLrBgipwxmb43VTl9W0d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/tXw9xNycuLrBgipwxmb43VTl9W0p.xml b/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/tXw9xNycuLrBgipwxmb43VTl9W0p.xml new file mode 100644 index 000000000..01cb34e67 --- /dev/null +++ b/Matlab/resources/project/mVuJOLmLpJ2FxQLNlNz3p3gSIWY/tXw9xNycuLrBgipwxmb43VTl9W0p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/CFKaf7YKwHdsPPwvW_vnk4ozl3Qd.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/CFKaf7YKwHdsPPwvW_vnk4ozl3Qd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/CFKaf7YKwHdsPPwvW_vnk4ozl3Qd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/CFKaf7YKwHdsPPwvW_vnk4ozl3Qp.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/CFKaf7YKwHdsPPwvW_vnk4ozl3Qp.xml new file mode 100644 index 000000000..b8d36f20a --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/CFKaf7YKwHdsPPwvW_vnk4ozl3Qp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/FVIFMHuse2VWlFgbqX2S_OQzxiUd.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/FVIFMHuse2VWlFgbqX2S_OQzxiUd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/FVIFMHuse2VWlFgbqX2S_OQzxiUd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/FVIFMHuse2VWlFgbqX2S_OQzxiUp.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/FVIFMHuse2VWlFgbqX2S_OQzxiUp.xml new file mode 100644 index 000000000..6262f8934 --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/FVIFMHuse2VWlFgbqX2S_OQzxiUp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/MDnWniV77enVhZz9_UXTaL0JBX8d.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/MDnWniV77enVhZz9_UXTaL0JBX8d.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/MDnWniV77enVhZz9_UXTaL0JBX8d.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/MDnWniV77enVhZz9_UXTaL0JBX8p.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/MDnWniV77enVhZz9_UXTaL0JBX8p.xml new file mode 100644 index 000000000..212332164 --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/MDnWniV77enVhZz9_UXTaL0JBX8p.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml new file mode 100644 index 000000000..77329db82 --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/TMK4UzWHdRLhy_w-CHt9y11Q8XAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/dbaDl4AUhYvN4Xb6qgAQ2WDPaAgd.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/dbaDl4AUhYvN4Xb6qgAQ2WDPaAgd.xml new file mode 100644 index 000000000..99772b421 --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/dbaDl4AUhYvN4Xb6qgAQ2WDPaAgd.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/dbaDl4AUhYvN4Xb6qgAQ2WDPaAgp.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/dbaDl4AUhYvN4Xb6qgAQ2WDPaAgp.xml new file mode 100644 index 000000000..bd343b6a8 --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/dbaDl4AUhYvN4Xb6qgAQ2WDPaAgp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/mVuJOLmLpJ2FxQLNlNz3p3gSIWYd.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/mVuJOLmLpJ2FxQLNlNz3p3gSIWYd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/mVuJOLmLpJ2FxQLNlNz3p3gSIWYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/mVuJOLmLpJ2FxQLNlNz3p3gSIWYp.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/mVuJOLmLpJ2FxQLNlNz3p3gSIWYp.xml new file mode 100644 index 000000000..ca5f21ebf --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/mVuJOLmLpJ2FxQLNlNz3p3gSIWYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml new file mode 100644 index 000000000..603491d35 --- /dev/null +++ b/Matlab/resources/project/qaw0eS1zuuY1ar9TdPn1GMfrjbQ/qD-kr16wmwlzR-nIg1IG_vvRrWkp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/root/2GpRyGDE8y_vvldl2K6-wfxxx0Ad.xml b/Matlab/resources/project/root/2GpRyGDE8y_vvldl2K6-wfxxx0Ad.xml new file mode 100644 index 000000000..7cdf3446f --- /dev/null +++ b/Matlab/resources/project/root/2GpRyGDE8y_vvldl2K6-wfxxx0Ad.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/root/2GpRyGDE8y_vvldl2K6-wfxxx0Ap.xml b/Matlab/resources/project/root/2GpRyGDE8y_vvldl2K6-wfxxx0Ap.xml new file mode 100644 index 000000000..c04d0d5b6 --- /dev/null +++ b/Matlab/resources/project/root/2GpRyGDE8y_vvldl2K6-wfxxx0Ap.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml b/Matlab/resources/project/root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml new file mode 100644 index 000000000..fee2cd2cf --- /dev/null +++ b/Matlab/resources/project/root/EEtUlUb-dLAdf0KpMVivaUlztwAp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQd.xml b/Matlab/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQd.xml new file mode 100644 index 000000000..654e73d19 --- /dev/null +++ b/Matlab/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQp.xml b/Matlab/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQp.xml new file mode 100644 index 000000000..2037c3329 --- /dev/null +++ b/Matlab/resources/project/root/GiiBklLgTxteCEmomM8RCvWT0nQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/root/amwE3LmoG--0pRWluRol6WgE4ZYd.xml b/Matlab/resources/project/root/amwE3LmoG--0pRWluRol6WgE4ZYd.xml new file mode 100644 index 000000000..e2f6de086 --- /dev/null +++ b/Matlab/resources/project/root/amwE3LmoG--0pRWluRol6WgE4ZYd.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/root/amwE3LmoG--0pRWluRol6WgE4ZYp.xml b/Matlab/resources/project/root/amwE3LmoG--0pRWluRol6WgE4ZYp.xml new file mode 100644 index 000000000..4ad31d17d --- /dev/null +++ b/Matlab/resources/project/root/amwE3LmoG--0pRWluRol6WgE4ZYp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/root/fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml b/Matlab/resources/project/root/fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml new file mode 100644 index 000000000..a4de013b9 --- /dev/null +++ b/Matlab/resources/project/root/fjRQtWiSIy7hIlj-Kmk87M7s21kp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/root/qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml b/Matlab/resources/project/root/qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml new file mode 100644 index 000000000..8b0d33670 --- /dev/null +++ b/Matlab/resources/project/root/qaw0eS1zuuY1ar9TdPn1GMfrjbQp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/project/rootp.xml b/Matlab/resources/project/rootp.xml new file mode 100644 index 000000000..4356a6aee --- /dev/null +++ b/Matlab/resources/project/rootp.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Matlab/resources/thumbnail_matlab.png b/Matlab/resources/thumbnail_matlab.png new file mode 100644 index 000000000..caf44d39d Binary files /dev/null and b/Matlab/resources/thumbnail_matlab.png differ diff --git a/Matlab/toolbox.ignore b/Matlab/toolbox.ignore new file mode 100644 index 000000000..d2bbfc48c --- /dev/null +++ b/Matlab/toolbox.ignore @@ -0,0 +1,42 @@ +# Copyright 2024-2025 The MathWorks, Inc. +% TOOLBOX IGNORE FILE +% Specify the files/folder to exclude from packaging. +% Paths are relative to the toolbox root folder. +% List only one exclusion per line. + +% EXAMPLES +% folder/ - Exclude folder and all of its content +% folder/* - Exclude contents of folder +% folder/** - Exclude all contents of folder and subfolders +% *.extension - Exclude files with extension in folder +% **/*.extension - Exclude all files with extension in folder and all subfolders +% file.extension - Exclude specific file +% folder/file.extension - Exclude specific file in a subfolder +% **/file.extension - Exclude specific file in all subfolders + +% Notes: +% - If a path starts with '%', include '\' before '%', for example, "\%examplefile.svn". +% - This file, 'toolbox.ignore', is always excluded from the toolbox and including it is not supported. + +%% Recommended Exclusions (remove lines to re-include files): + +% Exclude source control files +**/.git* +**/.git/ +**/*.svn + +% Toolbox files and project files +**/*.mltbx +**/*.prj + +% Backup files +**/*.asv +**/*.m~ +**/*.prj.bak + +% Local MATLAB/Simulink tool caches +**/slprj +**/.buildtool/ + +% Project resources folder +resources/ \ No newline at end of file diff --git a/Matlab/AirSimCameraTypes.m b/Matlab/toolbox/AirSimCameraTypes.m similarity index 100% rename from Matlab/AirSimCameraTypes.m rename to Matlab/toolbox/AirSimCameraTypes.m diff --git a/Matlab/AirSimClient.m b/Matlab/toolbox/AirSimClient.m similarity index 100% rename from Matlab/AirSimClient.m rename to Matlab/toolbox/AirSimClient.m diff --git a/Matlab/AirSimDrivetrainTypes.m b/Matlab/toolbox/AirSimDrivetrainTypes.m similarity index 100% rename from Matlab/AirSimDrivetrainTypes.m rename to Matlab/toolbox/AirSimDrivetrainTypes.m diff --git a/Matlab/AirSimGenerateColorMap.m b/Matlab/toolbox/AirSimGenerateColorMap.m similarity index 100% rename from Matlab/AirSimGenerateColorMap.m rename to Matlab/toolbox/AirSimGenerateColorMap.m diff --git a/Matlab/AirSimWeather.m b/Matlab/toolbox/AirSimWeather.m similarity index 100% rename from Matlab/AirSimWeather.m rename to Matlab/toolbox/AirSimWeather.m diff --git a/Matlab/colormap.csv b/Matlab/toolbox/colormap.csv similarity index 100% rename from Matlab/colormap.csv rename to Matlab/toolbox/colormap.csv diff --git a/Matlab/toolbox/doc/GettingStarted.mlx b/Matlab/toolbox/doc/GettingStarted.mlx new file mode 100644 index 000000000..ce91c4353 Binary files /dev/null and b/Matlab/toolbox/doc/GettingStarted.mlx differ diff --git a/Matlab/toolbox/doc/html/GettingStarted.html b/Matlab/toolbox/doc/html/GettingStarted.html new file mode 100644 index 000000000..d1c2e0652 --- /dev/null +++ b/Matlab/toolbox/doc/html/GettingStarted.html @@ -0,0 +1,361 @@ + +Cosys-AirSim Matlab Client

Cosys-AirSim Matlab Client

This a client implementation of the RPC API for Matlab for the Cosys-AirSim simulation framework. A main class AirSimClient is available which implements all API calls.
Do note that at this point not all functions have been tested and most function documentation was auto-generated. This is still a WIP client.

Dependencies

  • MATLAB 2024a or higher with the associated supported Python version, 3.7 or higher with the Cosys-AirSim python module.
  • Computer Vision, Aerospace, Signal Processing Toolboxes
You can install the Cosys-AirSim Python client from pip (not from matlab console but with terminal/powershell/bash):
pip install cosysairsim

Usage

Configure Python for MATLAB

First you need to correctly link your installed Python installation to MATLAB, as by default this isn't always the latest version of Python 3 you installed. You can verify which Python is linked by running:
pe = pyenv;
pe.Version
If this is not a version that you which to use you can alter this manually. Do note that you need to do this everytime before using the client! Once Python is loaded in matlab, you need to restart MATLAB first before changing it. Therefore, running the commands above will likely mean requiring a restart of MATLAB.
For Windows you can run for example:
pyenv('Version','your.version')
With 'your.version' indicating the 'major.minor' version number of you Python release, for example '3.6'.
On linux you need to refer to the path of your Python 3 installation,, for example:
pyenv('Version',"/usr/bin/python3")
You can also link to specific Python versions by altering the path.
Some more information can be found here.

Initial setup

When starting with this wrapper, first try to make a connection to the Cosys-AirSim simulation.
vehicle_name = "airsimvehicle";
airSimClient = AirSimClient(IsDrone=false, IP="127.0.0.1", port=41451);
Now the client object can be used to run API methods from. All functions have some help text written for more information on them.

Example

This example works well with the default example settings found in the docs folder op the Cosys-AirSim repository.
This example will:
  • Connect to AirSim
  • Get/set vehicle pose
  • Get instance segmentation groundtruth table
  • Get object pose(s)
  • Get sensor data (imu, echo (active/passive), (gpu)LiDAR, camera (info, rgb, depth, segmentation, annotation))
Do note that the AirSim matlab client has almost all API functions available but not all are listed in this test script. For a full list see the source code fo the AirSimClient class.
Do note the test script requires next to the toolboxes listed above in the Prerequisites the following Matlab toolboxes:
  • Lidar Toolbox
  • Navigation Toolbox
  • Robotics System Toolbox
  • ROS Toolbox
  • UAV Toolbox

Setup connection

 
%Define client
vehicle_name = "airsimvehicle";
airSimClient = AirSimClient(IsDrone=false, IP="127.0.0.1", port=41451);
 

Groundtruth labels

% Get groundtruth look-up-table of all objects and their instance
% segmentation colors for the cameras and GPU LiDAR
groundtruthLUT = airSimClient.getInstanceSegmentationLUT();
 

Get some poses

% All poses are right handed coordinate system X Y Z and
% orientations are defined as quaternions W X Y Z.
 
% Get poses of all objects in the scene, this takes a while for large
% scene so it is in comment by default
poses = airSimClient.getAllObjectPoses(false, false);
 
% Get vehicle pose
vehiclePoseLocal = airSimClient.getVehiclePose(vehicle_name);
vehiclePoseWorld = airSimClient.getObjectPose(vehicle_name, false);
 
% Choose the object to get the pose from (this one is in the Blocks env)
chosenObject = "Cylinder3";
 
% Get its pose
objectPoseLocal = airSimClient.getObjectPose(chosenObject, true);
objectPoseWorld = airSimClient.getObjectPose(chosenObject, false);
 
figure;
subplot(1, 2, 1);
plotTransforms([vehiclePoseLocal.position; objectPoseLocal.position], [vehiclePoseLocal.orientation; objectPoseLocal.orientation], FrameLabel=["Vehicle"; chosenObject], AxisLabels="on")
axis equal;
grid on;
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
title("Local Plot")
 
subplot(1, 2, 2);
plotTransforms([vehiclePoseWorld.position; objectPoseWorld.position], [vehiclePoseWorld.orientation; objectPoseWorld.orientation], FrameLabel=["Vehicle"; chosenObject], AxisLabels="on")
 
axis equal;
grid on;
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
title("World Plot")
drawnow
 
% Set vehicle pose
airSimClient.setVehiclePose(airSimClient.getVehiclePose(vehicle_name).position + [1 1 0], airSimClient.getVehiclePose(vehicle_name).orientation, true, vehicle_name)
 

IMU sensor Data

 
imuSensorName = "imu";
[imuData, imuTimestamp] = airSimClient.getIMUData(imuSensorName, vehicle_name)
 

Echo sensor data

% Example plots passive echo pointcloud
% and its reflection directions as 3D quivers
 
echoSensorName = "echo";
enablePassive = true;
[activePointCloud, activeData, passivePointCloud, passiveData , echoTimestamp, echoSensorPose] = airSimClient.getEchoData(echoSensorName, enablePassive, vehicle_name);
 
figure;
subplot(1, 2, 1);
if ~isempty(activePointCloud)
pcshow(activePointCloud, color="X", MarkerSize=50);
else
pcshow(pointCloud([0, 0, 0]));
end
title('Active Echo Sensor Pointcloud')
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
xlim([0 10])
ylim([-10 10])
zlim([-10 10])
 
subplot(1, 2, 2);
if ~isempty(passivePointCloud)
pcshow(passivePointCloud, color="X", MarkerSize=50);
hold on;
quiver3(passivePointCloud.Location(:, 1), passivePointCloud.Location(:, 2), passivePointCloud.Location(:, 3),...
passivePointCloud.Normal(:, 1), passivePointCloud.Normal(:, 2), passivePointCloud.Normal(:, 3), 2);
hold off
else
pcshow(pointCloud([0, 0, 0]));
end
title('Passive Echo Sensor Pointcloud')
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
xlim([0 10])
ylim([-10 10])
zlim([-10 10])
drawnow
 

LiDAR sensor data

% Example plots lidar pointcloud and getting the groundtruth labels
 
lidarSensorName = "lidar";
enableLabels = true;
[lidarPointCloud, lidarLabels, LidarTimestamp, LidarSensorPose] = airSimClient.getLidarData(lidarSensorName, enableLabels, vehicle_name);
 
figure;
if ~isempty(lidarPointCloud)
pcshow(lidarPointCloud, MarkerSize=50);
else
pcshow(pointCloud([0, 0, 0]));
end
title('LiDAR Pointcloud')
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
xlim([0 10])
ylim([-10 10])
zlim([-10 10])
drawnow
 

GPU LiDAR sensor data

% Example plots GPU lidar pointcloud with its RGB segmentation colors
 
gpuLidarSensorName = "gpulidar";
enableLabels = true;
[gpuLidarPointCloud, gpuLidarTimestamp, gpuLidarSensorPose] = airSimClient.getGPULidarData(gpuLidarSensorName, vehicle_name);
 
figure;
if ~isempty(gpuLidarPointCloud)
pcshow(gpuLidarPointCloud, MarkerSize=50);
else
pcshow(pointCloud([0, 0, 0]));
end
title('GPU-Accelerated LiDAR Pointcloud')
xlabel("X (m)")
ylabel("Y (m)")
zlabel("Z (m)")
xlim([0 10])
ylim([-10 10])
zlim([-10 10])
drawnow
 

Cameras

 
%% Get camera info
cameraSensorName = "frontcamera";
[intrinsics, cameraSensorPose] = airSimClient.getCameraInfo(cameraSensorName, vehicle_name);
 
%% Get single camera images
% Get images sequentially
 
cameraSensorName = "front_center";
[rgbImage, rgbCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Scene, vehicle_name);
[segmentationImage, segmentationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Segmentation,vehicle_name);
[depthImage, depthCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.DepthPlanar,vehicle_name);
figure;
subplot(3, 1, 1);
imshow(rgbImage)
title("RGB Camera Image")
subplot(3, 1, 2);
imshow(segmentationImage)
title("Segmentation Camera Image")
subplot(3, 1, 3);
imshow(depthImage ./ max(max(depthImage)).* 255, gray)
title("Depth Camera Image")
drawnow
 
 
%% Get synced camera images
% By combining the image requests they will be synced
% and taken in the same frame
 
cameraSensorName = "front_center";
[images, cameraIimestamp] = airSimClient.getCameraImages(cameraSensorName, ...
[AirSimCameraTypes.Scene, AirSimCameraTypes.Segmentation, AirSimCameraTypes.DepthPlanar], ...
vehicle_name, ["", "", ""]);
figure;
subplot(3, 1, 1);
imshow(images{1})
title("Synced RGB Camera Image")
subplot(3, 1, 2);
imshow(images{2})
title("Synced Segmentation Camera Image")
subplot(3, 1, 3);
imshow(images{3} ./ max(max(images{3})).* 255, gray)
title("Synced Depth Camera Image")
drawnow

Example Two Drones

This example works well with the settings file as in the comments below:
{
"SeeDocsAt": "https://cosys-lab.github.io/settings/",
"SettingsVersion": 2,
"ClockSpeed": 1,
"LocalHostIp": "127.0.0.1",
"ApiServerPort": 41451,
"RpcEnabled": true,
"SimMode": "Multirotor",
"Vehicles": {
"Drone1": {
"VehicleType": "SimpleFlight",
"AllowAPIAlways": true,
"X": 0,
"Y": 0,
"Z": 0,
"Yaw": 0
},
"Drone2": {
"VehicleType": "SimpleFlight",
"AllowAPIAlways": true,
"X": 5,
"Y": 0,
"Z": 0,
"Yaw": 0
}
}
}
airSimClient = AirSimClient(IsDrone=true, IP="127.0.0.1", port=41451);
 
airSimClient.setEnableApiControl("Drone1");
airSimClient.setEnableApiControl("Drone2");
 
airSimClient.setEnableDroneArm("Drone1");
airSimClient.setEnableDroneArm("Drone2");
 
airSimClient.takeoffAsync("Drone1", 20, true);
airSimClient.takeoffAsync("Drone2", 20, false);
 
airSimClient.moveToPositionAsync(10, 10, -5, 5, 3e+38, AirSimDrivetrainTypes.MaxDegreeOfFreedom, true, 0, -1, 1, "Drone1", true);
airSimClient.moveToPositionAsync(10, 14, -5, 5, 3e+38, AirSimDrivetrainTypes.MaxDegreeOfFreedom, true, 0, -1, 1, "Drone2", true);
 
airSimClient.landAsync("Drone1", 60, true);
airSimClient.landAsync("Drone2", 60, false);
 
airSimClient.setDisableDroneArm("Drone1");
airSimClient.setDisableDroneArm("Drone2");
 
airSimClient.setDisableApiControl("Drone1");
airSimClient.setDisableApiControl("Drone2");
+
+ +
\ No newline at end of file diff --git a/Matlab/example.m b/Matlab/toolbox/examples/example.m similarity index 90% rename from Matlab/example.m rename to Matlab/toolbox/examples/example.m index a5f54c404..4f5b6b87c 100644 --- a/Matlab/example.m +++ b/Matlab/toolbox/examples/example.m @@ -51,7 +51,7 @@ figure; subplot(1, 2, 1); -plotTransforms([vehiclePoseLocal.position; objectPoseLocal.position], [vehiclePoseLocal.orientation; objectPoseLocal.orientation], FrameLabel=["Vehicle"; finalName], AxisLabels="on") +plotTransforms([vehiclePoseLocal.position; objectPoseLocal.position], [vehiclePoseLocal.orientation; objectPoseLocal.orientation], FrameLabel=["Vehicle"; chosenObject], AxisLabels="on") axis equal; grid on; xlabel("X (m)") @@ -60,7 +60,7 @@ title("Local Plot") subplot(1, 2, 2); -plotTransforms([vehiclePoseWorld.position; objectPoseWorld.position], [vehiclePoseWorld.orientation; objectPoseWorld.orientation], FrameLabel=["Vehicle"; finalName], AxisLabels="on") +plotTransforms([vehiclePoseWorld.position; objectPoseWorld.position], [vehiclePoseWorld.orientation; objectPoseWorld.orientation], FrameLabel=["Vehicle"; chosenObject], AxisLabels="on") axis equal; grid on; @@ -71,7 +71,7 @@ drawnow % Set vehicle pose -airSimClient.setVehiclePose(airSimClient.getVehiclePose(vehicle_name).position + [1 1 0], airSimClient.getVehiclePose(vehicle_name).orientation, false, vehicle_name) +airSimClient.setVehiclePose(airSimClient.getVehiclePose(vehicle_name).position + [1 1 0], airSimClient.getVehiclePose(vehicle_name).orientation, true, vehicle_name) %% IMU sensor Data imuSensorName = "imu"; @@ -175,20 +175,16 @@ [rgbImage, rgbCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Scene, vehicle_name); [segmentationImage, segmentationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Segmentation,vehicle_name); [depthImage, depthCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.DepthPlanar,vehicle_name); -[annotationImage, annotationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Annotation, vehicle_name, "TextureTestDirect"); figure; -subplot(4, 1, 1); +subplot(3, 1, 1); imshow(rgbImage) title("RGB Camera Image") -subplot(4, 1, 2); +subplot(3, 1, 2); imshow(segmentationImage) title("Segmentation Camera Image") -subplot(4, 1, 3); +subplot(3, 1, 3); imshow(depthImage ./ max(max(depthImage)).* 255, gray) title("Depth Camera Image") -subplot(4, 1, 4); -imshow(annotationImage) -title("Annotation Camera Image") drawnow %% Get synced camera images @@ -196,19 +192,16 @@ cameraSensorName = "front_center"; [images, cameraIimestamp] = airSimClient.getCameraImages(cameraSensorName, ... - [AirSimCameraTypes.Scene, AirSimCameraTypes.Segmentation, AirSimCameraTypes.DepthPlanar, AirSimCameraTypes.Annotation], ... - vehicle_name, ["", "", "", "TextureTestDirect"]); + [AirSimCameraTypes.Scene, AirSimCameraTypes.Segmentation, AirSimCameraTypes.DepthPlanar], ... + vehicle_name, ["", "", ""]); figure; -subplot(4, 1, 1); +subplot(3, 1, 1); imshow(images{1}) title("Synced RGB Camera Image") -subplot(4, 1, 2); +subplot(3, 1, 2); imshow(images{2}) title("Synced Segmentation Camera Image") -subplot(4, 1, 3); +subplot(3, 1, 3); imshow(images{3} ./ max(max(images{3})).* 255, gray) title("Synced Depth Camera Image") -subplot(4, 1, 4); -imshow(images{4}) -title("Synced Annotation Camera Image") drawnow \ No newline at end of file diff --git a/Matlab/example_twodrones.m b/Matlab/toolbox/examples/example_twodrones.m similarity index 100% rename from Matlab/example_twodrones.m rename to Matlab/toolbox/examples/example_twodrones.m diff --git a/Matlab/info.xml b/Matlab/toolbox/info.xml similarity index 100% rename from Matlab/info.xml rename to Matlab/toolbox/info.xml diff --git a/Matlab/toolbox/toolbox.ignore b/Matlab/toolbox/toolbox.ignore new file mode 100644 index 000000000..09d094cb3 --- /dev/null +++ b/Matlab/toolbox/toolbox.ignore @@ -0,0 +1,39 @@ +# Copyright 2024-2025 The MathWorks, Inc. +% TOOLBOX IGNORE FILE +% Specify the files/folder to exclude from packaging. +% Paths are relative to the toolbox root folder. +% List only one exclusion per line. + +% EXAMPLES +% folder/ - Exclude folder and all of its content +% folder/* - Exclude contents of folder +% folder/** - Exclude all contents of folder and subfolders +% *.extension - Exclude files with extension in folder +% **/*.extension - Exclude all files with extension in folder and all subfolders +% file.extension - Exclude specific file +% folder/file.extension - Exclude specific file in a subfolder +% **/file.extension - Exclude specific file in all subfolders + +% Notes: +% - If a path starts with '%', include '\' before '%', for example, "\%examplefile.svn". +% - This file, 'toolbox.ignore', is always excluded from the toolbox and including it is not supported. + +%% Recommended Exclusions (remove lines to re-include files): + +% Exclude source control files +**/.git* +**/.git/ +**/*.svn + +% Toolbox files and project files +**/*.mltbx +**/*.prj + +% Backup files +**/*.asv +**/*.m~ +**/*.prj.bak + +% Local MATLAB/Simulink tool caches +**/slprj +**/.buildtool/ diff --git a/MavLinkCom/MavLinkTest/UnitTests.cpp b/MavLinkCom/MavLinkTest/UnitTests.cpp index dcbc59cd4..1b6f7ab36 100644 --- a/MavLinkCom/MavLinkTest/UnitTests.cpp +++ b/MavLinkCom/MavLinkTest/UnitTests.cpp @@ -134,7 +134,7 @@ void UnitTests::SerialPx4Test() int count = 0; Semaphore received; - auto id = connection->subscribe([&](std::shared_ptr con, const MavLinkMessage& msg) { + auto id = connection->subscribe([&](std::shared_ptr /*con*/, const MavLinkMessage& msg) { //printf(" Received message %d\n", static_cast(msg.msgid)); count++; if (msg.msgid == 0) { @@ -411,7 +411,7 @@ void UnitTests::JSonLogTest() int count = 0; Semaphore received; - auto id = connection->subscribe([&](std::shared_ptr con, const MavLinkMessage& msg) { + auto id = connection->subscribe([&](std::shared_ptr /*con*/, const MavLinkMessage& msg) { count++; log.write(msg); if (count > 50) { diff --git a/PythonClient/car/lights_test.py b/PythonClient/car/lights_test.py new file mode 100644 index 000000000..45613ffc9 --- /dev/null +++ b/PythonClient/car/lights_test.py @@ -0,0 +1,25 @@ +import cosysairsim as airsim +import time + +client = airsim.CarClient() +client.confirmConnection() + +client.simSetWorldLightIntensity("worldlight1", 4) +time.sleep(5) +client.simSetWorldLightIntensity("worldlight1", 16) +time.sleep(5) +client.simSetWorldLightVisibility("worldlight1", False) +time.sleep(5) +client.simSetWorldLightVisibility("worldlight1", True) + +time.sleep(5) + +client.simSetVehicleLightIntensity("airsimvehicle", "vehiclelight1", 4) +time.sleep(5) +client.simSetVehicleLightIntensity("airsimvehicle", "vehiclelight1", 16) +time.sleep(5) +client.simSetVehicleLightVisibility("airsimvehicle", "vehiclelight1", False) +time.sleep(5) +client.simSetVehicleLightVisibility("airsimvehicle", "vehiclelight1", True) + +print("done") diff --git a/PythonClient/cosysairsim/__init__.py b/PythonClient/cosysairsim/__init__.py index 5f6f05464..b759d0dc2 100644 --- a/PythonClient/cosysairsim/__init__.py +++ b/PythonClient/cosysairsim/__init__.py @@ -2,4 +2,4 @@ from .utils import * from .types import * -__version__ = "3.3.0" +__version__ = "3.4.0" diff --git a/PythonClient/imitation_learning/README.md b/PythonClient/imitation_learning/README.md index 6379ba3e8..7550cc3d9 100644 --- a/PythonClient/imitation_learning/README.md +++ b/PythonClient/imitation_learning/README.md @@ -6,7 +6,7 @@ The code in this section is based on the [Autonomous Driving Cookbook](https://g ## Prerequisites * Operating system: Windows 10 * GPU: Nvidia GTX 1080 or higher (recommended) -* Software: Unreal Engine 5.2.1 and Visual Studio 2022 +* Software: Unreal Engine 5.8 and Visual Studio 2022 * Development: CUDA 9.0 and python 3.5. * Python libraries: Keras 2.1.2, TensorFlow 1.6.0. * Note: Newer versions of keras or tensorflow are recommended but can cause syntax errors. diff --git a/PythonClient/pyproject.toml b/PythonClient/pyproject.toml index b2f1b61de..7fae18745 100644 --- a/PythonClient/pyproject.toml +++ b/PythonClient/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "cosysairsim" -version = "3.3.0" +version = "3.4.0" description = "This package contains simple Python client for Cosys-AirSim. This integrates most API functions over RPC." readme = {file = "README.md", content-type = "text/markdown"} authors = [{ name = "Shital Shah", email = "shitals@microsoft.com" }, diff --git a/PythonClient/segmentation/lighting_camera_test.py b/PythonClient/segmentation/lighting_camera_test.py new file mode 100644 index 000000000..7068c9589 --- /dev/null +++ b/PythonClient/segmentation/lighting_camera_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +import setup_path +import cosysairsim as airsim +import csv +import random +import numpy as np +from PIL import Image +from datetime import datetime +import matplotlib.pyplot as plt + + +if __name__ == '__main__': + + client = airsim.CarClient() + client.confirmConnection() + + responses = client.simGetImages([airsim.ImageRequest( "frontcamera", airsim.ImageType.Scene, False, False)]) + img_rgb_string = responses[0].image_data_uint8 + rgbarray = np.frombuffer(img_rgb_string, np.uint8) + rgbarray_shaped = rgbarray.reshape((540,960,3)) + # img = Image.fromarray(rgbarray_shaped, 'RGB') + # img.show() + + # 3. Create Figure and Subplots using Matplotlib + fig, axes = plt.subplots(1, 2, figsize=(15, 6)) # 1 row, 2 columns. Adjust figsize as needed. + + # Plot Scene Image + axes[0].imshow(rgbarray_shaped) + axes[0].set_title('Scene') + axes[0].axis('off') # Hide axes ticks and labels + + + responses = client.simGetImages([airsim.ImageRequest( "frontcamera", airsim.ImageType.Lighting, False, False)]) + img_rgb_string = responses[0].image_data_uint8 + rgbarray = np.frombuffer(img_rgb_string, np.uint8) + rgbarray_shaped = rgbarray.reshape((540,960,3)) + # img = Image.fromarray(rgbarray_shaped, 'RGB') + # img.show() + + + # Plot Lighting Image + axes[1].imshow(rgbarray_shaped) + axes[1].set_title('Lightning') # Changed from "Lighting" based on your prompt title request + axes[1].axis('off') # Hide axes ticks and labels + + # Adjust layout to prevent titles overlapping + plt.tight_layout() + + # Show the combined plot + plt.show() + + + diff --git a/README.md b/README.md index f0804bd5c..5d679aa19 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ Please note that we use that same [MIT license](https://github.com/Cosys-Lab/Cos Do note that this repository is provided as is, will not be actively updated and comes without warranty or support. Please contact a Cosys-Lab researcher to get more in depth information on which branch or version is best for your work. -This [main branch](https://github.com/Cosys-Lab/Cosys-AirSim/tree/main) is for the latest supported Unreal Version v5.5, maintained for support, and is available for builds in the [releases](https://github.com/Cosys-Lab/Cosys-AirSim/releases). -Unreal [5.2.1](https://github.com/Cosys-Lab/Cosys-AirSim/tree/5.2.1) is also available for long term support builds. +This [main branch](https://github.com/Cosys-Lab/Cosys-AirSim/tree/main) is for the latest supported Unreal Version v5.8, maintained for support, and is available for builds in the [releases](https://github.com/Cosys-Lab/Cosys-AirSim/releases). +Unreal [5.2.1](https://github.com/Cosys-Lab/Cosys-AirSim/tree/5.2.1) is also available for long term support. ## Associated publications @@ -22,10 +22,6 @@ Unreal [5.2.1](https://github.com/Cosys-Lab/Cosys-AirSim/tree/5.2.1) is also ava booktitle={2023 Annual Modeling and Simulation Conference (ANNSIM)}, title={COSYS-AIRSIM: A Real-Time Simulation Framework Expanded for Complex Industrial Applications}, year={2023}, - volume={}, - number={}, - pages={37-48}, - keywords={Industries;Simultaneous localization and mapping;Machine learning algorithms;Atmospheric modeling;Transfer learning;Sensor systems and applications;Real-time systems;sensors;procedural generation;digital twins;transfer learning;open-source}, doi={https://doi.org/10.48550/arXiv.2303.13381}} ``` @@ -39,8 +35,6 @@ You can also find the presentation of the live tutorial of Cosys-AirSim at ANNSI booktitle={2022 IEEE Sensors}, title={Physical LiDAR Simulation in Real-Time Engine}, year={2022}, - volume={}, - number={}, pages={1-4}, doi={10.1109/SENSORS52175.2022.9967197}} } @@ -77,7 +71,7 @@ You can also find the presentation of the live tutorial of Cosys-AirSim at ANNSI * Updated sensors like cameras, Echo sensor and GPU-LiDAR to ignore certain objects with the _MarkedIgnore_ Unreal tag and enabling the "IgnoreMarked" setting in [the settings file](https://cosys-lab.github.io/Cosys-AirSim/settings). * Updated cameras sensor with more distortion features such as chromatic aberration, motion blur and lens distortion. * Updated Python [ROS implementation](https://cosys-lab.github.io/Cosys-AirSim/ros_python) with completely new implementation and feature set. -* Updated C++ [ROS2 implementation](https://cosys-lab.github.io/Cosys-AirSim/ros_cplusplus) to support custom Cosys-AirSim features. +* Updated C++ [ROS2 implementation](https://cosys-lab.github.io/Cosys-AirSim/ros2) to support custom Cosys-AirSim features. * Dropped support for Unity Environments. Some more details on our changes can be found in the [changelog](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/CHANGELOG.md). diff --git a/Unreal/Environments/Blocks/Blocks.code-workspace b/Unreal/Environments/Blocks/Blocks.code-workspace deleted file mode 100644 index 97b4057b0..000000000 --- a/Unreal/Environments/Blocks/Blocks.code-workspace +++ /dev/null @@ -1,50 +0,0 @@ -{ - "folders": [ - { - "path": "." - }, - { - "path": "/home/girmi/opt/UnrealEngine" - } - ], - "settings": { - "typescript.tsc.autoDetect": "off", - "files.associations": { - "*.launch": "xml", - "*.machine": "xml", - "cctype": "cpp", - "clocale": "cpp", - "cmath": "cpp", - "cstdarg": "cpp", - "cstddef": "cpp", - "cstdio": "cpp", - "cstdlib": "cpp", - "cstring": "cpp", - "ctime": "cpp", - "cwchar": "cpp", - "cwctype": "cpp", - "atomic": "cpp", - "hash_map": "cpp", - "strstream": "cpp", - "*.tcc": "cpp", - "chrono": "cpp", - "cinttypes": "cpp", - "codecvt": "cpp", - "condition_variable": "cpp", - "cstdint": "cpp", - "forward_list": "cpp", - "optional": "cpp", - "string_view": "cpp", - "slist": "cpp", - "future": "cpp", - "initializer_list": "cpp", - "iosfwd": "cpp", - "mutex": "cpp", - "ratio": "cpp", - "system_error": "cpp", - "thread": "cpp", - "typeindex": "cpp", - "algorithm": "cpp" - } - } -} diff --git a/Unreal/Environments/Blocks/Blocks.uproject b/Unreal/Environments/Blocks/Blocks.uproject index 871dc2248..711324add 100644 --- a/Unreal/Environments/Blocks/Blocks.uproject +++ b/Unreal/Environments/Blocks/Blocks.uproject @@ -1,6 +1,6 @@ { "FileVersion": 3, - "EngineAssociation": "5.4", + "EngineAssociation": "5.8", "Category": "", "Description": "", "Modules": [ diff --git a/Unreal/Environments/Blocks/Config/DefaultEditor.ini b/Unreal/Environments/Blocks/Config/DefaultEditor.ini index f44257a4d..18b0921a3 100644 --- a/Unreal/Environments/Blocks/Config/DefaultEditor.ini +++ b/Unreal/Environments/Blocks/Config/DefaultEditor.ini @@ -8,4 +8,7 @@ bDontLoadBlueprintOutsideEditor= true bBlueprintIsNotBlueprintType= true [/Script/AdvancedPreviewScene.SharedProfiles] ++Profiles=(ProfileName="Epic Headquarters",bSharedProfile=True,bIsEngineDefaultProfile=True,bUseSkyLighting=True,DirectionalLightIntensity=1.000000,DirectionalLightColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SkyLightIntensity=1.000000,bRotateLightingRig=False,bShowEnvironment=True,bShowFloor=True,bShowGrid=False,EnvironmentColor=(R=0.200000,G=0.200000,B=0.200000,A=1.000000),EnvironmentIntensity=1.000000,EnvironmentCubeMapPath="/Engine/EditorMaterials/AssetViewer/EpicQuadPanorama_CC+EV1.EpicQuadPanorama_CC+EV1",bPostProcessingEnabled=True,PostProcessingSettings=(bOverride_TemperatureType=False,bOverride_WhiteTemp=False,bOverride_WhiteTint=False,bOverride_ColorSaturation=False,bOverride_ColorContrast=False,bOverride_ColorGamma=False,bOverride_ColorGain=False,bOverride_ColorOffset=False,bOverride_ColorSaturationShadows=False,bOverride_ColorContrastShadows=False,bOverride_ColorGammaShadows=False,bOverride_ColorGainShadows=False,bOverride_ColorOffsetShadows=False,bOverride_ColorSaturationMidtones=False,bOverride_ColorContrastMidtones=False,bOverride_ColorGammaMidtones=False,bOverride_ColorGainMidtones=False,bOverride_ColorOffsetMidtones=False,bOverride_ColorSaturationHighlights=False,bOverride_ColorContrastHighlights=False,bOverride_ColorGammaHighlights=False,bOverride_ColorGainHighlights=False,bOverride_ColorOffsetHighlights=False,bOverride_ColorCorrectionShadowsMax=False,bOverride_ColorCorrectionHighlightsMin=False,bOverride_ColorCorrectionHighlightsMax=False,bOverride_BlueCorrection=False,bOverride_ExpandGamut=False,bOverride_ToneCurveAmount=False,bOverride_FilmSlope=False,bOverride_FilmToe=False,bOverride_FilmShoulder=False,bOverride_FilmBlackClip=False,bOverride_FilmWhiteClip=False,bOverride_SceneColorTint=False,bOverride_SceneFringeIntensity=False,bOverride_ChromaticAberrationStartOffset=False,bOverride_bMegaLights=False,bOverride_AmbientCubemapTint=False,bOverride_AmbientCubemapIntensity=False,bOverride_BloomMethod=False,bOverride_BloomIntensity=False,bOverride_BloomGaussianIntensity=False,bOverride_BloomThreshold=False,bOverride_Bloom1Tint=False,bOverride_Bloom1Size=False,bOverride_Bloom2Size=False,bOverride_Bloom2Tint=False,bOverride_Bloom3Tint=False,bOverride_Bloom3Size=False,bOverride_Bloom4Tint=False,bOverride_Bloom4Size=False,bOverride_Bloom5Tint=False,bOverride_Bloom5Size=False,bOverride_Bloom6Tint=False,bOverride_Bloom6Size=False,bOverride_BloomSizeScale=False,bOverride_BloomConvolutionIntensity=False,bOverride_BloomConvolutionTexture=False,bOverride_BloomConvolutionScatterDispersion=False,bOverride_BloomConvolutionSize=False,bOverride_BloomConvolutionCenterUV=False,bOverride_BloomConvolutionPreFilterMin=False,bOverride_BloomConvolutionPreFilterMax=False,bOverride_BloomConvolutionPreFilterMult=False,bOverride_BloomConvolutionBufferScale=False,bOverride_BloomDirtMaskIntensity=False,bOverride_BloomDirtMaskTint=False,bOverride_BloomDirtMask=False,bOverride_CameraShutterSpeed=False,bOverride_CameraISO=False,bOverride_AutoExposureMethod=False,bOverride_AutoExposureLowPercent=False,bOverride_AutoExposureHighPercent=False,bOverride_AutoExposureMinBrightness=False,bOverride_AutoExposureMaxBrightness=False,bOverride_AutoExposureSpeedUp=False,bOverride_AutoExposureSpeedDown=False,bOverride_AutoExposureBias=False,bOverride_AutoExposureBiasCurve=False,bOverride_AutoExposureMeterMask=False,bOverride_AutoExposureApplyPhysicalCameraExposure=False,bOverride_HistogramLogMin=False,bOverride_HistogramLogMax=False,bOverride_LocalExposureMethod=False,bOverride_LocalExposureHighlightContrastScale=False,bOverride_LocalExposureShadowContrastScale=False,bOverride_LocalExposureHighlightContrastCurve=False,bOverride_LocalExposureShadowContrastCurve=False,bOverride_LocalExposureHighlightThreshold=False,bOverride_LocalExposureShadowThreshold=False,bOverride_LocalExposureDetailStrength=False,bOverride_LocalExposureBlurredLuminanceBlend=False,bOverride_LocalExposureBlurredLuminanceKernelSizePercent=False,bOverride_LocalExposureHighlightThresholdStrength=False,bOverride_LocalExposureShadowThresholdStrength=False,bOverride_LocalExposureMiddleGreyBias=False,bOverride_LensFlareIntensity=False,bOverride_LensFlareTint=False,bOverride_LensFlareTints=False,bOverride_LensFlareBokehSize=False,bOverride_LensFlareBokehShape=False,bOverride_LensFlareThreshold=False,bOverride_VignetteIntensity=False,bOverride_Sharpen=False,bOverride_FilmGrainIntensity=False,bOverride_FilmGrainIntensityShadows=False,bOverride_FilmGrainIntensityMidtones=False,bOverride_FilmGrainIntensityHighlights=False,bOverride_FilmGrainShadowsMax=False,bOverride_FilmGrainHighlightsMin=False,bOverride_FilmGrainHighlightsMax=False,bOverride_FilmGrainTexelSize=False,bOverride_FilmGrainTexture=False,bOverride_AmbientOcclusionIntensity=False,bOverride_AmbientOcclusionStaticFraction=False,bOverride_AmbientOcclusionRadius=False,bOverride_AmbientOcclusionFadeDistance=False,bOverride_AmbientOcclusionFadeRadius=False,bOverride_AmbientOcclusionRadiusInWS=False,bOverride_AmbientOcclusionPower=False,bOverride_AmbientOcclusionBias=False,bOverride_AmbientOcclusionQuality=False,bOverride_AmbientOcclusionMipBlend=False,bOverride_AmbientOcclusionMipScale=False,bOverride_AmbientOcclusionMipThreshold=False,bOverride_AmbientOcclusionTemporalBlendWeight=False,bOverride_RayTracingAO=False,bOverride_RayTracingAOSamplesPerPixel=False,bOverride_RayTracingAOIntensity=False,bOverride_RayTracingAORadius=False,bOverride_IndirectLightingColor=False,bOverride_IndirectLightingIntensity=False,bOverride_ColorGradingIntensity=False,bOverride_ColorGradingLUT=False,bOverride_DepthOfFieldFocalDistance=False,bOverride_DepthOfFieldFstop=False,bOverride_DepthOfFieldMinFstop=False,bOverride_DepthOfFieldBladeCount=False,bOverride_DepthOfFieldSensorWidth=False,bOverride_DepthOfFieldSqueezeFactor=False,bOverride_DepthOfFieldDepthBlurRadius=False,bOverride_DepthOfFieldUseHairDepth=False,bOverride_DepthOfFieldPetzvalBokeh=False,bOverride_DepthOfFieldPetzvalBokehFalloff=False,bOverride_DepthOfFieldPetzvalExclusionBoxExtents=False,bOverride_DepthOfFieldPetzvalExclusionBoxRadius=False,bOverride_DepthOfFieldAspectRatioScalar=False,bOverride_DepthOfFieldMatteBoxFlags=False,bOverride_DepthOfFieldBarrelRadius=False,bOverride_DepthOfFieldBarrelLength=False,bOverride_DepthOfFieldDepthBlurAmount=False,bOverride_DepthOfFieldFocalRegion=False,bOverride_DepthOfFieldNearTransitionRegion=False,bOverride_DepthOfFieldFarTransitionRegion=False,bOverride_DepthOfFieldScale=False,bOverride_DepthOfFieldNearBlurSize=False,bOverride_DepthOfFieldFarBlurSize=False,bOverride_MobileHQGaussian=False,bOverride_DepthOfFieldOcclusion=False,bOverride_DepthOfFieldSkyFocusDistance=False,bOverride_DepthOfFieldVignetteSize=False,bOverride_MotionBlurAmount=False,bOverride_MotionBlurMax=False,bOverride_MotionBlurTargetFPS=False,bOverride_MotionBlurPerObjectSize=False,bOverride_ReflectionMethod=False,bOverride_LumenReflectionQuality=False,bOverride_ScreenSpaceReflectionIntensity=False,bOverride_ScreenSpaceReflectionQuality=False,bOverride_ScreenSpaceReflectionMaxRoughness=False,bOverride_ScreenSpaceReflectionRoughnessScale=False,bOverride_UserFlags=False,bOverride_RayTracingReflectionsMaxRoughness=False,bOverride_RayTracingReflectionsMaxBounces=False,bOverride_RayTracingReflectionsSamplesPerPixel=False,bOverride_RayTracingReflectionsShadows=False,bOverride_RayTracingReflectionsTranslucency=False,bOverride_TranslucencyType=False,bOverride_RayTracingTranslucencyMaxRoughness=False,bOverride_RayTracingTranslucencyRefractionRays=False,bOverride_RayTracingTranslucencySamplesPerPixel=False,bOverride_RayTracingTranslucencyShadows=False,bOverride_RayTracingTranslucencyRefraction=False,bOverride_RayTracingTranslucencyMaxPrimaryHitEvents=False,bOverride_RayTracingTranslucencyMaxSecondaryHitEvents=False,bOverride_RayTracingTranslucencyUseRayTracedRefraction=False,bOverride_DynamicGlobalIlluminationMethod=False,bOverride_LumenSceneLightingQuality=False,bOverride_LumenSceneDetail=False,bOverride_LumenSceneViewDistance=False,bOverride_LumenSceneLightingUpdateSpeed=False,bOverride_LumenFinalGatherQuality=False,bOverride_LumenFinalGatherLightingUpdateSpeed=False,bOverride_LumenFinalGatherScreenTraces=False,bOverride_LumenMaxTraceDistance=False,bOverride_LumenDiffuseColorBoost=False,bOverride_LumenSkylightLeaking=False,bOverride_LumenSkylightLeakingTint=False,bOverride_LumenFullSkylightLeakingDistance=False,bOverride_LumenRayLightingMode=False,bOverride_LumenReflectionsScreenTraces=False,bOverride_LumenFrontLayerTranslucencyReflections=False,bOverride_LumenMaxRoughnessToTraceReflections=False,bOverride_LumenMaxReflectionBounces=False,bOverride_LumenMaxRefractionBounces=False,bOverride_LumenSurfaceCacheResolution=False,bOverride_RayTracingGI=False,bOverride_RayTracingGIMaxBounces=False,bOverride_RayTracingGISamplesPerPixel=False,bOverride_PathTracingMaxBounces=False,bOverride_PathTracingSamplesPerPixel=False,bOverride_PathTracingMaxPathIntensity=False,bOverride_PathTracingEnableEmissiveMaterials=False,bOverride_PathTracingEnableReferenceDOF=False,bOverride_PathTracingEnableReferenceAtmosphere=False,bOverride_PathTracingEnableDenoiser=False,bOverride_PathTracingIncludeEmissive=False,bOverride_PathTracingIncludeDiffuse=False,bOverride_PathTracingIncludeIndirectDiffuse=False,bOverride_PathTracingIncludeSpecular=False,bOverride_PathTracingIncludeIndirectSpecular=False,bOverride_PathTracingIncludeVolume=False,bOverride_PathTracingIncludeIndirectVolume=False,bMobileHQGaussian=False,BloomMethod=BM_SOG,AutoExposureMethod=AEM_Histogram,TemperatureType=TEMP_WhiteBalance,WhiteTemp=6500.000000,WhiteTint=0.000000,ColorSaturation=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrast=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGamma=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGain=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffset=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetShadows=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetMidtones=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetHighlights=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorCorrectionHighlightsMin=0.500000,ColorCorrectionHighlightsMax=1.000000,ColorCorrectionShadowsMax=0.090000,BlueCorrection=0.600000,ExpandGamut=1.000000,ToneCurveAmount=1.000000,FilmSlope=0.880000,FilmToe=0.550000,FilmShoulder=0.260000,FilmBlackClip=0.000000,FilmWhiteClip=0.040000,SceneColorTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SceneFringeIntensity=0.000000,ChromaticAberrationStartOffset=0.000000,BloomIntensity=0.675000,BloomGaussianIntensity=1.000000,BloomThreshold=-1.000000,BloomSizeScale=4.000000,Bloom1Size=0.300000,Bloom2Size=1.000000,Bloom3Size=2.000000,Bloom4Size=10.000000,Bloom5Size=30.000000,Bloom6Size=64.000000,Bloom1Tint=(R=0.346500,G=0.346500,B=0.346500,A=1.000000),Bloom2Tint=(R=0.138000,G=0.138000,B=0.138000,A=1.000000),Bloom3Tint=(R=0.117600,G=0.117600,B=0.117600,A=1.000000),Bloom4Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom5Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom6Tint=(R=0.061000,G=0.061000,B=0.061000,A=1.000000),BloomConvolutionIntensity=1.000000,BloomConvolutionScatterDispersion=1.000000,BloomConvolutionSize=1.000000,BloomConvolutionTexture=None,BloomConvolutionCenterUV=(X=0.500000,Y=0.500000),BloomConvolutionPreFilterMin=7.000000,BloomConvolutionPreFilterMax=15000.000000,BloomConvolutionPreFilterMult=15.000000,BloomConvolutionBufferScale=0.133000,BloomDirtMask=None,BloomDirtMaskIntensity=0.000000,BloomDirtMaskTint=(R=0.500000,G=0.500000,B=0.500000,A=1.000000),DynamicGlobalIlluminationMethod=Lumen,IndirectLightingColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),IndirectLightingIntensity=1.000000,LumenRayLightingMode=Default,LumenSceneLightingQuality=1.000000,LumenSceneDetail=1.000000,LumenSceneViewDistance=20000.000000,LumenSceneLightingUpdateSpeed=1.000000,LumenFinalGatherQuality=1.000000,LumenFinalGatherLightingUpdateSpeed=1.000000,LumenFinalGatherScreenTraces=True,LumenMaxTraceDistance=20000.000000,LumenDiffuseColorBoost=1.000000,LumenSkylightLeaking=0.000000,LumenSkylightLeakingTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),LumenFullSkylightLeakingDistance=1000.000000,LumenSurfaceCacheResolution=1.000000,ReflectionMethod=Lumen,LumenReflectionQuality=1.000000,LumenReflectionsScreenTraces=True,LumenFrontLayerTranslucencyReflections=False,LumenMaxRoughnessToTraceReflections=0.400000,LumenMaxReflectionBounces=1,LumenMaxRefractionBounces=0,ScreenSpaceReflectionIntensity=100.000000,ScreenSpaceReflectionQuality=50.000000,ScreenSpaceReflectionMaxRoughness=0.600000,bMegaLights=True,AmbientCubemapTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),AmbientCubemapIntensity=1.000000,AmbientCubemap=None,CameraShutterSpeed=60.000000,CameraISO=100.000000,DepthOfFieldFstop=4.000000,DepthOfFieldMinFstop=1.200000,DepthOfFieldBladeCount=5,AutoExposureBias=1.000000,AutoExposureBiasBackup=0.000000,bOverride_AutoExposureBiasBackup=False,AutoExposureApplyPhysicalCameraExposure=True,AutoExposureBiasCurve=None,AutoExposureMeterMask=None,AutoExposureLowPercent=10.000000,AutoExposureHighPercent=90.000000,AutoExposureMinBrightness=0.030000,AutoExposureMaxBrightness=8.000000,AutoExposureSpeedUp=3.000000,AutoExposureSpeedDown=1.000000,HistogramLogMin=-8.000000,HistogramLogMax=4.000000,LocalExposureMethod=Bilateral,LocalExposureHighlightContrastScale=1.000000,LocalExposureShadowContrastScale=1.000000,LocalExposureHighlightContrastCurve=None,LocalExposureShadowContrastCurve=None,LocalExposureHighlightThreshold=0.000000,LocalExposureShadowThreshold=0.000000,LocalExposureDetailStrength=1.000000,LocalExposureBlurredLuminanceBlend=0.600000,LocalExposureBlurredLuminanceKernelSizePercent=50.000000,LocalExposureHighlightThresholdStrength=1.000000,LocalExposureShadowThresholdStrength=1.000000,LocalExposureMiddleGreyBias=0.000000,LensFlareIntensity=1.000000,LensFlareTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),LensFlareBokehSize=3.000000,LensFlareThreshold=8.000000,LensFlareBokehShape=None,LensFlareTints[0]=(R=1.000000,G=0.800000,B=0.400000,A=0.600000),LensFlareTints[1]=(R=1.000000,G=1.000000,B=0.600000,A=0.530000),LensFlareTints[2]=(R=0.800000,G=0.800000,B=1.000000,A=0.460000),LensFlareTints[3]=(R=0.500000,G=1.000000,B=0.400000,A=0.390000),LensFlareTints[4]=(R=0.500000,G=0.800000,B=1.000000,A=0.310000),LensFlareTints[5]=(R=0.900000,G=1.000000,B=0.800000,A=0.270000),LensFlareTints[6]=(R=1.000000,G=0.800000,B=0.400000,A=0.220000),LensFlareTints[7]=(R=0.900000,G=0.700000,B=0.700000,A=0.150000),VignetteIntensity=0.400000,Sharpen=0.000000,FilmGrainIntensity=0.000000,FilmGrainIntensityShadows=1.000000,FilmGrainIntensityMidtones=1.000000,FilmGrainIntensityHighlights=1.000000,FilmGrainShadowsMax=0.090000,FilmGrainHighlightsMin=0.500000,FilmGrainHighlightsMax=1.000000,FilmGrainTexelSize=1.000000,FilmGrainTexture=None,AmbientOcclusionIntensity=0.500000,AmbientOcclusionStaticFraction=1.000000,AmbientOcclusionRadius=200.000000,AmbientOcclusionRadiusInWS=False,AmbientOcclusionFadeDistance=8000.000000,AmbientOcclusionFadeRadius=5000.000000,AmbientOcclusionPower=2.000000,AmbientOcclusionBias=3.000000,AmbientOcclusionQuality=50.000000,AmbientOcclusionMipBlend=0.600000,AmbientOcclusionMipScale=1.700000,AmbientOcclusionMipThreshold=0.010000,AmbientOcclusionTemporalBlendWeight=0.100000,RayTracingAO=False,RayTracingAOSamplesPerPixel=1,RayTracingAOIntensity=1.000000,RayTracingAORadius=200.000000,ColorGradingIntensity=1.000000,ColorGradingLUT=None,DepthOfFieldSensorWidth=24.576000,DepthOfFieldSqueezeFactor=1.000000,DepthOfFieldFocalDistance=0.000000,DepthOfFieldDepthBlurAmount=1.000000,DepthOfFieldDepthBlurRadius=0.000000,DepthOfFieldUseHairDepth=False,DepthOfFieldPetzvalBokeh=0.000000,DepthOfFieldPetzvalBokehFalloff=1.000000,DepthOfFieldPetzvalExclusionBoxExtents=(X=0.000000,Y=0.000000),DepthOfFieldPetzvalExclusionBoxRadius=0.000000,DepthOfFieldAspectRatioScalar=1.000000,DepthOfFieldBarrelRadius=5.000000,DepthOfFieldBarrelLength=0.000000,DepthOfFieldMatteBoxFlags[0]=(Pitch=0.000000,Roll=0.000000,Length=0.000000),DepthOfFieldMatteBoxFlags[1]=(Pitch=0.000000,Roll=0.000000,Length=0.000000),DepthOfFieldMatteBoxFlags[2]=(Pitch=0.000000,Roll=0.000000,Length=0.000000),DepthOfFieldFocalRegion=0.000000,DepthOfFieldNearTransitionRegion=300.000000,DepthOfFieldFarTransitionRegion=500.000000,DepthOfFieldScale=0.000000,DepthOfFieldNearBlurSize=15.000000,DepthOfFieldFarBlurSize=15.000000,DepthOfFieldOcclusion=0.400000,DepthOfFieldSkyFocusDistance=0.000000,DepthOfFieldVignetteSize=200.000000,MotionBlurAmount=0.500000,MotionBlurMax=5.000000,MotionBlurTargetFPS=30,MotionBlurPerObjectSize=0.000000,TranslucencyType=Raster,RayTracingTranslucencyMaxRoughness=0.600000,RayTracingTranslucencyRefractionRays=3,RayTracingTranslucencySamplesPerPixel=1,RayTracingTranslucencyMaxPrimaryHitEvents=4,RayTracingTranslucencyMaxSecondaryHitEvents=2,RayTracingTranslucencyShadows=Hard_shadows,RayTracingTranslucencyRefraction=True,RayTracingTranslucencyUseRayTracedRefraction=False,PathTracingMaxBounces=32,PathTracingSamplesPerPixel=2048,PathTracingMaxPathIntensity=24.000000,PathTracingEnableEmissiveMaterials=True,PathTracingEnableReferenceDOF=False,PathTracingEnableReferenceAtmosphere=False,PathTracingEnableDenoiser=True,PathTracingIncludeEmissive=True,PathTracingIncludeDiffuse=True,PathTracingIncludeIndirectDiffuse=True,PathTracingIncludeSpecular=True,PathTracingIncludeIndirectSpecular=True,PathTracingIncludeVolume=True,PathTracingIncludeIndirectVolume=True,UserFlags=0,WeightedBlendables=(Array=)),LightingRigRotation=0.000000,RotationSpeed=2.000000,DirectionalLightRotation=(Pitch=-40.000000,Yaw=-67.500000,Roll=0.000000),bEnableToneMapping=True,bShowMeshEdges=False) ++Profiles=(ProfileName="Grey Wireframe",bSharedProfile=True,bIsEngineDefaultProfile=True,bUseSkyLighting=True,DirectionalLightIntensity=1.000000,DirectionalLightColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SkyLightIntensity=1.000000,bRotateLightingRig=False,bShowEnvironment=False,bShowFloor=False,bShowGrid=True,EnvironmentColor=(R=0.039216,G=0.039216,B=0.039216,A=1.000000),EnvironmentIntensity=1.000000,EnvironmentCubeMapPath="/Engine/EditorMaterials/AssetViewer/EpicQuadPanorama_CC+EV1.EpicQuadPanorama_CC+EV1",bPostProcessingEnabled=False,PostProcessingSettings=(bOverride_TemperatureType=False,bOverride_WhiteTemp=False,bOverride_WhiteTint=False,bOverride_ColorSaturation=False,bOverride_ColorContrast=False,bOverride_ColorGamma=False,bOverride_ColorGain=False,bOverride_ColorOffset=False,bOverride_ColorSaturationShadows=False,bOverride_ColorContrastShadows=False,bOverride_ColorGammaShadows=False,bOverride_ColorGainShadows=False,bOverride_ColorOffsetShadows=False,bOverride_ColorSaturationMidtones=False,bOverride_ColorContrastMidtones=False,bOverride_ColorGammaMidtones=False,bOverride_ColorGainMidtones=False,bOverride_ColorOffsetMidtones=False,bOverride_ColorSaturationHighlights=False,bOverride_ColorContrastHighlights=False,bOverride_ColorGammaHighlights=False,bOverride_ColorGainHighlights=False,bOverride_ColorOffsetHighlights=False,bOverride_ColorCorrectionShadowsMax=False,bOverride_ColorCorrectionHighlightsMin=False,bOverride_ColorCorrectionHighlightsMax=False,bOverride_BlueCorrection=False,bOverride_ExpandGamut=False,bOverride_ToneCurveAmount=False,bOverride_FilmSlope=False,bOverride_FilmToe=False,bOverride_FilmShoulder=False,bOverride_FilmBlackClip=False,bOverride_FilmWhiteClip=False,bOverride_SceneColorTint=False,bOverride_SceneFringeIntensity=False,bOverride_ChromaticAberrationStartOffset=False,bOverride_bMegaLights=False,bOverride_AmbientCubemapTint=False,bOverride_AmbientCubemapIntensity=False,bOverride_BloomMethod=False,bOverride_BloomIntensity=False,bOverride_BloomGaussianIntensity=False,bOverride_BloomThreshold=False,bOverride_Bloom1Tint=False,bOverride_Bloom1Size=False,bOverride_Bloom2Size=False,bOverride_Bloom2Tint=False,bOverride_Bloom3Tint=False,bOverride_Bloom3Size=False,bOverride_Bloom4Tint=False,bOverride_Bloom4Size=False,bOverride_Bloom5Tint=False,bOverride_Bloom5Size=False,bOverride_Bloom6Tint=False,bOverride_Bloom6Size=False,bOverride_BloomSizeScale=False,bOverride_BloomConvolutionIntensity=False,bOverride_BloomConvolutionTexture=False,bOverride_BloomConvolutionScatterDispersion=False,bOverride_BloomConvolutionSize=False,bOverride_BloomConvolutionCenterUV=False,bOverride_BloomConvolutionPreFilterMin=False,bOverride_BloomConvolutionPreFilterMax=False,bOverride_BloomConvolutionPreFilterMult=False,bOverride_BloomConvolutionBufferScale=False,bOverride_BloomDirtMaskIntensity=False,bOverride_BloomDirtMaskTint=False,bOverride_BloomDirtMask=False,bOverride_CameraShutterSpeed=False,bOverride_CameraISO=False,bOverride_AutoExposureMethod=False,bOverride_AutoExposureLowPercent=False,bOverride_AutoExposureHighPercent=False,bOverride_AutoExposureMinBrightness=False,bOverride_AutoExposureMaxBrightness=False,bOverride_AutoExposureSpeedUp=False,bOverride_AutoExposureSpeedDown=False,bOverride_AutoExposureBias=False,bOverride_AutoExposureBiasCurve=False,bOverride_AutoExposureMeterMask=False,bOverride_AutoExposureApplyPhysicalCameraExposure=False,bOverride_HistogramLogMin=False,bOverride_HistogramLogMax=False,bOverride_LocalExposureMethod=False,bOverride_LocalExposureHighlightContrastScale=False,bOverride_LocalExposureShadowContrastScale=False,bOverride_LocalExposureHighlightContrastCurve=False,bOverride_LocalExposureShadowContrastCurve=False,bOverride_LocalExposureHighlightThreshold=False,bOverride_LocalExposureShadowThreshold=False,bOverride_LocalExposureDetailStrength=False,bOverride_LocalExposureBlurredLuminanceBlend=False,bOverride_LocalExposureBlurredLuminanceKernelSizePercent=False,bOverride_LocalExposureHighlightThresholdStrength=False,bOverride_LocalExposureShadowThresholdStrength=False,bOverride_LocalExposureMiddleGreyBias=False,bOverride_LensFlareIntensity=False,bOverride_LensFlareTint=False,bOverride_LensFlareTints=False,bOverride_LensFlareBokehSize=False,bOverride_LensFlareBokehShape=False,bOverride_LensFlareThreshold=False,bOverride_VignetteIntensity=False,bOverride_Sharpen=False,bOverride_FilmGrainIntensity=False,bOverride_FilmGrainIntensityShadows=False,bOverride_FilmGrainIntensityMidtones=False,bOverride_FilmGrainIntensityHighlights=False,bOverride_FilmGrainShadowsMax=False,bOverride_FilmGrainHighlightsMin=False,bOverride_FilmGrainHighlightsMax=False,bOverride_FilmGrainTexelSize=False,bOverride_FilmGrainTexture=False,bOverride_AmbientOcclusionIntensity=False,bOverride_AmbientOcclusionStaticFraction=False,bOverride_AmbientOcclusionRadius=False,bOverride_AmbientOcclusionFadeDistance=False,bOverride_AmbientOcclusionFadeRadius=False,bOverride_AmbientOcclusionRadiusInWS=False,bOverride_AmbientOcclusionPower=False,bOverride_AmbientOcclusionBias=False,bOverride_AmbientOcclusionQuality=False,bOverride_AmbientOcclusionMipBlend=False,bOverride_AmbientOcclusionMipScale=False,bOverride_AmbientOcclusionMipThreshold=False,bOverride_AmbientOcclusionTemporalBlendWeight=False,bOverride_RayTracingAO=False,bOverride_RayTracingAOSamplesPerPixel=False,bOverride_RayTracingAOIntensity=False,bOverride_RayTracingAORadius=False,bOverride_IndirectLightingColor=False,bOverride_IndirectLightingIntensity=False,bOverride_ColorGradingIntensity=False,bOverride_ColorGradingLUT=False,bOverride_DepthOfFieldFocalDistance=False,bOverride_DepthOfFieldFstop=False,bOverride_DepthOfFieldMinFstop=False,bOverride_DepthOfFieldBladeCount=False,bOverride_DepthOfFieldSensorWidth=False,bOverride_DepthOfFieldSqueezeFactor=False,bOverride_DepthOfFieldDepthBlurRadius=False,bOverride_DepthOfFieldUseHairDepth=False,bOverride_DepthOfFieldPetzvalBokeh=False,bOverride_DepthOfFieldPetzvalBokehFalloff=False,bOverride_DepthOfFieldPetzvalExclusionBoxExtents=False,bOverride_DepthOfFieldPetzvalExclusionBoxRadius=False,bOverride_DepthOfFieldAspectRatioScalar=False,bOverride_DepthOfFieldMatteBoxFlags=False,bOverride_DepthOfFieldBarrelRadius=False,bOverride_DepthOfFieldBarrelLength=False,bOverride_DepthOfFieldDepthBlurAmount=False,bOverride_DepthOfFieldFocalRegion=False,bOverride_DepthOfFieldNearTransitionRegion=False,bOverride_DepthOfFieldFarTransitionRegion=False,bOverride_DepthOfFieldScale=False,bOverride_DepthOfFieldNearBlurSize=False,bOverride_DepthOfFieldFarBlurSize=False,bOverride_MobileHQGaussian=False,bOverride_DepthOfFieldOcclusion=False,bOverride_DepthOfFieldSkyFocusDistance=False,bOverride_DepthOfFieldVignetteSize=False,bOverride_MotionBlurAmount=False,bOverride_MotionBlurMax=False,bOverride_MotionBlurTargetFPS=False,bOverride_MotionBlurPerObjectSize=False,bOverride_ReflectionMethod=False,bOverride_LumenReflectionQuality=False,bOverride_ScreenSpaceReflectionIntensity=False,bOverride_ScreenSpaceReflectionQuality=False,bOverride_ScreenSpaceReflectionMaxRoughness=False,bOverride_ScreenSpaceReflectionRoughnessScale=False,bOverride_UserFlags=False,bOverride_RayTracingReflectionsMaxRoughness=False,bOverride_RayTracingReflectionsMaxBounces=False,bOverride_RayTracingReflectionsSamplesPerPixel=False,bOverride_RayTracingReflectionsShadows=False,bOverride_RayTracingReflectionsTranslucency=False,bOverride_TranslucencyType=False,bOverride_RayTracingTranslucencyMaxRoughness=False,bOverride_RayTracingTranslucencyRefractionRays=False,bOverride_RayTracingTranslucencySamplesPerPixel=False,bOverride_RayTracingTranslucencyShadows=False,bOverride_RayTracingTranslucencyRefraction=False,bOverride_RayTracingTranslucencyMaxPrimaryHitEvents=False,bOverride_RayTracingTranslucencyMaxSecondaryHitEvents=False,bOverride_RayTracingTranslucencyUseRayTracedRefraction=False,bOverride_DynamicGlobalIlluminationMethod=False,bOverride_LumenSceneLightingQuality=False,bOverride_LumenSceneDetail=False,bOverride_LumenSceneViewDistance=False,bOverride_LumenSceneLightingUpdateSpeed=False,bOverride_LumenFinalGatherQuality=False,bOverride_LumenFinalGatherLightingUpdateSpeed=False,bOverride_LumenFinalGatherScreenTraces=False,bOverride_LumenMaxTraceDistance=False,bOverride_LumenDiffuseColorBoost=False,bOverride_LumenSkylightLeaking=False,bOverride_LumenSkylightLeakingTint=False,bOverride_LumenFullSkylightLeakingDistance=False,bOverride_LumenRayLightingMode=False,bOverride_LumenReflectionsScreenTraces=False,bOverride_LumenFrontLayerTranslucencyReflections=False,bOverride_LumenMaxRoughnessToTraceReflections=False,bOverride_LumenMaxReflectionBounces=False,bOverride_LumenMaxRefractionBounces=False,bOverride_LumenSurfaceCacheResolution=False,bOverride_RayTracingGI=False,bOverride_RayTracingGIMaxBounces=False,bOverride_RayTracingGISamplesPerPixel=False,bOverride_PathTracingMaxBounces=False,bOverride_PathTracingSamplesPerPixel=False,bOverride_PathTracingMaxPathIntensity=False,bOverride_PathTracingEnableEmissiveMaterials=False,bOverride_PathTracingEnableReferenceDOF=False,bOverride_PathTracingEnableReferenceAtmosphere=False,bOverride_PathTracingEnableDenoiser=False,bOverride_PathTracingIncludeEmissive=False,bOverride_PathTracingIncludeDiffuse=False,bOverride_PathTracingIncludeIndirectDiffuse=False,bOverride_PathTracingIncludeSpecular=False,bOverride_PathTracingIncludeIndirectSpecular=False,bOverride_PathTracingIncludeVolume=False,bOverride_PathTracingIncludeIndirectVolume=False,bMobileHQGaussian=False,BloomMethod=BM_SOG,AutoExposureMethod=AEM_Histogram,TemperatureType=TEMP_WhiteBalance,WhiteTemp=6500.000000,WhiteTint=0.000000,ColorSaturation=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrast=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGamma=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGain=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffset=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetShadows=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetMidtones=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetHighlights=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorCorrectionHighlightsMin=0.500000,ColorCorrectionHighlightsMax=1.000000,ColorCorrectionShadowsMax=0.090000,BlueCorrection=0.600000,ExpandGamut=1.000000,ToneCurveAmount=1.000000,FilmSlope=0.880000,FilmToe=0.550000,FilmShoulder=0.260000,FilmBlackClip=0.000000,FilmWhiteClip=0.040000,SceneColorTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SceneFringeIntensity=0.000000,ChromaticAberrationStartOffset=0.000000,BloomIntensity=0.675000,BloomGaussianIntensity=1.000000,BloomThreshold=-1.000000,BloomSizeScale=4.000000,Bloom1Size=0.300000,Bloom2Size=1.000000,Bloom3Size=2.000000,Bloom4Size=10.000000,Bloom5Size=30.000000,Bloom6Size=64.000000,Bloom1Tint=(R=0.346500,G=0.346500,B=0.346500,A=1.000000),Bloom2Tint=(R=0.138000,G=0.138000,B=0.138000,A=1.000000),Bloom3Tint=(R=0.117600,G=0.117600,B=0.117600,A=1.000000),Bloom4Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom5Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom6Tint=(R=0.061000,G=0.061000,B=0.061000,A=1.000000),BloomConvolutionIntensity=1.000000,BloomConvolutionScatterDispersion=1.000000,BloomConvolutionSize=1.000000,BloomConvolutionTexture=None,BloomConvolutionCenterUV=(X=0.500000,Y=0.500000),BloomConvolutionPreFilterMin=7.000000,BloomConvolutionPreFilterMax=15000.000000,BloomConvolutionPreFilterMult=15.000000,BloomConvolutionBufferScale=0.133000,BloomDirtMask=None,BloomDirtMaskIntensity=0.000000,BloomDirtMaskTint=(R=0.500000,G=0.500000,B=0.500000,A=1.000000),DynamicGlobalIlluminationMethod=Lumen,IndirectLightingColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),IndirectLightingIntensity=1.000000,LumenRayLightingMode=Default,LumenSceneLightingQuality=1.000000,LumenSceneDetail=1.000000,LumenSceneViewDistance=20000.000000,LumenSceneLightingUpdateSpeed=1.000000,LumenFinalGatherQuality=1.000000,LumenFinalGatherLightingUpdateSpeed=1.000000,LumenFinalGatherScreenTraces=True,LumenMaxTraceDistance=20000.000000,LumenDiffuseColorBoost=1.000000,LumenSkylightLeaking=0.000000,LumenSkylightLeakingTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),LumenFullSkylightLeakingDistance=1000.000000,LumenSurfaceCacheResolution=1.000000,ReflectionMethod=Lumen,LumenReflectionQuality=1.000000,LumenReflectionsScreenTraces=True,LumenFrontLayerTranslucencyReflections=False,LumenMaxRoughnessToTraceReflections=0.400000,LumenMaxReflectionBounces=1,LumenMaxRefractionBounces=0,ScreenSpaceReflectionIntensity=100.000000,ScreenSpaceReflectionQuality=50.000000,ScreenSpaceReflectionMaxRoughness=0.600000,bMegaLights=True,AmbientCubemapTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),AmbientCubemapIntensity=1.000000,AmbientCubemap=None,CameraShutterSpeed=60.000000,CameraISO=100.000000,DepthOfFieldFstop=4.000000,DepthOfFieldMinFstop=1.200000,DepthOfFieldBladeCount=5,AutoExposureBias=1.000000,AutoExposureBiasBackup=0.000000,bOverride_AutoExposureBiasBackup=False,AutoExposureApplyPhysicalCameraExposure=True,AutoExposureBiasCurve=None,AutoExposureMeterMask=None,AutoExposureLowPercent=10.000000,AutoExposureHighPercent=90.000000,AutoExposureMinBrightness=0.030000,AutoExposureMaxBrightness=8.000000,AutoExposureSpeedUp=3.000000,AutoExposureSpeedDown=1.000000,HistogramLogMin=-8.000000,HistogramLogMax=4.000000,LocalExposureMethod=Bilateral,LocalExposureHighlightContrastScale=1.000000,LocalExposureShadowContrastScale=1.000000,LocalExposureHighlightContrastCurve=None,LocalExposureShadowContrastCurve=None,LocalExposureHighlightThreshold=0.000000,LocalExposureShadowThreshold=0.000000,LocalExposureDetailStrength=1.000000,LocalExposureBlurredLuminanceBlend=0.600000,LocalExposureBlurredLuminanceKernelSizePercent=50.000000,LocalExposureHighlightThresholdStrength=1.000000,LocalExposureShadowThresholdStrength=1.000000,LocalExposureMiddleGreyBias=0.000000,LensFlareIntensity=1.000000,LensFlareTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),LensFlareBokehSize=3.000000,LensFlareThreshold=8.000000,LensFlareBokehShape=None,LensFlareTints[0]=(R=1.000000,G=0.800000,B=0.400000,A=0.600000),LensFlareTints[1]=(R=1.000000,G=1.000000,B=0.600000,A=0.530000),LensFlareTints[2]=(R=0.800000,G=0.800000,B=1.000000,A=0.460000),LensFlareTints[3]=(R=0.500000,G=1.000000,B=0.400000,A=0.390000),LensFlareTints[4]=(R=0.500000,G=0.800000,B=1.000000,A=0.310000),LensFlareTints[5]=(R=0.900000,G=1.000000,B=0.800000,A=0.270000),LensFlareTints[6]=(R=1.000000,G=0.800000,B=0.400000,A=0.220000),LensFlareTints[7]=(R=0.900000,G=0.700000,B=0.700000,A=0.150000),VignetteIntensity=0.400000,Sharpen=0.000000,FilmGrainIntensity=0.000000,FilmGrainIntensityShadows=1.000000,FilmGrainIntensityMidtones=1.000000,FilmGrainIntensityHighlights=1.000000,FilmGrainShadowsMax=0.090000,FilmGrainHighlightsMin=0.500000,FilmGrainHighlightsMax=1.000000,FilmGrainTexelSize=1.000000,FilmGrainTexture=None,AmbientOcclusionIntensity=0.500000,AmbientOcclusionStaticFraction=1.000000,AmbientOcclusionRadius=200.000000,AmbientOcclusionRadiusInWS=False,AmbientOcclusionFadeDistance=8000.000000,AmbientOcclusionFadeRadius=5000.000000,AmbientOcclusionPower=2.000000,AmbientOcclusionBias=3.000000,AmbientOcclusionQuality=50.000000,AmbientOcclusionMipBlend=0.600000,AmbientOcclusionMipScale=1.700000,AmbientOcclusionMipThreshold=0.010000,AmbientOcclusionTemporalBlendWeight=0.100000,RayTracingAO=False,RayTracingAOSamplesPerPixel=1,RayTracingAOIntensity=1.000000,RayTracingAORadius=200.000000,ColorGradingIntensity=1.000000,ColorGradingLUT=None,DepthOfFieldSensorWidth=24.576000,DepthOfFieldSqueezeFactor=1.000000,DepthOfFieldFocalDistance=0.000000,DepthOfFieldDepthBlurAmount=1.000000,DepthOfFieldDepthBlurRadius=0.000000,DepthOfFieldUseHairDepth=False,DepthOfFieldPetzvalBokeh=0.000000,DepthOfFieldPetzvalBokehFalloff=1.000000,DepthOfFieldPetzvalExclusionBoxExtents=(X=0.000000,Y=0.000000),DepthOfFieldPetzvalExclusionBoxRadius=0.000000,DepthOfFieldAspectRatioScalar=1.000000,DepthOfFieldBarrelRadius=5.000000,DepthOfFieldBarrelLength=0.000000,DepthOfFieldMatteBoxFlags[0]=(Pitch=0.000000,Roll=0.000000,Length=0.000000),DepthOfFieldMatteBoxFlags[1]=(Pitch=0.000000,Roll=0.000000,Length=0.000000),DepthOfFieldMatteBoxFlags[2]=(Pitch=0.000000,Roll=0.000000,Length=0.000000),DepthOfFieldFocalRegion=0.000000,DepthOfFieldNearTransitionRegion=300.000000,DepthOfFieldFarTransitionRegion=500.000000,DepthOfFieldScale=0.000000,DepthOfFieldNearBlurSize=15.000000,DepthOfFieldFarBlurSize=15.000000,DepthOfFieldOcclusion=0.400000,DepthOfFieldSkyFocusDistance=0.000000,DepthOfFieldVignetteSize=200.000000,MotionBlurAmount=0.500000,MotionBlurMax=5.000000,MotionBlurTargetFPS=30,MotionBlurPerObjectSize=0.000000,TranslucencyType=Raster,RayTracingTranslucencyMaxRoughness=0.600000,RayTracingTranslucencyRefractionRays=3,RayTracingTranslucencySamplesPerPixel=1,RayTracingTranslucencyMaxPrimaryHitEvents=4,RayTracingTranslucencyMaxSecondaryHitEvents=2,RayTracingTranslucencyShadows=Hard_shadows,RayTracingTranslucencyRefraction=True,RayTracingTranslucencyUseRayTracedRefraction=False,PathTracingMaxBounces=32,PathTracingSamplesPerPixel=2048,PathTracingMaxPathIntensity=24.000000,PathTracingEnableEmissiveMaterials=True,PathTracingEnableReferenceDOF=False,PathTracingEnableReferenceAtmosphere=False,PathTracingEnableDenoiser=True,PathTracingIncludeEmissive=True,PathTracingIncludeDiffuse=True,PathTracingIncludeIndirectDiffuse=True,PathTracingIncludeSpecular=True,PathTracingIncludeIndirectSpecular=True,PathTracingIncludeVolume=True,PathTracingIncludeIndirectVolume=True,UserFlags=0,WeightedBlendables=(Array=)),LightingRigRotation=0.000000,RotationSpeed=2.000000,DirectionalLightRotation=(Pitch=-40.000000,Yaw=-67.500000,Roll=0.000000),bEnableToneMapping=False,bShowMeshEdges=True) ++Profiles=(ProfileName="Grey Ambient",bSharedProfile=True,bIsEngineDefaultProfile=True,bUseSkyLighting=True,DirectionalLightIntensity=4.000000,DirectionalLightColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SkyLightIntensity=2.000000,bRotateLightingRig=False,bShowEnvironment=False,bShowFloor=True,bShowGrid=True,EnvironmentColor=(R=0.200000,G=0.200000,B=0.200000,A=1.000000),EnvironmentIntensity=1.000000,EnvironmentCubeMapPath="/Engine/EditorMaterials/AssetViewer/T_GreyAmbient",bPostProcessingEnabled=True,PostProcessingSettings=(bOverride_TemperatureType=False,bOverride_WhiteTemp=False,bOverride_WhiteTint=False,bOverride_ColorSaturation=False,bOverride_ColorContrast=False,bOverride_ColorGamma=False,bOverride_ColorGain=False,bOverride_ColorOffset=False,bOverride_ColorSaturationShadows=False,bOverride_ColorContrastShadows=False,bOverride_ColorGammaShadows=False,bOverride_ColorGainShadows=False,bOverride_ColorOffsetShadows=False,bOverride_ColorSaturationMidtones=False,bOverride_ColorContrastMidtones=False,bOverride_ColorGammaMidtones=False,bOverride_ColorGainMidtones=False,bOverride_ColorOffsetMidtones=False,bOverride_ColorSaturationHighlights=False,bOverride_ColorContrastHighlights=False,bOverride_ColorGammaHighlights=False,bOverride_ColorGainHighlights=False,bOverride_ColorOffsetHighlights=False,bOverride_ColorCorrectionShadowsMax=False,bOverride_ColorCorrectionHighlightsMin=False,bOverride_ColorCorrectionHighlightsMax=False,bOverride_BlueCorrection=False,bOverride_ExpandGamut=False,bOverride_ToneCurveAmount=False,bOverride_FilmSlope=False,bOverride_FilmToe=False,bOverride_FilmShoulder=False,bOverride_FilmBlackClip=False,bOverride_FilmWhiteClip=False,bOverride_SceneColorTint=False,bOverride_SceneFringeIntensity=False,bOverride_ChromaticAberrationStartOffset=False,bOverride_bMegaLights=False,bOverride_AmbientCubemapTint=False,bOverride_AmbientCubemapIntensity=False,bOverride_BloomMethod=False,bOverride_BloomIntensity=False,bOverride_BloomGaussianIntensity=False,bOverride_BloomThreshold=False,bOverride_Bloom1Tint=False,bOverride_Bloom1Size=False,bOverride_Bloom2Size=False,bOverride_Bloom2Tint=False,bOverride_Bloom3Tint=False,bOverride_Bloom3Size=False,bOverride_Bloom4Tint=False,bOverride_Bloom4Size=False,bOverride_Bloom5Tint=False,bOverride_Bloom5Size=False,bOverride_Bloom6Tint=False,bOverride_Bloom6Size=False,bOverride_BloomSizeScale=False,bOverride_BloomConvolutionIntensity=False,bOverride_BloomConvolutionTexture=False,bOverride_BloomConvolutionScatterDispersion=False,bOverride_BloomConvolutionSize=False,bOverride_BloomConvolutionCenterUV=False,bOverride_BloomConvolutionPreFilterMin=False,bOverride_BloomConvolutionPreFilterMax=False,bOverride_BloomConvolutionPreFilterMult=False,bOverride_BloomConvolutionBufferScale=False,bOverride_BloomDirtMaskIntensity=False,bOverride_BloomDirtMaskTint=False,bOverride_BloomDirtMask=False,bOverride_CameraShutterSpeed=False,bOverride_CameraISO=False,bOverride_AutoExposureMethod=False,bOverride_AutoExposureLowPercent=False,bOverride_AutoExposureHighPercent=False,bOverride_AutoExposureMinBrightness=False,bOverride_AutoExposureMaxBrightness=False,bOverride_AutoExposureSpeedUp=False,bOverride_AutoExposureSpeedDown=False,bOverride_AutoExposureBias=False,bOverride_AutoExposureBiasCurve=False,bOverride_AutoExposureMeterMask=False,bOverride_AutoExposureApplyPhysicalCameraExposure=False,bOverride_HistogramLogMin=False,bOverride_HistogramLogMax=False,bOverride_LocalExposureMethod=False,bOverride_LocalExposureHighlightContrastScale=False,bOverride_LocalExposureShadowContrastScale=False,bOverride_LocalExposureHighlightContrastCurve=False,bOverride_LocalExposureShadowContrastCurve=False,bOverride_LocalExposureHighlightThreshold=False,bOverride_LocalExposureShadowThreshold=False,bOverride_LocalExposureDetailStrength=False,bOverride_LocalExposureBlurredLuminanceBlend=False,bOverride_LocalExposureBlurredLuminanceKernelSizePercent=False,bOverride_LocalExposureHighlightThresholdStrength=False,bOverride_LocalExposureShadowThresholdStrength=False,bOverride_LocalExposureMiddleGreyBias=False,bOverride_LensFlareIntensity=False,bOverride_LensFlareTint=False,bOverride_LensFlareTints=False,bOverride_LensFlareBokehSize=False,bOverride_LensFlareBokehShape=False,bOverride_LensFlareThreshold=False,bOverride_VignetteIntensity=False,bOverride_Sharpen=False,bOverride_FilmGrainIntensity=False,bOverride_FilmGrainIntensityShadows=False,bOverride_FilmGrainIntensityMidtones=False,bOverride_FilmGrainIntensityHighlights=False,bOverride_FilmGrainShadowsMax=False,bOverride_FilmGrainHighlightsMin=False,bOverride_FilmGrainHighlightsMax=False,bOverride_FilmGrainTexelSize=False,bOverride_FilmGrainTexture=False,bOverride_AmbientOcclusionIntensity=False,bOverride_AmbientOcclusionStaticFraction=False,bOverride_AmbientOcclusionRadius=False,bOverride_AmbientOcclusionFadeDistance=False,bOverride_AmbientOcclusionFadeRadius=False,bOverride_AmbientOcclusionRadiusInWS=False,bOverride_AmbientOcclusionPower=False,bOverride_AmbientOcclusionBias=False,bOverride_AmbientOcclusionQuality=False,bOverride_AmbientOcclusionMipBlend=False,bOverride_AmbientOcclusionMipScale=False,bOverride_AmbientOcclusionMipThreshold=False,bOverride_AmbientOcclusionTemporalBlendWeight=False,bOverride_RayTracingAO=False,bOverride_RayTracingAOSamplesPerPixel=False,bOverride_RayTracingAOIntensity=False,bOverride_RayTracingAORadius=False,bOverride_IndirectLightingColor=False,bOverride_IndirectLightingIntensity=False,bOverride_ColorGradingIntensity=False,bOverride_ColorGradingLUT=False,bOverride_DepthOfFieldFocalDistance=False,bOverride_DepthOfFieldFstop=False,bOverride_DepthOfFieldMinFstop=False,bOverride_DepthOfFieldBladeCount=False,bOverride_DepthOfFieldSensorWidth=False,bOverride_DepthOfFieldSqueezeFactor=False,bOverride_DepthOfFieldDepthBlurRadius=False,bOverride_DepthOfFieldUseHairDepth=False,bOverride_DepthOfFieldPetzvalBokeh=False,bOverride_DepthOfFieldPetzvalBokehFalloff=False,bOverride_DepthOfFieldPetzvalExclusionBoxExtents=False,bOverride_DepthOfFieldPetzvalExclusionBoxRadius=False,bOverride_DepthOfFieldAspectRatioScalar=False,bOverride_DepthOfFieldMatteBoxFlags=False,bOverride_DepthOfFieldBarrelRadius=False,bOverride_DepthOfFieldBarrelLength=False,bOverride_DepthOfFieldDepthBlurAmount=False,bOverride_DepthOfFieldFocalRegion=False,bOverride_DepthOfFieldNearTransitionRegion=False,bOverride_DepthOfFieldFarTransitionRegion=False,bOverride_DepthOfFieldScale=False,bOverride_DepthOfFieldNearBlurSize=False,bOverride_DepthOfFieldFarBlurSize=False,bOverride_MobileHQGaussian=False,bOverride_DepthOfFieldOcclusion=False,bOverride_DepthOfFieldSkyFocusDistance=False,bOverride_DepthOfFieldVignetteSize=False,bOverride_MotionBlurAmount=False,bOverride_MotionBlurMax=False,bOverride_MotionBlurTargetFPS=False,bOverride_MotionBlurPerObjectSize=False,bOverride_ReflectionMethod=False,bOverride_LumenReflectionQuality=False,bOverride_ScreenSpaceReflectionIntensity=False,bOverride_ScreenSpaceReflectionQuality=False,bOverride_ScreenSpaceReflectionMaxRoughness=False,bOverride_ScreenSpaceReflectionRoughnessScale=False,bOverride_UserFlags=False,bOverride_RayTracingReflectionsMaxRoughness=False,bOverride_RayTracingReflectionsMaxBounces=False,bOverride_RayTracingReflectionsSamplesPerPixel=False,bOverride_RayTracingReflectionsShadows=False,bOverride_RayTracingReflectionsTranslucency=False,bOverride_TranslucencyType=False,bOverride_RayTracingTranslucencyMaxRoughness=False,bOverride_RayTracingTranslucencyRefractionRays=False,bOverride_RayTracingTranslucencySamplesPerPixel=False,bOverride_RayTracingTranslucencyShadows=False,bOverride_RayTracingTranslucencyRefraction=False,bOverride_RayTracingTranslucencyMaxPrimaryHitEvents=False,bOverride_RayTracingTranslucencyMaxSecondaryHitEvents=False,bOverride_RayTracingTranslucencyUseRayTracedRefraction=False,bOverride_DynamicGlobalIlluminationMethod=False,bOverride_LumenSceneLightingQuality=False,bOverride_LumenSceneDetail=False,bOverride_LumenSceneViewDistance=False,bOverride_LumenSceneLightingUpdateSpeed=False,bOverride_LumenFinalGatherQuality=False,bOverride_LumenFinalGatherLightingUpdateSpeed=False,bOverride_LumenFinalGatherScreenTraces=False,bOverride_LumenMaxTraceDistance=False,bOverride_LumenDiffuseColorBoost=False,bOverride_LumenSkylightLeaking=False,bOverride_LumenSkylightLeakingTint=False,bOverride_LumenFullSkylightLeakingDistance=False,bOverride_LumenRayLightingMode=False,bOverride_LumenReflectionsScreenTraces=False,bOverride_LumenFrontLayerTranslucencyReflections=False,bOverride_LumenMaxRoughnessToTraceReflections=False,bOverride_LumenMaxReflectionBounces=False,bOverride_LumenMaxRefractionBounces=False,bOverride_LumenSurfaceCacheResolution=False,bOverride_RayTracingGI=False,bOverride_RayTracingGIMaxBounces=False,bOverride_RayTracingGISamplesPerPixel=False,bOverride_PathTracingMaxBounces=False,bOverride_PathTracingSamplesPerPixel=False,bOverride_PathTracingMaxPathIntensity=False,bOverride_PathTracingEnableEmissiveMaterials=False,bOverride_PathTracingEnableReferenceDOF=False,bOverride_PathTracingEnableReferenceAtmosphere=False,bOverride_PathTracingEnableDenoiser=False,bOverride_PathTracingIncludeEmissive=False,bOverride_PathTracingIncludeDiffuse=False,bOverride_PathTracingIncludeIndirectDiffuse=False,bOverride_PathTracingIncludeSpecular=False,bOverride_PathTracingIncludeIndirectSpecular=False,bOverride_PathTracingIncludeVolume=False,bOverride_PathTracingIncludeIndirectVolume=False,bMobileHQGaussian=False,BloomMethod=BM_SOG,AutoExposureMethod=AEM_Histogram,TemperatureType=TEMP_WhiteBalance,WhiteTemp=6500.000000,WhiteTint=0.000000,ColorSaturation=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrast=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGamma=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGain=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffset=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainShadows=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetShadows=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainMidtones=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetMidtones=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorSaturationHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorContrastHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGammaHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorGainHighlights=(X=1.000000,Y=1.000000,Z=1.000000,W=1.000000),ColorOffsetHighlights=(X=0.000000,Y=0.000000,Z=0.000000,W=0.000000),ColorCorrectionHighlightsMin=0.500000,ColorCorrectionHighlightsMax=1.000000,ColorCorrectionShadowsMax=0.090000,BlueCorrection=0.600000,ExpandGamut=1.000000,ToneCurveAmount=1.000000,FilmSlope=0.880000,FilmToe=0.550000,FilmShoulder=0.260000,FilmBlackClip=0.000000,FilmWhiteClip=0.040000,SceneColorTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),SceneFringeIntensity=0.000000,ChromaticAberrationStartOffset=0.000000,BloomIntensity=0.675000,BloomGaussianIntensity=1.000000,BloomThreshold=-1.000000,BloomSizeScale=4.000000,Bloom1Size=0.300000,Bloom2Size=1.000000,Bloom3Size=2.000000,Bloom4Size=10.000000,Bloom5Size=30.000000,Bloom6Size=64.000000,Bloom1Tint=(R=0.346500,G=0.346500,B=0.346500,A=1.000000),Bloom2Tint=(R=0.138000,G=0.138000,B=0.138000,A=1.000000),Bloom3Tint=(R=0.117600,G=0.117600,B=0.117600,A=1.000000),Bloom4Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom5Tint=(R=0.066000,G=0.066000,B=0.066000,A=1.000000),Bloom6Tint=(R=0.061000,G=0.061000,B=0.061000,A=1.000000),BloomConvolutionIntensity=1.000000,BloomConvolutionScatterDispersion=1.000000,BloomConvolutionSize=1.000000,BloomConvolutionTexture=None,BloomConvolutionCenterUV=(X=0.500000,Y=0.500000),BloomConvolutionPreFilterMin=7.000000,BloomConvolutionPreFilterMax=15000.000000,BloomConvolutionPreFilterMult=15.000000,BloomConvolutionBufferScale=0.133000,BloomDirtMask=None,BloomDirtMaskIntensity=0.000000,BloomDirtMaskTint=(R=0.500000,G=0.500000,B=0.500000,A=1.000000),DynamicGlobalIlluminationMethod=Lumen,IndirectLightingColor=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),IndirectLightingIntensity=1.000000,LumenRayLightingMode=Default,LumenSceneLightingQuality=1.000000,LumenSceneDetail=1.000000,LumenSceneViewDistance=20000.000000,LumenSceneLightingUpdateSpeed=1.000000,LumenFinalGatherQuality=1.000000,LumenFinalGatherLightingUpdateSpeed=1.000000,LumenFinalGatherScreenTraces=True,LumenMaxTraceDistance=20000.000000,LumenDiffuseColorBoost=1.000000,LumenSkylightLeaking=0.000000,LumenSkylightLeakingTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),LumenFullSkylightLeakingDistance=1000.000000,LumenSurfaceCacheResolution=1.000000,ReflectionMethod=Lumen,LumenReflectionQuality=1.000000,LumenReflectionsScreenTraces=True,LumenFrontLayerTranslucencyReflections=False,LumenMaxRoughnessToTraceReflections=0.400000,LumenMaxReflectionBounces=1,LumenMaxRefractionBounces=0,ScreenSpaceReflectionIntensity=100.000000,ScreenSpaceReflectionQuality=50.000000,ScreenSpaceReflectionMaxRoughness=0.600000,bMegaLights=True,AmbientCubemapTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),AmbientCubemapIntensity=1.000000,AmbientCubemap=None,CameraShutterSpeed=60.000000,CameraISO=100.000000,DepthOfFieldFstop=4.000000,DepthOfFieldMinFstop=1.200000,DepthOfFieldBladeCount=5,AutoExposureBias=1.000000,AutoExposureBiasBackup=0.000000,bOverride_AutoExposureBiasBackup=False,AutoExposureApplyPhysicalCameraExposure=True,AutoExposureBiasCurve=None,AutoExposureMeterMask=None,AutoExposureLowPercent=10.000000,AutoExposureHighPercent=90.000000,AutoExposureMinBrightness=0.030000,AutoExposureMaxBrightness=8.000000,AutoExposureSpeedUp=3.000000,AutoExposureSpeedDown=1.000000,HistogramLogMin=-8.000000,HistogramLogMax=4.000000,LocalExposureMethod=Bilateral,LocalExposureHighlightContrastScale=1.000000,LocalExposureShadowContrastScale=1.000000,LocalExposureHighlightContrastCurve=None,LocalExposureShadowContrastCurve=None,LocalExposureHighlightThreshold=0.000000,LocalExposureShadowThreshold=0.000000,LocalExposureDetailStrength=1.000000,LocalExposureBlurredLuminanceBlend=0.600000,LocalExposureBlurredLuminanceKernelSizePercent=50.000000,LocalExposureHighlightThresholdStrength=1.000000,LocalExposureShadowThresholdStrength=1.000000,LocalExposureMiddleGreyBias=0.000000,LensFlareIntensity=1.000000,LensFlareTint=(R=1.000000,G=1.000000,B=1.000000,A=1.000000),LensFlareBokehSize=3.000000,LensFlareThreshold=8.000000,LensFlareBokehShape=None,LensFlareTints[0]=(R=1.000000,G=0.800000,B=0.400000,A=0.600000),LensFlareTints[1]=(R=1.000000,G=1.000000,B=0.600000,A=0.530000),LensFlareTints[2]=(R=0.800000,G=0.800000,B=1.000000,A=0.460000),LensFlareTints[3]=(R=0.500000,G=1.000000,B=0.400000,A=0.390000),LensFlareTints[4]=(R=0.500000,G=0.800000,B=1.000000,A=0.310000),LensFlareTints[5]=(R=0.900000,G=1.000000,B=0.800000,A=0.270000),LensFlareTints[6]=(R=1.000000,G=0.800000,B=0.400000,A=0.220000),LensFlareTints[7]=(R=0.900000,G=0.700000,B=0.700000,A=0.150000),VignetteIntensity=0.400000,Sharpen=0.000000,FilmGrainIntensity=0.000000,FilmGrainIntensityShadows=1.000000,FilmGrainIntensityMidtones=1.000000,FilmGrainIntensityHighlights=1.000000,FilmGrainShadowsMax=0.090000,FilmGrainHighlightsMin=0.500000,FilmGrainHighlightsMax=1.000000,FilmGrainTexelSize=1.000000,FilmGrainTexture=None,AmbientOcclusionIntensity=0.500000,AmbientOcclusionStaticFraction=1.000000,AmbientOcclusionRadius=200.000000,AmbientOcclusionRadiusInWS=False,AmbientOcclusionFadeDistance=8000.000000,AmbientOcclusionFadeRadius=5000.000000,AmbientOcclusionPower=2.000000,AmbientOcclusionBias=3.000000,AmbientOcclusionQuality=50.000000,AmbientOcclusionMipBlend=0.600000,AmbientOcclusionMipScale=1.700000,AmbientOcclusionMipThreshold=0.010000,AmbientOcclusionTemporalBlendWeight=0.100000,RayTracingAO=False,RayTracingAOSamplesPerPixel=1,RayTracingAOIntensity=1.000000,RayTracingAORadius=200.000000,ColorGradingIntensity=1.000000,ColorGradingLUT=None,DepthOfFieldSensorWidth=24.576000,DepthOfFieldSqueezeFactor=1.000000,DepthOfFieldFocalDistance=0.000000,DepthOfFieldDepthBlurAmount=1.000000,DepthOfFieldDepthBlurRadius=0.000000,DepthOfFieldUseHairDepth=False,DepthOfFieldPetzvalBokeh=0.000000,DepthOfFieldPetzvalBokehFalloff=1.000000,DepthOfFieldPetzvalExclusionBoxExtents=(X=0.000000,Y=0.000000),DepthOfFieldPetzvalExclusionBoxRadius=0.000000,DepthOfFieldAspectRatioScalar=1.000000,DepthOfFieldBarrelRadius=5.000000,DepthOfFieldBarrelLength=0.000000,DepthOfFieldMatteBoxFlags[0]=(Pitch=0.000000,Roll=0.000000,Length=0.000000),DepthOfFieldMatteBoxFlags[1]=(Pitch=0.000000,Roll=0.000000,Length=0.000000),DepthOfFieldMatteBoxFlags[2]=(Pitch=0.000000,Roll=0.000000,Length=0.000000),DepthOfFieldFocalRegion=0.000000,DepthOfFieldNearTransitionRegion=300.000000,DepthOfFieldFarTransitionRegion=500.000000,DepthOfFieldScale=0.000000,DepthOfFieldNearBlurSize=15.000000,DepthOfFieldFarBlurSize=15.000000,DepthOfFieldOcclusion=0.400000,DepthOfFieldSkyFocusDistance=0.000000,DepthOfFieldVignetteSize=200.000000,MotionBlurAmount=0.500000,MotionBlurMax=5.000000,MotionBlurTargetFPS=30,MotionBlurPerObjectSize=0.000000,TranslucencyType=Raster,RayTracingTranslucencyMaxRoughness=0.600000,RayTracingTranslucencyRefractionRays=3,RayTracingTranslucencySamplesPerPixel=1,RayTracingTranslucencyMaxPrimaryHitEvents=4,RayTracingTranslucencyMaxSecondaryHitEvents=2,RayTracingTranslucencyShadows=Hard_shadows,RayTracingTranslucencyRefraction=True,RayTracingTranslucencyUseRayTracedRefraction=False,PathTracingMaxBounces=32,PathTracingSamplesPerPixel=2048,PathTracingMaxPathIntensity=24.000000,PathTracingEnableEmissiveMaterials=True,PathTracingEnableReferenceDOF=False,PathTracingEnableReferenceAtmosphere=False,PathTracingEnableDenoiser=True,PathTracingIncludeEmissive=True,PathTracingIncludeDiffuse=True,PathTracingIncludeIndirectDiffuse=True,PathTracingIncludeSpecular=True,PathTracingIncludeIndirectSpecular=True,PathTracingIncludeVolume=True,PathTracingIncludeIndirectVolume=True,UserFlags=0,WeightedBlendables=(Array=)),LightingRigRotation=0.000000,RotationSpeed=2.000000,DirectionalLightRotation=(Pitch=-40.000000,Yaw=-67.500000,Roll=0.000000),bEnableToneMapping=False,bShowMeshEdges=False) diff --git a/Unreal/Environments/Blocks/Config/DefaultEngine.ini b/Unreal/Environments/Blocks/Config/DefaultEngine.ini index 2a01d0ef6..bbf45de09 100644 --- a/Unreal/Environments/Blocks/Config/DefaultEngine.ini +++ b/Unreal/Environments/Blocks/Config/DefaultEngine.ini @@ -124,6 +124,8 @@ r.Lumen.HardwareRayTracing=True r.Shadow.Virtual.Enable=1 r.Nanite.ProjectEnabled=True r.Vulkan.RayTracing=True +r.Nanite.Foliage=True +r.RayTracing.RayTracingProxies.ProjectEnabled=True [/Script/LinuxTargetPlatform.LinuxTargetSettings] SpatializationPlugin= diff --git a/Unreal/Environments/Blocks/Config/DefaultGameUserSettings.ini b/Unreal/Environments/Blocks/Config/DefaultGameUserSettings.ini index 87f51567e..9067d2468 100644 --- a/Unreal/Environments/Blocks/Config/DefaultGameUserSettings.ini +++ b/Unreal/Environments/Blocks/Config/DefaultGameUserSettings.ini @@ -1,2 +1,12 @@ [/Script/Engine.GameUserSettings] -FullscreenMode=1 \ No newline at end of file +FullscreenMode=2 +PreferredFullscreenMode=2 +LastConfirmedFullscreenMode=2 +ResolutionSizeX=1280 +ResolutionSizeY=720 +LastUserConfirmedResolutionSizeX=1280 +LastUserConfirmedResolutionSizeY=720 +DesiredScreenWidth=1280 +DesiredScreenHeight=720 +LastUserConfirmedDesiredScreenWidth=1280 +LastUserConfirmedDesiredScreenHeight=720 \ No newline at end of file diff --git a/Unreal/Environments/Blocks/Content/FlyingCPP/Maps/FlyingExampleMap.umap b/Unreal/Environments/Blocks/Content/FlyingCPP/Maps/FlyingExampleMap.umap index d3d90e293..17d51981a 100644 Binary files a/Unreal/Environments/Blocks/Content/FlyingCPP/Maps/FlyingExampleMap.umap and b/Unreal/Environments/Blocks/Content/FlyingCPP/Maps/FlyingExampleMap.umap differ diff --git a/Unreal/Environments/Blocks/Content/Geometry/Meshes/CubeMaterial.uasset b/Unreal/Environments/Blocks/Content/Geometry/Meshes/CubeMaterial.uasset index 5beb2fb6f..dba071748 100644 Binary files a/Unreal/Environments/Blocks/Content/Geometry/Meshes/CubeMaterial.uasset and b/Unreal/Environments/Blocks/Content/Geometry/Meshes/CubeMaterial.uasset differ diff --git a/Unreal/Environments/Blocks/Source/Blocks.Target.cs b/Unreal/Environments/Blocks/Source/Blocks.Target.cs index ceb9ad2f8..e19e2241d 100644 --- a/Unreal/Environments/Blocks/Source/Blocks.Target.cs +++ b/Unreal/Environments/Blocks/Source/Blocks.Target.cs @@ -7,7 +7,7 @@ public class BlocksTarget : TargetRules { public BlocksTarget(TargetInfo Target) : base(Target) { - DefaultBuildSettings = BuildSettingsVersion.V5; + DefaultBuildSettings = BuildSettingsVersion.V7; Type = TargetType.Game; ExtraModuleNames.AddRange(new string[] { "Blocks" }); //bUseUnityBuild = false; diff --git a/Unreal/Environments/Blocks/Source/BlocksEditor.Target.cs b/Unreal/Environments/Blocks/Source/BlocksEditor.Target.cs index 5cf2d73c5..ddac85fa4 100644 --- a/Unreal/Environments/Blocks/Source/BlocksEditor.Target.cs +++ b/Unreal/Environments/Blocks/Source/BlocksEditor.Target.cs @@ -7,7 +7,7 @@ public class BlocksEditorTarget : TargetRules { public BlocksEditorTarget(TargetInfo Target) : base(Target) { - DefaultBuildSettings = BuildSettingsVersion.V5; + DefaultBuildSettings = BuildSettingsVersion.V7; Type = TargetType.Editor; ExtraModuleNames.AddRange(new string[] { "Blocks" }); IncludeOrderVersion = EngineIncludeOrderVersion.Latest; diff --git a/Unreal/Plugins/AirSim/Config/FilterPlugin.ini b/Unreal/Plugins/AirSim/Config/FilterPlugin.ini new file mode 100644 index 000000000..ccebca2f3 --- /dev/null +++ b/Unreal/Plugins/AirSim/Config/FilterPlugin.ini @@ -0,0 +1,8 @@ +[FilterPlugin] +; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and +; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. +; +; Examples: +; /README.txt +; /Extras/... +; /Binaries/ThirdParty/*.dll diff --git a/Unreal/Plugins/AirSim/Content/Blueprints/BP_PIPCamera.uasset b/Unreal/Plugins/AirSim/Content/Blueprints/BP_PIPCamera.uasset index d14de4e4f..d3a1606c3 100644 Binary files a/Unreal/Plugins/AirSim/Content/Blueprints/BP_PIPCamera.uasset and b/Unreal/Plugins/AirSim/Content/Blueprints/BP_PIPCamera.uasset differ diff --git a/Unreal/Plugins/AirSim/Content/HUDAssets/AnnotationMaterial.uasset b/Unreal/Plugins/AirSim/Content/HUDAssets/AnnotationMaterial.uasset index 00b9e5afd..c8da48436 100644 Binary files a/Unreal/Plugins/AirSim/Content/HUDAssets/AnnotationMaterial.uasset and b/Unreal/Plugins/AirSim/Content/HUDAssets/AnnotationMaterial.uasset differ diff --git a/Unreal/Plugins/AirSim/Source/AirBlueprintLib.cpp b/Unreal/Plugins/AirSim/Source/AirBlueprintLib.cpp index 93b4f43fd..89346e6b5 100644 --- a/Unreal/Plugins/AirSim/Source/AirBlueprintLib.cpp +++ b/Unreal/Plugins/AirSim/Source/AirBlueprintLib.cpp @@ -58,7 +58,20 @@ EAppReturnType::Type UAirBlueprintLib::ShowMessage(EAppMsgType::Type message_typ ULineBatchComponent* GetLineBatcher(const UWorld* InWorld, bool bPersistentLines, float LifeTime, bool bDepthIsForeground) { - return (InWorld ? (bDepthIsForeground ? InWorld->ForegroundLineBatcher : ((bPersistentLines || (LifeTime > 0.f)) ? InWorld->PersistentLineBatcher : InWorld->LineBatcher)) : NULL); + + if (InWorld) + { + if (bPersistentLines || LifeTime > 0.f) + { + return bDepthIsForeground ? InWorld->GetLineBatcher(UWorld::ELineBatcherType::ForegroundPersistent) : InWorld->GetLineBatcher(UWorld::ELineBatcherType::WorldPersistent); + } + else + { + return bDepthIsForeground ? InWorld->GetLineBatcher(UWorld::ELineBatcherType::Foreground) : InWorld->GetLineBatcher(UWorld::ELineBatcherType::World); + } + } + return nullptr; + //return (InWorld ? (bDepthIsForeground ? InWorld->ForegroundLineBatcher : ((bPersistentLines || (LifeTime > 0.f)) ? InWorld->PersistentLineBatcher : InWorld->LineBatcher)) : NULL); } static float GetLineLifeTime(ULineBatchComponent* LineBatcher, float LifeTime, bool bPersistent) diff --git a/Unreal/Plugins/AirSim/Source/AirSim.Build.cs b/Unreal/Plugins/AirSim/Source/AirSim.Build.cs index 6109d172d..cd9a0b70f 100644 --- a/Unreal/Plugins/AirSim/Source/AirSim.Build.cs +++ b/Unreal/Plugins/AirSim/Source/AirSim.Build.cs @@ -93,6 +93,13 @@ public AirSim(ReadOnlyTargetRules Target) : base(Target) PublicIncludePaths.Add(Path.Combine(AirLibPath, "deps", "eigen3")); AddOSLibDependencies(Target); + PrivateIncludePaths.AddRange( + new string[] { + Path.Combine(GetModuleDirectory("Renderer"), "Private"), + Path.Combine(GetModuleDirectory("Renderer"), "Internal"), + } + ); + SetupCompileMode(CompileMode.HeaderOnlyWithRpc, Target); } diff --git a/Unreal/Plugins/AirSim/Source/AirSimCameraDirector.cpp b/Unreal/Plugins/AirSim/Source/AirSimCameraDirector.cpp index 9881b9f17..17f0b8c9b 100644 --- a/Unreal/Plugins/AirSim/Source/AirSimCameraDirector.cpp +++ b/Unreal/Plugins/AirSim/Source/AirSimCameraDirector.cpp @@ -207,6 +207,8 @@ void AAirSimCameraDirector::EndPlay(const EEndPlayReason::Type EndPlayReason) backup_camera_ = nullptr; front_camera_ = nullptr; follow_actor_ = nullptr; + + Super::EndPlay(EndPlayReason); } APIPCamera* AAirSimCameraDirector::getFpvCamera() const diff --git a/Unreal/Plugins/AirSim/Source/Annotation/AnnotationComponent.cpp b/Unreal/Plugins/AirSim/Source/Annotation/AnnotationComponent.cpp index 27d0a5583..725fce10c 100644 --- a/Unreal/Plugins/AirSim/Source/Annotation/AnnotationComponent.cpp +++ b/Unreal/Plugins/AirSim/Source/Annotation/AnnotationComponent.cpp @@ -1,501 +1,703 @@ -// This class and its functions are derivatives of the work of UnrealCV, https://unrealcv.org/ -// Licensed under the MIT License. - - -#include "AnnotationComponent.h" -// Overwrite the material - -#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h" -#include "Runtime/Engine/Public/Materials/Material.h" -#include "Runtime/Engine/Public/Materials/MaterialInstanceDynamic.h" -#include "Runtime/Engine/Classes/Engine/StaticMesh.h" -#include "Runtime/Engine/Classes/Components/SkeletalMeshComponent.h" -#include "Runtime/Launch/Resources/Version.h" -#include "Runtime/Engine/Public/MaterialShared.h" -#include "Runtime/Engine/Classes/Engine/Engine.h" -#include "AirBlueprintLib.h" - -#if ENGINE_MAJOR_VERSION >= 5 -//different header files in UE -#include "Runtime/Engine/Public/StaticMeshSceneProxy.h" -#include "Runtime/Engine/Public/SkeletalMeshSceneProxy.h" - -#endif -#include "Runtime/Engine/Public/Rendering/SkeletalMeshRenderData.h" - -/** A proxy class to get mesh data from StaticMesh, should be used together with AnnotationCamSensor. -Inheritance is needed because I need to access protected data -Use `show Material` command to see the effect of this component -Note that some area might be not colored, this is caused by the issue that -both the original mesh and the annotation mesh are rendered, this is not an issue for the AnnotationCamSensor, which will exclude original meshes. -*/ -class FStaticAnnotationSceneProxy : public FStaticMeshSceneProxy -{ -public: - FMaterialRenderProxy* MaterialRenderProxy; - - //FStaticMeshSceneProxyDesc::InitializeFrom(UStaticMeshComponent* Component); - - FStaticAnnotationSceneProxy(UStaticMeshComponent* Component, bool bForceLODsShareStaticLighting, UMaterialInterface* AnnotationMID) : - FStaticMeshSceneProxy(Component, bForceLODsShareStaticLighting) - { - MaterialRenderProxy = AnnotationMID->GetRenderProxy(); - // this->MaterialRelevance = AnnotationMID->GetRelevance(GetScene().GetFeatureLevel()); - // Note: This MaterailRelevance makes no difference? - - this->bVerifyUsedMaterials = false; - // This is required, otherwise the code will fail - - bCastShadow = false; - } - - virtual void GetDynamicMeshElements( - const TArray < const FSceneView * > & Views, - const FSceneViewFamily & ViewFamily, - uint32 VisibilityMap, - FMeshElementCollector & Collector) const override; - - virtual bool GetMeshElement - ( - int32 LODIndex, - int32 BatchIndex, - int32 ElementIndex, - uint8 InDepthPriorityGroup, - bool bUseSelectedMaterial, - bool bAllowPreCulledIndices, - FMeshBatch & OutMeshBatch - ) const override; - - virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView * View) const override; -}; - -FPrimitiveViewRelevance FStaticAnnotationSceneProxy::GetViewRelevance(const FSceneView * View) const -{ - if (View->Family->EngineShowFlags.Materials) - { - FPrimitiveViewRelevance ViewRelevance; - ViewRelevance.bDrawRelevance = 0; - // This will make the AnnotationComponent gets ignored if the Materials flag is on - // Which means it won't affect regulary rendering. - return ViewRelevance; - } - else - { - return FStaticMeshSceneProxy::GetViewRelevance(View); - } -} - - -void FStaticAnnotationSceneProxy::GetDynamicMeshElements( - const TArray < const FSceneView * > & Views, - const FSceneViewFamily & ViewFamily, - uint32 VisibilityMap, - FMeshElementCollector & Collector) const -{ - //if (MaterialRenderProxy->GetMaterialName().Contains("AnnotationMaterialMID")) { - // FStaticMeshSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector); - //} - FStaticMeshSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector); - -} - -bool FStaticAnnotationSceneProxy::GetMeshElement( - int32 LODIndex, - int32 BatchIndex, - int32 ElementIndex, - uint8 InDepthPriorityGroup, - bool bUseSelectedMaterial, - bool bAllowPreCulledIndices, - FMeshBatch & OutMeshBatch) const -{ - bool Ret = FStaticMeshSceneProxy::GetMeshElement(LODIndex, BatchIndex, ElementIndex, InDepthPriorityGroup, - bUseSelectedMaterial, bAllowPreCulledIndices, OutMeshBatch); - OutMeshBatch.MaterialRenderProxy = this->MaterialRenderProxy; - return Ret; -} - -class FSkeletalAnnotationSceneProxy : public FSkeletalMeshSceneProxy -{ -public: - FSkeletalAnnotationSceneProxy(const USkinnedMeshComponent* Component, FSkeletalMeshRenderData* InSkeletalMeshRenderData, UMaterialInterface* AnnotationMID) - : FSkeletalMeshSceneProxy(Component, InSkeletalMeshRenderData) - { - // TODO: Update MaterialRelevance - this->bVerifyUsedMaterials = false; - // this->bCastShadow = false; - this->bCastDynamicShadow = false; - for(int32 LODIdx=0; LODIdx < LODSections.Num(); LODIdx++) - { - FLODSectionElements& LODSection = LODSections[LODIdx]; - for(int32 SectionIndex = 0; SectionIndex < LODSection.SectionElements.Num(); SectionIndex++) - { - if (IsValid(AnnotationMID)) - { - LODSection.SectionElements[SectionIndex].Material = AnnotationMID; - } - else - { - UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: AnnotationMaterial is Invalid in FSkeletalSceneProxy")); - } - } - } - } - virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView * View) const override; - - virtual void GetDynamicMeshElements( - const TArray& Views, - const FSceneViewFamily& ViewFamily, - uint32 VisibilityMap, - FMeshElementCollector& Collector) const; -}; - - -void FSkeletalAnnotationSceneProxy::GetDynamicMeshElements( - const TArray& Views, - const FSceneViewFamily& ViewFamily, - uint32 VisibilityMap, - FMeshElementCollector& Collector) const -{ - //if (LODSections.Num() > 0){ - // if (LODSections[0].SectionElements.Num() > 0) { - // if (LODSections[0].SectionElements[0].Material->GetName().Contains("AnnotationMaterialMID")) { - // FSkeletalMeshSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector); - // } - // } - //} - FSkeletalMeshSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector); - -} - -FPrimitiveViewRelevance FSkeletalAnnotationSceneProxy::GetViewRelevance(const FSceneView * View) const -{ - if (View->Family->EngineShowFlags.Materials) - { - FPrimitiveViewRelevance ViewRelevance; - ViewRelevance.bDrawRelevance = 0; // This will make it gets ignored, when materials flag is enabled. - return ViewRelevance; - } - else - { - return FSkeletalMeshSceneProxy::GetViewRelevance(View); - } -} - -// FString MeterialPath = TEXT("MaterialInstanceConstant'/UnrealCV/AnnotationColor_Inst.AnnotationColor_Inst'"); -// static ConstructorHelpers::FObjectFinder AnnotationMaterialObject(*MaterialPath); -UAnnotationComponent::UAnnotationComponent(const FObjectInitializer& ObjectInitializer) - : Super(ObjectInitializer) - // , ParentMeshInfo(nullptr) -{ - bSkeletalMesh = false; - bTexture = false; - - FString MaterialPath = TEXT("Material'/AirSim/HUDAssets/AnnotationMaterial.AnnotationMaterial'"); - static ConstructorHelpers::FObjectFinder AnnotationMaterialObject(*MaterialPath); - if (AnnotationMaterialObject.Object == nullptr) - { - UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Annotation material is not valid.")); - } - else - { - AnnotationMaterial = AnnotationMaterialObject.Object; - } - - FString MaterialPathSphere = TEXT("Material'/AirSim/HUDAssets/AnnotationMaterialSphere.AnnotationMaterialSphere'"); - static ConstructorHelpers::FObjectFinder SphereMaterialObject(*MaterialPathSphere); - if (SphereMaterialObject.Object == nullptr) - { - UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Sphere annotation material is not valid.")); - } - else - { - SphereMaterial = SphereMaterialObject.Object; - } - - // ParentMeshInfo = MakeShareable(new FParentMeshInfo(nullptr)); - // This will be invalid until attached to a MeshComponent - this->PrimaryComponentTick.bCanEverTick = true; -} - -void UAnnotationComponent::OnRegister() -{ - Super::OnRegister(); - - if (this->GetFName().ToString().Contains("annotation_sphere")) { - AnnotationMID = UMaterialInstanceDynamic::Create(SphereMaterial, this, TEXT("AnnotationMaterialMID")); - if (!IsValid(AnnotationMID)) - { - UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: SphereMaterial is not correctly initialized")); - return; - } - FLinearColor LinearAnnotationColor = FLinearColor(0, 0, 0, 1.0); - AnnotationMID->SetVectorParameterValue("AnnotationColor", LinearAnnotationColor); - } - else { - // Note: This can not be placed in the constructor, MID means material instance dynamic - AnnotationMID = UMaterialInstanceDynamic::Create(AnnotationMaterial, this, TEXT("AnnotationMaterialMID")); - if (!IsValid(AnnotationMID)) - { - UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: ColorAnnotationMaterial is not correctly initialized")); - return; - } - const float OneOver255 = 1.0f / 255.0f; - FLinearColor LinearAnnotationColor = FLinearColor( - this->AnnotationColor.R * OneOver255, - this->AnnotationColor.G * OneOver255, - this->AnnotationColor.B * OneOver255, - 1.0 - ); - AnnotationMID->SetVectorParameterValue("AnnotationColor", LinearAnnotationColor); - } -} - -/** - * Note: The "exposure compensation" in "PostProcessVolume3" in the RR map will destroy the color - * Saturate the color to 1. This is a mysterious behavior after tedious debug. - */ -void UAnnotationComponent::SetAnnotationColor(FColor NewAnnotationColor) -{ - if (NewAnnotationColor.R == 27)NewAnnotationColor.R = 26; - if (NewAnnotationColor.G == 27)NewAnnotationColor.G = 26; - if (NewAnnotationColor.B == 27)NewAnnotationColor.B = 26; - if (NewAnnotationColor.R == 32)NewAnnotationColor.R = 31; - if (NewAnnotationColor.G == 32)NewAnnotationColor.G = 31; - if (NewAnnotationColor.B == 32)NewAnnotationColor.B = 31; - if (NewAnnotationColor.R == 35)NewAnnotationColor.R = 34; - if (NewAnnotationColor.G == 35)NewAnnotationColor.G = 34; - if (NewAnnotationColor.B == 35)NewAnnotationColor.B = 34; - if (NewAnnotationColor.R == 41)NewAnnotationColor.R = 40; - if (NewAnnotationColor.G == 41)NewAnnotationColor.G = 40; - if (NewAnnotationColor.B == 41)NewAnnotationColor.B = 40; - if (NewAnnotationColor.R == 44)NewAnnotationColor.R = 43; - if (NewAnnotationColor.G == 44)NewAnnotationColor.G = 43; - if (NewAnnotationColor.B == 44)NewAnnotationColor.B = 43; - if (NewAnnotationColor.R == 49)NewAnnotationColor.R = 48; - if (NewAnnotationColor.G == 49)NewAnnotationColor.G = 48; - if (NewAnnotationColor.B == 49)NewAnnotationColor.B = 48; - if (NewAnnotationColor.R == 51)NewAnnotationColor.R = 50; - if (NewAnnotationColor.G == 51)NewAnnotationColor.G = 50; - if (NewAnnotationColor.B == 51)NewAnnotationColor.B = 50; - this->AnnotationColor = NewAnnotationColor; - const float OneOver255 = 1.0f / 255.0f; // TODO: Check 255 or 256? - - FLinearColor LinearAnnotationColor = FLinearColor( - AnnotationColor.R * OneOver255, - AnnotationColor.G * OneOver255, - AnnotationColor.B * OneOver255, - 1.0 - ); - - if (IsValid(AnnotationMID)) - { - AnnotationMID->SetVectorParameterValue("AnnotationColor", LinearAnnotationColor); - } -} - -void UAnnotationComponent::SetAnnotationTexture(FString NewAnnotationTexturePath) -{ - bTexture = true; - AnnotationMID->SetScalarParameterValue("TextureEnabled", 1); - this->AnnotationTexturePath = NewAnnotationTexturePath; - TArray splitPath; - NewAnnotationTexturePath.ParseIntoArray(splitPath, TEXT("/"), true); - FString TextureFileName = splitPath.Last(); - FString FullPath = FString::Printf(TEXT("%s.%s"), *NewAnnotationTexturePath, *TextureFileName); - UTexture* AnnotationTexture = LoadObject(NULL, *FullPath); - - if (AnnotationTexture != nullptr) - { - if (IsValid(AnnotationMID)) - { - AnnotationMID->SetTextureParameterValue("AnnotationTexture", AnnotationTexture); - }else - { - UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Could not set annotation texture to %s cause something wrong with MID."), *FullPath); - } - } - else - { - UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Could not set annotation texture to %s."), *FullPath); - } -} - -void UAnnotationComponent::SetAnnotationTexture(UTexture* NewAnnotationTexture) -{ - bTexture = true; - AnnotationMID->SetScalarParameterValue("TextureEnabled", 1); - TArray splitPath; - NewAnnotationTexture->GetPathName().ParseIntoArray(splitPath, TEXT("."), true); - FString TextureFilePath = splitPath[0]; - this->AnnotationTexturePath = TextureFilePath; - if (IsValid(AnnotationMID)) - { - AnnotationMID->SetTextureParameterValue("AnnotationTexture", NewAnnotationTexture); - } -} - -FColor UAnnotationComponent::GetAnnotationColor() -{ - return AnnotationColor; -} - -FString UAnnotationComponent::GetAnnotationTexturePath() -{ - return AnnotationTexturePath; -} - -FPrimitiveSceneProxy* UAnnotationComponent::CreateSceneProxy(UStaticMeshComponent* StaticMeshComponent) -{ - // FPrimitiveSceneProxy* PrimitiveSceneProxy = StaticMeshComponent->CreateSceneProxy(); - // FStaticMeshSceneProxy* StaticMeshSceneProxy = (FStaticMeshSceneProxy*)PrimitiveSceneProxy; - UMaterialInterface* ProxyMaterial = AnnotationMID; // Material Instance Dynamic - UStaticMesh* ParentStaticMesh = StaticMeshComponent->GetStaticMesh(); - if(ParentStaticMesh == NULL - || ParentStaticMesh->GetRenderData() == NULL - || ParentStaticMesh->GetRenderData()->LODResources.Num() == 0) - // || StaticMesh->RenderData->LODResources[0].VertexBuffer.GetNumVertices() == 0) - { - // UE_LOG(LogTemp, Warning, TEXT("%s, ParentStaticMesh is invalid."), *StaticMeshComponent->GetName()); - return NULL; - } - - // FPrimitiveSceneProxy* Proxy = ::new FStaticMeshSceneProxy(OwnerComponent, false); - FPrimitiveSceneProxy* Proxy = ::new FStaticAnnotationSceneProxy(StaticMeshComponent, false, ProxyMaterial); - return Proxy; - // This is not recommended, but I know what I am doing. -} - -// See https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Source/Runtime/Engine/Private/Components/SkinnedMeshComponent.cpp:417 -FPrimitiveSceneProxy* UAnnotationComponent::CreateSceneProxy(USkeletalMeshComponent* SkeletalMeshComponent) -{ - UMaterialInterface* ProxyMaterial = AnnotationMID; // Material Instance Dynamic - - ERHIFeatureLevel::Type SceneFeatureLevel = GetWorld()->GetFeatureLevel(); - - // Ref: https://github.com/EpicGames/UnrealEngine/blob/4.19/Engine/Source/Runtime/Engine/Private/Components/SkinnedMeshComponent.cpp#L415 - FSkeletalMeshRenderData* SkelMeshRenderData = SkeletalMeshComponent->GetSkeletalMeshRenderData(); - - // Only create a scene proxy for rendering if properly initialized - if (SkelMeshRenderData && - SkelMeshRenderData->LODRenderData.IsValidIndex(SkeletalMeshComponent->GetPredictedLODLevel()) && - SkeletalMeshComponent->MeshObject) // The risk of using MeshObject - { - // Only create a scene proxy if the bone count being used is supported, or if we don't have a skeleton (this is the case with destructibles) - // int32 MaxBonesPerChunk = SkelMeshResource->GetMaxBonesPerSection(); - // if (MaxBonesPerChunk <= GetFeatureLevelMaxNumberOfBones(SceneFeatureLevel)) - // { - // Result = ::new FSkeletalAnnotationSceneProxy(SkeletalMeshComponent, SkelMeshResource, AnnotationMID); - // } - // TODO: The SkeletalMeshComponent might need to be recreated - return new FSkeletalAnnotationSceneProxy(SkeletalMeshComponent, SkelMeshRenderData, ProxyMaterial); - } - else - { - UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: The data of SkeletalMeshComponent %s is invalid."), *SkeletalMeshComponent->GetName()); - return nullptr; - } -} - - -// TODO: This needs to be involked when the ParentComponent refresh its render state, otherwise it will crash the engine -FPrimitiveSceneProxy* UAnnotationComponent::CreateSceneProxy() -{ - // UMaterialInstanceDynamic* AnnotationMID = UMaterialInstanceDynamic::Create(AnnotationMaterial, this); - // FColor AnnotationColor = FColor::MakeRandomColor(); - // AnnotationMID->SetVectorParameterByIndex(0, AnnotationColor); - - USceneComponent* ParentComponent = this->GetAttachParent(); - // USceneComponent* ParentComponent = this->ParentMeshInfo->GetParentMeshComponent(); - - if (!IsValid(ParentComponent)) - { - UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Parent component is invalid.")); - return nullptr; - } - - - UStaticMeshComponent* StaticMeshComponent = Cast(ParentComponent); - USkeletalMeshComponent* SkeletalMeshComponent = Cast(ParentComponent); - // UCableComponent* CableComponent = Cast(ParentComponent); - if (IsValid(StaticMeshComponent)) - { - return CreateSceneProxy(StaticMeshComponent); - } - else if (IsValid(SkeletalMeshComponent)) - { - bSkeletalMesh = true; - return CreateSceneProxy(SkeletalMeshComponent); - } - // else if (IsValid(CableComponent)) - // { - // return CreateSceneProxy(CableComponent); - // } - else - { - //UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: The type of ParentMeshComponent : %s can not be supported."), *ParentComponent->GetClass()->GetName()); - return nullptr; - } - // return nullptr; -} - -FBoxSphereBounds UAnnotationComponent::CalcBounds(const FTransform & LocalToWorld) const -{ - // UMeshComponent* ParentMeshComponent = ParentMeshInfo->GetParentMeshComponent(); - // if (IsValid(ParentMeshComponent)) - // { - // return ParentMeshComponent->CalcBounds(LocalToWorld); - // } - // else - // { - // FBoxSphereBounds DefaultBounds; - // return DefaultBounds; - // } - - USceneComponent* Parent = this->GetAttachParent(); - UStaticMeshComponent* StaticMeshComponent = Cast(Parent); - if (IsValid(StaticMeshComponent)) - { - return StaticMeshComponent->CalcBounds(LocalToWorld); - } - - USkeletalMeshComponent* SkeletalMeshComponent = Cast(Parent); - if (IsValid(SkeletalMeshComponent)) - { - return SkeletalMeshComponent->CalcBounds(LocalToWorld); - } - - FBoxSphereBounds DefaultBounds; - DefaultBounds.Origin = LocalToWorld.GetLocation(); - DefaultBounds.BoxExtent = FVector::ZeroVector; - DefaultBounds.SphereRadius = 0.f; - return DefaultBounds; -} - -// Extra overhead for the game scene -void UAnnotationComponent::TickComponent( - float DeltaTime, - enum ELevelTick TickType, - FActorComponentTickFunction * ThisTickFunction) -{ - Super::TickComponent(DeltaTime, TickType, ThisTickFunction); - - if (bSkeletalMesh) - { - MarkRenderStateDirty(); // Without it will break the SkeletalMeshComponent - } - /* - // if (ParentMeshInfo->RequiresUpdate()) - // TODO: This sometimes miss a required update, see OWIMap. Not sure why. - // TODO: Per-frame update is certainly wasted. - { - // FIXME: Update the render proxy per frame will cause jittering on the material. - ParentMeshInfo = MakeShareable(new FParentMeshInfo(this->GetAttachParent())); - } - */ -} - - -void UAnnotationComponent::ForceUpdate() -{ - this->MarkRenderStateDirty(); -} +// This class and its functions are derivatives of the work of UnrealCV, https://unrealcv.org/ +// Licensed under the MIT License. + + +#include "AnnotationComponent.h" +// Overwrite the material + +#include "Runtime/CoreUObject/Public/UObject/ConstructorHelpers.h" +#include "Runtime/Engine/Public/Materials/Material.h" +#include "Runtime/Engine/Public/Materials/MaterialInstanceDynamic.h" +#include "Runtime/Engine/Classes/Engine/StaticMesh.h" +#include "Runtime/Engine/Classes/Components/SkeletalMeshComponent.h" +#include "Runtime/Launch/Resources/Version.h" +#include "Runtime/Engine/Public/MaterialShared.h" +#include "Runtime/Engine/Classes/Engine/Engine.h" +#include "SceneView.h" +#include "AirBlueprintLib.h" + +#if ENGINE_MAJOR_VERSION >= 5 +//different header files in UE +#include "Runtime/Engine/Public/StaticMeshSceneProxy.h" +#include "Runtime/Engine/Public/SkeletalMeshSceneProxy.h" +#include "Runtime/Engine/Public/SkinnedMeshSceneProxyDesc.h" +#endif +#include "Runtime/Engine/Public/Rendering/SkeletalMeshRenderData.h" + +/** A proxy class to get mesh data from StaticMesh, should be used together with AnnotationCamSensor. +Inheritance is needed because I need to access protected data +Use `show Material` command to see the effect of this component +Note that some area might be not colored, this is caused by the issue that +both the original mesh and the annotation mesh are rendered, this is not an issue for the AnnotationCamSensor, which will exclude original meshes. +*/ +class FStaticAnnotationSceneProxy : public FStaticMeshSceneProxy +{ +public: + FMaterialRenderProxy* MaterialRenderProxy; + + //FStaticMeshSceneProxyDesc::InitializeFrom(UStaticMeshComponent* Component); + + FStaticAnnotationSceneProxy(UStaticMeshComponent* Component, bool bForceLODsShareStaticLighting, UMaterialInterface* AnnotationMID) : + FStaticMeshSceneProxy(Component, bForceLODsShareStaticLighting) + { + MaterialRenderProxy = AnnotationMID->GetRenderProxy(); + // this->MaterialRelevance = AnnotationMID->GetRelevance(GetScene().GetFeatureLevel()); + // Note: This MaterailRelevance makes no difference? + + this->bVerifyUsedMaterials = false; + // This is required, otherwise the code will fail + + bCastShadow = false; + } + + virtual void GetDynamicMeshElements( + const TArray < const FSceneView * > & Views, + const FSceneViewFamily & ViewFamily, + uint32 VisibilityMap, + FMeshElementCollector & Collector) const override; + + virtual bool GetMeshElement + ( + int32 LODIndex, + int32 BatchIndex, + int32 ElementIndex, + uint8 InDepthPriorityGroup, + bool bUseSelectedMaterial, + bool bAllowPreCulledIndices, + FMeshBatch & OutMeshBatch + ) const override; + + virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView * View) const override; +}; + +FPrimitiveViewRelevance FStaticAnnotationSceneProxy::GetViewRelevance(const FSceneView * View) const +{ + if (View->Family->EngineShowFlags.Materials) + { + FPrimitiveViewRelevance ViewRelevance; + ViewRelevance.bDrawRelevance = 0; + return ViewRelevance; + } + else + { + return FStaticMeshSceneProxy::GetViewRelevance(View); + } +} + + +void FStaticAnnotationSceneProxy::GetDynamicMeshElements( + const TArray < const FSceneView * > & Views, + const FSceneViewFamily & ViewFamily, + uint32 VisibilityMap, + FMeshElementCollector & Collector) const +{ + //if (MaterialRenderProxy->GetMaterialName().Contains("AnnotationMaterialMID")) { + // FStaticMeshSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector); + //} + FStaticMeshSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector); + +} + +bool FStaticAnnotationSceneProxy::GetMeshElement( + int32 LODIndex, + int32 BatchIndex, + int32 ElementIndex, + uint8 InDepthPriorityGroup, + bool bUseSelectedMaterial, + bool bAllowPreCulledIndices, + FMeshBatch & OutMeshBatch) const +{ + bool Ret = FStaticMeshSceneProxy::GetMeshElement(LODIndex, BatchIndex, ElementIndex, InDepthPriorityGroup, + bUseSelectedMaterial, bAllowPreCulledIndices, OutMeshBatch); + OutMeshBatch.MaterialRenderProxy = this->MaterialRenderProxy; + return Ret; +} + +class FSkeletalAnnotationSceneProxy : public FSkeletalMeshSceneProxy +{ +public: + FSkeletalAnnotationSceneProxy(const USkinnedMeshComponent* Component, FSkeletalMeshRenderData* InSkeletalMeshRenderData, UMaterialInterface* AnnotationMID) + : FSkeletalMeshSceneProxy(Component, InSkeletalMeshRenderData) + { + this->bVerifyUsedMaterials = false; + this->bCastDynamicShadow = false; + for(int32 LODIdx=0; LODIdx < LODSections.Num(); LODIdx++) + { + FLODSectionElements& LODSection = LODSections[LODIdx]; + for(int32 SectionIndex = 0; SectionIndex < LODSection.SectionElements.Num(); SectionIndex++) + { + if (IsValid(AnnotationMID)) + { + LODSection.SectionElements[SectionIndex].Material = AnnotationMID; + } + else + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: AnnotationMaterial is Invalid in FSkeletalSceneProxy")); + } + } + } + } + virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView * View) const override; + + virtual void GetDynamicMeshElements( + const TArray& Views, + const FSceneViewFamily& ViewFamily, + uint32 VisibilityMap, + FMeshElementCollector& Collector) const; +}; + +// Nanite skeletal mesh annotation proxy. +// Uses Nanite's own rendering pipeline so it works correctly in annotation cameras +// (ShowFlags.Materials=false does NOT disable Nanite shading — Nanite is gated by NaniteMeshes). +// GetViewRelevance hides this proxy from the main viewport (Materials=true) so no duplicate +// copies appear alongside the original Nanite mesh. +// +// IMPORTANT: The proxy is constructed from SkeletalMeshComponent (for mesh/skin data) but +// overrides ComponentId to use AnnotationComponent's ID. This prevents a PrimitiveComponentId +// conflict with the original Nanite proxy and ensures ShowOnlyComponents/HiddenComponents +// filtering correctly identifies this proxy as belonging to the UAnnotationComponent. +class FNaniteSkeletalAnnotationSceneProxy : public Nanite::FSkinnedSceneProxy +{ +public: + FNaniteSkeletalAnnotationSceneProxy( + const USkinnedMeshComponent* SkeletalMeshComponent, + const UPrimitiveComponent* AnnotationComponent, + FSkeletalMeshRenderData* InRenderData, + UMaterialInterface* AnnotationMID + ) + : Nanite::FSkinnedSceneProxy( + CreateNaniteMaterialAudit(SkeletalMeshComponent), + CreateAnnotationDesc(SkeletalMeshComponent, AnnotationComponent), + InRenderData, + true) + { + if (!IsValid(AnnotationMID)) + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Nanite skeletal annotation material is invalid")); + return; + } + + FMaterialRenderProxy* AnnotationRenderProxy = AnnotationMID->GetRenderProxy(); + for (Nanite::FSceneProxyBase::FMaterialSection& MaterialSection : GetMaterialSections()) + { + if (!MaterialSection.bHidden) + { + MaterialSection.ShadingMaterialProxy = AnnotationRenderProxy; + } + } + OnMaterialsUpdated(); + } + + virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override + { + // Hide from main pass and RGB cameras (Materials=true) to avoid duplicating the original mesh. + // Annotation cameras set Materials=false — Nanite still shades normally in that mode, + // so the annotation color is correctly applied there. + if (View->Family->EngineShowFlags.Materials) + { + FPrimitiveViewRelevance ViewRelevance; + ViewRelevance.bDrawRelevance = 0; + return ViewRelevance; + } + return Nanite::FSkinnedSceneProxy::GetViewRelevance(View); + } + +private: + static Nanite::FMaterialAudit CreateNaniteMaterialAudit(const USkinnedMeshComponent* Component) + { + Nanite::FMaterialAudit Audit; + if (Component) + { + Nanite::AuditMaterials(Component, Audit, false); + } + return Audit; + } + + // Creates a proxy desc from the skeletal mesh but overrides ComponentId to match + // the annotation component. This ensures the proxy is correctly identified for + // ShowOnlyComponents/HiddenComponents filtering without conflicting with the + // original Nanite skeletal proxy (which uses SkeletalMeshComponent's ComponentId). + static FSkinnedMeshSceneProxyDesc CreateAnnotationDesc( + const USkinnedMeshComponent* SkeletalMeshComponent, + const UPrimitiveComponent* AnnotationComponent) + { + FSkinnedMeshSceneProxyDesc Desc(SkeletalMeshComponent); + Desc.ComponentId = AnnotationComponent->GetPrimitiveSceneId(); + return Desc; + } +}; + + +void FSkeletalAnnotationSceneProxy::GetDynamicMeshElements( + const TArray& Views, + const FSceneViewFamily& ViewFamily, + uint32 VisibilityMap, + FMeshElementCollector& Collector) const +{ + //if (LODSections.Num() > 0){ + // if (LODSections[0].SectionElements.Num() > 0) { + // if (LODSections[0].SectionElements[0].Material->GetName().Contains("AnnotationMaterialMID")) { + // FSkeletalMeshSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector); + // } + // } + //} + FSkeletalMeshSceneProxy::GetDynamicMeshElements(Views, ViewFamily, VisibilityMap, Collector); + +} + +FPrimitiveViewRelevance FSkeletalAnnotationSceneProxy::GetViewRelevance(const FSceneView * View) const +{ + if (View->Family->EngineShowFlags.Materials) + { + FPrimitiveViewRelevance ViewRelevance; + ViewRelevance.bDrawRelevance = 0; + return ViewRelevance; + } + else + { + return FSkeletalMeshSceneProxy::GetViewRelevance(View); + } +} + +// FString MeterialPath = TEXT("MaterialInstanceConstant'/UnrealCV/AnnotationColor_Inst.AnnotationColor_Inst'"); +UAnnotationComponent::UAnnotationComponent(const FObjectInitializer& ObjectInitializer) + : Super(ObjectInitializer) + // , ParentMeshInfo(nullptr) +{ + bSkeletalMesh = false; + bTexture = false; + last_foliage_type_ = EFoliageComponentType::None; + + FString MaterialPath = TEXT("Material'/AirSim/HUDAssets/AnnotationMaterial.AnnotationMaterial'"); + static ConstructorHelpers::FObjectFinder AnnotationMaterialObject(*MaterialPath); + if (AnnotationMaterialObject.Object == nullptr) + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Annotation material is not valid.")); + } + else + { + AnnotationMaterial = AnnotationMaterialObject.Object; + } + + FString MaterialPathSphere = TEXT("Material'/AirSim/HUDAssets/AnnotationMaterialSphere.AnnotationMaterialSphere'"); + static ConstructorHelpers::FObjectFinder SphereMaterialObject(*MaterialPathSphere); + if (SphereMaterialObject.Object == nullptr) + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Sphere annotation material is not valid.")); + } + else + { + SphereMaterial = SphereMaterialObject.Object; + } + + // ParentMeshInfo = MakeShareable(new FParentMeshInfo(nullptr)); + // This will be invalid until attached to a MeshComponent + this->PrimaryComponentTick.bCanEverTick = true; +} + +void UAnnotationComponent::OnRegister() +{ + Super::OnRegister(); + + // Ensure the annotation material supports Nanite skeletal mesh shading. + // Nanite checks both MATUSAGE_Nanite and MATUSAGE_SkeletalMesh (NaniteResources.cpp:2535). + // In the editor, CheckMaterialUsage sets the flag and triggers a one-time shader recompile if needed. + if (AnnotationMaterial) + { + AnnotationMaterial->CheckMaterialUsage(MATUSAGE_Nanite); + AnnotationMaterial->CheckMaterialUsage(MATUSAGE_SkeletalMesh); + } + + if (this->GetFName().ToString().Contains("annotation_sphere")) { + AnnotationMID = UMaterialInstanceDynamic::Create(SphereMaterial, this, TEXT("AnnotationMaterialMID")); + if (!IsValid(AnnotationMID)) + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: SphereMaterial is not correctly initialized")); + return; + } + FLinearColor LinearAnnotationColor = FLinearColor(0, 0, 0, 1.0); + AnnotationMID->SetVectorParameterValue("AnnotationColor", LinearAnnotationColor); + } + else { + // Note: This can not be placed in the constructor, MID means material instance dynamic + AnnotationMID = UMaterialInstanceDynamic::Create(AnnotationMaterial, this, TEXT("AnnotationMaterialMID")); + if (!IsValid(AnnotationMID)) + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: ColorAnnotationMaterial is not correctly initialized")); + return; + } + const float OneOver255 = 1.0f / 255.0f; + FLinearColor LinearAnnotationColor = FLinearColor( + this->AnnotationColor.R * OneOver255, + this->AnnotationColor.G * OneOver255, + this->AnnotationColor.B * OneOver255, + 1.0 + ); + AnnotationMID->SetVectorParameterValue("AnnotationColor", LinearAnnotationColor); + } +} + +/** + * Note: The "exposure compensation" in "PostProcessVolume3" in the RR map will destroy the color + * Saturate the color to 1. This is a mysterious behavior after tedious debug. + */ +void UAnnotationComponent::SetAnnotationColor(FColor NewAnnotationColor) +{ + if (NewAnnotationColor.R == 27)NewAnnotationColor.R = 26; + if (NewAnnotationColor.G == 27)NewAnnotationColor.G = 26; + if (NewAnnotationColor.B == 27)NewAnnotationColor.B = 26; + if (NewAnnotationColor.R == 32)NewAnnotationColor.R = 31; + if (NewAnnotationColor.G == 32)NewAnnotationColor.G = 31; + if (NewAnnotationColor.B == 32)NewAnnotationColor.B = 31; + if (NewAnnotationColor.R == 35)NewAnnotationColor.R = 34; + if (NewAnnotationColor.G == 35)NewAnnotationColor.G = 34; + if (NewAnnotationColor.B == 35)NewAnnotationColor.B = 34; + if (NewAnnotationColor.R == 41)NewAnnotationColor.R = 40; + if (NewAnnotationColor.G == 41)NewAnnotationColor.G = 40; + if (NewAnnotationColor.B == 41)NewAnnotationColor.B = 40; + if (NewAnnotationColor.R == 44)NewAnnotationColor.R = 43; + if (NewAnnotationColor.G == 44)NewAnnotationColor.G = 43; + if (NewAnnotationColor.B == 44)NewAnnotationColor.B = 43; + if (NewAnnotationColor.R == 49)NewAnnotationColor.R = 48; + if (NewAnnotationColor.G == 49)NewAnnotationColor.G = 48; + if (NewAnnotationColor.B == 49)NewAnnotationColor.B = 48; + if (NewAnnotationColor.R == 51)NewAnnotationColor.R = 50; + if (NewAnnotationColor.G == 51)NewAnnotationColor.G = 50; + if (NewAnnotationColor.B == 51)NewAnnotationColor.B = 50; + this->AnnotationColor = NewAnnotationColor; + const float OneOver255 = 1.0f / 255.0f; // TODO: Check 255 or 256? + + FLinearColor LinearAnnotationColor = FLinearColor( + AnnotationColor.R * OneOver255, + AnnotationColor.G * OneOver255, + AnnotationColor.B * OneOver255, + 1.0 + ); + + if (IsValid(AnnotationMID)) + { + AnnotationMID->SetVectorParameterValue("AnnotationColor", LinearAnnotationColor); + } +} + +void UAnnotationComponent::SetAnnotationTexture(FString NewAnnotationTexturePath) +{ + bTexture = true; + AnnotationMID->SetScalarParameterValue("TextureEnabled", 1); + this->AnnotationTexturePath = NewAnnotationTexturePath; + TArray splitPath; + NewAnnotationTexturePath.ParseIntoArray(splitPath, TEXT("/"), true); + FString TextureFileName = splitPath.Last(); + FString FullPath = FString::Printf(TEXT("%s.%s"), *NewAnnotationTexturePath, *TextureFileName); + UTexture* AnnotationTexture = LoadObject(NULL, *FullPath); + + if (AnnotationTexture != nullptr) + { + if (IsValid(AnnotationMID)) + { + AnnotationMID->SetTextureParameterValue("AnnotationTexture", AnnotationTexture); + }else + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Could not set annotation texture to %s cause something wrong with MID."), *FullPath); + } + } + else + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Could not set annotation texture to %s."), *FullPath); + } +} + +void UAnnotationComponent::SetAnnotationTexture(UTexture* NewAnnotationTexture) +{ + bTexture = true; + AnnotationMID->SetScalarParameterValue("TextureEnabled", 1); + TArray splitPath; + NewAnnotationTexture->GetPathName().ParseIntoArray(splitPath, TEXT("."), true); + FString TextureFilePath = splitPath[0]; + this->AnnotationTexturePath = TextureFilePath; + if (IsValid(AnnotationMID)) + { + AnnotationMID->SetTextureParameterValue("AnnotationTexture", NewAnnotationTexture); + } +} + +FColor UAnnotationComponent::GetAnnotationColor() +{ + return AnnotationColor; +} + +FString UAnnotationComponent::GetAnnotationTexturePath() +{ + return AnnotationTexturePath; +} + +UAnnotationComponent::EFoliageComponentType UAnnotationComponent::GetLastDetectedFoliageType() const +{ + return last_foliage_type_; +} + +UAnnotationComponent::EFoliageComponentType UAnnotationComponent::ClassifyFoliageType(const USceneComponent* Component) +{ + const UMeshComponent* MeshComponent = Cast(Component); + if (!IsValid(MeshComponent)) + { + return EFoliageComponentType::None; + } + + const FString ClassName = MeshComponent->GetClass()->GetName().ToLower(); + const FString ComponentName = MeshComponent->GetName().ToLower(); + const AActor* Owner = MeshComponent->GetOwner(); + const FString OwnerName = Owner ? Owner->GetName().ToLower() : TEXT(""); + const FString OwnerClassName = Owner ? Owner->GetClass()->GetName().ToLower() : TEXT(""); + + const bool bFoliageLike = + ClassName.Contains(TEXT("foliage")) || + ClassName.Contains(TEXT("vegetation")) || + ComponentName.Contains(TEXT("foliage")) || + ComponentName.Contains(TEXT("vegetation")) || + OwnerName.Contains(TEXT("foliage")) || + OwnerName.Contains(TEXT("vegetation")) || + OwnerClassName.Contains(TEXT("foliage")) || + OwnerClassName.Contains(TEXT("vegetation")); + + if (!bFoliageLike) + { + return EFoliageComponentType::None; + } + + if (Cast(MeshComponent)) + { + return EFoliageComponentType::StaticFoliage; + } + + if (Cast(MeshComponent)) + { + return EFoliageComponentType::SkeletalFoliage; + } + + const bool bInstancedSkeletalLike = + ClassName.Contains(TEXT("instancedskeletal")) || + ClassName.Contains(TEXT("instancedskinned")) || + (ClassName.Contains(TEXT("instanced")) && (ClassName.Contains(TEXT("skeletal")) || ClassName.Contains(TEXT("skinned")))) || + ComponentName.Contains(TEXT("instancedskeletal")) || + ComponentName.Contains(TEXT("instancedskinned")); + + if (bInstancedSkeletalLike) + { + return EFoliageComponentType::InstancedSkeletalFoliage; + } + + return EFoliageComponentType::None; +} + +bool UAnnotationComponent::IsNaniteSkeletalMesh(const USkeletalMeshComponent* SkeletalMeshComponent) +{ + if (!IsValid(SkeletalMeshComponent)) + { + return false; + } + // USkeletalMesh::IsNaniteEnabled()/NaniteSettings reflect the editor-only build *intent* and are + // compiled out entirely in packaged/cooked builds (gated behind WITH_EDITORONLY_DATA), and + // USkeletalMesh::HasValidNaniteData() turned out to be private. FSkeletalMeshRenderData's own + // HasValidNaniteData() is public and reflects the actual cooked render data, and is available in + // every build configuration, so it's used here instead. + const FSkeletalMeshRenderData* SkelMeshRenderData = SkeletalMeshComponent->GetSkeletalMeshRenderData(); + return SkelMeshRenderData && SkelMeshRenderData->HasValidNaniteData(); +} + +FPrimitiveSceneProxy* UAnnotationComponent::CreateSceneProxyNaniteSkeletal(USkeletalMeshComponent* SkeletalMeshComponent) +{ + FSkeletalMeshRenderData* SkelMeshRenderData = SkeletalMeshComponent->GetSkeletalMeshRenderData(); + if (!SkelMeshRenderData || !SkelMeshRenderData->LODRenderData.IsValidIndex(SkeletalMeshComponent->GetPredictedLODLevel())) + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Nanite skeletal proxy creation skipped for %s - render data not ready (LOD level %d)"), + *SkeletalMeshComponent->GetName(), SkeletalMeshComponent->GetPredictedLODLevel()); + return nullptr; + } + if (!IsValid(AnnotationMID)) + { + return nullptr; + } + UE_LOG(LogTemp, Verbose, TEXT("AirSim Annotation: Creating Nanite skeletal annotation proxy for %s"), *SkeletalMeshComponent->GetName()); + // Pass 'this' (UAnnotationComponent) as the annotation component so the proxy gets the + // correct PrimitiveComponentId, preventing conflicts with the original Nanite proxy. + return ::new FNaniteSkeletalAnnotationSceneProxy(SkeletalMeshComponent, this, SkelMeshRenderData, AnnotationMID); +} + +FPrimitiveSceneProxy* UAnnotationComponent::CreateSceneProxyNaniteInstancedSkeletal(USkinnedMeshComponent* InstancedMeshComponent) +{ + FSkeletalMeshRenderData* SkelMeshRenderData = InstancedMeshComponent->GetSkeletalMeshRenderData(); + if (!SkelMeshRenderData || SkelMeshRenderData->LODRenderData.Num() == 0) + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Nanite instanced skinned proxy creation skipped for %s - render data not ready"), + *InstancedMeshComponent->GetName()); + return nullptr; + } + if (!IsValid(AnnotationMID)) + { + return nullptr; + } + // MeshObject must be valid — it's set up by the component's CreateRenderState_Concurrent. + // If null, the render state hasn't been created yet; return nullptr and rely on TickComponent to retry. + if (!InstancedMeshComponent->MeshObject) + { + return nullptr; + } + // See the comment in IsNaniteSkeletalMesh() above: FSkeletalMeshRenderData::HasValidNaniteData() + // (already fetched above as SkelMeshRenderData) is used instead of the editor-only/private + // USkeletalMesh accessors so this also compiles/works in packaged builds. + if (!SkelMeshRenderData->HasValidNaniteData()) + { + UE_LOG(LogTemp, Verbose, TEXT("AirSim Annotation: Skipping non-Nanite instanced skinned mesh %s"), *InstancedMeshComponent->GetName()); + return nullptr; + } + UE_LOG(LogTemp, Verbose, TEXT("AirSim Annotation: Creating Nanite instanced skeletal annotation proxy for %s"), *InstancedMeshComponent->GetName()); + // Share the existing MeshObject (already set up by the component's CreateRenderState_Concurrent) + // via FSkinnedMeshSceneProxyDesc. This means all instances' skinning data is available to Nanite. + return ::new FNaniteSkeletalAnnotationSceneProxy(InstancedMeshComponent, this, SkelMeshRenderData, AnnotationMID); +} + +FPrimitiveSceneProxy* UAnnotationComponent::CreateSceneProxy(UStaticMeshComponent* StaticMeshComponent) +{ + UMaterialInterface* ProxyMaterial = AnnotationMID; // Material Instance Dynamic + UStaticMesh* ParentStaticMesh = StaticMeshComponent->GetStaticMesh(); + if (ParentStaticMesh == NULL + || ParentStaticMesh->GetRenderData() == NULL + || ParentStaticMesh->GetRenderData()->LODResources.Num() == 0) + { + return NULL; + } + + UE_LOG(LogTemp, VeryVerbose, TEXT("AirSim Annotation: Creating FStaticAnnotationSceneProxy for %s"), *StaticMeshComponent->GetName()); + FPrimitiveSceneProxy* Proxy = ::new FStaticAnnotationSceneProxy(StaticMeshComponent, false, ProxyMaterial); + return Proxy; +} + +FPrimitiveSceneProxy* UAnnotationComponent::CreateSceneProxy(USkeletalMeshComponent* SkeletalMeshComponent) +{ + // Nanite skeletal meshes must use FNaniteSkeletalAnnotationSceneProxy. + // FSkeletalMeshSceneProxy cannot be used with FSkeletalMeshObjectNanite because + // Nanite does not initialize the traditional GPU skin vertex factories (only for ray tracing), + // leading to null uniform buffer crashes in the non-Nanite rendering path. + if (IsNaniteSkeletalMesh(SkeletalMeshComponent)) + { + return CreateSceneProxyNaniteSkeletal(SkeletalMeshComponent); + } + + UMaterialInterface* ProxyMaterial = AnnotationMID; + FSkeletalMeshRenderData* SkelMeshRenderData = SkeletalMeshComponent->GetSkeletalMeshRenderData(); + + if (SkelMeshRenderData + && SkelMeshRenderData->LODRenderData.IsValidIndex(SkeletalMeshComponent->GetPredictedLODLevel()) + && SkeletalMeshComponent->MeshObject) + { + return new FSkeletalAnnotationSceneProxy(SkeletalMeshComponent, SkelMeshRenderData, ProxyMaterial); + } + + return nullptr; +} + +FPrimitiveSceneProxy* UAnnotationComponent::CreateSceneProxy() +{ + USceneComponent* ParentComponent = this->GetAttachParent(); + if (!IsValid(ParentComponent)) + { + UE_LOG(LogTemp, Warning, TEXT("AirSim Annotation: Parent component is invalid.")); + return nullptr; + } + + last_foliage_type_ = ClassifyFoliageType(ParentComponent); + + UStaticMeshComponent* StaticMeshComponent = Cast(ParentComponent); + USkeletalMeshComponent* SkeletalMeshComponent = Cast(ParentComponent); + // UInstancedSkinnedMeshComponent inherits from USkinnedMeshComponent but NOT USkeletalMeshComponent. + // We detect it without including its experimental header (which causes C3837 on MSVC) by checking + // that the component is a USkinnedMeshComponent but not a USkeletalMeshComponent. + USkinnedMeshComponent* SkinnedMeshComponent = Cast(ParentComponent); + const bool bIsInstancedSkinnedMesh = IsValid(SkinnedMeshComponent) && !IsValid(SkeletalMeshComponent); + + if (IsValid(StaticMeshComponent)) + { + bSkeletalMesh = false; + return CreateSceneProxy(StaticMeshComponent); + } + else if (bIsInstancedSkinnedMesh) + { + FPrimitiveSceneProxy* Proxy = CreateSceneProxyNaniteInstancedSkeletal(SkinnedMeshComponent); + bSkeletalMesh = (Proxy != nullptr); + return Proxy; + } + else if (IsValid(SkeletalMeshComponent)) + { + FPrimitiveSceneProxy* Proxy = CreateSceneProxy(SkeletalMeshComponent); + bSkeletalMesh = (Proxy != nullptr); + return Proxy; + } + else + { + return nullptr; + } +} + +FBoxSphereBounds UAnnotationComponent::CalcBounds(const FTransform & LocalToWorld) const +{ + // UMeshComponent* ParentMeshComponent = ParentMeshInfo->GetParentMeshComponent(); + // if (IsValid(ParentMeshComponent)) + // { + // return ParentMeshComponent->CalcBounds(LocalToWorld); + // } + // else + // { + // FBoxSphereBounds DefaultBounds; + // return DefaultBounds; + // } + + USceneComponent* Parent = this->GetAttachParent(); + UStaticMeshComponent* StaticMeshComponent = Cast(Parent); + if (IsValid(StaticMeshComponent)) + { + return StaticMeshComponent->CalcBounds(LocalToWorld); + } + + USkinnedMeshComponent* SkinnedMeshComponent = Cast(Parent); + if (IsValid(SkinnedMeshComponent)) + { + return SkinnedMeshComponent->CalcBounds(LocalToWorld); + } + + FBoxSphereBounds DefaultBounds; + DefaultBounds.Origin = LocalToWorld.GetLocation(); + DefaultBounds.BoxExtent = FVector::ZeroVector; + DefaultBounds.SphereRadius = 0.f; + return DefaultBounds; +} + +// Extra overhead for the game scene +void UAnnotationComponent::TickComponent( + float DeltaTime, + enum ELevelTick TickType, + FActorComponentTickFunction * ThisTickFunction) +{ + Super::TickComponent(DeltaTime, TickType, ThisTickFunction); + + if (bSkeletalMesh) + { + USceneComponent* ParentComponent = this->GetAttachParent(); + // Use USkinnedMeshComponent to cover both USkeletalMeshComponent and UInstancedSkinnedMeshComponent + USkinnedMeshComponent* SkinnedMeshComponent = Cast(ParentComponent); + if (SkinnedMeshComponent) + { + // Update render state for regular, Nanite, and instanced skeletal meshes + // This ensures animations and deformations are properly synced + MarkRenderStateDirty(); + } + } +} + + +void UAnnotationComponent::ForceUpdate() +{ + this->MarkRenderStateDirty(); +} + + diff --git a/Unreal/Plugins/AirSim/Source/Annotation/AnnotationComponent.h b/Unreal/Plugins/AirSim/Source/Annotation/AnnotationComponent.h index e220b4119..9196c966b 100644 --- a/Unreal/Plugins/AirSim/Source/Annotation/AnnotationComponent.h +++ b/Unreal/Plugins/AirSim/Source/Annotation/AnnotationComponent.h @@ -9,8 +9,14 @@ #include "Runtime/Engine/Classes/Components/StaticMeshComponent.h" #include "Runtime/Engine/Public/SkeletalRenderPublic.h" -#include "AnnotationComponent.generated.h" +#if ENGINE_MAJOR_VERSION >= 5 +// different header files in UE +#include "Runtime/Engine/Public/StaticMeshSceneProxy.h" +#include "Runtime/Engine/Public/SkeletalMeshSceneProxy.h" +#include "Runtime/Engine/Public/NaniteSceneProxy.h" +#endif +#include "AnnotationComponent.generated.h" // TODO: Might need to annotate every frame if there are new actors got spawned /** A proxy component class to render annotation color @@ -49,6 +55,18 @@ class AIRSIM_API UAnnotationComponent : public UPrimitiveComponent /** Force the component to update to capture changes from the parent */ void ForceUpdate(); +public: + // Simple classification for foliage-related mesh components. + enum class EFoliageComponentType : uint8 + { + None = 0, + StaticFoliage, + SkeletalFoliage, + InstancedSkeletalFoliage + }; + + EFoliageComponentType GetLastDetectedFoliageType() const; + private: // FParentMeshInfo ParentMeshInfo; // TSharedPtr ParentMeshInfo; @@ -65,7 +83,12 @@ class AIRSIM_API UAnnotationComponent : public UPrimitiveComponent bool bSkeletalMesh; // indicate whether this is for a SkeletalMesh bool bTexture; // indicate if this is a texture annotation component + EFoliageComponentType last_foliage_type_; + static EFoliageComponentType ClassifyFoliageType(const USceneComponent* Component); + static bool IsNaniteSkeletalMesh(const USkeletalMeshComponent* SkeletalMeshComponent); FPrimitiveSceneProxy* CreateSceneProxy(UStaticMeshComponent* StaticMeshComponent); FPrimitiveSceneProxy* CreateSceneProxy(USkeletalMeshComponent* SkeletalMeshComponent); + FPrimitiveSceneProxy* CreateSceneProxyNaniteSkeletal(USkeletalMeshComponent* SkeletalMeshComponent); + FPrimitiveSceneProxy* CreateSceneProxyNaniteInstancedSkeletal(USkinnedMeshComponent* InstancedMeshComponent); }; diff --git a/Unreal/Plugins/AirSim/Source/Annotation/ObjectAnnotator.cpp b/Unreal/Plugins/AirSim/Source/Annotation/ObjectAnnotator.cpp index 3aeacd2b0..b6708d75b 100644 --- a/Unreal/Plugins/AirSim/Source/Annotation/ObjectAnnotator.cpp +++ b/Unreal/Plugins/AirSim/Source/Annotation/ObjectAnnotator.cpp @@ -152,15 +152,17 @@ void FObjectAnnotator::getPaintableComponentMeshes(AActor* actor, TMapEmplace(component_name, component); + index++; } } if (USkinnedMeshComponent* skinnedmesh_component = Cast(component)) { component_name = actor->GetName(); component_name.Append("_"); component_name.Append(FString::FromInt(PersistentPrimitiveIndex)); + paintable_components_meshes->Emplace(component_name, component); + index++; } - paintable_components_meshes->Emplace(component_name, component); - index++; } } } @@ -217,8 +219,7 @@ void FObjectAnnotator::getPaintableComponentMeshesAndTags(AActor* actor, TMapEmplace(component_name, component); if (actor->Tags.Num() > 0) paintable_components_tags->Emplace(component_name, actor->Tags); - else - paintable_components_tags->Emplace(component_name, staticmesh_component->ComponentTags); + paintable_components_tags->Emplace(component_name, staticmesh_component->ComponentTags); } else { FString component_name = actor->GetName(); @@ -227,8 +228,7 @@ void FObjectAnnotator::getPaintableComponentMeshesAndTags(AActor* actor, TMapEmplace(component_name, component); if (actor->Tags.Num() > 0) paintable_components_tags->Emplace(component_name, actor->Tags); - else - paintable_components_tags->Emplace(component_name, staticmesh_component->ComponentTags); + paintable_components_tags->Emplace(component_name, staticmesh_component->ComponentTags); } } @@ -239,8 +239,7 @@ void FObjectAnnotator::getPaintableComponentMeshesAndTags(AActor* actor, TMapTags.Num() > 0) paintable_components_tags->Emplace(component_name, actor->Tags); - else - paintable_components_tags->Emplace(component_name, SkinnedMeshComponent->ComponentTags); + paintable_components_tags->Emplace(component_name, SkinnedMeshComponent->ComponentTags); paintable_components_meshes->Emplace(component_name, component); } } @@ -262,19 +261,21 @@ void FObjectAnnotator::getPaintableComponentMeshesAndTags(AActor* actor, TMapGetName()); } + component_name.Append("_"); + component_name.Append(FString::FromInt(PersistentPrimitiveIndex)); + paintable_components_tags->Emplace(component_name, staticmesh_component->ComponentTags); + paintable_components_meshes->Emplace(component_name, component); + index++; } - component_name.Append("_"); - component_name.Append(FString::FromInt(PersistentPrimitiveIndex)); - paintable_components_tags->Emplace(component_name, staticmesh_component->ComponentTags); } if (USkinnedMeshComponent* skinnedmesh_component = Cast(component)) { component_name = actor->GetName(); component_name.Append("_"); component_name.Append(FString::FromInt(PersistentPrimitiveIndex)); paintable_components_tags->Emplace(component_name, skinnedmesh_component->ComponentTags); + paintable_components_meshes->Emplace(component_name, component); + index++; } - paintable_components_meshes->Emplace(component_name, component); - index++; } } } @@ -289,21 +290,9 @@ bool FObjectAnnotator::SetComponentRGBColorByIndex(FString component_id, uint32 { FString color_string = FString::FromInt(color.R) + "," + FString::FromInt(color.G) + "," + FString::FromInt(color.B); FString color_string_gammacorrected = FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(color.R)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(color.G)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(color.B)); - const FString* found_index_color = color_to_name_map_.FindKey(component_id); - - if (found_index_color != nullptr) { - color_to_name_map_.Remove(*found_index_color); - } - color_to_name_map_.Emplace(color_string, component_id); - const FString* found_index_color_gamma = gammacorrected_color_to_name_map_.FindKey(component_id); - if (found_index_color != nullptr) { - gammacorrected_color_to_name_map_.Remove(*found_index_color_gamma); - } - color_to_name_map_.Emplace(color_string, component_id); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, component_id); name_to_color_index_map_[component_id] = color_index; name_to_gammacorrected_color_map_[component_id] = color_string_gammacorrected; - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted RGB annotation of object %s to new ID # %s (RGB: %s)"), *name_, *component_id, *FString::FromInt(color_index), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted RGB annotation of object %s to new ID # %s (RGB: %s)"), *name_, *component_id, *FString::FromInt(color_index), *color_string_gammacorrected); return true; } else @@ -328,21 +317,9 @@ bool FObjectAnnotator::SetComponentRGBColorByColor(FString component_id, FColor { FString color_string = FString::FromInt(color.R) + "," + FString::FromInt(color.G) + "," + FString::FromInt(color.B); FString color_string_gammacorrected = FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(color.R)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(color.G)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(color.B)); - const FString* found_index_color = color_to_name_map_.FindKey(component_id); - - if (found_index_color != nullptr) { - color_to_name_map_.Remove(*found_index_color); - } - color_to_name_map_.Emplace(color_string, component_id); - const FString* found_index_color_gamma = gammacorrected_color_to_name_map_.FindKey(component_id); - if (found_index_color != nullptr) { - gammacorrected_color_to_name_map_.Remove(*found_index_color_gamma); - } - color_to_name_map_.Emplace(color_string, component_id); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, component_id); name_to_color_index_map_[component_id] = color_index; name_to_gammacorrected_color_map_[component_id] = color_string_gammacorrected; - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted RGB annotation of object %s to new RGB color: %s (ID # %s)"), *name_, *component_id, *color_string_gammacorrected , *FString::FromInt(color_index)); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted RGB annotation of object %s to new RGB color: %s (ID # %s)"), *name_, *component_id, *color_string_gammacorrected , *FString::FromInt(color_index)); return true; } else @@ -373,21 +350,9 @@ bool FObjectAnnotator::SetComponentGreyScaleColorByValue(FString component_id, f { FString color_string = FString::FromInt(color.R) + "," + FString::FromInt(color.G) + "," + FString::FromInt(color.B); FString color_string_gammacorrected = color_string; - const FString* found_index_color = color_to_name_map_.FindKey(component_id); - - if (found_index_color != nullptr) { - color_to_name_map_.Remove(*found_index_color); - } - color_to_name_map_.Emplace(color_string, component_id); - const FString* found_index_color_gamma = gammacorrected_color_to_name_map_.FindKey(component_id); - if (found_index_color != nullptr) { - gammacorrected_color_to_name_map_.Remove(*found_index_color_gamma); - } - color_to_name_map_.Emplace(color_string, component_id); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, component_id); name_to_gammacorrected_color_map_[component_id] = color_string_gammacorrected; name_to_value_map_[component_id] = greyscale_value; - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted greyscale annotation of object %s to new value %f (RGB: %s)"), *name_, *component_id, greyscale_value, *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted greyscale annotation of object %s to new value %f (RGB: %s)"), *name_, *component_id, greyscale_value, *color_string_gammacorrected); return true; } else @@ -418,7 +383,7 @@ bool FObjectAnnotator::SetComponentTextureByDirectPath(FString component_id, FSt if (UpdatePaintTextureComponent(component, path, component_id)) { name_to_texture_path_map_[component_id] = new_texture; - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted texture annotation of object %s to new direct texture %s"), *name_, *component_id, *path); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted texture annotation of object %s to new direct texture %s"), *name_, *component_id, *path); return true; } else @@ -460,7 +425,7 @@ bool FObjectAnnotator::SetComponentTextureByRelativePath(FString component_id) if (UpdatePaintTextureComponent(component, new_texture, component_id)) { name_to_texture_path_map_[component_id] = new_texture; - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted texture annotation of object %s to new relative texture %s"), *name_, *component_id, *new_texture); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Adjusted texture annotation of object %s to new relative texture %s"), *name_, *component_id, *new_texture); return true; } else @@ -515,12 +480,10 @@ bool FObjectAnnotator::AnnotateNewActorInstanceSegmentation(AActor* actor) { FString color_string = FString::FromInt(new_color.R) + "," + FString::FromInt(new_color.G) + "," + FString::FromInt(new_color.B); FString color_string_gammacorrected = FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.R)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.G)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.B)); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); check(PaintRGBComponent(it.Value(), new_color, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(ObjectIndex), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(ObjectIndex), *color_string_gammacorrected); }else{ - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Ignored new object %s"), *name_, *it.Key()); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Ignored new object %s"), *name_, *it.Key()); } } } @@ -565,40 +528,28 @@ bool FObjectAnnotator::AnnotateNewActorRGB(AActor* actor) { if (name_to_component_map_.Contains(it.Key())) { name_to_color_index_map_[it.Key()] = color_index; - const FString* found_index_color = color_to_name_map_.FindKey(it.Key()); - if (found_index_color != nullptr) { - color_to_name_map_.Remove(*found_index_color); - } - color_to_name_map_.Emplace(color_string, it.Key()); - const FString* found_index_color_gamma = gammacorrected_color_to_name_map_.FindKey(it.Key()); - if (found_index_color != nullptr) { - gammacorrected_color_to_name_map_.Remove(*found_index_color_gamma); - } - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); check(UpdatePaintRGBComponent(it.Value(), new_color, it.Key())); if (set_direct_) { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated RGB annotated object %s with direct RGB color: %s (ID # %s)"), *name_, *it.Key(), *color_string_gammacorrected, *FString::FromInt(color_index)); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated RGB annotated object %s with direct RGB color: %s"), *name_, *it.Key(), *color_string_gammacorrected); } else { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated RGB annotated object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(color_index), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated RGB annotated object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(color_index), *color_string_gammacorrected); } } else { name_to_component_map_.Emplace(it.Key(), it.Value()); component_to_name_map_.Emplace(it.Value(), it.Key()); name_to_color_index_map_.Emplace(it.Key(), color_index); - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); check(PaintRGBComponent(it.Value(), new_color, it.Key())); if (set_direct_) { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new RGB annotated object %s with direct RGB color: %s (ID # %s)"), *name_, *it.Key(), *color_string_gammacorrected, *FString::FromInt(color_index)); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new RGB annotated object %s with direct RGB color: %s"), *name_, *it.Key(), *color_string_gammacorrected); } else { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new RGB annotated object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(color_index), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new RGB annotated object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(color_index), *color_string_gammacorrected); } } }else if (show_by_default_ && !it.Key().Contains("hidden_sphere") && !it.Key().Contains("AnnotationSphere")) { @@ -608,11 +559,9 @@ bool FObjectAnnotator::AnnotateNewActorRGB(AActor* actor) { name_to_color_index_map_.Emplace(it.Key(), 2744000 - 1); FString color_string = FString::FromInt(new_color.R) + "," + FString::FromInt(new_color.G) + "," + FString::FromInt(new_color.B); FString color_string_gammacorrected = FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.R)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.G)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.B)); - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); check(PaintRGBComponent(it.Value(), new_color, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged RGB annotated object %s with default color (RGB: %s)"), *name_, *it.Key(), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged RGB annotated object %s with default color (RGB: %s)"), *name_, *it.Key(), *color_string_gammacorrected); } } return true; @@ -653,31 +602,19 @@ bool FObjectAnnotator::AnnotateNewActorGreyscale(AActor* actor) { if (name_to_component_map_.Contains(it.Key())) { - const FString* found_index_color = color_to_name_map_.FindKey(it.Key()); - if (found_index_color != nullptr) { - color_to_name_map_.Remove(*found_index_color); - } - color_to_name_map_.Emplace(color_string, it.Key()); - const FString* found_index_color_gamma = gammacorrected_color_to_name_map_.FindKey(it.Key()); - if (found_index_color != nullptr) { - gammacorrected_color_to_name_map_.Remove(*found_index_color_gamma); - } name_to_value_map_[it.Key()] = greyscale_value; - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_[it.Key()] = color_string_gammacorrected; check(UpdatePaintRGBComponent(it.Value(), new_color, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated greyscale annotated object %s with value %f (RGB: %s)"), *name_, *it.Key(), greyscale_value, *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated greyscale annotated object %s with value %f (RGB: %s)"), *name_, *it.Key(), greyscale_value, *color_string_gammacorrected); } else { name_to_component_map_.Emplace(it.Key(), it.Value()); - component_to_name_map_.Emplace(it.Value(), it.Key()); - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); + component_to_name_map_.Emplace(it.Value(), it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); name_to_value_map_.Emplace(it.Key(), greyscale_value); check(PaintRGBComponent(it.Value(), new_color, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new greyscale annotated object %s with value %f (RGB: %s)"), *name_, *it.Key(), greyscale_value, *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new greyscale annotated object %s with value %f (RGB: %s)"), *name_, *it.Key(), greyscale_value, *color_string_gammacorrected); } }else if (show_by_default_ && !it.Key().Contains("hidden_sphere") && !it.Key().Contains("AnnotationSphere")) { name_to_component_map_.Emplace(it.Key(), it.Value()); @@ -685,12 +622,10 @@ bool FObjectAnnotator::AnnotateNewActorGreyscale(AActor* actor) { FColor new_color = FColor(0, 0, 0); FString color_string = FString::FromInt(new_color.R) + "," + FString::FromInt(new_color.G) + "," + FString::FromInt(new_color.B); FString color_string_gammacorrected = color_string; - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); name_to_value_map_.Emplace(it.Key(), 0); check(PaintRGBComponent(it.Value(), new_color, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged greyscale annotated object %s with default color (RGB: %s)"), *name_, *it.Key(), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged greyscale annotated object %s with default color (RGB: %s)"), *name_, *it.Key(), *color_string_gammacorrected); } } return true; @@ -739,11 +674,11 @@ bool FObjectAnnotator::AnnotateNewActorTexture(AActor* actor) { name_to_texture_path_map_[it.Key()] = new_texture; check(UpdatePaintTextureComponent(it.Value(), new_texture, it.Key())); if (set_direct_) { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); } else { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Updated texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); } } else { @@ -752,11 +687,11 @@ bool FObjectAnnotator::AnnotateNewActorTexture(AActor* actor) { name_to_texture_path_map_.Emplace(it.Key(), new_texture); check(PaintTextureComponent(it.Value(), new_texture, it.Key())); if (set_direct_) { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); } else { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); } } }else if (show_by_default_ && !it.Key().Contains("hidden_sphere") && !it.Key().Contains("AnnotationSphere")) { @@ -765,7 +700,7 @@ bool FObjectAnnotator::AnnotateNewActorTexture(AActor* actor) { FString new_texture = "/AirSim/HUDAssets/k"; name_to_texture_path_map_.Emplace(it.Key(), new_texture); check(PaintTextureComponent(it.Value(), new_texture, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged texture annotated object %s with default texture"), *name_, *it.Key()); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged texture annotated object %s with default texture"), *name_, *it.Key()); } } return true; @@ -786,7 +721,7 @@ bool FObjectAnnotator::DeleteActor(AActor* actor) component_to_name_map_.Remove(it.Value()); check(DeleteComponent(it.Value())); name_to_component_map_.Remove(it.Key()); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Deleted object %s."), *name_, *it.Key()); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Deleted object %s."), *name_, *it.Key()); } else { @@ -868,7 +803,7 @@ FString FObjectAnnotator::GetComponentTexturePath(FString component_id) void FObjectAnnotator::InitializeInstanceSegmentation(ULevel* InLevel) { uint32 color_index = 0; - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Starting full level instance segmentation annotation."), *name_); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Starting full level instance segmentation annotation."), *name_); for (AActor* actor : InLevel->Actors) { if (actor && IsPaintable(actor)) @@ -884,11 +819,9 @@ void FObjectAnnotator::InitializeInstanceSegmentation(ULevel* InLevel) name_to_color_index_map_.Emplace(it.Key(), color_index); FString color_string = FString::FromInt(new_color.R) + "," + FString::FromInt(new_color.G) + "," + FString::FromInt(new_color.B); FString color_string_gammacorrected = FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.R)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.G)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.B)); - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); check(PaintRGBComponent(it.Value(), new_color, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(color_index), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(color_index), *color_string_gammacorrected); color_index++; } } @@ -899,7 +832,7 @@ void FObjectAnnotator::InitializeInstanceSegmentation(ULevel* InLevel) void FObjectAnnotator::InitializeRGB(ULevel* InLevel) { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Starting full level RGB annotation by searching for tags."), *name_); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Starting full level RGB annotation by searching for tags."), *name_); for (AActor* actor : InLevel->Actors) { if (actor && IsPaintable(actor)) @@ -935,16 +868,14 @@ void FObjectAnnotator::InitializeRGB(ULevel* InLevel) name_to_color_index_map_.Emplace(it.Key(), color_index); FString color_string = FString::FromInt(new_color.R) + "," + FString::FromInt(new_color.G) + "," + FString::FromInt(new_color.B); FString color_string_gammacorrected = FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.R)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.G)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.B)); - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); check(PaintRGBComponent(it.Value(), new_color, it.Key())); if (set_direct_) { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new RGB annotated object %s with direct RGB color: %s (ID # %s)"), *name_, *it.Key(), *color_string_gammacorrected, *FString::FromInt(color_index)); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new RGB annotated object %s with direct RGB color: %s"), *name_, *it.Key(), *color_string_gammacorrected); } else { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new RGB annotated object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(color_index), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new RGB annotated object %s with ID # %s (RGB: %s)"), *name_, *it.Key(), *FString::FromInt(color_index), *color_string_gammacorrected); } } else if (show_by_default_ && !it.Key().Contains("hidden_sphere") && !it.Key().Contains("AnnotationSphere")) { @@ -954,11 +885,9 @@ void FObjectAnnotator::InitializeRGB(ULevel* InLevel) name_to_color_index_map_.Emplace(it.Key(), 2744000 - 1); FString color_string = FString::FromInt(new_color.R) + "," + FString::FromInt(new_color.G) + "," + FString::FromInt(new_color.B); FString color_string_gammacorrected = FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.R)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.G)) + "," + FString::FromInt(ColorGenerator_.GetGammaCorrectedColor(new_color.B)); - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); check(PaintRGBComponent(it.Value(), new_color, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged RGB annotated object %s with default color (RGB: %s)"), *name_, *it.Key(), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged RGB annotated object %s with default color (RGB: %s)"), *name_, *it.Key(), *color_string_gammacorrected); } } @@ -969,7 +898,7 @@ void FObjectAnnotator::InitializeRGB(ULevel* InLevel) void FObjectAnnotator::InitializeGreyscale(ULevel* InLevel) { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Starting full level greyscale annotation by searching for tags."), *name_); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Starting full level greyscale annotation by searching for tags."), *name_); for (AActor* actor : InLevel->Actors) { if (actor && IsPaintable(actor)) @@ -1004,12 +933,10 @@ void FObjectAnnotator::InitializeGreyscale(ULevel* InLevel) FString color_string = FString::FromInt(new_color.R) + "," + FString::FromInt(new_color.G) + "," + FString::FromInt(new_color.B); FString color_string_gammacorrected = color_string; - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); name_to_value_map_.Emplace(it.Key(), greyscale_value); check(PaintRGBComponent(it.Value(), new_color, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new greyscale annotated object %s with direct greyscale value %f (RGB: %s)"), *name_, *it.Key(), greyscale_value , *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new greyscale annotated object %s with direct greyscale value %f (RGB: %s)"), *name_, *it.Key(), greyscale_value , *color_string_gammacorrected); } else if (show_by_default_ && !it.Key().Contains("hidden_sphere") && !it.Key().Contains("AnnotationSphere")) { name_to_component_map_.Emplace(it.Key(), it.Value()); @@ -1017,12 +944,10 @@ void FObjectAnnotator::InitializeGreyscale(ULevel* InLevel) FColor new_color = FColor(0, 0, 0); FString color_string = FString::FromInt(new_color.R) + "," + FString::FromInt(new_color.G) + "," + FString::FromInt(new_color.B); FString color_string_gammacorrected = color_string; - color_to_name_map_.Emplace(color_string, it.Key()); - gammacorrected_color_to_name_map_.Emplace(color_string_gammacorrected, it.Key()); name_to_gammacorrected_color_map_.Emplace(it.Key(), color_string_gammacorrected); name_to_value_map_.Emplace(it.Key(), 0); check(PaintRGBComponent(it.Value(), new_color, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged greyscale annotated object %s with default color (RGB: %s)"), *name_, *it.Key(), *color_string_gammacorrected); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged greyscale annotated object %s with default color (RGB: %s)"), *name_, *it.Key(), *color_string_gammacorrected); } } } @@ -1032,7 +957,7 @@ void FObjectAnnotator::InitializeGreyscale(ULevel* InLevel) void FObjectAnnotator::InitializeTexture(ULevel* InLevel) { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Starting full level texture annotation by searching for tags."), *name_); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Starting full level texture annotation by searching for tags."), *name_); for (AActor* actor : InLevel->Actors) { if (actor && IsPaintable(actor)) @@ -1052,22 +977,18 @@ void FObjectAnnotator::InitializeTexture(ULevel* InLevel) FString tag = found_tag->ToString(); TArray splitTag; tag.ParseIntoArray(splitTag, TEXT("_"), true); - name_to_component_map_.Emplace(it.Key(), it.Value()); - component_to_name_map_.Emplace(it.Value(), it.Key()); - + FString new_texture; if (set_direct_) { new_texture = splitTag[1]; - } - else { + } else { FString component_name; if (UStaticMeshComponent* staticmesh_component = Cast(it.Value())) { if (staticmesh_component->GetStaticMesh() != nullptr) { component_name = staticmesh_component->GetStaticMesh()->GetName(); } - } - else if (USkinnedMeshComponent* skinnedmesh_component = Cast(it.Value())) { + } else if (USkinnedMeshComponent* skinnedmesh_component = Cast(it.Value())) { if (skinnedmesh_component->GetSkinnedAsset() != nullptr) { component_name = skinnedmesh_component->GetSkinnedAsset()->GetName(); } @@ -1077,10 +998,11 @@ void FObjectAnnotator::InitializeTexture(ULevel* InLevel) name_to_texture_path_map_.Emplace(it.Key(), new_texture); check(PaintTextureComponent(it.Value(), new_texture, it.Key())); if (set_direct_) { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); + } else { - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added new texture annotated object %s with texture: %s"), *name_, *it.Key(), *new_texture); } } else if (show_by_default_ && !it.Key().Contains("hidden_sphere") && !it.Key().Contains("AnnotationSphere")) { @@ -1089,7 +1011,7 @@ void FObjectAnnotator::InitializeTexture(ULevel* InLevel) FString new_texture = "/AirSim/HUDAssets/k"; name_to_texture_path_map_.Emplace(it.Key(), new_texture); check(PaintTextureComponent(it.Value(), new_texture, it.Key())); - UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged texture annotated object %s with default texture"), *name_, *it.Key()); + //UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Added untagged texture annotated object %s with default texture"), *name_, *it.Key()); } } @@ -1263,7 +1185,9 @@ void FObjectAnnotator::UpdateAnnotationComponents(UWorld* World) for (UObject* Object : UObjectList) { + if (!IsValid(Object)) continue; UPrimitiveComponent* Component = Cast(Object); + if (!Component) continue; FName componentFName = *Component->GetName(); FString componentName = componentFName.ToString(); if (Component->GetWorld() == World @@ -1282,6 +1206,10 @@ void FObjectAnnotator::UpdateAnnotationComponents(UWorld* World) } TArray> FObjectAnnotator::GetAnnotationComponents() { + annotation_component_list_.RemoveAll([](const TWeakObjectPtr& Component) + { + return !Component.IsValid(); + }); return annotation_component_list_; } @@ -1303,11 +1231,6 @@ TMap FObjectAnnotator::GetComponentToNameMap() { return component_to_name_map_; } - -TMap FObjectAnnotator::GetColorToComponentNameMap() { - return gammacorrected_color_to_name_map_; -} - TMap FObjectAnnotator::GetComponentToValueMap() { return name_to_value_map_; } @@ -1327,7 +1250,9 @@ void FObjectAnnotator::EndPlay() { GetObjectsOfClass(UAnnotationComponent::StaticClass(), UObjectList, bIncludeDerivedClasses, ExclusionFlags, ExclusionInternalFlags); for (UObject* Object : UObjectList) { + if (!IsValid(Object)) continue; UPrimitiveComponent* Component = Cast(Object); + if (!Component) continue; FName componentFName = *Component->GetName(); FString componentName = componentFName.ToString(); if (componentName.Contains(name_)) @@ -1337,8 +1262,6 @@ void FObjectAnnotator::EndPlay() { } name_to_color_index_map_.Empty(); - color_to_name_map_.Empty(); - gammacorrected_color_to_name_map_.Empty(); name_to_component_map_.Empty(); annotation_component_list_.Empty(); name_to_gammacorrected_color_map_.Empty(); @@ -1347,6 +1270,7 @@ void FObjectAnnotator::EndPlay() { component_to_name_map_.Empty(); } + int32 FColorGenerator::GetChannelValue(uint32 index) { static int32 values[256] = { 0 }; diff --git a/Unreal/Plugins/AirSim/Source/Annotation/ObjectAnnotator.h b/Unreal/Plugins/AirSim/Source/Annotation/ObjectAnnotator.h index b74527332..0990ca8a9 100644 --- a/Unreal/Plugins/AirSim/Source/Annotation/ObjectAnnotator.h +++ b/Unreal/Plugins/AirSim/Source/Annotation/ObjectAnnotator.h @@ -88,7 +88,6 @@ class AIRSIM_API FObjectAnnotator std::vector GetAllComponentNames(); TMap GetNameToComponentMap(); - TMap GetColorToComponentNameMap(); TMap GetComponentToValueMap(); TMap GetComponentToNameMap(); @@ -120,8 +119,6 @@ class AIRSIM_API FObjectAnnotator TMap name_to_gammacorrected_color_map_; TMap name_to_value_map_; TMap name_to_texture_path_map_; - TMap color_to_name_map_; - TMap gammacorrected_color_to_name_map_; TMap name_to_component_map_; TMap component_to_name_map_; TArray> annotation_component_list_; diff --git a/Unreal/Plugins/AirSim/Source/LidarCamera.cpp b/Unreal/Plugins/AirSim/Source/LidarCamera.cpp index 0f0bf5274..b5379d49b 100755 --- a/Unreal/Plugins/AirSim/Source/LidarCamera.cpp +++ b/Unreal/Plugins/AirSim/Source/LidarCamera.cpp @@ -54,7 +54,6 @@ int32 getIndexLowerClosest(TArray range, float value) { else { return GetNum(range) - 1; } - return 0; } // Constructor @@ -127,7 +126,11 @@ void ALidarCamera::BeginPlay() void ALidarCamera::Tick(float DeltaTime) { Super::Tick(DeltaTime); - + + if (async_capture_mode_ && async_capture_in_flight_.load()) { + ServiceAsyncCapture(); + } + if (!used_by_airsim_) { msr::airlib::vector point_cloud_empty; Update(DeltaTime, point_cloud_empty, point_cloud_empty); @@ -142,6 +145,7 @@ void ALidarCamera::EndPlay(const EEndPlayReason::Type EndPlayReason) render_target_2D_segmentation_ = nullptr; capture_2D_intensity_ = nullptr; render_target_2D_intensity_ = nullptr; + Super::EndPlay(EndPlayReason); } // Get all the settings from AirSim @@ -171,6 +175,10 @@ void ALidarCamera::InitializeSettingsFromAirSim(const msr::airlib::GPULidarSimpl rain_constant_a_ = settings.rain_constant_a; rain_constant_b_ = settings.rain_constant_b; generate_distance_noise_ = settings.generate_noise; + async_capture_mode_ = settings.async_capture_mode; + if (async_capture_mode_ && draw_debug_) { + UAirBlueprintLib::LogMessageString("LidarCamera", "draw_debug_ is not supported in multirotor's async GPU LiDAR capture mode and will be ignored.", LogDebugLevel::Failure); + } // Load materials.csv file holding the lambertian reflectance coefficients for certain material types and save tem into a map std::string material_List_content; @@ -287,6 +295,10 @@ bool ALidarCamera::Update(float delta_time, msr::airlib::vector& point_cloud, + msr::airlib::vector& point_cloud_final) +{ + bool refresh_pointcloud = false; + + if (async_capture_ready_.load()) { + refresh_pointcloud = ProcessCapturedBuffers(async_job_rotation_angle_, async_job_fov_, point_cloud, point_cloud_final); + async_capture_ready_ = false; + } + + float sensor_rotation_angle_ = hfov_ * delta_time * sensor_rotation_frequency_; + sensor_sum_rotation_angle_ += sensor_rotation_angle_; + + if (sensor_sum_rotation_angle_ > h_delta_angle_) { + + if (async_capture_in_flight_.load()) { + return refresh_pointcloud; + } + + if (reset_hfov_) { + sensor_cur_angle_ = FMath::Fmod(horizontal_fov_min_, 360); + sensor_prev_rotation_angle_ = 0; + completed_hfov_ = 0; + reset_hfov_ = false; + } + + int32 cur_fov = target_fov_; + if (sensor_sum_rotation_angle_ > target_fov_) cur_fov = FMath::CeilToInt(FMath::Min(sensor_sum_rotation_angle_ + (3 * h_delta_angle_), 178.0f)); + if (cur_fov % 2 != 0) cur_fov += 1; + if (cur_fov < 90) cur_fov = 90; + + float capture_rotation = FMath::Fmod(sensor_cur_angle_ + sensor_prev_rotation_angle_ + (cur_fov / 2), 360); + sensor_cur_angle_ = FMath::Fmod(sensor_cur_angle_ + sensor_prev_rotation_angle_, 360); + + if (sensor_sum_rotation_angle_ > cur_fov) sensor_sum_rotation_angle_ = cur_fov; + + if (sensor_sum_rotation_angle_ >= hfov_ - completed_hfov_ && hfov_ != 360) { + sensor_sum_rotation_angle_ = hfov_ - completed_hfov_; + reset_hfov_ = true; + } + completed_hfov_ += sensor_sum_rotation_angle_; + + bool do_capture = waited_frames_ >= wait_frames_; + if (!do_capture) waited_frames_++; + + async_job_rotation_angle_ = sensor_sum_rotation_angle_; + async_job_fov_ = cur_fov; + StartAsyncCapture(capture_rotation, cur_fov, do_capture); + + // Set up the values for the next frame + sensor_prev_rotation_angle_ = sensor_sum_rotation_angle_; + sensor_sum_rotation_angle_ = 0; + } + return refresh_pointcloud; +} + +void ALidarCamera::StartAsyncCapture(float capture_rotation, int32 cur_fov, bool do_capture) +{ + pending_capture_rotation_ = capture_rotation; + pending_capture_fov_ = cur_fov; + pending_do_capture_ = do_capture; + async_capture_in_flight_ = true; +} + +void ALidarCamera::ServiceAsyncCapture() +{ + if (!capture_2D_depth_ || !capture_2D_segmentation_ || !capture_2D_intensity_) { + async_capture_in_flight_ = false; + return; + } + + int32 cur_fov = pending_capture_fov_; + capture_2D_depth_->FOVAngle = cur_fov; + capture_2D_segmentation_->FOVAngle = cur_fov; + capture_2D_intensity_->FOVAngle = cur_fov; + RotateCamera(pending_capture_rotation_); + + if (pending_do_capture_ && capture_2D_depth_->TextureTarget && capture_2D_segmentation_->TextureTarget && capture_2D_intensity_->TextureTarget) { + capture_2D_depth_->CaptureScene(); + capture_2D_segmentation_->CaptureScene(); + capture_2D_intensity_->CaptureScene(); + + FTextureRenderTarget2DResource* render_target_2D_depth = (FTextureRenderTarget2DResource*)capture_2D_depth_->TextureTarget->GetResource(); + render_target_2D_depth->ReadPixels(async_buffer_2D_depth_); + if (generate_groundtruth_) { + FTextureRenderTarget2DResource* render_target_2D_segmentation = (FTextureRenderTarget2DResource*)capture_2D_segmentation_->TextureTarget->GetResource(); + FReadSurfaceDataFlags flags(RCM_UNorm, CubeFace_MAX); + flags.SetLinearToGamma(false); + render_target_2D_segmentation->ReadPixels(async_buffer_2D_segmentation_); + } + if (generate_intensity_) { + FTextureRenderTarget2DResource* render_target_2D_intensity = (FTextureRenderTarget2DResource*)capture_2D_intensity_->TextureTarget->GetResource(); + render_target_2D_intensity->ReadPixels(async_buffer_2D_intensity_); + } + + async_capture_ready_ = true; + } + + async_capture_in_flight_ = false; +} + +bool ALidarCamera::ProcessCapturedBuffers(float sensor_rotation_angle, float fov, + msr::airlib::vector& point_cloud, msr::airlib::vector& point_cloud_final) +{ + bool refresh_pointcloud = false; + + // Calculate the camera intrensic parameters + float c_x = resolution_ / 2.0f; + float c_y = resolution_ / 2.0f; + float f_x = resolution_ / (2.0f * FMath::Tan(FMath::DegreesToRadians(fov / 2.0f))); + float f_y = resolution_ / (2.0f * FMath::Tan(FMath::DegreesToRadians(fov / 2.0f))); + + // Calculate the first and last horizontal angle of the LiDAR that will be captured in this frame + int32 h_first_index = h_cur_atan2_index_ + 1; + float h_max_angle = FMath::Fmod(sensor_cur_angle_ + sensor_rotation_angle, 360); + int32 h_last_index = getIndexLowerClosest(h_angles_atan2_, h_max_angle); + + // variable that keeps the current horizontal angle index that is being calculated + int32 h_cur_index = h_first_index; + + // Calculate the last horizontal angle that was measured in the previous frame, used to seeing if the full pointcloud is completed + float h_prev_angle = 10000; // This is done to avoid an issue with the very first measurement + if (h_cur_atan2_index_ != -1) { + h_prev_angle = h_angles_[h_cur_atan2_index_]; + } + + // get the current rain intensity from the AirSim API + float rain_value; + if (generate_intensity_) { + rain_value = UWeatherLib::getWeatherParamScalar(this->GetWorld(), msr::airlib::Utils::toEnum(0)); + } + + // State boolean to check if the loop is still the first and last horizontal angle range that will be captured in this frame + bool within_range = true; + + while (within_range) { + + // Calculate the index so that it keeps within the Eucledian Plane (between 0 and 360 degrees) by making it circular from 0 to the total horizontal measurement number + h_cur_atan2_index_ = (h_cur_index) % horizontal_samples_; + + // If the current index is the last to perform during this frame, disable the loop + if (h_last_index == h_cur_atan2_index_)within_range = false; + + // Get the current horizontal angle, also in Eucledian plane form (between 0 and 360 degrees) + float h_cur_angle = h_angles_[h_cur_atan2_index_]; + float h_cur_atan2_angle = FMath::Fmod(FMath::Fmod(FMath::Fmod(h_cur_angle, 360) - sensor_cur_angle_, 360) - (fov / 2), 360); + + // Calculate the cosine and sine of the horizontal angle and calculate the pixel index from the render texture target that matches this laser's horizontal angle + float h_cur_angle_cos = FMath::Cos(FMath::DegreesToRadians(h_cur_atan2_angle)); + float h_cur_angle_sin = FMath::Sin(FMath::DegreesToRadians(h_cur_atan2_angle)); + int32 h_pixel = FMath::FloorToInt(((h_cur_angle_sin * f_x) / h_cur_angle_cos) + c_x); + if (h_pixel == -1)h_pixel = 0; // for edge case avoiding + if (h_pixel == resolution_)h_pixel = resolution_ - 1; // for edge case avoiding + + // Loop the vertical lasers + for (int32 v_cur_index = 0; v_cur_index < num_lasers_; v_cur_index++) + { + // if the previous horizontal angle was larger than the current one, it means the sensor has done a full circle and a new pointcloud can be started + if (used_by_airsim_) { + if ((h_prev_angle >h_cur_angle) && (point_cloud.size() != 0)) { + if (v_cur_index == 0) { + // Check edge cases where the amount of points in the pointcloud doesnt equal the desired full pointcloud size. In this case, throw away the current data + if ((((int)point_cloud.size() / 5) != horizontal_samples_ * num_lasers_)) + { + UE_LOG(LogTemp, Warning, TEXT("Pointcloud incorrect size! points:%i %f %f"), (int)(point_cloud.size() / 5), h_prev_angle, h_cur_angle); + point_cloud.clear(); + refresh_pointcloud = false; + } + // Else, save the completed pointcloud into the right array and clear the current one + else { + point_cloud_final = point_cloud; + point_cloud.clear(); + refresh_pointcloud = true; + } + } + } + } + + // Calculate the cosine and sine of the verticle angle and calculate the pixel index from the render texture target that matches this laser's verticle angle + float v_cur_angle = v_angles_[v_cur_index]; + float v_cur_angle_cos = FMath::Cos(FMath::DegreesToRadians(v_cur_angle)); + float v_cur_angle_sin = FMath::Sin(FMath::DegreesToRadians(v_cur_angle)); + int32 v_pixel = FMath::FloorToInt((v_cur_angle_sin * -f_y) / (v_cur_angle_cos * h_cur_angle_cos) + c_y); + + // If the pixel coordinates are within bounds of the render target texture (should always be the case) we can proceed to read from it + if (h_pixel >= 0 && h_pixel < resolution_ && v_pixel >= 0 && v_pixel < resolution_) { + + // Get the depth value in centimeters, the depth value is spread of the full 3 bytes to achieve three bytes unsigned precision + FColor value_depth = async_buffer_2D_depth_[h_pixel + (v_pixel * resolution_)]; + float depth = 100000 * ((value_depth.R + value_depth.G * 256 + value_depth.B * 256 * 256) / static_cast(256 * 256 * 256 - 1)); + + // Added random distance based noise + if (generate_distance_noise_) { + float distance_noise = dist_(gen_) * (1 + ((depth / 100) / max_range_) * (distance_noise_scale_ - 1)); + depth = depth + distance_noise; + } + + // If the depth value is beneath the maximum detected range of the sensor, proceed, otherwise discard this point + if (depth < (max_range_ * 100)) { + + // Add noise based on the rain intensity, see publication for more information + if (generate_intensity_) { + float noise = dist_(gen_) * 0.02 * depth * FMath::Pow(1 - FMath::Exp(-rain_max_intensity_ * rain_value), 2); + depth = depth + noise; + } + + // Calculate the true distance based on the projection and get the XYZ coordinates for the 3D pointcloud from the polar angles of the laser + float distance = depth / (v_cur_angle_cos * h_cur_angle_cos); + FVector point = (distance * polar_to_cartesian_lut_[v_cur_index + (h_cur_atan2_index_ * num_lasers_)]); + + // State that determines based on the surface material and the angle of impact if the laser signal still gets reflected based on the capability of the sensor, + // if not the point is dropped. See the paper for more details + bool threshold_enable = true; + + // Default values for groundtruth segmentation and intensity + FColor value_segmentation(0, 0, 0); + float final_intensity = 1; + + if (generate_intensity_) { + + // Get the impact angle in radians, it is spread of the full 3 bytes to achieve three bytes unsigned precision + FColor value_intensity = async_buffer_2D_intensity_[h_pixel + (v_pixel * resolution_)]; + float impact_angle = ((value_intensity.R + value_intensity.G * 256 + value_intensity.B * 256 * 256) / static_cast(256 * 256 * 256 - 1)); + + // Get the stencil color (saved in the alpha channel of the intensity render target) that defines the surface material + // and therefore the Lambertian reflectance coefficient of that material and calculate together with the impact angle on that material the final intensity. + // Furthermroe, detract the rain-intensity based drop as well. + // See the paper for more details + final_intensity = impact_angle * material_map_.at(value_intensity.A) * FMath::Exp(-2.0f * rain_constant_a_ * FMath::Pow(rain_max_intensity_ * rain_value, rain_constant_b_) * (depth / 100.0f)); + + // if the intensity based on the surface material and the impact angle is below the (linear) reflectance limit function the point will be dropped + // See the paper for more details + if ((impact_angle * material_map_.at(value_intensity.A)) < (max_range_ / max_range_lambertian_percentage_ / 100) * depth / 100.0)threshold_enable = false; + } + + if (generate_groundtruth_) { + // Get the RGB value associated with the instance segmentation index of the object detected in this point + value_segmentation = async_buffer_2D_segmentation_[h_pixel + (v_pixel * resolution_)]; + } + + // If the point is not dropped based on the reflectance limit function of the sensor, add the final point data to the pointcloud, else place an empty point + if (threshold_enable && used_by_airsim_) { + point_cloud.emplace_back(point.X / 100); + point_cloud.emplace_back(point.Y / 100); + point_cloud.emplace_back(-point.Z / 100); + std::uint32_t rgb = ((std::uint32_t)value_segmentation.R << 16 | (std::uint32_t)value_segmentation.G << 8 | (std::uint32_t)value_segmentation.B); + point_cloud.emplace_back(rgb); + point_cloud.emplace_back(final_intensity); + } + else if(used_by_airsim_){ + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + } + } + else if (used_by_airsim_) { + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + } + } + else { + if (used_by_airsim_) { + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + point_cloud.emplace_back(0); + } + } + } + + // Set the variables right for the next horizontal angle + h_prev_angle = h_cur_angle; + h_cur_index += 1; + } + return refresh_pointcloud; +} + void ALidarCamera::updateInstanceSegmentationAnnotation(TArray >& ComponentList) { capture_2D_segmentation_->ShowOnlyComponents = ComponentList; } diff --git a/Unreal/Plugins/AirSim/Source/LidarCamera.h b/Unreal/Plugins/AirSim/Source/LidarCamera.h index 05cfac351..9dd2551ab 100644 --- a/Unreal/Plugins/AirSim/Source/LidarCamera.h +++ b/Unreal/Plugins/AirSim/Source/LidarCamera.h @@ -22,6 +22,7 @@ #include "sensors/lidar/GPULidarSimple.hpp" #include "common/Common.hpp" #include +#include #include "LidarCamera.generated.h" @@ -133,6 +134,22 @@ class AIRSIM_API ALidarCamera : public AActor //void ExecuteScanTask(); std::shared_ptr wait_signal_; + bool async_capture_mode_ = false; + std::atomic async_capture_in_flight_{ false }; + std::atomic async_capture_ready_{ false }; + float pending_capture_rotation_ = 0; + int32 pending_capture_fov_ = 0; + bool pending_do_capture_ = false; + float async_job_rotation_angle_ = 0; + float async_job_fov_ = 0; + TArray async_buffer_2D_depth_; + TArray async_buffer_2D_segmentation_; + TArray async_buffer_2D_intensity_; + bool UpdateAsync(float delta_time, msr::airlib::vector& point_cloud, msr::airlib::vector& point_cloud_final); + void StartAsyncCapture(float capture_rotation, int32 cur_fov, bool do_capture); + void ServiceAsyncCapture(); + bool ProcessCapturedBuffers(float sensor_rotation_angle, float fov, msr::airlib::vector& point_cloud, msr::airlib::vector& point_cloud_final); + UPROPERTY() USceneCaptureComponent2D* capture_2D_depth_; diff --git a/Unreal/Plugins/AirSim/Source/PIPCamera.cpp b/Unreal/Plugins/AirSim/Source/PIPCamera.cpp index df94876ce..47d101fdd 100644 --- a/Unreal/Plugins/AirSim/Source/PIPCamera.cpp +++ b/Unreal/Plugins/AirSim/Source/PIPCamera.cpp @@ -150,6 +150,8 @@ void APIPCamera::PostInitializeComponents() FObjectAnnotator::SetViewForAnnotationRender(captures_[Utils::toNumeric(ImageType::Segmentation)]->ShowFlags); captures_[Utils::toNumeric(ImageType::Segmentation)]->PrimitiveRenderMode = ESceneCapturePrimitiveRenderMode::PRM_UseShowOnlyList; + // Initialize ShowOnlyComponents as empty - will be populated by UpdateAnnotationComponentsFromObjectAnnotator + captures_[Utils::toNumeric(ImageType::Segmentation)]->ShowOnlyComponents.Empty(); captures_[Utils::toNumeric(ImageType::Lighting)]->ShowFlags.SetLighting(true); captures_[Utils::toNumeric(ImageType::Lighting)]->ShowFlags.SetMaterials(false); @@ -224,7 +226,6 @@ msr::airlib::ProjectionMatrix APIPCamera::getProjectionMatrix() const } if (capture->ProjectionType == ECameraProjectionMode::Orthographic) { - check((int32)ERHIZBuffer::IsInverted); const float OrthoWidth = capture->OrthoWidth / 2.0f; const float OrthoHeight = capture->OrthoWidth / 2.0f * x_axis_multiplier / y_axis_multiplier; @@ -242,25 +243,13 @@ msr::airlib::ProjectionMatrix APIPCamera::getProjectionMatrix() const } else { float halfFov = Utils::degreesToRadians(capture->FOVAngle) / 2; - if ((int32)ERHIZBuffer::IsInverted) { - proj_mat_transpose = FReversedZPerspectiveMatrix( - halfFov, - halfFov, - x_axis_multiplier, - y_axis_multiplier, - GNearClippingPlane, - GNearClippingPlane); - } - else { - //The FPerspectiveMatrix() constructor actually returns the transpose of the perspective matrix. - proj_mat_transpose = FPerspectiveMatrix( - halfFov, - halfFov, - x_axis_multiplier, - y_axis_multiplier, - GNearClippingPlane, - GNearClippingPlane); - } + proj_mat_transpose = FReversedZPerspectiveMatrix( + halfFov, + halfFov, + x_axis_multiplier, + y_axis_multiplier, + GNearClippingPlane, + GNearClippingPlane); } //Takes a vector from NORTH-EAST-DOWN coordinates (AirSim) to EAST-UP-SOUTH coordinates (Unreal). Leaves W coordinate unchanged. @@ -399,6 +388,9 @@ void APIPCamera::EndPlay(const EEndPlayReason::Type EndPlayReason) captures_.Empty(); render_targets_.Empty(); detections_.Empty(); + + + Super::EndPlay(EndPlayReason); } unsigned int APIPCamera::imageTypeCount() @@ -545,13 +537,16 @@ void APIPCamera::updateInstanceSegmentationAnnotation(TArray >& ComponentList, FString annotation_name, bool only_hide) { + if (!annotator_name_to_index_map_.Contains(annotation_name)) + { + return; + } if (!only_hide) { captures_[annotator_name_to_index_map_[annotation_name]]->ShowOnlyComponents = ComponentList; if (sphere_annotation_component_map_.Contains(annotation_name)) captures_[annotator_name_to_index_map_[annotation_name]]->ShowOnlyComponents.Add(sphere_annotation_component_map_[annotation_name]); - } + } APlayerController* controller = this->GetWorld()->GetFirstPlayerController(); - for (TWeakObjectPtr component : ComponentList) { captures_[Utils::toNumeric(ImageType::Scene)]->HiddenComponents.AddUnique(component); captures_[Utils::toNumeric(ImageType::Lighting)]->HiddenComponents.AddUnique(component); @@ -1315,4 +1310,28 @@ void APIPCamera::copyCameraSettingsToSceneCapture(UCameraComponent* src, USceneC } } -//end CinemAirSim methods +//end CinemAirSim + +void APIPCamera::updateAnnotationComponentsFromObjectAnnotator(FObjectAnnotator& annotator, const FString& annotator_name) { + // Get annotation components from ObjectAnnotator and set them in the appropriate scene capture + TArray> annotation_components = annotator.GetAnnotationComponents(); + + UE_LOG(LogTemp, Log, TEXT("updateAnnotationComponentsFromObjectAnnotator: Found %d annotation components"), annotation_components.Num()); + + if (annotator_name.IsEmpty() || annotator_name.Equals(TEXT("InstanceSegmentation"), ESearchCase::IgnoreCase)) { + // Update instance segmentation (RGB annotation) + UE_LOG(LogTemp, Log, TEXT("updateAnnotationComponentsFromObjectAnnotator: Adding to InstanceSegmentation scene capture")); + updateInstanceSegmentationAnnotation(annotation_components, false); + } + else { + // Update named annotation camera + UE_LOG(LogTemp, Log, TEXT("updateAnnotationComponentsFromObjectAnnotator: Adding to annotation camera '%s'"), *annotator_name); + updateAnnotation(annotation_components, annotator_name, false); + } + + if (Utils::toNumeric(ImageType::Segmentation) < captures_.Num()) { + UE_LOG(LogTemp, Log, TEXT("updateAnnotationComponentsFromObjectAnnotator: Completed. Scene capture ShowOnlyComponents has %d items"), + captures_[Utils::toNumeric(ImageType::Segmentation)]->ShowOnlyComponents.Num()); + } +} + diff --git a/Unreal/Plugins/AirSim/Source/PIPCamera.h b/Unreal/Plugins/AirSim/Source/PIPCamera.h index cc4894c7e..6d038e531 100644 --- a/Unreal/Plugins/AirSim/Source/PIPCamera.h +++ b/Unreal/Plugins/AirSim/Source/PIPCamera.h @@ -73,6 +73,7 @@ class AIRSIM_API APIPCamera : public ACineCameraActor //CinemAirSim void updateInstanceSegmentationAnnotation(TArray >& ComponentList, bool only_hide=false); bool GetAnnotationNameExist(std::string annotation_name); void updateAnnotation(TArray >& ComponentList, FString annotation_name, bool only_hide = false); + void updateAnnotationComponentsFromObjectAnnotator(FObjectAnnotator& annotator, const FString& annotator_name = TEXT("InstanceSegmentation")); void addAnnotationCamera(FString name, FObjectAnnotator::AnnotatorType type, float max_view_distance = -1.0f); void setupCameraFromSettings(const APIPCamera::CameraSetting& camera_setting, const NedTransform& ned_transform); void setCameraPose(const msr::airlib::Pose& relative_pose); diff --git a/Unreal/Plugins/AirSim/Source/PawnSimApi.cpp b/Unreal/Plugins/AirSim/Source/PawnSimApi.cpp index 508062eb1..f0d23b50b 100755 --- a/Unreal/Plugins/AirSim/Source/PawnSimApi.cpp +++ b/Unreal/Plugins/AirSim/Source/PawnSimApi.cpp @@ -438,12 +438,12 @@ bool PawnSimApi::testLineOfSightToPoint(const msr::airlib::GeoPoint& lla) const if (hit) { // No LOS, so draw red line FLinearColor color{ 1.0f, 0, 0, 0.4f }; - params_.pawn->GetWorld()->LineBatcher->DrawLine(params_.pawn->GetActorLocation(), target_location, color, SDPG_World, 10, -1); + UAirBlueprintLib::DrawLine(params_.pawn->GetWorld(), params_.pawn->GetActorLocation(), target_location, color.ToFColor(false), SDPG_World, 10, -1); } else { // Yes LOS, so draw green line FLinearColor color{ 0, 1.0f, 0, 0.4f }; - params_.pawn->GetWorld()->LineBatcher->DrawLine(params_.pawn->GetActorLocation(), target_location, color, SDPG_World, 10, -1); + UAirBlueprintLib::DrawLine(params_.pawn->GetWorld(), params_.pawn->GetActorLocation(), target_location, color.ToFColor(false), SDPG_World, 10, -1); } } }, diff --git a/Unreal/Plugins/AirSim/Source/RenderRequest.cpp b/Unreal/Plugins/AirSim/Source/RenderRequest.cpp index 4914db1f4..d325ab08f 100644 --- a/Unreal/Plugins/AirSim/Source/RenderRequest.cpp +++ b/Unreal/Plugins/AirSim/Source/RenderRequest.cpp @@ -109,7 +109,7 @@ void RenderRequest::getScreenshot(std::shared_ptr params[], std::v if (params[i]->render_target != nullptr && params[i]->render_component != nullptr) { if (!params[i]->pixels_as_float) { if (results[i]->width != 0 && results[i]->height != 0) { - results[i]->image_data_uint8.SetNumUninitialized(results[i]->width * results[i]->height * 3, false); + results[i]->image_data_uint8.SetNumUninitialized(results[i]->width * results[i]->height * 3, EAllowShrinking::No); if (params[i]->compress) UAirBlueprintLib::CompressImageArray(results[i]->width, results[i]->height, results[i]->bmp, results[i]->image_data_uint8); else { @@ -152,7 +152,7 @@ void RenderRequest::ExecuteTask() FRHICommandListImmediate& RHICmdList = GetImmediateCommandList_ForRenderCommand(); auto rt_resource = params_[i]->render_target->GetRenderTargetResource(); if (rt_resource != nullptr) { - const FTexture2DRHIRef& rhi_texture = rt_resource->GetRenderTargetTexture(); + const FTextureRHIRef& rhi_texture = rt_resource->GetRenderTargetTexture(); FIntPoint size; auto flags = setupRenderResource(rt_resource, params_[i].get(), results_[i].get(), size); diff --git a/Unreal/Plugins/AirSim/Source/RenderRequest.h b/Unreal/Plugins/AirSim/Source/RenderRequest.h index 3ae42d7de..51cd8459f 100644 --- a/Unreal/Plugins/AirSim/Source/RenderRequest.h +++ b/Unreal/Plugins/AirSim/Source/RenderRequest.h @@ -9,7 +9,7 @@ #include "common/Common.hpp" -class RenderRequest : public FRenderCommand +class RenderRequest { public: struct RenderParams { @@ -55,16 +55,6 @@ class RenderRequest : public FRenderCommand RenderRequest(UGameViewportClient * game_viewport, std::function&& query_camera_pose_cb); ~RenderRequest(); - void DoTask(ENamedThreads::Type CurrentThread, const FGraphEventRef& MyCompletionGraphEvent) - { - ExecuteTask(); - } - - FORCEINLINE TStatId GetStatId() const - { - RETURN_QUICK_DECLARE_CYCLE_STAT(RenderRequest, STATGROUP_RenderThreadCommands); - } - // read pixels from render target using render thread, then compress the result into PNG // argument on the thread that calls this method. void getScreenshot( diff --git a/Unreal/Plugins/AirSim/Source/SimHUD/SimHUD.cpp b/Unreal/Plugins/AirSim/Source/SimHUD/SimHUD.cpp index c82ecae77..c808f737a 100644 --- a/Unreal/Plugins/AirSim/Source/SimHUD/SimHUD.cpp +++ b/Unreal/Plugins/AirSim/Source/SimHUD/SimHUD.cpp @@ -171,7 +171,7 @@ void ASimHUD::createMainWidget() //create main widget if (widget_class_ != nullptr) { APlayerController* player_controller = this->GetWorld()->GetFirstPlayerController(); - auto* pawn = player_controller->GetPawn(); + TObjectPtr pawn = player_controller->GetPawn(); if (pawn) { std::string pawn_name = std::string(TCHAR_TO_ANSI(*pawn->GetName())); Utils::log(pawn_name); diff --git a/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp b/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp index 1869ef94f..2dea003e5 100755 --- a/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp +++ b/Unreal/Plugins/AirSim/Source/SimMode/SimModeBase.cpp @@ -1247,6 +1247,7 @@ void ASimModeBase::ForceUpdateAnnotation(FString annotation_name) { } void ASimModeBase::updateInstanceSegmentationAnnotation() { + instance_segmentation_annotator_.UpdateAnnotationComponents(this->GetWorld()); TArray> current_segmentation_components = instance_segmentation_annotator_.GetAnnotationComponents(); TArray cameras_found; @@ -1287,6 +1288,7 @@ void ASimModeBase::updateAnnotation(FString annotation_name) { UE_LOG(LogTemp, Log, TEXT("AirSim Annotation [%s]: Could not find annotation layer %s"), *annotation_name, *annotation_name); } else { + annotators_[annotation_name].UpdateAnnotationComponents(this->GetWorld()); TArray> current_annotation_components = annotators_[annotation_name].GetAnnotationComponents(); TArray cameras_found; UAirBlueprintLib::RunCommandOnGameThread([this, &cameras_found]() { @@ -1313,13 +1315,13 @@ void ASimModeBase::updateAnnotation(FString annotation_name) { } if (CameraDirector != nullptr) { if (CameraDirector->getFpvCamera() != nullptr) - CameraDirector->getFpvCamera()->updateInstanceSegmentationAnnotation(current_annotation_components, true); + CameraDirector->getFpvCamera()->updateInstanceSegmentationAnnotation(current_annotation_components, true); if (CameraDirector->getExternalCamera() != nullptr) - CameraDirector->getExternalCamera()->updateInstanceSegmentationAnnotation(current_annotation_components, true); + CameraDirector->getExternalCamera()->updateInstanceSegmentationAnnotation(current_annotation_components, true); if (CameraDirector->getBackupCamera() != nullptr) - CameraDirector->getBackupCamera()->updateInstanceSegmentationAnnotation(current_annotation_components, true); + CameraDirector->getBackupCamera()->updateInstanceSegmentationAnnotation(current_annotation_components, true); if (CameraDirector->getFrontCamera() != nullptr) - CameraDirector->getFrontCamera()->updateInstanceSegmentationAnnotation(current_annotation_components, true); + CameraDirector->getFrontCamera()->updateInstanceSegmentationAnnotation(current_annotation_components, true); } } } diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp index 952683e41..ccf326da2 100644 --- a/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp +++ b/Unreal/Plugins/AirSim/Source/Vehicles/Car/CarPawn.cpp @@ -236,6 +236,8 @@ void ACarPawn::EndPlay(const EEndPlayReason::Type EndPlayReason) camera_front_right_base_ = nullptr; camera_driver_base_ = nullptr; camera_back_center_base_ = nullptr; + + Super::EndPlay(EndPlayReason); } void ACarPawn::Tick(float Delta) diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/ComputerVision/ComputerVisionPawn.cpp b/Unreal/Plugins/AirSim/Source/Vehicles/ComputerVision/ComputerVisionPawn.cpp index 1855cd5e8..0b02082bd 100644 --- a/Unreal/Plugins/AirSim/Source/Vehicles/ComputerVision/ComputerVisionPawn.cpp +++ b/Unreal/Plugins/AirSim/Source/Vehicles/ComputerVision/ComputerVisionPawn.cpp @@ -105,6 +105,9 @@ void AComputerVisionPawn::EndPlay(const EEndPlayReason::Type EndPlayReason) camera_back_center_base_ = nullptr; manual_pose_controller_ = nullptr; + + + Super::EndPlay(EndPlayReason); } void AComputerVisionPawn::Tick(float Delta) diff --git a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp index 209d43ca0..917a9b768 100755 --- a/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp +++ b/Unreal/Plugins/AirSim/Source/Vehicles/SkidSteer/SkidVehiclePawn.cpp @@ -239,6 +239,9 @@ void ASkidVehiclePawn::EndPlay(const EEndPlayReason::Type EndPlayReason) camera_front_right_base_ = nullptr; camera_driver_base_ = nullptr; camera_back_center_base_ = nullptr; + + + Super::EndPlay(EndPlayReason); } void ASkidVehiclePawn::Tick(float Delta) diff --git a/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp b/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp index bffd69967..1df0dea0d 100644 --- a/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp +++ b/Unreal/Plugins/AirSim/Source/WorldSimApi.cpp @@ -856,8 +856,7 @@ bool WorldSimApi::testLineOfSightBetweenPoints(const msr::airlib::GeoPoint& lla1 // Yes LOS, so draw green line color = FLinearColor{ 0, 1.0f, 0, 0.4f }; } - - simmode_->GetWorld()->PersistentLineBatcher->DrawLine(point1, point2, color, SDPG_World, 4, 999999); + UAirBlueprintLib::DrawLine(simmode_->GetWorld(), point1, point2, color.ToFColor(false), SDPG_World, 10, -1); } }, true); diff --git a/build.cmd b/build.cmd index bc53d978e..30134329e 100644 --- a/build.cmd +++ b/build.cmd @@ -10,12 +10,12 @@ set "buildMode=" REM //check VS version if "%VisualStudioVersion%" == "" ( echo( - echo oh oh... You need to run this command from x64 Native Tools Command Prompt for VS 2022. + echo oh oh... You need to run this command from x64 Native Tools Command Prompt for VS 2026. goto :buildfailed_nomsg ) if "%VisualStudioVersion%" lss "17.0" ( echo( - echo Hello there! We just upgraded AirSim to Unreal Engine 5.4 and Visual Studio 2022. + echo Hello there! We just upgraded AirSim to Unreal Engine 5.8 and Visual Studio 2026. echo Here are few easy steps for upgrade so everything is new and shiny: echo https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/docs/unreal_upgrade.md goto :buildfailed_nomsg diff --git a/build.sh b/build.sh index 431ed017c..c70eafa7f 100755 --- a/build.sh +++ b/build.sh @@ -9,6 +9,7 @@ set -x debug=false gcc=false +ue_root="${UE_ROOT:-}" # Parse command line arguments while [[ $# -gt 0 ]] do @@ -23,10 +24,20 @@ do gcc=true shift # past argument ;; + --ue-root) + ue_root="$2" + shift # past argument + shift # past value + ;; esac done +if [[ -n "$ue_root" && $gcc == true ]]; then + echo "ERROR: --ue-root and --gcc are mutually exclusive (Unreal Engine's bundled toolchain is Clang-only)." + exit 1 +fi + function version_less_than_equal_to() { test "$(printf '%s\n' "$@" | sort -V | head -n 1)" = "$1"; } # check for rpclib @@ -62,6 +73,32 @@ if [ "$(uname)" == "Darwin" ]; then #now pick up whatever setup.sh installs export CC="$(brew --prefix)/opt/llvm/bin/clang" export CXX="$(brew --prefix)/opt/llvm/bin/clang++" +elif [[ -n "$ue_root" ]]; then + # Unreal Engine links its Linux targets with its own bundled Clang + sysroot, not the + # system compiler/libc. Building AirLib/rpclib with the matching toolchain here avoids + # ABI mismatches (e.g. "undefined symbol: __isoc23_strtol") that show up when a host with + # a newer glibc (Ubuntu 24.04+, glibc >= 2.38) builds against UE's older bundled sysroot. + ue_toolchain_dirs=("$ue_root"/Engine/Extras/ThirdPartyNotUE/SDKs/HostLinux/Linux_x64/*/x86_64-unknown-linux-gnu) + if [[ ! -e "${ue_toolchain_dirs[0]}" ]]; then + echo "ERROR: could not find Unreal Engine's bundled Linux toolchain under:" + echo " $ue_root/Engine/Extras/ThirdPartyNotUE/SDKs/HostLinux/Linux_x64/*/x86_64-unknown-linux-gnu" + echo "Check that --ue-root points at a valid Unreal Engine install root." + exit 1 + fi + if [[ ${#ue_toolchain_dirs[@]} -gt 1 ]]; then + echo "ERROR: found multiple Unreal Engine bundled Linux toolchains under $ue_root, expected one:" + printf ' %s\n' "${ue_toolchain_dirs[@]}" + exit 1 + fi + UE_TOOLCHAIN_DIR="${ue_toolchain_dirs[0]}" + if [[ ! -x "$UE_TOOLCHAIN_DIR/bin/clang++" ]]; then + echo "ERROR: $UE_TOOLCHAIN_DIR/bin/clang++ not found or not executable." + exit 1 + fi + echo "Using Unreal Engine's bundled Linux toolchain at $UE_TOOLCHAIN_DIR" + export CC="$UE_TOOLCHAIN_DIR/bin/clang" + export CXX="$UE_TOOLCHAIN_DIR/bin/clang++" + CMAKE_VARS="$CMAKE_VARS -DUSING_UE_TOOLCHAIN=ON -DCMAKE_CXX_FLAGS=--sysroot=$UE_TOOLCHAIN_DIR -DCMAKE_C_FLAGS=--sysroot=$UE_TOOLCHAIN_DIR -DCMAKE_EXE_LINKER_FLAGS=--sysroot=$UE_TOOLCHAIN_DIR -DCMAKE_SHARED_LINKER_FLAGS=--sysroot=$UE_TOOLCHAIN_DIR" else if $gcc; then export CC="gcc" @@ -132,9 +169,9 @@ set +x echo "" echo "" -echo "===============================" -echo " Cosys-AirSim plugin is built!." -echo "===============================" +echo "==========================================" +echo " Cosys-AirSim airlib c++ plugin is built!." +echo "==========================================" echo "" echo "For further info see for installation see:" echo "https://github.com/Cosys-Lab/Cosys-AirSim/tree/main/docs/install_linux.md" diff --git a/cmake/cmake-modules/CommonSetup.cmake b/cmake/cmake-modules/CommonSetup.cmake index 3c45f2df2..f5d8f9265 100644 --- a/cmake/cmake-modules/CommonSetup.cmake +++ b/cmake/cmake-modules/CommonSetup.cmake @@ -1,8 +1,7 @@ # Common setup instructions shared by all AirSim CMakeLists. macro(CommonTargetLink) - target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) - #target_link_libraries(c++abi) + target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT} ${CXX_EXP_LIB}) endmacro(CommonTargetLink) macro(IncludeEigen) @@ -58,8 +57,20 @@ macro(CommonSetup) if (${CMAKE_CXX_COMPILER_ID} MATCHES "Clang") set(CMAKE_CXX_FLAGS "-stdlib=libc++ -Wno-documentation -Wno-unknown-warning-option ${CMAKE_CXX_FLAGS}") - find_package(LLVM REQUIRED CONFIG) - set(CXX_EXP_LIB "-L${LLVM_LIBRARY_DIRS} -ferror-limit=10") + if (USING_UE_TOOLCHAIN) + # Unreal Engine's bundled Clang ships its own libc++/libc++abi under its sysroot. + # Linking against the system LLVM's libc++ here (via -L) pulls in newer glibc + # symbols (e.g. pthread_once@GLIBC_2.34) that aren't present in UE's older + # bundled sysroot, causing undefined reference errors at link time. + # UE only ships static libc++.a/libc++abi.a (no .so), so unlike the dynamic-linked + # system libc++ (which auto-resolves libc++abi via DT_NEEDED), the static libc++abi + # must be linked explicitly. --start-group/--end-group lets ld resolve the mutual + # libc++ <-> libc++abi symbol dependencies regardless of scan order. + set(CXX_EXP_LIB "-Wl,--start-group -lc++ -lc++abi -Wl,--end-group -ferror-limit=10") + else() + find_package(LLVM REQUIRED CONFIG) + set(CXX_EXP_LIB "-L${LLVM_LIBRARY_DIRS} -ferror-limit=10") + endif() else() set(CXX_EXP_LIB "-fmax-errors=10 -Wnoexcept -Wstrict-null-sentinel") endif () diff --git a/docker/Dockerfile_binary b/docker/Dockerfile_binary index ad8c77550..469f9dff0 100644 --- a/docker/Dockerfile_binary +++ b/docker/Dockerfile_binary @@ -1,4 +1,4 @@ -ARG BASE_IMAGE=ghcr.io/epicgames/unreal-engine:dev-slim-5.5.4 +ARG BASE_IMAGE=ghcr.io/epicgames/unreal-engine:dev-slim-5.8.0 FROM $BASE_IMAGE USER root diff --git a/docker/Dockerfile_source b/docker/Dockerfile_source index c828b8755..8a392aab8 100644 --- a/docker/Dockerfile_source +++ b/docker/Dockerfile_source @@ -1,4 +1,4 @@ -ARG BASE_IMAGE=ghcr.io/epicgames/unreal-engine:dev-slim-5.5.4 +ARG BASE_IMAGE=ghcr.io/epicgames/unreal-engine:dev-slim-5.8.0 FROM $BASE_IMAGE USER root @@ -17,10 +17,11 @@ RUN python3 -m pip install --upgrade pip && \ pip3 install cosysairsim USER ue4 +ENV UE_ROOT=/home/ue4/UnrealEngine RUN cd /home/ue4 && \ git clone --progress https://github.com/Cosys-Lab/Cosys-AirSim.git && \ cd Cosys-AirSim && \ ./setup.sh && \ - ./build.sh + ./build.sh --ue-root $UE_ROOT WORKDIR /home/ue4 diff --git a/docker/build_airsim_image.py b/docker/build_airsim_image.py index cbbe8d0f2..338b124c5 100644 --- a/docker/build_airsim_image.py +++ b/docker/build_airsim_image.py @@ -13,7 +13,7 @@ def build_docker_image(args): dockerfile = 'Dockerfile_source' if args.source: if not args.base_image: - args.base_image = "ghcr.io/epicgames/unreal-engine:dev-slim-5.5.4" + args.base_image = "ghcr.io/epicgames/unreal-engine:dev-slim-5.8.0" target_image_tag = args.base_image.split(":")[1] # take tag from base image if not args.target_image: args.target_image = 'airsim_source' + ':' + target_image_tag @@ -21,7 +21,7 @@ def build_docker_image(args): else: dockerfile = 'Dockerfile_binary' if not args.base_image: - args.base_image = "ghcr.io/epicgames/unreal-engine:dev-slim-5.5.4" + args.base_image = "ghcr.io/epicgames/unreal-engine:dev-slim-5.8.0" target_image_tag = args.base_image.split(":")[1] # take tag from base image if not args.target_image: args.target_image = 'airsim_binary' + ':' + target_image_tag diff --git a/docker/download_blocks_env_binary.sh b/docker/download_blocks_env_binary.sh index 3077e157e..c121a7a93 100755 --- a/docker/download_blocks_env_binary.sh +++ b/docker/download_blocks_env_binary.sh @@ -5,7 +5,7 @@ if ! which unzip; then sudo apt-get install unzip fi -wget -c https://github.com/Cosys-Lab/Cosys-AirSim/releases/download/5.5-v3.3/Blocks_packaged_Linux_55_33.zip -unzip -q Blocks_packaged_Linux_55_33.zip -rm Blocks_packaged_Linux_55_33.zip -mv Blocks_packaged_Linux_55_33 LinuxBlocks +wget -c https://github.com/Cosys-Lab/Cosys-AirSim/releases/download/5.8-v3.4/Blocks_packaged_Linux_58_34.zip +unzip -q Blocks_packaged_Linux_56_34.zip +rm Blocks_packaged_Linux_56_34.zip +mv Blocks_packaged_Linux_56_34 LinuxBlocks diff --git a/docs/README.md b/docs/README.md index 79525e720..1d8431574 100644 --- a/docs/README.md +++ b/docs/README.md @@ -10,8 +10,8 @@ Please note that we use that same [MIT license](https://github.com/Cosys-Lab/Cos Do note that this repository is provided as is, will not be actively updated and comes without warranty or support. Please contact a Cosys-Lab researcher to get more in depth information on which branch or version is best for your work. -This documentation is for the latest stable Unreal Version v5.5 on the [main branch](https://github.com/Cosys-Lab/Cosys-AirSim/tree/main), maintained for support, and is available for builds in the [releases](https://github.com/Cosys-Lab/Cosys-AirSim/releases). -Unreal [5.2.1](https://github.com/Cosys-Lab/Cosys-AirSim/tree/5.2.1) is also available for long term support builds but the documentation is best read from [source](https://github.com/Cosys-Lab/Cosys-AirSim/tree/5.2.1/docs). +This documentation is for the latest stable Unreal Version v5.8 on the [main branch](https://github.com/Cosys-Lab/Cosys-AirSim/tree/main), maintained for support, and is available for builds in the [releases](https://github.com/Cosys-Lab/Cosys-AirSim/releases). +Unreal [5.2.1](https://github.com/Cosys-Lab/Cosys-AirSim/tree/5.2.1) is also available for long term support but the documentation is best read from [source](https://github.com/Cosys-Lab/Cosys-AirSim/tree/5.2.1/docs). ## Associated publications @@ -22,10 +22,7 @@ Unreal [5.2.1](https://github.com/Cosys-Lab/Cosys-AirSim/tree/5.2.1) is also ava booktitle={2023 Annual Modeling and Simulation Conference (ANNSIM)}, title={COSYS-AIRSIM: A Real-Time Simulation Framework Expanded for Complex Industrial Applications}, year={2023}, - volume={}, - number={}, - pages={37-48}, - doi={}} + doi={https://doi.org/10.48550/arXiv.2303.13381}} ``` You can also find the presentation of the live tutorial of Cosys-AirSim at ANNSIM '23 conference [here](https://github.com/Cosys-Lab/Cosys-AirSim/tree/main/docs/annsim23_tutorial) together with the associated videos. @@ -38,8 +35,6 @@ You can also find the presentation of the live tutorial of Cosys-AirSim at ANNSI booktitle={2022 IEEE Sensors}, title={Physical LiDAR Simulation in Real-Time Engine}, year={2022}, - volume={}, - number={}, pages={1-4}, doi={10.1109/SENSORS52175.2022.9967197}} } @@ -76,7 +71,7 @@ You can also find the presentation of the live tutorial of Cosys-AirSim at ANNSI * Updated sensors like cameras, Echo sensor and GPU-LiDAR to ignore certain objects with the _MarkedIgnore_ Unreal tag and enabling the "IgnoreMarked" setting in [the settings file](https://cosys-lab.github.io/Cosys-AirSim/settings). * Updated cameras sensor with more distortion features such as chromatic aberration, motion blur and lens distortion. * Updated Python [ROS implementation](https://cosys-lab.github.io/Cosys-AirSim/ros_python) with completely new implementation and feature set. -* Updated C++ [ROS2 implementation](https://cosys-lab.github.io/Cosys-AirSim/ros_cplusplus) to support custom Cosys-AirSim features. +* Updated C++ [ROS2 implementation](https://cosys-lab.github.io/Cosys-AirSim/ros2) to support custom Cosys-AirSim features. * Dropped support for Unity Environments. Some more details on our changes can be found in the [changelog](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/CHANGELOG.md). diff --git a/docs/annotation.md b/docs/annotation.md index ecca4e537..fc06a6bf8 100644 --- a/docs/annotation.md +++ b/docs/annotation.md @@ -16,6 +16,7 @@ The annotation system uses actor and/or component tags to set these values for t * Foliage objects aren't supported. This is the special object type in Unreal to place trees, grass and other plants that move with the wind. As a work-around, StaticMesh objects must be used. * Brush objects aren't supported. This is a special object type in Unreal to create your own meshes with. As a work-around, you can convert them to a StaticMesh. * These and other unsupported object types that are less common that either will not be rendered (decals, text, foliage, ...) or will by default be given the RGB color value of [149,149,149] or [0,0,0]. (brush objects, landscape,...). + * Skeletal meshes are not well supported on UE 5.2.1. On UE 5.8 (Cosys-AirSim v3.4 or higher) (nanite) skeletal meshes work but may still face limitations such as skeletal meshes consisisting of multiple meshes. ## Usage diff --git a/docs/apis.md b/docs/apis.md index 0d0feec3c..69e2ad55b 100644 --- a/docs/apis.md +++ b/docs/apis.md @@ -1,322 +1,320 @@ -# AirSim APIs - -## Introduction -AirSim exposes APIs so you can interact with vehicle in the simulation programmatically. You can use these APIs to retrieve images, get state, control the vehicle and so on. - -## Python Quickstart -If you want to use Python to call AirSim APIs, we recommend using Anaconda with Python 3.5 or later versions however some code may also work with Python 2.7. - -First install this package: - -``` -pip install rpc-msgpack -``` - -Once you can run AirSim, choose Car as vehicle and then navigate to `PythonClient\car\` folder and run: - -``` -python hello_car.py -``` - -If you are using Visual Studio 2019 then just open AirSim.sln, set PythonClient as startup project and choose `car\hello_car.py` as your startup script. - -### Installing AirSim Package - -You can also install the AirSim python module to your Python environment to use anywhere by running `pip install .` in the _PythonClient_ folder. - -**Notes** -1. You may notice a file `setup_path.py` in our example folders. This file has simple code to detect if `airsim` package is available in parent folder and in that case we use that instead of pip installed package so you always use latest code. -2. AirSim is still under heavy development which means you might frequently need to update the package to use new APIs. - -## C++ Users -If you want to use C++ APIs and examples, please see [C++ APIs Guide](apis_cpp.md). - - -## Hello Car -Here's how to use AirSim APIs using Python to control simulated car (see also [C++ example](apis_cpp.md#hello_car)): - -```python -# ready to run example: PythonClient/car/hello_car.py -import cosysairsim as airsim -import time - -# connect to the AirSim simulator -client = airsim.CarClient() -client.confirmConnection() -client.enableApiControl(True) -car_controls = airsim.CarControls() - -while True: - # get state of the car - car_state = client.getCarState() - print("Speed %d, Gear %d" % (car_state.speed, car_state.gear)) - - # set the controls for car - car_controls.throttle = 1 - car_controls.steering = 1 - client.setCarControls(car_controls) - - # let car drive a bit - time.sleep(1) - - # get camera images from the car - responses = client.simGetImages([ - airsim.ImageRequest(0, airsim.ImageType.DepthVis), - airsim.ImageRequest(1, airsim.ImageType.DepthPlanar, True)]) - print('Retrieved images: %d', len(responses)) - - # do something with images - for response in responses: - if response.pixels_as_float: - print("Type %d, size %d" % (response.image_type, len(response.image_data_float))) - airsim.write_pfm('py1.pfm', airsim.get_pfm_array(response)) - else: - print("Type %d, size %d" % (response.image_type, len(response.image_data_uint8))) - airsim.write_file('py1.png', response.image_data_uint8) - -``` - -## Hello Drone -Here's how to use AirSim APIs using Python to control simulated quadrotor (see also [C++ example](apis_cpp.md#hello_drone)): - -```python -# ready to run example: PythonClient/multirotor/hello_drone.py -import cosysairsim as airsim -import os - -# connect to the AirSim simulator -client = airsim.MultirotorClient() -client.confirmConnection() -client.enableApiControl(True) -client.armDisarm(True) - -# Async methods returns Future. Call join() to wait for task to complete. -client.takeoffAsync().join() -client.moveToPositionAsync(-10, 10, -10, 5).join() - -# take images -responses = client.simGetImages([ - airsim.ImageRequest("0", airsim.ImageType.DepthVis), - airsim.ImageRequest("1", airsim.ImageType.DepthPlanar, True)]) -print('Retrieved images: %d', len(responses)) - -# do something with the images -for response in responses: - if response.pixels_as_float: - print("Type %d, size %d" % (response.image_type, len(response.image_data_float))) - airsim.write_pfm(os.path.normpath('/temp/py1.pfm'), airsim.get_pfm_array(response)) - else: - print("Type %d, size %d" % (response.image_type, len(response.image_data_uint8))) - airsim.write_file(os.path.normpath('/temp/py1.png'), response.image_data_uint8) -``` - -## Common APIs - -* `reset`: This resets the vehicle to its original starting state. Note that you must call `enableApiControl` and `armDisarm` again after the call to `reset`. -* `confirmConnection`: Checks state of connection every 1 sec and reports it in Console so user can see the progress for connection. -* `enableApiControl`: For safety reasons, by default API control for autonomous vehicle is not enabled and human operator has full control (usually via RC or joystick in simulator). The client must make this call to request control via API. It is likely that human operator of vehicle might have disallowed API control which would mean that enableApiControl has no effect. This can be checked by `isApiControlEnabled`. -* `isApiControlEnabled`: Returns true if API control is established. If false (which is default) then API calls would be ignored. After a successful call to `enableApiControl`, the `isApiControlEnabled` should return true. -* `ping`: If connection is established then this call will return true otherwise it will be blocked until timeout. -* `simPrintLogMessage`: Prints the specified message in the simulator's window. If message_param is also supplied then its printed next to the message and in that case if this API is called with same message value but different message_param again then previous line is overwritten with new line (instead of API creating new line on display). For example, `simPrintLogMessage("Iteration: ", to_string(i))` keeps updating same line on display when API is called with different values of i. The valid values of severity parameter is 0 to 3 inclusive that corresponds to different colors. -* `simGetObjectPose(ned=true)`, `simSetObjectPose`: Gets and sets the pose of specified object in Unreal environment. Here the object means "actor" in Unreal terminology. They are searched by tag as well as name. Please note that the names shown in UE Editor are *auto-generated* in each run and are not permanent. So if you want to refer to actor by name, you must change its auto-generated name in UE Editor. Alternatively you can add a tag to actor which can be done by clicking on that actor in Unreal Editor and then going to [Tags property](https://answers.unrealengine.com/questions/543807/whats-the-difference-between-tag-and-tag.html), click "+" sign and add some string value. If multiple actors have same tag then the first match is returned. If no matches are found then NaN pose is returned. The returned pose is in NED coordinates in SI units with its origin at Player Start by default or in Unreal NED frame if the `ned` boolean argument is set to `talse`. For `simSetObjectPose`, the specified actor must have [Mobility](https://docs.unrealengine.com/en-us/Engine/Actors/Mobility) set to Movable or otherwise you will get undefined behavior. The `simSetObjectPose` has parameter `teleport` which means object is [moved through other objects](https://www.unrealengine.com/en-US/blog/moving-physical-objects) in its way and it returns true if move was successful -* `simListSceneObjects`: Provides a list of all objects in the environment. You can also use regular expression to filter specific objects by name. For example, the code below sets all meshes which have names starting with "wall" you can use `simListSceneObjects("wall[\w]*")`. - -### Image/Computer Vision/Instance segmentation APIs -AirSim offers comprehensive images APIs to retrieve synchronized images from multiple cameras along with ground truth including depth, disparity, surface normals and vision. You can set the resolution, FOV, motion blur etc parameters in [settings.json](settings.md). There is also API for detecting collision state. See also [complete code](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/Examples/DataCollection/StereoImageGenerator.hpp) that generates specified number of stereo images and ground truth depth with normalization to camera plan, computation of disparity image and saving it to [pfm format](pfm.md). -Furthermore, the [Instance Segmentation](instance_segmentation.md) system can also be manipulated through the API. - -More on [image APIs, Computer Vision mode and instance segmentation configuration](image_apis.md). - -### Pause and Continue APIs -AirSim allows to pause and continue the simulation through `pause(is_paused)` API. To pause the simulation call `pause(True)` and to continue the simulation call `pause(False)`. You may have scenario, especially while using reinforcement learning, to run the simulation for specified amount of time and then automatically pause. While simulation is paused, you may then do some expensive computation, send a new command and then again run the simulation for specified amount of time. This can be achieved by API `continueForTime(seconds)`. This API runs the simulation for the specified number of seconds and then pauses the simulation. For example usage, please see [pause_continue_car.py](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/car/pause_continue_car.py) and [pause_continue_drone.py](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/multirotor/pause_continue_drone.py). - - -### Collision API -The collision information can be obtained using `simGetCollisionInfo` API. This call returns a struct that has information not only whether collision occurred but also collision position, surface normal, penetration depth and so on. - -### Time of Day API -AirSim assumes there exist sky sphere of class `EngineSky/BP_Sky_Sphere` in your environment with ADirectionalLight actor. By default, the position of the sun in the scene doesn't move with time. You can use [settings](settings.md#timeofday) to set up latitude, longitude, date and time which AirSim uses to compute the position of sun in the scene. - -You can also use following API call to set the sun position according to given date time: - -``` -simSetTimeOfDay(self, is_enabled, start_datetime = "", is_start_datetime_dst = False, celestial_clock_speed = 1, update_interval_secs = 60, move_sun = True) -``` - -The `is_enabled` parameter must be `True` to enable time of day effect. If it is `False` then sun position is reset to its original in the environment. - -Other parameters are same as in [settings](settings.md#timeofday). - -### Line-of-sight and world extent APIs -To test line-of-sight in the sim from a vehicle to a point or between two points, see simTestLineOfSightToPoint(point, vehicle_name) and simTestLineOfSightBetweenPoints(point1, point2), respectively. -Sim world extent, in the form of a vector of two GeoPoints, can be retrieved using simGetWorldExtents(). - -### Weather APIs -By default all weather effects are disabled. To enable weather effect, first call: - -``` -simEnableWeather(True) -``` - -Various weather effects can be enabled by using `simSetWeatherParameter` method which takes `WeatherParameter`, for example, - -``` -client.simSetWeatherParameter(airsim.WeatherParameter.Rain, 0.25); -``` -The second parameter value is from 0 to 1. The first parameter provides following options: - -``` -class WeatherParameter: - Rain = 0 - Roadwetness = 1 - Snow = 2 - RoadSnow = 3 - MapleLeaf = 4 - RoadLeaf = 5 - Dust = 6 - Fog = 7 -``` - -Please note that `Roadwetness`, `RoadSnow` and `RoadLeaf` effects requires adding [materials](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/Unreal/Plugins/AirSim/Content/Weather/WeatherFX) to your scene. - -Please see [example code](https://github.com/Cosys-Lab/Cosys-AirSim/tree/main/PythonClient/environment/weather.py) for more details. - -### Recording APIs - -Recording APIs can be used to start recording data through APIs. Data to be recorded can be specified using [settings](settings.md#recording). To start recording, use - - -``` -client.startRecording() -``` - -Similarly, to stop recording, use `client.stopRecording()`. To check whether Recording is running, call `client.isRecording()`, returns a `bool`. - -This API works alongwith toggling Recording using R button, therefore if it's enabled using R key, `isRecording()` will return `True`, and recording can be stopped via API using `stopRecording()`. Similarly, recording started using API will be stopped if R key is pressed in Viewport. LogMessage will also appear in the top-left of the viewport if recording is started or stopped using API. - -Note that this will only save the data as specfied in the settings. For full freedom in storing data such as certain sensor information, or in a different format or layout, use the other APIs to fetch the data and save as desired. Check out [Modifying Recording Data](modify_recording_data.md) for details on how to modify the kinematics data being recorded. - -### Wind API - -Wind can be changed during simulation using `simSetWind()`. Wind is specified in World frame, NED direction and m/s values - -E.g. To set 20m/s wind in North (forward) direction - - -```python -# Set wind to (20,0,0) in NED (forward direction) -wind = airsim.Vector3r(20, 0, 0) -client.simSetWind(wind) -``` - -Also see example script in [set_wind.py](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/multirotor/set_wind.py) - -### Lidar APIs -AirSim offers API to retrieve point cloud data from (GPU)Lidar sensors on vehicles. You can set the number of channels, points per second, horizontal and vertical FOV, etc parameters in [settings.json](settings.md). - -More on [lidar APIs and settings](lidar.md), [GPUlidar APIs and settings](gpulidar.md) and [sensor settings](sensors.md) - -### Light Control APIs - -Lights that can be manipulated inside Cosys-AirSim can be created via the [Artificial Lights system](lights.md). The original AirSim Lights API is deprecated. - -### Texture APIs - -Textures can be dynamically set on objects via these APIs: - -* `simSetObjectMaterial`: This sets an object's material using an existing Unreal material asset. It takes two string parameters, `object_name` and `material_name`. -* `simSetObjectMaterialFromTexture`: This sets an object's material using a path to a texture. It takes two string parameters, `object_name` and `texture_path`. - -### Multiple Vehicles -AirSim supports multiple vehicles and control them through APIs. Please [Multiple Vehicles](multi_vehicle.md) doc. - -### Coordinate System -All AirSim API uses NED coordinate system, i.e., +X is North, +Y is East and +Z is Down. All units are in SI system. Please note that this is different from coordinate system used internally by Unreal Engine. In Unreal Engine, +Z is up instead of down and length unit is in centimeters instead of meters. AirSim APIs takes care of the appropriate conversions. The starting point of the vehicle is always coordinates (0, 0, 0) in NED system. Thus when converting from Unreal coordinates to NED, we first subtract the starting offset and then scale by 100 for cm to m conversion. The vehicle is spawned in Unreal environment where the Player Start component is placed. There is a setting called `OriginGeopoint` in [settings.json](settings.md) which assigns geographic longitude, longitude and altitude to the Player Start component. -If wanted, one can move the Unreal origin to the same location as the AirSim origin player start position by setting the `MoveWorldOrigin` in the settings.json to `true`. - -## Vehicle Specific APIs -### APIs for Car -Car has followings APIs available: - -* `setCarControls`: This allows you to set throttle, steering, handbrake and auto or manual gear. -* `getCarState`: This retrieves the state information including speed, current gear and 6 kinematics quantities: position, orientation, linear and angular velocity, linear and angular acceleration. All quantities are in NED coordinate system, SI units in world frame except for angular velocity and accelerations which are in body frame. -* [Image APIs](image_apis.md). - -### APIs for Multirotor -Multirotor can be controlled by specifying angles, velocity vector, destination position or some combination of these. There are corresponding `move*` APIs for this purpose. When doing position control, we need to use some path following algorithm. By default AirSim uses carrot following algorithm. This is often referred to as "high level control" because you just need to specify high level goal and the firmware takes care of the rest. Currently lowest level control available in AirSim is `moveByAngleThrottleAsync` API. - -#### getMultirotorState -This API returns the state of the vehicle in one call. The state includes, collision, estimated kinematics (i.e. kinematics computed by fusing sensors), and timestamp (nano seconds since epoch). The kinematics here means 6 quantities: position, orientation, linear and angular velocity, linear and angular acceleration. Please note that simple_slight currently doesn't support state estimator which means estimated and ground truth kinematics values would be same for simple_flight. Estimated kinematics are however available for PX4 except for angular acceleration. All quantities are in NED coordinate system, SI units in world frame except for angular velocity and accelerations which are in body frame. - -#### Async methods, duration and max_wait_seconds -Many API methods has parameters named `duration` or `max_wait_seconds` and they have *Async* as suffix, for example, `takeoffAsync`. These methods will return immediately after starting the task in AirSim so that your client code can do something else while that task is being executed. If you want to wait for this task to complete then you can call `waitOnLastTask` like this: - -```cpp -//C++ -client.takeoffAsync()->waitOnLastTask(); -``` - -```cpp -# Python -client.takeoffAsync().join() -``` - -If you start another command then it automatically cancels the previous task and starts new command. This allows to use pattern where your coded continuously does the sensing, computes a new trajectory to follow and issues that path to vehicle in AirSim. Each newly issued trajectory cancels the previous trajectory allowing your code to continuously do the update as new sensor data arrives. - -All *Async* method returns `concurrent.futures.Future` in Python (`std::future` in C++). Please note that these future classes currently do not allow to check status or cancel the task; they only allow to wait for task to complete. AirSim does provide API `cancelLastTask`, however. - -#### drivetrain -There are two modes you can fly vehicle: `drivetrain` parameter is set to `airsim.DrivetrainType.ForwardOnly` or `airsim.DrivetrainType.MaxDegreeOfFreedom`. When you specify ForwardOnly, you are saying that vehicle's front should always point in the direction of travel. So if you want drone to take left turn then it would first rotate so front points to left. This mode is useful when you have only front camera and you are operating vehicle using FPV view. This is more or less like travelling in car where you always have front view. The MaxDegreeOfFreedom means you don't care where the front points to. So when you take left turn, you just start going left like crab. Quadrotors can go in any direction regardless of where front points to. The MaxDegreeOfFreedom enables this mode. - -#### yaw_mode -`yaw_mode` is a struct `YawMode` with two fields, `yaw_or_rate` and `is_rate`. If `is_rate` field is True then `yaw_or_rate` field is interpreted as angular velocity in degrees/sec which means you want vehicle to rotate continuously around its axis at that angular velocity while moving. If `is_rate` is False then `yaw_or_rate` is interpreted as angle in degrees which means you want vehicle to rotate to specific angle (i.e. yaw) and keep that angle while moving. - -You can probably see that when `yaw_mode.is_rate == true`, the `drivetrain` parameter shouldn't be set to `ForwardOnly` because you are contradicting by saying that keep front pointing ahead but also rotate continuously. However if you have `yaw_mode.is_rate = false` in `ForwardOnly` mode then you can do some funky stuff. For example, you can have drone do circles and have yaw_or_rate set to 90 so camera is always pointed to center ("super cool selfie mode"). In `MaxDegreeofFreedom` also you can get some funky stuff by setting `yaw_mode.is_rate = true` and say `yaw_mode.yaw_or_rate = 20`. This will cause drone to go in its path while rotating which may allow to do 360 scanning. - -In most cases, you just don't want yaw to change which you can do by setting yaw rate of 0. The shorthand for this is `airsim.YawMode.Zero()` (or in C++: `YawMode::Zero()`). - -#### lookahead and adaptive_lookahead -When you ask vehicle to follow a path, AirSim uses "carrot following" algorithm. This algorithm operates by looking ahead on path and adjusting its velocity vector. The parameters for this algorithm is specified by `lookahead` and `adaptive_lookahead`. For most of the time you want algorithm to auto-decide the values by simply setting `lookahead = -1` and `adaptive_lookahead = 0`. - -## Using APIs on Real Vehicles -We want to be able to run *same code* that runs in simulation as on real vehicle. This allows you to test your code in simulator and deploy to real vehicle. - -Generally speaking, APIs therefore shouldn't allow you to do something that cannot be done on real vehicle (for example, getting the ground truth). But, of course, simulator has much more information and it would be useful in applications that may not care about running things on real vehicle. For this reason, we clearly delineate between sim-only APIs by attaching `sim` prefix, for example, `simGetGroundTruthKinematics`. This way you can avoid using these simulation-only APIs if you care about running your code on real vehicles. - -The AirLib is self-contained library that you can put on an offboard computing module such as the Gigabyte barebone Mini PC. This module then can talk to the flight controllers such as PX4 using exact same code and flight controller protocol. The code you write for testing in the simulator remains unchanged. See [AirLib on custom drones](custom_drone.md). - -## Adding New APIs to AirSim - -See the [Adding New APIs](adding_new_apis.md) page - -## References and Examples - -* [C++ API Examples](apis_cpp.md) -* [Car Examples](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/car) -* [Multirotor Examples](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/multirotor) -* [Computer Vision Examples](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/computer_vision) -* [Move on Path](https://github.com/Microsoft/AirSim/wiki/moveOnPath-demo) demo showing video of fast multirotor flight through Modular Neighborhood environment -* [Building a Hexacopter](https://github.com/Microsoft/AirSim/wiki/hexacopter) -* [Building Point Clouds](https://github.com/Microsoft/AirSim/wiki/Point-Clouds) - - -## FAQ - -#### Unreal is slowed down dramatically when I run API -If you see Unreal getting slowed down dramatically when Unreal Engine window loses focus then go to 'Edit->Editor Preferences' in Unreal Editor, in the 'Search' box type 'CPU' and ensure that the 'Use Less CPU when in Background' is unchecked. - -#### Do I need anything else on Windows? -You should install VS2019 with VC++, Windows SDK 10.0 and Python. To use Python APIs you will need Python 3.5 or later (install it using Anaconda). - -#### Which version of Python should I use? -We recommend [Anaconda](https://www.anaconda.com/download/) to get Python tools and libraries. Our code is tested with Python 3.5.3 :: Anaconda 4.4.0. This is important because older version have been known to have [problems](https://stackoverflow.com/a/45934992/207661). - -#### I get error on `import cv2` -You can install OpenCV using: -``` -conda install opencv -pip install opencv-python -``` - -#### TypeError: unsupported operand type(s) for *: 'AsyncIOLoop' and 'float' - -This error happens if you install Jupyter, which somehow breaks the msgpackrpc library. Create a new python environment -which the minimal required packages. +# AirSim APIs + +## Introduction +AirSim exposes APIs so you can interact with vehicle in the simulation programmatically. You can use these APIs to retrieve images, get state, control the vehicle and so on. + +## Python Quickstart +If you want to use Python to call AirSim APIs, we recommend using Anaconda with Python 3.5 or later versions however some code may also work with Python 2.7. + +First install this package: + +``` +pip install rpc-msgpack +``` + +Once you can run AirSim, choose Car as vehicle and then navigate to `PythonClient\car\` folder and run: + +``` +python hello_car.py +``` + +If you are using Visual Studio 2019 then just open AirSim.sln, set PythonClient as startup project and choose `car\hello_car.py` as your startup script. + +### Installing AirSim Package + +You can install the Cosys-AirSim Python client from pip with `pip install cosysairsim`. +You can also install the AirSim python module to your Python environment by running `pip install .` in the _PythonClient_ folder. + + +## C++ Users +If you want to use C++ APIs and examples, please see [C++ APIs Guide](apis_cpp.md). + + +## Hello Car +Here's how to use AirSim APIs using Python to control simulated car (see also [C++ example](apis_cpp.md#hello-car)): + +```python +# ready to run example: PythonClient/car/hello_car.py +import cosysairsim as airsim +import time + +# connect to the AirSim simulator +client = airsim.CarClient() +client.confirmConnection() +client.enableApiControl(True) +car_controls = airsim.CarControls() + +while True: + # get state of the car + car_state = client.getCarState() + print("Speed %d, Gear %d" % (car_state.speed, car_state.gear)) + + # set the controls for car + car_controls.throttle = 1 + car_controls.steering = 1 + client.setCarControls(car_controls) + + # let car drive a bit + time.sleep(1) + + # get camera images from the car + responses = client.simGetImages([ + airsim.ImageRequest(0, airsim.ImageType.DepthVis), + airsim.ImageRequest(1, airsim.ImageType.DepthPlanar, True)]) + print('Retrieved images: %d', len(responses)) + + # do something with images + for response in responses: + if response.pixels_as_float: + print("Type %d, size %d" % (response.image_type, len(response.image_data_float))) + airsim.write_pfm('py1.pfm', airsim.get_pfm_array(response)) + else: + print("Type %d, size %d" % (response.image_type, len(response.image_data_uint8))) + airsim.write_file('py1.png', response.image_data_uint8) + +``` + +## Hello Drone +Here's how to use AirSim APIs using Python to control simulated quadrotor (see also [C++ example](apis_cpp.md#hello-drone)): + +```python +# ready to run example: PythonClient/multirotor/hello_drone.py +import cosysairsim as airsim +import os + +# connect to the AirSim simulator +client = airsim.MultirotorClient() +client.confirmConnection() +client.enableApiControl(True) +client.armDisarm(True) + +# Async methods returns Future. Call join() to wait for task to complete. +client.takeoffAsync().join() +client.moveToPositionAsync(-10, 10, -10, 5).join() + +# take images +responses = client.simGetImages([ + airsim.ImageRequest("0", airsim.ImageType.DepthVis), + airsim.ImageRequest("1", airsim.ImageType.DepthPlanar, True)]) +print('Retrieved images: %d', len(responses)) + +# do something with the images +for response in responses: + if response.pixels_as_float: + print("Type %d, size %d" % (response.image_type, len(response.image_data_float))) + airsim.write_pfm(os.path.normpath('/temp/py1.pfm'), airsim.get_pfm_array(response)) + else: + print("Type %d, size %d" % (response.image_type, len(response.image_data_uint8))) + airsim.write_file(os.path.normpath('/temp/py1.png'), response.image_data_uint8) +``` + +## Common APIs + +* `reset`: This resets the vehicle to its original starting state. Note that you must call `enableApiControl` and `armDisarm` again after the call to `reset`. +* `confirmConnection`: Checks state of connection every 1 sec and reports it in Console so user can see the progress for connection. +* `enableApiControl`: For safety reasons, by default API control for autonomous vehicle is not enabled and human operator has full control (usually via RC or joystick in simulator). The client must make this call to request control via API. It is likely that human operator of vehicle might have disallowed API control which would mean that enableApiControl has no effect. This can be checked by `isApiControlEnabled`. +* `isApiControlEnabled`: Returns true if API control is established. If false (which is default) then API calls would be ignored. After a successful call to `enableApiControl`, the `isApiControlEnabled` should return true. +* `ping`: If connection is established then this call will return true otherwise it will be blocked until timeout. +* `simPrintLogMessage`: Prints the specified message in the simulator's window. If message_param is also supplied then its printed next to the message and in that case if this API is called with same message value but different message_param again then previous line is overwritten with new line (instead of API creating new line on display). For example, `simPrintLogMessage("Iteration: ", to_string(i))` keeps updating same line on display when API is called with different values of i. The valid values of severity parameter is 0 to 3 inclusive that corresponds to different colors. +* `simGetObjectPose(ned=true)`, `simSetObjectPose`: Gets and sets the pose of specified object in Unreal environment. Here the object means "actor" in Unreal terminology. They are searched by tag as well as name. Please note that the names shown in UE Editor are *auto-generated* in each run and are not permanent. So if you want to refer to actor by name, you must change its auto-generated name in UE Editor. Alternatively you can add a tag to actor which can be done by clicking on that actor in Unreal Editor and then going to [Tags property](https://answers.unrealengine.com/questions/543807/whats-the-difference-between-tag-and-tag.html), click "+" sign and add some string value. If multiple actors have same tag then the first match is returned. If no matches are found then NaN pose is returned. The returned pose is in NED coordinates in SI units with its origin at Player Start by default or in Unreal NED frame if the `ned` boolean argument is set to `talse`. For `simSetObjectPose`, the specified actor must have [Mobility](https://docs.unrealengine.com/en-us/Engine/Actors/Mobility) set to Movable or otherwise you will get undefined behavior. The `simSetObjectPose` has parameter `teleport` which means object is [moved through other objects](https://www.unrealengine.com/en-US/blog/moving-physical-objects) in its way and it returns true if move was successful +* `simListSceneObjects`: Provides a list of all objects in the environment. You can also use regular expression to filter specific objects by name. For example, the code below sets all meshes which have names starting with "wall" you can use `simListSceneObjects("wall[\w]*")`. + +### Image/Computer Vision/Instance segmentation APIs +AirSim offers comprehensive images APIs to retrieve synchronized images from multiple cameras along with ground truth including depth, disparity, surface normals and vision. You can set the resolution, FOV, motion blur etc parameters in [settings.json](settings.md). There is also API for detecting collision state. See also [complete code](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/Examples/DataCollection/StereoImageGenerator.hpp) that generates specified number of stereo images and ground truth depth with normalization to camera plan, computation of disparity image and saving it to [pfm format](pfm.md). +Furthermore, the [Instance Segmentation](instance_segmentation.md) system can also be manipulated through the API. + +More on [image APIs, Computer Vision mode and instance segmentation configuration](image_apis.md). + +### Pause and Continue APIs +AirSim allows to pause and continue the simulation through `pause(is_paused)` API. To pause the simulation call `pause(True)` and to continue the simulation call `pause(False)`. You may have scenario, especially while using reinforcement learning, to run the simulation for specified amount of time and then automatically pause. While simulation is paused, you may then do some expensive computation, send a new command and then again run the simulation for specified amount of time. This can be achieved by API `continueForTime(seconds)`. This API runs the simulation for the specified number of seconds and then pauses the simulation. For example usage, please see [pause_continue_car.py](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/car/pause_continue_car.py) and [pause_continue_drone.py](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/multirotor/pause_continue_drone.py). + + +### Collision API +The collision information can be obtained using `simGetCollisionInfo` API. This call returns a struct that has information not only whether collision occurred but also collision position, surface normal, penetration depth and so on. + +### Time of Day API +AirSim assumes there exist sky sphere of class `EngineSky/BP_Sky_Sphere` in your environment with ADirectionalLight actor. By default, the position of the sun in the scene doesn't move with time. You can use [settings](settings.md#timeofday) to set up latitude, longitude, date and time which AirSim uses to compute the position of sun in the scene. + +You can also use following API call to set the sun position according to given date time: + +``` +simSetTimeOfDay(self, is_enabled, start_datetime = "", is_start_datetime_dst = False, celestial_clock_speed = 1, update_interval_secs = 60, move_sun = True) +``` + +The `is_enabled` parameter must be `True` to enable time of day effect. If it is `False` then sun position is reset to its original in the environment. + +Other parameters are same as in [settings](settings.md#timeofday). + +### Line-of-sight and world extent APIs +To test line-of-sight in the sim from a vehicle to a point or between two points, see simTestLineOfSightToPoint(point, vehicle_name) and simTestLineOfSightBetweenPoints(point1, point2), respectively. +Sim world extent, in the form of a vector of two GeoPoints, can be retrieved using simGetWorldExtents(). + +### Weather APIs +By default all weather effects are disabled. To enable weather effect, first call: + +``` +simEnableWeather(True) +``` + +Various weather effects can be enabled by using `simSetWeatherParameter` method which takes `WeatherParameter`, for example, + +``` +client.simSetWeatherParameter(airsim.WeatherParameter.Rain, 0.25); +``` +The second parameter value is from 0 to 1. The first parameter provides following options: + +``` +class WeatherParameter: + Rain = 0 + Roadwetness = 1 + Snow = 2 + RoadSnow = 3 + MapleLeaf = 4 + RoadLeaf = 5 + Dust = 6 + Fog = 7 +``` + +Please note that `Roadwetness`, `RoadSnow` and `RoadLeaf` effects requires adding [materials](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/Unreal/Plugins/AirSim/Content/Weather/WeatherFX) to your scene. + +Please see [example code](https://github.com/Cosys-Lab/Cosys-AirSim/tree/main/PythonClient/environment/weather.py) for more details. + +### Recording APIs + +Recording APIs can be used to start recording data through APIs. Data to be recorded can be specified using [settings](settings.md#recording). To start recording, use - + +``` +client.startRecording() +``` + +Similarly, to stop recording, use `client.stopRecording()`. To check whether Recording is running, call `client.isRecording()`, returns a `bool`. + +This API works alongwith toggling Recording using R button, therefore if it's enabled using R key, `isRecording()` will return `True`, and recording can be stopped via API using `stopRecording()`. Similarly, recording started using API will be stopped if R key is pressed in Viewport. LogMessage will also appear in the top-left of the viewport if recording is started or stopped using API. + +Note that this will only save the data as specfied in the settings. For full freedom in storing data such as certain sensor information, or in a different format or layout, use the other APIs to fetch the data and save as desired. Check out [Modifying Recording Data](modify_recording_data.md) for details on how to modify the kinematics data being recorded. + +### Wind API + +Wind can be changed during simulation using `simSetWind()`. Wind is specified in World frame, NED direction and m/s values + +E.g. To set 20m/s wind in North (forward) direction - + +```python +# Set wind to (20,0,0) in NED (forward direction) +wind = airsim.Vector3r(20, 0, 0) +client.simSetWind(wind) +``` + +Also see example script in [set_wind.py](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/multirotor/set_wind.py) + +### Lidar APIs +AirSim offers API to retrieve point cloud data from (GPU)Lidar sensors on vehicles. You can set the number of channels, points per second, horizontal and vertical FOV, etc parameters in [settings.json](settings.md). + +More on [lidar APIs and settings](lidar.md), [GPUlidar APIs and settings](gpulidar.md) and [sensor settings](sensors.md) + +### Light Control APIs + +Lights that can be manipulated inside Cosys-AirSim can be created via the [Artificial Lights system](lights.md). The original AirSim Lights API is deprecated. + +### Texture APIs + +Textures can be dynamically set on objects via these APIs: + +* `simSetObjectMaterial`: This sets an object's material using an existing Unreal material asset. It takes two string parameters, `object_name` and `material_name`. +* `simSetObjectMaterialFromTexture`: This sets an object's material using a path to a texture. It takes two string parameters, `object_name` and `texture_path`. + +### Multiple Vehicles +AirSim supports multiple vehicles and control them through APIs. Please [Multiple Vehicles](multi_vehicle.md) doc. + +### Coordinate System +All AirSim API uses NED coordinate system, i.e., +X is North, +Y is East and +Z is Down. All units are in SI system. Please note that this is different from coordinate system used internally by Unreal Engine. In Unreal Engine, +Z is up instead of down and length unit is in centimeters instead of meters. AirSim APIs takes care of the appropriate conversions. The starting point of the vehicle is always coordinates (0, 0, 0) in NED system. Thus when converting from Unreal coordinates to NED, we first subtract the starting offset and then scale by 100 for cm to m conversion. The vehicle is spawned in Unreal environment where the Player Start component is placed. There is a setting called `OriginGeopoint` in [settings.json](settings.md) which assigns geographic longitude, longitude and altitude to the Player Start component. +If wanted, one can move the Unreal origin to the same location as the AirSim origin player start position by setting the `MoveWorldOrigin` in the settings.json to `true`. + +## Vehicle Specific APIs +### APIs for Car +Car has followings APIs available: + +* `setCarControls`: This allows you to set throttle, steering, handbrake and auto or manual gear. +* `getCarState`: This retrieves the state information including speed, current gear and 6 kinematics quantities: position, orientation, linear and angular velocity, linear and angular acceleration. All quantities are in NED coordinate system, SI units in world frame except for angular velocity and accelerations which are in body frame. +* [Image APIs](image_apis.md). + +### APIs for Multirotor +Multirotor can be controlled by specifying angles, velocity vector, destination position or some combination of these. There are corresponding `move*` APIs for this purpose. When doing position control, we need to use some path following algorithm. By default AirSim uses carrot following algorithm. This is often referred to as "high level control" because you just need to specify high level goal and the firmware takes care of the rest. Currently lowest level control available in AirSim is `moveByAngleThrottleAsync` API. + +#### getMultirotorState +This API returns the state of the vehicle in one call. The state includes, collision, estimated kinematics (i.e. kinematics computed by fusing sensors), and timestamp (nano seconds since epoch). The kinematics here means 6 quantities: position, orientation, linear and angular velocity, linear and angular acceleration. Please note that simple_slight currently doesn't support state estimator which means estimated and ground truth kinematics values would be same for simple_flight. Estimated kinematics are however available for PX4 except for angular acceleration. All quantities are in NED coordinate system, SI units in world frame except for angular velocity and accelerations which are in body frame. + +#### Async methods, duration and max_wait_seconds +Many API methods has parameters named `duration` or `max_wait_seconds` and they have *Async* as suffix, for example, `takeoffAsync`. These methods will return immediately after starting the task in AirSim so that your client code can do something else while that task is being executed. If you want to wait for this task to complete then you can call `waitOnLastTask` like this: + +```cpp +//C++ +client.takeoffAsync()->waitOnLastTask(); +``` + +```cpp +# Python +client.takeoffAsync().join() +``` + +If you start another command then it automatically cancels the previous task and starts new command. This allows to use pattern where your coded continuously does the sensing, computes a new trajectory to follow and issues that path to vehicle in AirSim. Each newly issued trajectory cancels the previous trajectory allowing your code to continuously do the update as new sensor data arrives. + +All *Async* method returns `concurrent.futures.Future` in Python (`std::future` in C++). Please note that these future classes currently do not allow to check status or cancel the task; they only allow to wait for task to complete. AirSim does provide API `cancelLastTask`, however. + +#### drivetrain +There are two modes you can fly vehicle: `drivetrain` parameter is set to `airsim.DrivetrainType.ForwardOnly` or `airsim.DrivetrainType.MaxDegreeOfFreedom`. When you specify ForwardOnly, you are saying that vehicle's front should always point in the direction of travel. So if you want drone to take left turn then it would first rotate so front points to left. This mode is useful when you have only front camera and you are operating vehicle using FPV view. This is more or less like travelling in car where you always have front view. The MaxDegreeOfFreedom means you don't care where the front points to. So when you take left turn, you just start going left like crab. Quadrotors can go in any direction regardless of where front points to. The MaxDegreeOfFreedom enables this mode. + +#### yaw_mode +`yaw_mode` is a struct `YawMode` with two fields, `yaw_or_rate` and `is_rate`. If `is_rate` field is True then `yaw_or_rate` field is interpreted as angular velocity in degrees/sec which means you want vehicle to rotate continuously around its axis at that angular velocity while moving. If `is_rate` is False then `yaw_or_rate` is interpreted as angle in degrees which means you want vehicle to rotate to specific angle (i.e. yaw) and keep that angle while moving. + +You can probably see that when `yaw_mode.is_rate == true`, the `drivetrain` parameter shouldn't be set to `ForwardOnly` because you are contradicting by saying that keep front pointing ahead but also rotate continuously. However if you have `yaw_mode.is_rate = false` in `ForwardOnly` mode then you can do some funky stuff. For example, you can have drone do circles and have yaw_or_rate set to 90 so camera is always pointed to center ("super cool selfie mode"). In `MaxDegreeofFreedom` also you can get some funky stuff by setting `yaw_mode.is_rate = true` and say `yaw_mode.yaw_or_rate = 20`. This will cause drone to go in its path while rotating which may allow to do 360 scanning. + +In most cases, you just don't want yaw to change which you can do by setting yaw rate of 0. The shorthand for this is `airsim.YawMode.Zero()` (or in C++: `YawMode::Zero()`). + +#### lookahead and adaptive_lookahead +When you ask vehicle to follow a path, AirSim uses "carrot following" algorithm. This algorithm operates by looking ahead on path and adjusting its velocity vector. The parameters for this algorithm is specified by `lookahead` and `adaptive_lookahead`. For most of the time you want algorithm to auto-decide the values by simply setting `lookahead = -1` and `adaptive_lookahead = 0`. + +## Using APIs on Real Vehicles +We want to be able to run *same code* that runs in simulation as on real vehicle. This allows you to test your code in simulator and deploy to real vehicle. + +Generally speaking, APIs therefore shouldn't allow you to do something that cannot be done on real vehicle (for example, getting the ground truth). But, of course, simulator has much more information and it would be useful in applications that may not care about running things on real vehicle. For this reason, we clearly delineate between sim-only APIs by attaching `sim` prefix, for example, `simGetGroundTruthKinematics`. This way you can avoid using these simulation-only APIs if you care about running your code on real vehicles. + +The AirLib is self-contained library that you can put on an offboard computing module such as the Gigabyte barebone Mini PC. This module then can talk to the flight controllers such as PX4 using exact same code and flight controller protocol. The code you write for testing in the simulator remains unchanged. See [AirLib on custom drones](custom_drone.md). + +## Adding New APIs to AirSim + +See the [Adding New APIs](adding_new_apis.md) page + +## References and Examples + +* [C++ API Examples](apis_cpp.md) +* [Car Examples](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/car) +* [Multirotor Examples](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/multirotor) +* [Computer Vision Examples](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/PythonClient/computer_vision) +* [Move on Path](https://github.com/Microsoft/AirSim/wiki/moveOnPath-demo) demo showing video of fast multirotor flight through Modular Neighborhood environment +* [Building a Hexacopter](https://github.com/Microsoft/AirSim/wiki/hexacopter) +* [Building Point Clouds](https://github.com/Microsoft/AirSim/wiki/Point-Clouds) + + +## FAQ + +#### Unreal is slowed down dramatically when I run API +If you see Unreal getting slowed down dramatically when Unreal Engine window loses focus then go to 'Edit->Editor Preferences' in Unreal Editor, in the 'Search' box type 'CPU' and ensure that the 'Use Less CPU when in Background' is unchecked. + +#### Do I need anything else on Windows? +You should install VS2019 with VC++, Windows SDK 10.0 and Python. To use Python APIs you will need Python 3.5 or later (install it using Anaconda). + +#### Which version of Python should I use? +We recommend [Anaconda](https://www.anaconda.com/download/) to get Python tools and libraries. Our code is tested with Python 3.5.3 :: Anaconda 4.4.0. This is important because older version have been known to have [problems](https://stackoverflow.com/a/45934992/207661). + +#### I get error on `import cv2` +You can install OpenCV using: +``` +conda install opencv +pip install opencv-python +``` + +#### TypeError: unsupported operand type(s) for *: 'AsyncIOLoop' and 'float' + +This error happens if you install Jupyter, which somehow breaks the msgpackrpc library. Create a new python environment +which the minimal required packages. diff --git a/docs/apis_cpp.md b/docs/apis_cpp.md index 928480de3..f631a604e 100644 --- a/docs/apis_cpp.md +++ b/docs/apis_cpp.md @@ -12,7 +12,7 @@ Fastest way to get started is to open AirSim.sln in Visual Studio 2017. You will ## Hello Car -Here's how to use AirSim APIs using Python to control simulated car (see also [Python example](apis.md#hello_car)): +Here's how to use AirSim APIs using Python to control simulated car (see also [Python example](apis.md#hello-car)): ```cpp @@ -50,7 +50,7 @@ int main() ## Hello Drone -Here's how to use AirSim APIs using Python to control simulated car (see also [Python example](apis.md#hello_drone)): +Here's how to use AirSim APIs using Python to control simulated car (see also [Python example](apis.md#hello-drone)): ```cpp diff --git a/docs/contributed_tutorials.md b/docs/contributed_tutorials.md new file mode 100644 index 000000000..b9216e033 --- /dev/null +++ b/docs/contributed_tutorials.md @@ -0,0 +1,12 @@ +# Contributed Tutorials + +This page lists community-contributed tutorials, demos and write-ups covering Cosys-AirSim and its upstream project, AirSim. + +* [Using Environments from Marketplace](https://www.youtube.com/watch?v=y09VbdQWvQY) +* [Simple Collision Avoidance](https://github.com/simondlevy/AirSimTensorFlow) +* [Autonomous Driving on Azure](https://aka.ms/AutonomousDrivingCookbook) +* [Building Hexacopter](https://github.com/Microsoft/AirSim/wiki/hexacopter) +* [Moving on Path Demo](https://github.com/Microsoft/AirSim/wiki/moveOnPath-demo) +* [Importing a custom multirotor mesh](https://youtu.be/Bp86WiLUC80) +* [Object Detection](object_detection.md) +* [AirSim with MAVROS and PX4](https://youtu.be/ZonkdMcwXH4) diff --git a/docs/docker_ubuntu.md b/docs/docker_ubuntu.md index 3f392f04b..b4423d14d 100644 --- a/docs/docker_ubuntu.md +++ b/docs/docker_ubuntu.md @@ -1,5 +1,5 @@ # Cosys-AirSim on Docker in Linux -We've two options for docker. You can either build an image for running [Cosys-AirSim binaries](#runtime-binaries), or for compiling Cosys-AirSim [from source](#source). +We've two options for docker. You can either build an image for running [Cosys-AirSim binaries](#packaged-runtime-binaries), or for compiling Cosys-AirSim [from source](#source). ## Packaged runtime Binaries @@ -16,8 +16,8 @@ We've two options for docker. You can either build an image for running [Cosys-A ```bash cd Airsim/docker; python build_airsim_image.py \ - --base_image=ghcr.io/epicgames/unreal-engine:dev-slim-5.5.4 \ - --target_image=airsim_binary:dev-slim-5.5.4 + --base_image=ghcr.io/epicgames/unreal-engine:dev-slim-5.8.0 \ + --target_image=airsim_binary:dev-slim-5.8.0 ``` - Verify you have an image by: @@ -44,10 +44,9 @@ xhost +local:docker ``` Do not forget to run the xhost command first to bind the X11 to docker. - For Blocks, you can do a `./run_airsim_image_binary.sh airsim_binary:dev-slim-5.5.4 LinuxBlocks/Linux/Blocks.sh -windowed -ResX=1080 -ResY=720` -` + For Blocks, you can do a `./run_airsim_image_binary.sh airsim_binary:dev-slim-5.8.0 LinuxBlocks/Linux/Blocks.sh -windowed -ResX=1080 -ResY=720` - * `DOCKER_IMAGE_NAME`: Same as `target_image` parameter in previous step. By default, enter `airsim_binary:dev-slim-5.5.4` + * `DOCKER_IMAGE_NAME`: Same as `target_image` parameter in previous step. By default, enter `airsim_binary:dev-slim-5.8.0` * `UNREAL_BINARY_SHELL_SCRIPT`: for Blocks enviroment, it will be `LinuxBlocks/Linux/Blocks.sh` * [`UNREAL_BINARY_ARGUMENTS`](https://docs.unrealengine.com/en-us/Programming/Basics/CommandLineArguments): For airsim, most relevant would be `-windowed`, `-ResX`, `-ResY`. Click on link to see all options. @@ -69,8 +68,8 @@ xhost +local:docker $ cd Airsim/docker; $ python build_airsim_image.py \ --source \ - --base_image ghcr.io/epicgames/unreal-engine:dev-slim-5.5.4 \ - --target_image=airsim_source:dev-slim-5.5.4 + --base_image ghcr.io/epicgames/unreal-engine:dev-slim-5.8.0 \ + --target_image=airsim_source:dev-slim-5.8.0 ``` #### Running Cosys-AirSim container @@ -78,7 +77,7 @@ $ python build_airsim_image.py \ ```bash xhost +local:docker -./run_airsim_image_source.sh airsim_source:dev-slim-5.5.4 +./run_airsim_image_source.sh airsim_source:dev-slim-5.8.0 ``` Syntax is `./run_airsim_image_source.sh DOCKER_IMAGE_NAME` @@ -87,6 +86,7 @@ xhost +local:docker * Inside the container, you can see `UnrealEngine` and `Cosys-AirSim` under `/home/ue4`. * Start unreal engine inside the container: `/home/ue4/UnrealEngine/Engine/Binaries/Linux/UnrealEditor` +* The image builds AirLib with `./build.sh --ue-root /home/ue4/UnrealEngine` (see [Linux build docs](install_linux.md#build-cosys-airsim)) so that AirLib is linked with Unreal's own bundled Clang toolchain instead of the container's system compiler, avoiding ABI mismatches when building the Unreal plugin. The image also sets the `UE_ROOT` environment variable to `/home/ue4/UnrealEngine`, so if you make code changes and re-run `./build.sh` manually inside the container it will keep using the correct toolchain automatically. * [Specifying an airsim settings.json](#specifying-settingsjson) * Continue with [Cosys-AirSims's Linux docs](install_linux.md#build-unreal-environment). For example start the Blocks environment in the container run (This will first copy the plugin and afterwards start open the project with the Unreal Editor): diff --git a/docs/gazebo_drone.md b/docs/gazebo_drone.md index cea5ef623..db5a9a871 100644 --- a/docs/gazebo_drone.md +++ b/docs/gazebo_drone.md @@ -25,7 +25,7 @@ Run from your AirSim root folder: ## Cosys-AirSim simulator -The Cosys-AirSim UE plugin needs to be built with clang, so you can't use the one compiled in the previous step. You can use [our binaries](https://github.com/microsoft/AirSim/releases) or you can clone AirSim again in another folder and buid it without the above option, then you can [run Blocks](install_linux.md#how-to-use-airsim) or your own environment. +The Cosys-AirSim UE plugin needs to be built with clang, so you can't use the one compiled in the previous step. You can use [our binaries](https://github.com/microsoft/AirSim/releases) or you can clone AirSim again in another folder and buid it without the above option, then you can [run Blocks](install_linux.md#how-to-use-cosys-airsim) or your own environment. ### Cosys-AirSim settings diff --git a/docs/gpulidar.md b/docs/gpulidar.md index 5129d1c27..51318a89e 100644 --- a/docs/gpulidar.md +++ b/docs/gpulidar.md @@ -5,7 +5,8 @@ Cosys-AirSim supports a GPU accelerated Lidar for multirotors and cars. It uses The enablement of a GPU lidar and the other lidar settings can be configured via AirSimSettings json. Please see [general sensors](sensors.md) for information on configuration of general/shared sensor settings. -Note that this sensor type is currently not supported for Multirotor mode. It only works for Car and Computervision. +Note that on Multirotor simmode, the sensor capture is dispatched asynchronously to the Unreal game thread , so its measurements lag by roughly one game frame compared to other simmodes. Real-time debug point drawing (`DrawDebugPoints`) is not supported on Multirotor for this reason. + ## Enabling GPU lidar on a vehicle * By default, GPU lidars are not enabled. To enable the sensor, set the SensorType and Enabled attributes in settings json. ``` @@ -105,7 +106,7 @@ asphalt,0.1 This needs to be saved as 'materials.csv' in your documents folder where also your settings json file resides. ## Server side visualization for debugging -By default, the lidar points are not drawn on the viewport. To enable the drawing of hit laser points on the viewport, please enable setting 'DrawDebugPoints' via settings json. *This is only for testing purposes and will affect the data slightly. It also needs to be disabled when using multiple Lidar sensors to avoid artifacts!!* +By default, the lidar points are not drawn on the viewport. To enable the drawing of hit laser points on the viewport, please enable setting 'DrawDebugPoints' via settings json. Note this does not work for Multirotor vehicles. *This is only for testing purposes and will affect the data slightly. It also needs to be disabled when using multiple Lidar sensors to avoid artifacts!!* e.g.: ``` diff --git a/docs/image_apis.md b/docs/image_apis.md index 1705a3d1c..edfae2da1 100644 --- a/docs/image_apis.md +++ b/docs/image_apis.md @@ -146,7 +146,7 @@ Before AirSim v1.2, cameras were accessed using ID numbers instead of names. For ## "Computer Vision" Mode -You can use AirSim in so-called "Computer Vision" mode. In this mode, physics engine is disabled and there is no vehicle, just cameras (If you want to have the vehicle but without its kinematics, you can use the Multirotor mode with the Physics Engine [ExternalPhysicsEngine](settings.md##physicsenginename)). You can move around using keyboard (use F1 to see help on keys). You can press Record button to continuously generate images. Or you can call APIs to move cameras around and take images. +You can use AirSim in so-called "Computer Vision" mode. In this mode, physics engine is disabled and there is no vehicle, just cameras (If you want to have the vehicle but without its kinematics, you can use the Multirotor mode with the Physics Engine [ExternalPhysicsEngine](settings.md#physicsenginename)). You can move around using keyboard (use F1 to see help on keys). You can press Record button to continuously generate images. Or you can call APIs to move cameras around and take images. You can use AirSim in so-called "Computer Vision" mode. In this mode, physics engine is disabled. It has a standard set of cameras and can have any sensor added similar to other vehicles. You can move around using keyboard (use F1 to see help on keys, additionally use left shift to go faster and spacebar to hold in place (handy for when moving camera manually). You can press Record button to continuously generate images. Or you can call APIs to move cameras around and take images. To active this mode, edit [settings.json](settings.md) that you can find in your `Documents\AirSim` folder (or `~/Documents/AirSim` on Linux) and make sure following values exist at root level: diff --git a/docs/install_linux.md b/docs/install_linux.md index 4f0d87ccf..182f03e02 100755 --- a/docs/install_linux.md +++ b/docs/install_linux.md @@ -1,21 +1,32 @@ -# Intall or Build Cosys-AirSim on Linux +# Build Cosys-AirSim on Linux from Source -The current recommended and tested environment is **Ubuntu 22.04 LTS**. Theoretically, you can build on other distros as well, but we haven't tested it. +The current recommended and tested environment is **Ubuntu 24.04 LTS**. Theoretically, you can build on other distros as well, but we haven't tested it. ## Install Compiler Toolchain -Unreal Engine requires a correct version of the compiler toolchain clang. You can find the right version on [this page](https://dev.epicgames.com/documentation/en-us/unreal-engine/linux-development-requirements-for-unreal-engine#gettingthetoolchain) for the Unreal version you wish to install. -To easily install this version on your machine, you can use the following script: -```bash -wget https://apt.llvm.org/llvm.sh -chmod +x llvm.sh -sudo ./llvm.sh -``` +You will need the following dependencies. Newer versions may also work but are not tested: +- clang 20 +- clang++-20 +- libc++-20-dev +- libc++abi-20-dev +- libstdc++-20-dev +- cmake 2.28 +- glib 2.28 +- build-essential +- lsb-release +- rsync +- software-properties-common +- wget +- unzip + +`clang 18` above is only needed for `setup.sh`'s own tooling (and as a fallback compiler). The actual +AirLib/rpclib build should use Unreal Engine's own bundled Clang toolchain instead of the system +compiler, see the note in the next section. ## Install Unreal Engine -Download the latest version of Unreal Engine 5.5 from the [official download page](https://www.unrealengine.com/en-US/linux). +Download the latest version of Unreal Engine 5.8.X from the [official download page](https://www.unrealengine.com/en-US/linux). This will require an Epic Games account. Once the zip archive is downloaded you can extract it to where you want to install the Unreal Engine. ```bash -unzip Linux_Unreal_Engine_5.5.X.zip -d destination_folder +unzip -o Linux_Unreal_Engine_5.8.X.zip -d destination_folder ``` If you chose a folder such as for example `/opt/UnrealEngine` make sure to provide permissions and to set the owner, otherwise you might run into issues: ```bash @@ -23,19 +34,36 @@ sudo chmod -R 777 /opt/UnrealEngine sudo chown -r yourusername /opt/UnrealEngine ``` From where you install Unreal Engine, you can run `Engine/Binaries/Linux/UnrealEditor` from the terminal to launch Unreal Engine. -For more information you can read the [quick start guide](https://dev.epicgames.com/documentation/en-us/unreal-engine/linux-development-quickstart-for-unreal-engine?application_version=5.4). +For more information you can read the [quick start guide](https://dev.epicgames.com/documentation/en-us/unreal-engine/linux-development-quickstart-for-unreal-engine?application_version=5.8). You can alternatively install Unreal Engine from source if you do not use a Ubuntu distribution, see the documentation linked above for more information. ## Build Cosys-Airsim -- Clone Cosys-AirSim and build it: +- Clone Cosys-AirSim and build it, passing the path to your Unreal Engine install with `--ue-root`: ```bash - # go to the folder where you clone GitHub projects git clone https://github.com/Cosys-Lab/Cosys-AirSim.git cd Cosys-AirSim ./setup.sh + ./build.sh --ue-root /path/to/UnrealEngine + ``` + + Instead of passing `--ue-root` on every invocation, you can instead export the `UE_ROOT` + environment variable once (e.g. in your `~/.bashrc`) and just run `./build.sh`: + ```bash + export UE_ROOT=/path/to/UnrealEngine ./build.sh ``` + `--ue-root` takes precedence if both are set. `/path/to/UnrealEngine` is the folder containing + `Engine/`, i.e. the same folder from which you run `Engine/Binaries/Linux/UnrealEditor`. + + Unreal Engine links its Linux targets using its own bundled Clang compiler, not your system compiler/libc. If you build AirLib with the plain system `clang` the resulting built library can end up incompatible with UE's linker, and building the Unreal plugin will fail. + + `--ue-root`/`UE_ROOT` avoids this by locating Unreal's bundled Linux toolchain (under + `Engine/Extras/ThirdPartyNotUE/SDKs/HostLinux/Linux_x64/`) and building AirLib with that exact + compiler and `--sysroot`, so the produced static libraries are always ABI-compatible with the + engine install you point it at. Omitting `--ue-root` still works and falls back to the system + `clang`/`clang++` (or `gcc`/`g++` with `--gcc`), but is only recommended if you hit no link + errors when building the Unreal plugin. ## Build Unreal Environment @@ -51,6 +79,7 @@ Once Cosys-AirSim is setup: - If you get prompts to convert project, look for More Options or Convert-In-Place option. If you get prompted to build, choose Yes. If you get prompted to disable Cosys-AirSim plugin, choose No. - After Unreal Editor loads, press Play button. +You can install the Cosys-AirSim Python client from pip with `pip install cosysairsim`. See [Using APIs](apis.md) and [settings.json](settings.md) for various options available for Cosys-AirSim usage. !!! tip @@ -58,6 +87,6 @@ Go to 'Edit->Editor Preferences', in the 'Search' box type 'CPU' and ensure that ### [Optional] Setup Remote Control (Multirotor Only) -A remote control is required if you want to fly manually. See the [remote control setup](remote_control.md) for more details. +A remote control is required if you want to fly the drones manually. See the [remote control setup](remote_control.md) for more details. Alternatively, you can use [APIs](apis.md) for programmatic control or use the so-called [Computer Vision mode](image_apis.md) to move around using the keyboard. diff --git a/docs/install_precompiled.md b/docs/install_precompiled.md index 77edc2eb7..6805e7f0d 100644 --- a/docs/install_precompiled.md +++ b/docs/install_precompiled.md @@ -1,7 +1,10 @@ -# Download and install precompiled Plugin +# Download and use precompiled Plugin -If you wish to not build the plugin from source, you can download the precompiled plugin from the [releases page](https://github.com/Cosys-Lab/Cosys-AirSim/releases) for the right version of Unreal you are using. -It does not come with a environment so you will need to create your own Unreal project. Follow this [step-by-step guide](unreal_custenv.md). +If you wish to not build the plugin from source, you can download the precompiled plugin from the [releases page](https://github.com/Cosys-Lab/Cosys-AirSim/releases) for the version of Unreal and operating system you are using. + +You will also be able to find a sample _Blocks_ project in that release where you can install the plugin. Extract the _Blocks_ environment, create a _Plugins_ folder in it and extract the precompiled plugin _AirSim_ folder into that _Plugins_ folder. Doubleclick the Blocks.uproject file in the _Blocks_ folder to start a build of the project and open the Unreal Editor. + +Follow this [step-by-step guide](unreal_custenv.md) to setup your own custom environment and Unreal Project to use Cosys-AirSim. But the installation process is the same as described above for the _Blocks_ sample project. The releases page also comes with additional downloads and links to the several API implementations for ROS(2) and the Python and Matlab API clients for that specific version of the Cosys-AirSim plugin. diff --git a/docs/install_windows.md b/docs/install_windows.md index 24f1ee6da..37fb8f274 100644 --- a/docs/install_windows.md +++ b/docs/install_windows.md @@ -1,15 +1,15 @@ -# Install or Build Cosys-AirSim on Windows +# Build Cosys-AirSim on Windows from Source ## Install Unreal Engine 1. [Download](https://www.unrealengine.com/download) the Epic Games Launcher. While the Unreal Engine is open source and free to download, registration is still required. 2. Run the Epic Games Launcher, open the `Unreal Engine` tab on the left pane. -Click on the `Install` button on the top right, which should show the option to download **Unreal Engine 5.5.X**. Chose the install location to suit your needs, as shown in the images below. If you have multiple versions of Unreal installed then **make sure the version you are using is set to `current`** by clicking down arrow next to the Launch button for the version. +Click on the `Install` button on the top right, which should show the option to download **Unreal Engine 5.8.X**. Chose the install location to suit your needs, as shown in the images below. If you have multiple versions of Unreal installed then **make sure the version you are using is set to `current`** by clicking down arrow next to the Launch button for the version. ![Unreal Engine Tab UI Screenshot](images/ue_install.png) ![Unreal Engine Install Location UI Screenshot](images/ue_install_location.png) ## Build Cosys-AirSim -* Install Visual Studio 2022. Make sure to select Desktop Development with C++ and Windows 10/11 SDK **10.0.X (choose latest)** and select the latest .NET Framework SDK under the 'Individual Components' tab while installing VS 2022. More info [here](https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine?application_version=5.4). -* Start `Developer Command Prompt for VS 2022`. +* Install Visual Studio 2026. Make sure to select Desktop Development with C++ and Windows 10/11 SDK **10.0.X (choose latest)** and select the latest .NET Framework SDK under the 'Individual Components' tab while installing VS 2026. More info [here](https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine?application_version=5.8). +* Start `Developer Command Prompt for VS 2026`. * Clone the repo: `git clone https://github.com/Cosys-Lab/Cosys-AirSim.git`, and go the AirSim directory by `cd Cosys-AirSim`. * Run `build.cmd` from the command line. This will create ready to use plugin bits in the `Unreal\Plugins` folder that can be dropped into any Unreal project. @@ -19,13 +19,12 @@ Finally, you will need an Unreal project that hosts the environment for your veh ## Setup Remote Control (Multirotor only) -A remote control is required if you want to fly manually. See the [remote control setup](remote_control.md) for more details. - +A remote control is required if you want to fly the drone manually. See the [remote control setup](remote_control.md) for more details. Alternatively, you can use [APIs](apis.md) for programmatic control or use the so-called [Computer Vision mode](image_apis.md) to move around using the keyboard. ## How to Use Cosys-AirSim -Once Cosys-AirSim is set up by following above steps, you can, +Once Cosys-AirSim is set up by following above steps, for launching and building it through Visual Studio you can, 1. Navigate to folder `Unreal\Environments\Blocks` and run `update_from_git.bat`. 2. Double click on .sln file to load the Blocks project in `Unreal\Environments\Blocks` (or .sln file in your own [custom](unreal_custenv.md) Unreal project). If you don't see .sln file then you probably haven't completed steps in Build Unreal Project section above. 3. Select your Unreal project as Start Up project (for example, Blocks project) and make sure Build config is set to "Develop Editor" and x64. @@ -34,8 +33,11 @@ Once Cosys-AirSim is set up by following above steps, you can, !!! tip Go to 'Edit->Editor Preferences', in the 'Search' box type 'CPU' and ensure that the 'Use Less CPU when in Background' is unchecked. +You can install the Cosys-AirSim Python client from pip with `pip install cosysairsim`. See [Using APIs](apis.md) and [settings.json](settings.md) for various options available. +Alternatively you can also simply open the Unreal Engine project by double clicking the _Blocks.uproject_ file. + # FAQ @@ -52,7 +54,6 @@ Open or create a file called `BuildConfiguration.xml` in _C:\Users\USERNAME\AppD ``` - #### I get `error C100 : An internal error has occurred in the compiler` when running build.cmd We have noticed this happening with VS version `15.9.0` and have checked-in a workaround in Cosys-AirSim code. If you have this VS version, please make sure to pull the latest Cosys-AirSim code. diff --git a/docs/matlab.md b/docs/matlab.md index 9e8761ba5..7c3bf29d0 100644 --- a/docs/matlab.md +++ b/docs/matlab.md @@ -6,8 +6,8 @@ This can be used from source or installed as a toolbox (install from [File Excha ## Prerequisites These instructions are for Matlab 2024a (with toolboxes for the client: Computer Vision, Aerospace, Signal Processing Toolbox) UE 5.X and latest Cosys-AirSim release. -It also requires the AirSim python package to be installed. -For this go into the _PythonClient_ folder and use pip to install it to your python environment that is also used in Matlab with `pip install .` +It also requires the cosysairsim python package to be installed. You can install the Cosys-AirSim Python client from pip with `pip install cosysairsim`. +You can also install the AirSim python module to your Python environment by running `pip install .` in the _PythonClient_ folder. You can find out in Matlab what Python version is used with ```matlab pe = pyenv; @@ -89,7 +89,7 @@ objectPoseWorld = airSimClient.getObjectPose(chosenObject, false); figure; subplot(1, 2, 1); -plotTransforms([vehiclePoseLocal.position; objectPoseLocal.position], [vehiclePoseLocal.orientation; objectPoseLocal.orientation], FrameLabel=["Vehicle"; finalName], AxisLabels="on") +plotTransforms([vehiclePoseLocal.position; objectPoseLocal.position], [vehiclePoseLocal.orientation; objectPoseLocal.orientation], FrameLabel=["Vehicle"; chosenObject], AxisLabels="on") axis equal; grid on; xlabel("X (m)") @@ -98,7 +98,7 @@ zlabel("Z (m)") title("Local Plot") subplot(1, 2, 2); -plotTransforms([vehiclePoseWorld.position; objectPoseWorld.position], [vehiclePoseWorld.orientation; objectPoseWorld.orientation], FrameLabel=["Vehicle"; finalName], AxisLabels="on") +plotTransforms([vehiclePoseWorld.position; objectPoseWorld.position], [vehiclePoseWorld.orientation; objectPoseWorld.orientation], FrameLabel=["Vehicle"; chosenObject], AxisLabels="on") axis equal; grid on; @@ -236,20 +236,16 @@ cameraSensorName = "front_center"; [rgbImage, rgbCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Scene, vehicle_name); [segmentationImage, segmentationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Segmentation,vehicle_name); [depthImage, depthCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.DepthPlanar,vehicle_name); -[annotationImage, annotationCameraIimestamp] = airSimClient.getCameraImage(cameraSensorName, AirSimCameraTypes.Annotation, vehicle_name, "TextureTestDirect"); figure; -subplot(4, 1, 1); +subplot(3, 1, 1); imshow(rgbImage) title("RGB Camera Image") -subplot(4, 1, 2); +subplot(3, 1, 2); imshow(segmentationImage) title("Segmentation Camera Image") -subplot(4, 1, 3); +subplot(3, 1, 3); imshow(depthImage ./ max(max(depthImage)).* 255, gray) title("Depth Camera Image") -subplot(4, 1, 4); -imshow(annotationImage) -title("Annotation Camera Image") drawnow ``` @@ -261,21 +257,18 @@ drawnow cameraSensorName = "front_center"; [images, cameraIimestamp] = airSimClient.getCameraImages(cameraSensorName, ... - [AirSimCameraTypes.Scene, AirSimCameraTypes.Segmentation, AirSimCameraTypes.DepthPlanar, AirSimCameraTypes.Annotation], ... - vehicle_name, ["", "", "", "TextureTestDirect"]); + [AirSimCameraTypes.Scene, AirSimCameraTypes.Segmentation, AirSimCameraTypes.DepthPlanar], ... + vehicle_name, ["", "", ""]); figure; -subplot(4, 1, 1); +subplot(3, 1, 1); imshow(images{1}) title("Synced RGB Camera Image") -subplot(4, 1, 2); +subplot(3, 1, 2); imshow(images{2}) title("Synced Segmentation Camera Image") -subplot(4, 1, 3); +subplot(3, 1, 3); imshow(images{3} ./ max(max(images{3})).* 255, gray) title("Synced Depth Camera Image") -subplot(4, 1, 4); -imshow(images{4}) -title("Synced Annotation Camera Image") drawnow ``` diff --git a/docs/packaging.md b/docs/packaging.md index 101faa894..77ec50edc 100644 --- a/docs/packaging.md +++ b/docs/packaging.md @@ -9,7 +9,7 @@ packaging an entire project including the plugin. First you need to build the library. On Windows: -* Install Visual Studio 2022. Make sure to select Desktop Development with C++ and Windows 10/11 SDK **10.0.X (choose latest)** and select the latest .NET Framework SDK under the 'Individual Components' tab while installing VS 2022. More info [here](https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine?application_version=5.4). +* Install Visual Studio 2022. Make sure to select Desktop Development with C++ and Windows 10/11 SDK **10.0.X (choose latest)** and select the latest .NET Framework SDK under the 'Individual Components' tab while installing VS 2022. More info [here](https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-visual-studio-development-environment-for-cplusplus-projects-in-unreal-engine?application_version=5.8). * Start `Developer Command Prompt for VS 2022`. * Clone the repo: `git clone https://github.com/Cosys-Lab/Cosys-AirSim.git`, and go the AirSim directory by `cd Cosys-AirSim`. * Run `build.cmd` from the command line. This will create ready to use plugin bits in the `Unreal\Plugins` folder. @@ -57,11 +57,7 @@ On Windows: On Linux: * Open the Blocks project in Unreal Engine `cd Cosys-AirSim/Unreal/Environments/Blocks` and pull the latest plugin files by running `update_from_git.sh`. -<<<<<<< HEAD * Go to your Unreal Engine installation folder, move to the subfolder `/Engine/Build/BatchFile`, and run the build script while pointing at the Blocks project: `./RunUAT.sh BuildCookRun -nop4 -utf8output -cook -project="..../Cosys-AirSim/Unreal/Environments/Blocks/Blocks.uproject" -target=Blocks -platform=Linux -installed -stage -archive -package -build -pak -iostore -compressed -prereqs -archivedirectory="..../blockslinux/" -clientconfig=Development -nocompile -nocompileuat` -======= -* Go to your Unreal Engine installation folder and run the build script while pointing at the Blocks project: `./RunUAT.sh BuildCookRun -nop4 -utf8output -cook -project="..../Cosys-AirSim/Unreal/Environments/Blocks/Blocks.uproject" -target=Blocks -platform=Linux -installed -stage -archive -package -build -pak -iostore -compressed -prereqs -archivedirectory="..../blockslinux/" -clientconfig=Development -nocompile -nocompileuat` ->>>>>>> 74d6b95347a4b6b1d3dc2d7823dd1cbbc2160fdd diff --git a/docs/px4_multi_vehicle.md b/docs/px4_multi_vehicle.md index 797e0ac4e..c8e4666eb 100644 --- a/docs/px4_multi_vehicle.md +++ b/docs/px4_multi_vehicle.md @@ -52,7 +52,7 @@ However, the provided script does not let us view the PX4 console. If you want t You can add more than two vehicles but you will need to make sure you adjust the TCP port for each (ie: vehicle 3's port would be `4562` and so on..) and adjust the spawn point. 4. Now run your Unreal Cosys-AirSim environment and it should connect to SITL PX4 via TCP. -If you are running the instances with the [PX4 console visible](px4_multi_vehicle.md#Starting-sitl-instances-with-px4-console), you should see a bunch of messages from each SITL PX4 window. +If you are running the instances with the [PX4 console visible](px4_multi_vehicle.md#starting-sitl-instances-with-px4-console), you should see a bunch of messages from each SITL PX4 window. Specifically, the following messages tell you that Cosys-AirSim is connected properly and GPS fusion is stable: ``` INFO [simulator] Simulator connected on UDP port 14560 @@ -66,7 +66,7 @@ Specifically, the following messages tell you that Cosys-AirSim is connected pro 5. You should also be able to use QGroundControl with SITL mode. Make sure there is no Pixhawk hardware plugged in, otherwise QGroundControl will choose to use that instead. Note that as we don't have a physical board, an RC cannot be connected directly to it. So the alternatives are either use XBox 360 Controller or connect your RC using USB (for example, in case of FrSky Taranis X9D Plus) or using trainer USB cable to your PC. This makes your RC look like a joystick. You will need to do extra set up in QGroundControl to use virtual joystick for RC control. You do not need to do this unless you plan to fly a drone manually in Cosys-AirSim. Autonomous flight using the Python -API does not require RC, see [`No Remote Control`](px4_sitl.md#No-Remote-Control). +API does not require RC, see [`No Remote Control`](px4_sitl.md#no-remote-control). ## Starting SITL instances with PX4 console diff --git a/docs/ros_cplusplus.md b/docs/ros2.md similarity index 99% rename from docs/ros_cplusplus.md rename to docs/ros2.md index 33309f816..d047f721d 100644 --- a/docs/ros_cplusplus.md +++ b/docs/ros2.md @@ -1,7 +1,7 @@ -# airsim_ros_pkgs +# ROS2 Node A ROS2 wrapper over the Cosys-AirSim C++ client library. All coordinates and data are in the right-handed coordinate frame of the ROS standard and not in NED except for geo points. -The following was tested on Ubuntu 22.04 with ROS2 Iron. +The following was tested with ROS2 Jazzy. ## Build diff --git a/docs/ros_python.md b/docs/ros_python.md index f9eeb2c30..c0780f273 100644 --- a/docs/ros_python.md +++ b/docs/ros_python.md @@ -1,4 +1,4 @@ -# How to use AirSim with Robot Operating System (ROS) +# ROS1 Python Node AirSim and ROS can be integrated using Python. Some example ROS node are provided demonstrating how to publish data from AirSim as ROS topics. diff --git a/docs/run_packaged.md b/docs/run_packaged.md index 49bfb748c..9fd93c492 100644 --- a/docs/run_packaged.md +++ b/docs/run_packaged.md @@ -1,7 +1,7 @@ -# Download and run Packaged Binary +# Download and run Packaged Demo -If you wish to test the Cosys-AirSim plugin a simple environment without having to install Unreal Engine, you can download the prepackaged binary for the Blocks test environment from the [releases page](https://github.com/Cosys-Lab/Cosys-AirSim/releases) and run it as a binary executable on Windows (_Blocks.exe_) or start it with a shell script (_./Blocks.sh_) on Linux systems. -They support multiple launch arguments. More info can be found [here](https://dev.epicgames.com/documentation/en-us/unreal-engine/command-line-arguments-in-unreal-engine?application_version=5.5). +If you wish to test Cosys-AirSim in a simple environment without having to install Unreal Engine, you can download the prepackaged binary demo for the Blocks test environment from the [releases page](https://github.com/Cosys-Lab/Cosys-AirSim/releases) and run it as a binary executable on Windows (_Blocks.exe_) or start it with a shell script (_./Blocks.sh_) on Linux systems. +They support multiple launch arguments. More info can be found [here](https://dev.epicgames.com/documentation/en-us/unreal-engine/command-line-arguments-in-unreal-engine?application_version=5.8). The releases page also comes with additional downloads and links to the several API implementations for ROS(2) and the Python and Matlab API clients for that specific version of the Cosys-AirSim plugin. diff --git a/docs/settings.md b/docs/settings.md index 11e762b80..cbcb502c6 100644 --- a/docs/settings.md +++ b/docs/settings.md @@ -1,653 +1,653 @@ -# Cosys-AirSim Settings - -A good basic settings file that works with many of the examples can be found here as [settings_example.json](settings_example.json). -It shows many of the custom sensors and vehicles that were added by Cosys-Lab. - -## Where are Settings Stored? -Cosys-AirSim is searching for the settings definition in the following order. The first match will be used: - -1. Looking at the (absolute) path specified by the `-settings` command line argument. -For example, in Windows: `AirSim.exe -settings="C:\path\to\settings.json"` -In Linux `./Blocks.sh -settings="/home/$USER/path/to/settings.json"` - -2. Looking for a json document passed as a command line argument by the `-settings` argument. -For example, in Windows: `AirSim.exe -settings={"foo":"bar"}` -In Linux `./Blocks.sh -settings={"foo":"bar"}` - -3. Looking in the folder of the executable for a file called `settings.json`. -This will be a deep location where the actual executable of the Editor or binary is stored. -For e.g. with the Blocks binary, the location searched is `/LinuxNoEditor/Blocks/Binaries/Linux/settings.json`. - -4. Searching for `settings.json` in the folder from where the executable is launched - - This is a top-level directory containing the launch script or executable. For e.g. Linux: `/LinuxNoEditor/settings.json`, Windows: `/WindowsNoEditor/settings.json` - - Note that this path changes depending on where its invoked from. On Linux, if executing the `Blocks.sh` script from inside LinuxNoEditor folder like `./Blocks.sh`, then the previous mentioned path is used. However, if launched from outside LinuxNoEditor folder such as `./LinuxNoEditor/Blocks.sh`, then `/settings.json` will be used. - -5. Looking in the AirSim subfolder for a file called `settings.json`. The AirSim subfolder is located at `Documents\AirSim` on Windows and `~/Documents/AirSim` on Linux systems. - -The file is in usual [json format](https://en.wikipedia.org/wiki/JSON). On first startup Cosys-AirSim would create `settings.json` file with no settings at the users home folder. To avoid problems, always use ASCII format to save json file. - -## How to Chose Between Car/SkidVehicle/Multirotor? -The default is to use multirotor. To use car simple set `"SimMode": "Car"` like this: - -``` -{ - "SettingsVersion": 2.0, - "SimMode": "Car" -} -``` - -To choose multirotor or skid vehicle, set `"SimMode": "Multirotor"` or `"SimMode": "SkidVehicle"` respectively. If you want to prompt user to select vehicle type then use `"SimMode": ""`. - -## Available Settings and Their Defaults -Below are complete list of settings available along with their default values. If any of the settings is missing from json file, then default value is used. Some default values are simply specified as `""` which means actual value may be chosen based on the vehicle you are using. For example, `ViewMode` setting has default value `""` which translates to `"FlyWithMe"` for drones and `"SpringArmChase"` for cars. -Note this does not include most sensor types. - -**WARNING:** Do not copy paste all of below in your settings.json. We strongly recommend adding only those settings that you don't want default values. Only required element is `"SettingsVersion"`. - -```json -{ - "SimMode": "", - "ClockType": "", - "ClockSpeed": 1, - "LocalHostIp": "127.0.0.1", - "ApiServerPort": 41451, - "RecordUIVisible": true, - "MoveWorldOrigin": false, - "InitialInstanceSegmentation": true, - "LogMessagesVisible": true, - "ShowLosDebugLines": false, - "ViewMode": "", - "RpcEnabled": true, - "EngineSound": true, - "PhysicsEngineName": "", - "SpeedUnitFactor": 1.0, - "SpeedUnitLabel": "m/s", - "Wind": { "X": 0, "Y": 0, "Z": 0 }, - "CameraDirector": { - "FollowDistance": -3, - "X": NaN, "Y": NaN, "Z": NaN, - "Pitch": NaN, "Roll": NaN, "Yaw": NaN - }, - "Recording": { - "RecordOnMove": false, - "RecordInterval": 0.05, - "Folder": "", - "Enabled": false, - "Cameras": [ - { "CameraName": "0", "ImageType": 0, "PixelsAsFloat": false, "VehicleName": "", "Compress": true } - ] - }, - "CameraDefaults": { - "CaptureSettings": [ - { - "ImageType": 0, - "Width": 256, - "Height": 144, - "FOV_Degrees": 90, - "AutoExposureSpeed": 100, - "AutoExposureBias": 0, - "AutoExposureMaxBrightness": 0.64, - "AutoExposureMinBrightness": 0.03, - "MotionBlurAmount": 0, - "TargetGamma": 1.0, - "ProjectionMode": "", - "OrthoWidth": 5.12, - "MotionBlurAmount": 1, - "MotionBlurMax": 10, - "ChromaticAberrationScale": 2, - "IgnoreMarked": false, - "LumenGIEnable": true, - "LumenReflectionEnable": true, - "LumenFinalQuality": 1, - "LumenSceneDetail": 1, - "LumenSceneLightningDetail": 1 - } - ], - "NoiseSettings": [ - { - "Enabled": false, - "ImageType": 0, - - "RandContrib": 0.2, - "RandSpeed": 100000.0, - "RandSize": 500.0, - "RandDensity": 2, - - "HorzWaveContrib":0.03, - "HorzWaveStrength": 0.08, - "HorzWaveVertSize": 1.0, - "HorzWaveScreenSize": 1.0, - - "HorzNoiseLinesContrib": 1.0, - "HorzNoiseLinesDensityY": 0.01, - "HorzNoiseLinesDensityXY": 0.5, - - "HorzDistortionContrib": 1.0, - "HorzDistortionStrength": 0.002, - - "LensDistortionEnable": true, - "LensDistortionAreaFalloff": 2, - "LensDistortionAreaRadius": 1, - "LensDistortionInvert": false - } - ], - "Gimbal": { - "Stabilization": 0, - "Pitch": NaN, "Roll": NaN, "Yaw": NaN - }, - "X": NaN, "Y": NaN, "Z": NaN, - "Pitch": NaN, "Roll": NaN, "Yaw": NaN, - "UnrealEngine": { - "PixelFormatOverride": [ - { - "ImageType": 0, - "PixelFormat": 0 - } - ] - } - }, - "OriginGeopoint": { - "Latitude": 47.641468, - "Longitude": -122.140165, - "Altitude": 122 - }, - "TimeOfDay": { - "Enabled": false, - "StartDateTime": "", - "CelestialClockSpeed": 1, - "StartDateTimeDst": false, - "UpdateIntervalSecs": 60 - }, - "SubWindows": [ - {"WindowID": 0, "CameraName": "0", "ImageType": 3, "VehicleName": "", "Visible": false}, - {"WindowID": 1, "CameraName": "0", "ImageType": 5, "VehicleName": "", "Visible": false}, - {"WindowID": 2, "CameraName": "0", "ImageType": 0, "VehicleName": "", "Visible": false} - ], - "PawnPaths": { - "BareboneCar": {"PawnBP": "Class'/AirSim/VehicleAdv/Vehicle/VehicleAdvPawn.VehicleAdvPawn_C'"}, - "DefaultCar": {"PawnBP": "Class'/AirSim/VehicleAdv/SUV/SuvCarPawn.SuvCarPawn_C'"}, - "DefaultQuadrotor": {"PawnBP": "Class'/AirSim/Blueprints/BP_FlyingPawn.BP_FlyingPawn_C'"}, - "DefaultComputerVision": {"PawnBP": "Class'/AirSim/Blueprints/BP_ComputerVisionPawn.BP_ComputerVisionPawn_C'"} - }, - "Vehicles": { - "SimpleFlight": { - "VehicleType": "SimpleFlight", - "DefaultVehicleState": "Armed", - "AutoCreate": true, - "PawnPath": "", - "EnableCollisionPassthrough": false, - "EnableCollisions": true, - "AllowAPIAlways": true, - "EnableTrace": false, - "RC": { - "RemoteControlID": 0, - "AllowAPIWhenDisconnected": false - }, - "Cameras": { - //same elements as CameraDefaults above, key as name - }, - "X": NaN, "Y": NaN, "Z": NaN, - "Pitch": NaN, "Roll": NaN, "Yaw": NaN - }, - "PhysXCar": { - "VehicleType": "PhysXCar", - "DefaultVehicleState": "", - "AutoCreate": true, - "PawnPath": "", - "EnableCollisionPassthrough": false, - "EnableCollisions": true, - "RC": { - "RemoteControlID": -1 - }, - "Cameras": { - "MyCamera1": { - //same elements as elements inside CameraDefaults above - }, - "MyCamera2": { - //same elements as elements inside CameraDefaults above - }, - }, - "X": NaN, "Y": NaN, "Z": NaN, - "Pitch": NaN, "Roll": NaN, "Yaw": NaN - } - } -} -``` - -## SimMode -SimMode determines which simulation mode will be used. Below are currently supported values: -- `""`: prompt user to select vehicle type multirotor or car -- `"Multirotor"`: Use multirotor simulation -- `"Car"`: Use car simulation -- `"ComputerVision"`: Use only camera, no vehicle or physics -- `"SkidVehicle"`: use [skid-steering vehicle](skid_steer_vehicle.md) simulation - -## ViewMode -The ViewMode determines which camera to use as default and how camera will follow the vehicle. For multirotors, the default ViewMode is `"FlyWithMe"` while for cars the default ViewMode is `"SpringArmChase"`. - -* `FlyWithMe`: Chase the vehicle from behind with 6 degrees of freedom -* `GroundObserver`: Chase the vehicle from 6' above the ground but with full freedom in XY plane. -* `Fpv`: View the scene from front camera of vehicle -* `Manual`: Don't move camera automatically. Use arrow keys and ASWD keys for move camera manually. -* `SpringArmChase`: Chase the vehicle with camera mounted on (invisible) arm that is attached to the vehicle via spring (so it has some latency in movement). -* `NoDisplay`: This will freeze rendering for main screen however rendering for subwindows, recording and APIs remain active. This mode is useful to save resources in "headless" mode where you are only interested in getting images and don't care about what gets rendered on main screen. This may also improve FPS for recording images. - -## Annotation -The annotation system allows you to choose different groundtruth labeling techniques to create more data from your simulation. Find more info [here](annotation.md) for defining the settings. - -## TimeOfDay -This setting controls the position of Sun in the environment. By default `Enabled` is false which means Sun's position is left at whatever was the default in the environment and it doesn't change over the time. If `Enabled` is true then Sun position is computed using longitude, latitude and altitude specified in `OriginGeopoint` section for the date specified in `StartDateTime` in the string format as [%Y-%m-%d %H:%M:%S](https://en.cppreference.com/w/cpp/io/manip/get_time), for example, `2018-02-12 15:20:00`. If this string is empty then current date and time is used. If `StartDateTimeDst` is true then we adjust for day light savings time. The Sun's position is then continuously updated at the interval specified in `UpdateIntervalSecs`. In some cases, it might be desirable to have celestial clock run faster or slower than simulation clock. This can be specified using `CelestialClockSpeed`, for example, value 100 means for every 1 second of simulation clock, Sun's position is advanced by 100 seconds so Sun will move in sky much faster. - -Also see [Time of Day API](apis.md#time-of-day-api). - -## OriginGeopoint -This setting specifies the latitude, longitude and altitude of the Player Start component placed in the Unreal environment. The vehicle's home point is computed using this transformation. Note that all coordinates exposed via APIs are using NED system in SI units which means each vehicle starts at (0, 0, 0) in NED system. Time of Day settings are computed for geographical coordinates specified in `OriginGeopoint`. - -## SubWindows -This setting determines what is shown in each of 3 subwindows which are visible when you press 1,2,3 keys. - -* `WindowID`: Can be 0 to 2 -* `CameraName`: is any [available camera](image_apis.md#available-cameras) on the vehicle -* `ImageType`: integer value determines what kind of image gets shown according to [ImageType enum](image_apis.md#available-imagetype-values). -* `VehicleName`: string allows you to specify the vehicle to use the camera from, used when multiple vehicles are specified in the settings. First vehicle's camera will be used if there are any mistakes such as incorrect vehicle name, or only a single vehicle. -* `Annotation`: string allows you to specify the annotation layer to use for the camera. This is only if using the Annotation camera type for `ImageType` (value is 10). - -For example, for a single car vehicle, below shows driver view, front bumper view and rear view as scene, depth and surface normals respectively. -```json - "SubWindows": [ - {"WindowID": 0, "ImageType": 0, "CameraName": "3", "Visible": true}, - {"WindowID": 1, "ImageType": 3, "CameraName": "0", "Visible": true}, - {"WindowID": 2, "ImageType": 6, "CameraName": "4", "Visible": true} - ] -``` - -In case of multiple vehicles, different vehicles can be specified as follows- - -```json - "SubWindows": [ - {"WindowID": 0, "CameraName": "0", "ImageType": 3, "VehicleName": "Car1", "Visible": false}, - {"WindowID": 1, "CameraName": "0", "ImageType": 5, "VehicleName": "Car2", "Visible": false}, - {"WindowID": 2, "CameraName": "0", "ImageType": 0, "VehicleName": "Car1", "Visible": false} - ] -``` - -## Recording -The recording feature allows you to record data such as position, orientation, velocity along with the captured image at specified intervals. You can start recording by pressing red Record button on lower right or the R key. The data is stored in the `Documents\AirSim` folder (or the folder specified using `Folder`), in a time stamped subfolder for each recording session, as tab separated file. - -* `RecordInterval`: specifies minimal interval in seconds between capturing two images. -* `RecordOnMove`: specifies that do not record frame if there was vehicle's position or orientation hasn't changed. -* `Folder`: Parent folder where timestamped subfolder with recordings are created. Absolute path of the directory must be specified. If not used, then `Documents/AirSim` folder will be used. E.g. `"Folder": "/home//Documents"` -* `Enabled`: Whether Recording should start from the beginning itself, setting to `true` will start recording automatically when the simulation starts. By default, it's set to `false` -* `Cameras`: this element controls which cameras are used to capture images. By default scene image from camera 0 is recorded as compressed png format. This setting is json array so you can specify multiple cameras to capture images, each with potentially different [image types](settings.md#image-capture-settings). - * When `PixelsAsFloat` is true, image is saved as [pfm](pfm.md) file instead of png file. - * `VehicleName` option allows you to specify separate cameras for individual vehicles. If the `Cameras` element isn't present, `Scene` image from the default camera of each vehicle will be recorded. - * If you don't want to record any images and just the vehicle's physics data, then specify the `Cameras` element but leave it empty, like this: `"Cameras": []` - * add the field `Annotation`, a string allowing you to specify the annotation layer to use for the camera. This is only if using the Annotation camera type for `ImageType`. -For example, the `Cameras` element below records scene & segmentation images for `Car1` & scene for `Car2`- - -```json -"Cameras": [ - { "CameraName": "0", "ImageType": 0, "PixelsAsFloat": false, "VehicleName": "Car1", "Compress": true }, - { "CameraName": "0", "ImageType": 5, "PixelsAsFloat": false, "VehicleName": "Car1", "Compress": true }, - { "CameraName": "0", "ImageType": 0, "PixelsAsFloat": false, "VehicleName": "Car2", "Compress": true } -] -``` - -Check out [Modifying Recording Data](modify_recording_data.md) for details on how to modify the kinematics data being recorded. - -## ClockSpeed -This setting allows you to set the speed of simulation clock with respect to wall clock. For example, value of 5.0 would mean simulation clock has 5 seconds elapsed when wall clock has 1 second elapsed (i.e. simulation is running faster). The value of 0.1 means that simulation clock is 10X slower than wall clock. The value of 1 means simulation is running in real time. It is important to realize that quality of simulation may decrease as the simulation clock runs faster. You might see artifacts like object moving past obstacles because collision is not detected. However slowing down simulation clock (i.e. values < 1.0) generally improves the quality of simulation. - -## Wind Settings - -This setting specifies the wind speed in World frame, in NED direction. Values are in m/s. By default, speed is 0, i.e. no wind. - -## Camera Director Settings - -This element specifies the settings used for the camera following the vehicle in the ViewPort. - -* `FollowDistance`: Distance at which camera follows the vehicle, default is -8 (8 meters) for Car, -3 for others. -* `X, Y, Z, Yaw, Roll, Pitch`: These elements allows you to specify the position and orientation of the camera relative to the vehicle. Position is in NED coordinates in SI units with origin set to Player Start location in Unreal environment. The orientation is specified in degrees. - -The `CameraDefaults` element at root level specifies defaults used for all cameras. These defaults can be overridden for individual camera in `Cameras` element inside `Vehicles` as described later. - -### Main settings -Like other sensors the pose of the sensor in the vehicle frame can be defined by X, Y, Z, Roll, Pitch, Yaw parameters. -Furthermore there are some other settings available: -* `DrawSensor`: Draw the physical sensor in the world on the vehicle with a 3D axes shown where the sensor is. -* `External`: Uncouple the sensor from the vehicle. If enabled, the position and orientation will be relative to Unreal world coordinates. Note that if `MoveWorldOrigin` in the settings.json is set to `true` the Unreal coordinates will be moved to be the same origin as the player start location and as such this may effect where the sensor will spawn. -* `ExternalLocal`: When in external mode, if this is enabled the retrieved pose of the sensor will be in Local NED coordinates(from starting position from vehicle) and not converted Unreal NED coordinates which is default. Note that if `MoveWorldOrigin` in the settings.json is set to `true` the Unreal coordinates will be moved to be the same origin as the player start location and as such this may effect what coordinates are returned if set to `false`. - -### Note on ImageType element -The `ImageType` element in JSON array determines which image type that settings applies to. The valid values are described in [ImageType section](image_apis.md#available-imagetype). - -For example, `CaptureSettings` element is json array so you can add settings for multiple image types easily. - -### CaptureSettings -The `CaptureSettings` in the settings.json file for either the `CameraDefaults` or specific camera settings determines how different image types such as scene, depth, disparity, surface normals and segmentation views are rendered. -The Width, Height and FOV settings should be self-explanatory. The `ProjectionMode` decides the projection used by the capture camera and can take value "perspective" (default) or "orthographic". If projection mode is "orthographic" then `OrthoWidth` determines width of projected area captured in meters. - -To disable the rendering of certain objects on specific cameras or all, use the `IgnoreMarked` boolean setting. This requires to mark individual objects that have to be ignore using an Unreal Tag called _MarkedIgnore_. - -Unreal 5 introduces Lumen lightning. Due to the cameras using scene capture components enabling Lumen for them can be costly on performance. Settings have been added specfically for the scene camera to customize the usage of Lumen for Global Illumination and Reflections. -The `LumenGIEnable` and `LumenReflectionEnable` settings enable or disable Lumen for the camera. The `LumenFinalQuality`(0.25-2) setting determines the quality of the final image. The `LumenSceneDetail`(0.25-4) setting determines the quality of the scene. The `LumenSceneLightningDetail`(0.25-2) setting determines the quality of the lightning in the scene. - -`ForceUpdate` can be enabled to force a camera (only works for scene) to update the render target every frame. This is costly on performance but can solve issues with with exposure settings not applying for example. - -Below you can find a list of all available settings and their purpose. -They are settings that are directly transferred to the post-processing settings of cameras of which more documentation can be found [here](https://dev.epicgames.com/documentation/en-us/unreal-engine/post-process-effects-in-unreal-engine). - - -#### General -* **Width**: The width of the captured image in pixels. (Default: 256) -* **Height**: The height of the captured image in pixels. (Default: 144) -* **FOV_Degrees**: The horizontal field of view of the camera in degrees. -* **ImageType**: The type of image being captured (e.g., scene, depth, etc.). (Default: 0) -* **TargetGamma**: The gamma value applied to the captured image. -* **IgnoreMarked**: Whether to ignore objects marked for a specific purpose (e.g., segmentation). (Default: false) -* **ProjectionMode**: The camera's projection mode ("Perspective" or "Orthographic"). (Default: "Perspective") -* **OrthoWidth**: The width of the orthographic view frustum. -* **ForceUpdate**: Force a camera to update the render target every frame. Costly on performance! Only works for scene camera type. (Default: false) - -#### Lumen Global Illumination and Reflections -* **LumenGIEnable**: Whether Lumen Global Illumination is enabled. (Default: false) -* **LumenReflectionEnable**: Whether Lumen Reflections are enabled. (Default: false) -* **LumenFinalQuality**: The quality of Lumen's final gather. -* **LumenSceneDetail**: Controls the size of instances that can be represented in the Lumen Scene. -* **LumenSceneLightningDetail**: The quality of Lumen Scene lighting. - -#### Camera Settings -* **CameraShutterSpeed**: The camera's shutter speed in seconds. -* **CameraISO**: The camera's sensor sensitivity (ISO). -* **CameraAperture**: The camera's aperture value (f-stop). -* **CameraMaxAperture**: The camera's maximum aperture value (minimum f-stop). -* **CameraNumBlades**: The number of blades in the camera's aperture diaphragm. - -#### Depth of Field -* **DepthOfFieldSensorWidth**: Width of the camera sensor to assume, in millimeters. -* **DepthOfFieldSqueezeFactor**: Squeeze factor for the depth of field, emulating anamorphic lenses. -* **DepthOfFieldFocalDistance**: Distance at which the depth of field effect should be sharp, in centimeters. -* **DepthOfFieldDepthBlurAmount**: Depth blur in kilometers for 50% (CircleDOF only). -* **DepthOfFieldDepthBlurRadius**: Depth blur radius in pixels at 1920x resolution (CircleDOF only). -* **DepthOfFieldUseHairDepth**: Whether to use hair depth for computing the circle of confusion size. *Not supported on UE5.2!* - -#### Exposure -* **AutoExposureMethod**: Luminance computation method. (0: Histogram, 1: Basic, 2: Manual) -* **AutoExposureCompensation**: Logarithmic adjustment for the exposure. 0: no adjustment, -1: 2x darker, -2: 4x darker, 1: 2x brighter, 2: 4x brighter, ... -* **AutoExposureApplyPhysicalCameraExposure**: Enables physical camera exposure using Shutter Speed, ISO, and Aperture. (Only affects Manual exposure mode, default=: true) -* **AutoExposureMinBrightness**: Minimum brightness for auto exposure adaptation. -* **AutoExposureMaxBrightness**: Maximum brightness for auto exposure adaptation. -* **AutoExposureSpeedUp**: Speed of exposure adaptation upwards (in f-stops per second). -* **AutoExposureSpeedDown**: Speed of exposure adaptation downwards (in f-stops per second). -* **AutoExposureLowPercent**: The lower percentage for the luminance histogram used in auto exposure. -* **AutoExposureHighPercent**: The higher percentage for the luminance histogram used in auto exposure. -* **AutoExposureHistogramLogMin**: Minimum value for the auto exposure histogram (expressed in Log2(Luminance) or EV100). -* **AutoExposureHistogramLogMax**: Maximum value for the auto exposure histogram (expressed in Log2(Luminance) or EV100). - -#### Motion Blur -* **MotionBlurAmount**: The strength of motion blur applied to the image. 0: off. -* **MotionBlurMax**: The maximum distortion caused by motion blur, in percent of the screen width. 0: off. -* **MotionBlurTargetFPS**: Defines the target FPS for motion blur. Makes motion blur independent of actual frame rate. - -#### Bloom -* **BloomIntensity**: The intensity of the bloom effect. -* **BloomThreshold**: The minimum brightness for pixels to contribute to the bloom effect. - -#### Chromatic Aberration -* **ChromaticAberrationIntensity**: The intensity of chromatic aberration. -* **ChromaticAberrationStartOffset**: A normalized distance to the center of the framebuffer where the chromatic aberration effect takes place. - -#### Lens Flare -* **LensFlareIntensity**: Brightness scale of the image-based lens flares. -* **LensFlareBokehSize**: Size of the lens blur (Bokeh) used for lens flares, as a percentage of the view width. -* **LensFlareThreshold**: Minimum brightness for lens flares to take effect. - -### NoiseSettings -The `NoiseSettings` allows to add noise to the specified image type with a goal of simulating camera sensor noise, interference and other artifacts. By default no noise is added, i.e., `Enabled: false`. If you set `Enabled: true` then following different types of noise and interference artifacts are enabled, each can be further tuned using setting. -Demo of camera noise and interference simulation: - -[![AirSim Drone Demo Video](images/camera_noise_demo.png)](https://youtu.be/1BeCEZmQyp0) - -#### Random Noise -This adds random noise blobs with the following parameters: - -* **RandContrib** (float): Blend ratio of noise pixels with image pixels. 0 means no noise, and 1 means only noise. (Default: 0.2) -* **RandSpeed** (float): How fast the noise fluctuates. 1 means no fluctuation, and higher values like 1E6 mean full fluctuation. (Default: 100000.0) -* **RandSize** (float): How coarse the noise is. 1 means every pixel has its own noise, while higher values mean more than one pixel shares the same noise value. (Default: 500.0) -* **RandDensity** (float): How many pixels out of the total will have noise. 1 means all pixels, while higher values mean fewer pixels (exponentially). (Default: 2.0) - -#### Horizontal Bump Distortion -This adds horizontal bumps/flickering/ghosting effects: - -* **HorzWaveContrib** (float): Blend ratio of distorted pixels with original image pixels. 0 means no distortion, and 1 means only distorted pixels. (Default: 0.03) -* **HorzWaveStrength** (float): Overall strength of the distortion effect. (Default: 0.08) -* **HorzWaveVertSize** (float): How many vertical pixels are affected by the effect. (Default: 1.0) -* **HorzWaveScreenSize** (float): How much of the screen is affected by the effect. (Default: 1.0) - -#### Horizontal Noise Lines -This adds regions of noise on horizontal lines: - -* **HorzNoiseLinesContrib** (float): Blend ratio of noise pixels with image pixels on the affected lines. 0 means no noise, and 1 means only noise. (Default: 1.0) -* **HorzNoiseLinesDensityY** (float): How many pixels in a horizontal line are affected by noise. (Default: 0.01) -* **HorzNoiseLinesDensityXY** (float): How many lines on the screen are affected by noise. (Default: 0.5) - - -#### Horizontal Line Distortion -This adds fluctuations to horizontal lines: - -* **HorzDistortionContrib** (float): Blend ratio of distorted pixels with original image pixels on the affected lines. 0 means no distortion, and 1 means fully distorted. (Default: 1.0) -* **HorzDistortionStrength** (float): The magnitude of the distortion. (Default: 0.002) - - -#### Radial Lens Distortion -This adds radial lens distortion to the camera sensor. Note this only applies to the scene image type, not other types like depth or segmentation. - -* **LensDistortionEnable** (bool): Enable or disable lens distortion. (Default: false) -* **LensDistortionAreaFalloff** (float): Size of the area to distort. (Default: 1.0) -* **LensDistortionAreaRadius** (float): Radius of the distortion. (Default: 1.0) -* **LensDistortionIntensity** (float): Intensity of the lens distortion. (Default: 0.5) -* **LensDistortionInvert** (bool): Set to true to invert and create 'pincushion distortion' or false for 'barrel distortion'. (Default: false) - - -#### Blur -This can add various blur effects to the camera sensor. Note this only applies to the scene image type. - -The fake motion blur can be handy when the camera is static, and you want to simulate motion blur. The radial blur can simulate centered lenses. -The Gaussian blur can simulate out-of-focus effects. - -* **FakeMotionBlurEnable** (bool): Whether fake motion blur is enabled. (Default: false) -* **FakeMotionBlurDirectionX** (float): X-component of the motion blur direction vector. (Default: 0.0) -* **FakeMotionBlurDirectionY** (float): Y-component of the motion blur direction vector. (Default: 1.0) -* **FakeMotionBlurMovementSpeed** (float): Movement speed used for the fake motion blur effect. (Default: 1.0) -* **FakeMotionBlurShutterSpeed** (float): Simulated shutter speed for the fake motion blur. (Default: 0.0167) -* **FakeMotionBlurFocalLength** (float): Focal length used in the fake motion blur calculation. (Default: 35.0) -* **FakeMotionBlurSamples** (int): Number of samples used in the fake motion blur effect. (Default: 50) -* **RadialBlurEnable** (bool): Whether radial blur is enabled. (Default: false) -* **RadialBlurDistance** (float): Distance parameter for the radial blur. (Default: 1.0) -* **RadialBlurRadius** (float): Radius parameter for the radial blur. (Default: 1.0) -* **RadialBlurDensity** (float): Density parameter for the radial blur. (Default: 4.0) -* **GuassianBlurEnable** (bool): Whether Gaussian blur is enabled. (Default: false) -* **GuassianBlurDirections** (float): Number of directions used in the Gaussian blur. (Default: 16.0) -* **GuassianBlurQuality** (float): Quality level of the Gaussian blur. (Default: 3.0) -* **GuassianBlurSize** (float): Size of the Gaussian blur kernel. (Default: 8.0) - -### Gimbal -The `Gimbal` element allows to freeze camera orientation for pitch, roll and/or yaw. This setting is ignored unless `ImageType` is -1. The `Stabilization` is defaulted to 0 meaning no gimbal i.e. camera orientation changes with body orientation on all axis. The value of 1 means full stabilization. The value between 0 to 1 acts as a weight for fixed angles specified (in degrees, in world-frame) in `Pitch`, `Roll` and `Yaw` elements and orientation of the vehicle body. When any of the angles is omitted from json or set to NaN, that angle is not stabilized (i.e. it moves along with vehicle body). - -### UnrealEngine -This element contains settings specific to the Unreal Engine. These will be ignored in the Unity project. -* `PixelFormatOverride`: This contains a list of elements that have both a `ImageType` and `PixelFormat` setting. Each element allows you to override the default pixel format of the UTextureRenderTarget2D object instantiated for the capture specified by the `ImageType` setting. Specifying this element allows you to prevent crashes caused by unexpected pixel formats (see [#4120](https://github.com/microsoft/AirSim/issues/4120) and [#4339](https://github.com/microsoft/AirSim/issues/4339) for examples of these crashes). A full list of pixel formats can be viewed [here](https://docs.unrealengine.com/4.27/en-US/API/Runtime/Core/EPixelFormat/). - -## Vehicles Settings -Each simulation mode will go through the list of vehicles specified in this setting and create the ones that has `"AutoCreate": true`. Each vehicle specified in this setting has key which becomes the name of the vehicle. If `"Vehicles"` element is missing then this list is populated with default car named "PhysXCar" and default multirotor named "SimpleFlight". - -### Common Vehicle Setting -- `VehicleType`: This could be either `PhysXCar`, `ArduRover` or `BoxCar` for the Car SimMode, `SimpleFlight`, `ArduCopter` or `PX4Multirotor` for the MultiRotor SimMode, `ComputerVision` for the ComputerVision SimMode and `CPHusky` or `Pioneer` for SkidVehicle SimMode. you can use There is no default value therefore this element must be specified. -- `PawnPath`: This allows to override the pawn blueprint to use for the vehicle. For example, you may create new pawn blueprint derived from ACarPawn for a warehouse robot in your own project outside the Cosys-AirSim code and then specify its path here. See also [PawnPaths](settings.md#PawnPaths). Note that you have to specify your custom pawn blueprint class path inside the global `PawnPaths` object using your proprietarily defined object name, and quote that name inside the `Vehicles` setting. For example, -```json - { - ... - "PawnPaths": { - "CustomPawn": {"PawnBP": "Class'/Game/Assets/Blueprints/MyPawn.MyPawn_C'"} - }, - "Vehicles": { - "MyVehicle": { - "VehicleType": ..., - "PawnPath": "CustomPawn", - ... - } - } - } -``` -- `DefaultVehicleState`: Possible value for multirotors is `Armed` or `Disarmed`. -- `AutoCreate`: If true then this vehicle would be spawned (if supported by selected sim mode). -- `RC`: This sub-element allows to specify which remote controller to use for vehicle using `RemoteControlID`. The value of -1 means use keyboard (not supported yet for multirotors). The value >= 0 specifies one of many remote controllers connected to the system. The list of available RCs can be seen in Game Controllers panel in Windows, for example. -- `X, Y, Z, Yaw, Roll, Pitch`: These elements allows you to specify the initial position and orientation of the vehicle. Position is in NED coordinates in SI units with origin set to Player Start location in Unreal environment. The orientation is specified in degrees. -- `Sensors`: This element specifies the sensors associated with the vehicle, see [Sensors](sensors.md) page for details. -- `IsFpvVehicle`: This setting allows to specify which vehicle camera will follow and the view that will be shown when ViewMode is set to Fpv. By default, Cosys-AirSim selects the first vehicle in settings as FPV vehicle. -- `Cameras`: This element specifies camera settings for vehicle. The key in this element is name of the [available camera](image_apis.md#available_cameras) and the value is same as `CameraDefaults` as described above. For example, to change FOV for the front center camera to 120 degrees, you can use this for `Vehicles` setting: - -```json -"Vehicles": { - "FishEyeDrone": { - "VehicleType": "SimpleFlight", - "Cameras": { - "front-center": { - "CaptureSettings": [ - { - "ImageType": 0, - "FOV_Degrees": 120 - } - ] - } - } - } -} -``` - -### Using PX4 -By default we use [simple_flight](simple_flight.md) so you don't have to do separate HITL or SITL setups. We also support ["PX4"](px4_setup.md) for advanced users. To use PX4 with Cosys-AirSim, you can use the following for `Vehicles` setting: - -``` -"Vehicles": { - "PX4": { - "VehicleType": "PX4Multirotor", - } -} -``` - -#### Additional PX4 Settings - -The defaults for PX4 is to enable hardware-in-loop setup. There are various other settings available for PX4 as follows with their default values: - -``` -"Vehicles": { - "PX4": { - "VehicleType": "PX4Multirotor", - "Lockstep": true, - "ControlIp": "127.0.0.1", - "ControlPortLocal": 14540, - "ControlPortRemote": 14580, - "LogViewerHostIp": "127.0.0.1", - "LogViewerPort": 14388, - "OffboardCompID": 1, - "OffboardSysID": 134, - "QgcHostIp": "127.0.0.1", - "QgcPort": 14550, - "SerialBaudRate": 115200, - "SerialPort": "*", - "SimCompID": 42, - "SimSysID": 142, - "TcpPort": 4560, - "UdpIp": "127.0.0.1", - "UdpPort": 14560, - "UseSerial": true, - "UseTcp": false, - "VehicleCompID": 1, - "VehicleSysID": 135, - "Model": "Generic", - "LocalHostIp": "127.0.0.1", - "Logs": "d:\\temp\\mavlink", - "Sensors": { - ... - } - "Parameters": { - ... - } - } -} -``` - -These settings define the MavLink SystemId and ComponentId for the Simulator (SimSysID, SimCompID), -and for the vehicle (VehicleSysID, VehicleCompID) and the node that allows remote control of the -drone from another app this is called the offboard node (OffboardSysID, OffboardCompID). - -If you want the simulator to also forward mavlink messages to your ground control app (like -QGroundControl) you can also set the UDP address for that in case you want to run that on a -different machine (QgcHostIp, QgcPort). The default is local host so QGroundControl should "just -work" if it is running on the same machine. - -You can connect the simulator to the LogViewer app, provided in this repo, by setting the UDP -address for that (LogViewerHostIp, LogViewerPort). - -And for each flying drone added to the simulator there is a named block of additional settings. In -the above you see the default name "PX4". You can change this name from the Unreal Editor when you -add a new BP_FlyingPawn asset. You will see these properties grouped under the category "MavLink". -The MavLink node for this pawn can be remote over UDP or it can be connected to a local serial port. -If serial then set UseSerial to true, otherwise set UseSerial to false. For serial connections you -also need to set the appropriate SerialBaudRate. The default of 115200 works with Pixhawk version 2 -over USB. - -When communicating with the PX4 drone over serial port both the HIL_* messages and vehicle control -messages share the same serial port. When communicating over UDP or TCP PX4 requires two separate -channels. If UseTcp is false, then UdpIp, UdpPort are used to send HIL_* messages, otherwise the -TcpPort is used. TCP support in PX4 was added in 1.9.2 with the `lockstep` feature because the -guarantee of message delivery that TCP provides is required for the proper functioning of lockstep. -Cosys-AirSim becomes a TCP server in that case, and waits for a connection from the PX4 app. The second -channel for controlling the vehicle is defined by (ControlIp, ControlPort) and is always a UDP -channel. - -The `Sensors` section can provide customized settings for simulated sensors, see -[Sensors](sensors.md). The `Parameters` section can set PX4 parameters during initialization of the -PX4 connection. See [Setting up PX4 Software-in-Loop](px4_sitl.md) for an example. - -### Using ArduPilot - -[ArduPilot](https://ardupilot.org/) Copter & Rover vehicles are supported in latest Cosys-AirSim main branch & releases `v1.3.0` and later. For settings and how to use, please see [ArduPilot SITL with Cosys-AirSim](https://ardupilot.org/dev/docs/sitl-with-airsim.html) - -## Other Settings - -### EngineSound -To turn off the engine sound use [setting](settings.md) `"EngineSound": false`. Currently this setting applies only to car. - -### PawnPaths -This allows you to specify your own vehicle pawn blueprints, for example, you can replace the default car in AirSim with your own car. Your vehicle BP can reside in Content folder of your own Unreal project (i.e. outside of AirSim plugin folder). For example, if you have a car BP located in file `Content\MyCar\MySedanBP.uasset` in your project then you can set `"DefaultCar": {"PawnBP":"Class'/Game/MyCar/MySedanBP.MySedanBP_C'"}`. The `XYZ.XYZ_C` is a special notation required to specify class for BP `XYZ`. Please note that your BP must be derived from CarPawn class. By default this is not the case but you can re-parent the BP using the "Class Settings" button in toolbar in UE editor after you open the BP and then choosing "Car Pawn" for Parent Class settings in Class Options. It is also a good idea to disable "Auto Possess Player" and "Auto Possess AI" as well as set AI Controller Class to None in BP details. Please make sure your asset is included for cooking in packaging options if you are creating binary. - -### PhysicsEngineName -For cars, we support only PhysX for now (regardless of value in this setting). For multirotors, we support `"FastPhysicsEngine"` and `"ExternalPhysicsEngine"`. `"ExternalPhysicsEngine"` allows the drone to be controlled via setVehiclePose (), keeping the drone in place until the next call. It is especially useful for moving the AirSim drone using an external simulator or on a saved path. - -### LocalHostIp Setting -Now when connecting to remote machines you may need to pick a specific Ethernet adapter to reach those machines, for example, it might be -over Ethernet or over Wi-Fi, or some other special virtual adapter or a VPN. Your PC may have multiple networks, and those networks might not -be allowed to talk to each other, in which case the UDP messages from one network will not get through to the others. - -So the LocalHostIp allows you to configure how you are reaching those machines. The default of 127.0.0.1 is not able to reach external machines, -this default is only used when everything you are talking to is contained on a single PC. - -### ApiServerPort -This setting determines the server port that used by airsim clients, default port is 41451. -By specifying different ports, the user can run multiple environments in parallel to accelerate data collection process. - -### SpeedUnitFactor -Unit conversion factor for speed related to `m/s`, default is 1. Used in conjunction with SpeedUnitLabel. This may be only used for display purposes for example on-display speed when car is being driven. For example, to get speed in `miles/hr` use factor 2.23694. - -### SpeedUnitLabel -Unit label for speed, default is `m/s`. Used in conjunction with SpeedUnitFactor. - -### PassiveEchoBeacons -For the [Echo Sensor](echo.md) one can define through the settings file passive sources directly. For more information see [here](echo.md#passive-echo-beacons). - -### WorldLights -For the [Artificial Lights](lights.md) system, one can define static world lights through the settings file directly. For more information see [here](lights.md). +# Cosys-AirSim Settings + +A good basic settings file that works with many of the examples can be found here as [settings_example.json](settings_example.json). +It shows many of the custom sensors and vehicles that were added by Cosys-Lab. + +## Where are Settings Stored? +Cosys-AirSim is searching for the settings definition in the following order. The first match will be used: + +1. Looking at the (absolute) path specified by the `-settings` command line argument. +For example, in Windows: `AirSim.exe -settings="C:\path\to\settings.json"` +In Linux `./Blocks.sh -settings="/home/$USER/path/to/settings.json"` + +2. Looking for a json document passed as a command line argument by the `-settings` argument. +For example, in Windows: `AirSim.exe -settings={"foo":"bar"}` +In Linux `./Blocks.sh -settings={"foo":"bar"}` + +3. Looking in the folder of the executable for a file called `settings.json`. +This will be a deep location where the actual executable of the Editor or binary is stored. +For e.g. with the Blocks binary, the location searched is `/LinuxNoEditor/Blocks/Binaries/Linux/settings.json`. + +4. Searching for `settings.json` in the folder from where the executable is launched + + This is a top-level directory containing the launch script or executable. For e.g. Linux: `/LinuxNoEditor/settings.json`, Windows: `/WindowsNoEditor/settings.json` + + Note that this path changes depending on where its invoked from. On Linux, if executing the `Blocks.sh` script from inside LinuxNoEditor folder like `./Blocks.sh`, then the previous mentioned path is used. However, if launched from outside LinuxNoEditor folder such as `./LinuxNoEditor/Blocks.sh`, then `/settings.json` will be used. + +5. Looking in the AirSim subfolder for a file called `settings.json`. The AirSim subfolder is located at `Documents\AirSim` on Windows and `~/Documents/AirSim` on Linux systems. + +The file is in usual [json format](https://en.wikipedia.org/wiki/JSON). On first startup Cosys-AirSim would create `settings.json` file with no settings at the users home folder. To avoid problems, always use ASCII format to save json file. + +## How to Chose Between Car/SkidVehicle/Multirotor? +The default is to use multirotor. To use car simple set `"SimMode": "Car"` like this: + +``` +{ + "SettingsVersion": 2.0, + "SimMode": "Car" +} +``` + +To choose multirotor or skid vehicle, set `"SimMode": "Multirotor"` or `"SimMode": "SkidVehicle"` respectively. If you want to prompt user to select vehicle type then use `"SimMode": ""`. + +## Available Settings and Their Defaults +Below are complete list of settings available along with their default values. If any of the settings is missing from json file, then default value is used. Some default values are simply specified as `""` which means actual value may be chosen based on the vehicle you are using. For example, `ViewMode` setting has default value `""` which translates to `"FlyWithMe"` for drones and `"SpringArmChase"` for cars. +Note this does not include most sensor types. + +**WARNING:** Do not copy paste all of below in your settings.json. We strongly recommend adding only those settings that you don't want default values. Only required element is `"SettingsVersion"`. + +```json +{ + "SimMode": "", + "ClockType": "", + "ClockSpeed": 1, + "LocalHostIp": "127.0.0.1", + "ApiServerPort": 41451, + "RecordUIVisible": true, + "MoveWorldOrigin": false, + "InitialInstanceSegmentation": true, + "LogMessagesVisible": true, + "ShowLosDebugLines": false, + "ViewMode": "", + "RpcEnabled": true, + "EngineSound": true, + "PhysicsEngineName": "", + "SpeedUnitFactor": 1.0, + "SpeedUnitLabel": "m/s", + "Wind": { "X": 0, "Y": 0, "Z": 0 }, + "CameraDirector": { + "FollowDistance": -3, + "X": NaN, "Y": NaN, "Z": NaN, + "Pitch": NaN, "Roll": NaN, "Yaw": NaN + }, + "Recording": { + "RecordOnMove": false, + "RecordInterval": 0.05, + "Folder": "", + "Enabled": false, + "Cameras": [ + { "CameraName": "0", "ImageType": 0, "PixelsAsFloat": false, "VehicleName": "", "Compress": true } + ] + }, + "CameraDefaults": { + "CaptureSettings": [ + { + "ImageType": 0, + "Width": 256, + "Height": 144, + "FOV_Degrees": 90, + "AutoExposureSpeed": 100, + "AutoExposureBias": 0, + "AutoExposureMaxBrightness": 0.64, + "AutoExposureMinBrightness": 0.03, + "MotionBlurAmount": 0, + "TargetGamma": 1.0, + "ProjectionMode": "", + "OrthoWidth": 5.12, + "MotionBlurAmount": 1, + "MotionBlurMax": 10, + "ChromaticAberrationScale": 2, + "IgnoreMarked": false, + "LumenGIEnable": true, + "LumenReflectionEnable": true, + "LumenFinalQuality": 1, + "LumenSceneDetail": 1, + "LumenSceneLightningDetail": 1 + } + ], + "NoiseSettings": [ + { + "Enabled": false, + "ImageType": 0, + + "RandContrib": 0.2, + "RandSpeed": 100000.0, + "RandSize": 500.0, + "RandDensity": 2, + + "HorzWaveContrib":0.03, + "HorzWaveStrength": 0.08, + "HorzWaveVertSize": 1.0, + "HorzWaveScreenSize": 1.0, + + "HorzNoiseLinesContrib": 1.0, + "HorzNoiseLinesDensityY": 0.01, + "HorzNoiseLinesDensityXY": 0.5, + + "HorzDistortionContrib": 1.0, + "HorzDistortionStrength": 0.002, + + "LensDistortionEnable": true, + "LensDistortionAreaFalloff": 2, + "LensDistortionAreaRadius": 1, + "LensDistortionInvert": false + } + ], + "Gimbal": { + "Stabilization": 0, + "Pitch": NaN, "Roll": NaN, "Yaw": NaN + }, + "X": NaN, "Y": NaN, "Z": NaN, + "Pitch": NaN, "Roll": NaN, "Yaw": NaN, + "UnrealEngine": { + "PixelFormatOverride": [ + { + "ImageType": 0, + "PixelFormat": 0 + } + ] + } + }, + "OriginGeopoint": { + "Latitude": 47.641468, + "Longitude": -122.140165, + "Altitude": 122 + }, + "TimeOfDay": { + "Enabled": false, + "StartDateTime": "", + "CelestialClockSpeed": 1, + "StartDateTimeDst": false, + "UpdateIntervalSecs": 60 + }, + "SubWindows": [ + {"WindowID": 0, "CameraName": "0", "ImageType": 3, "VehicleName": "", "Visible": false}, + {"WindowID": 1, "CameraName": "0", "ImageType": 5, "VehicleName": "", "Visible": false}, + {"WindowID": 2, "CameraName": "0", "ImageType": 0, "VehicleName": "", "Visible": false} + ], + "PawnPaths": { + "BareboneCar": {"PawnBP": "Class'/AirSim/VehicleAdv/Vehicle/VehicleAdvPawn.VehicleAdvPawn_C'"}, + "DefaultCar": {"PawnBP": "Class'/AirSim/VehicleAdv/SUV/SuvCarPawn.SuvCarPawn_C'"}, + "DefaultQuadrotor": {"PawnBP": "Class'/AirSim/Blueprints/BP_FlyingPawn.BP_FlyingPawn_C'"}, + "DefaultComputerVision": {"PawnBP": "Class'/AirSim/Blueprints/BP_ComputerVisionPawn.BP_ComputerVisionPawn_C'"} + }, + "Vehicles": { + "SimpleFlight": { + "VehicleType": "SimpleFlight", + "DefaultVehicleState": "Armed", + "AutoCreate": true, + "PawnPath": "", + "EnableCollisionPassthrough": false, + "EnableCollisions": true, + "AllowAPIAlways": true, + "EnableTrace": false, + "RC": { + "RemoteControlID": 0, + "AllowAPIWhenDisconnected": false + }, + "Cameras": { + //same elements as CameraDefaults above, key as name + }, + "X": NaN, "Y": NaN, "Z": NaN, + "Pitch": NaN, "Roll": NaN, "Yaw": NaN + }, + "PhysXCar": { + "VehicleType": "PhysXCar", + "DefaultVehicleState": "", + "AutoCreate": true, + "PawnPath": "", + "EnableCollisionPassthrough": false, + "EnableCollisions": true, + "RC": { + "RemoteControlID": -1 + }, + "Cameras": { + "MyCamera1": { + //same elements as elements inside CameraDefaults above + }, + "MyCamera2": { + //same elements as elements inside CameraDefaults above + }, + }, + "X": NaN, "Y": NaN, "Z": NaN, + "Pitch": NaN, "Roll": NaN, "Yaw": NaN + } + } +} +``` + +## SimMode +SimMode determines which simulation mode will be used. Below are currently supported values: +- `""`: prompt user to select vehicle type multirotor or car +- `"Multirotor"`: Use multirotor simulation +- `"Car"`: Use car simulation +- `"ComputerVision"`: Use only camera, no vehicle or physics +- `"SkidVehicle"`: use [skid-steering vehicle](skid_steer_vehicle.md) simulation + +## ViewMode +The ViewMode determines which camera to use as default and how camera will follow the vehicle. For multirotors, the default ViewMode is `"FlyWithMe"` while for cars the default ViewMode is `"SpringArmChase"`. + +* `FlyWithMe`: Chase the vehicle from behind with 6 degrees of freedom +* `GroundObserver`: Chase the vehicle from 6' above the ground but with full freedom in XY plane. +* `Fpv`: View the scene from front camera of vehicle +* `Manual`: Don't move camera automatically. Use arrow keys and ASWD keys for move camera manually. +* `SpringArmChase`: Chase the vehicle with camera mounted on (invisible) arm that is attached to the vehicle via spring (so it has some latency in movement). +* `NoDisplay`: This will freeze rendering for main screen however rendering for subwindows, recording and APIs remain active. This mode is useful to save resources in "headless" mode where you are only interested in getting images and don't care about what gets rendered on main screen. This may also improve FPS for recording images. + +## Annotation +The annotation system allows you to choose different groundtruth labeling techniques to create more data from your simulation. Find more info [here](annotation.md) for defining the settings. + +## TimeOfDay +This setting controls the position of Sun in the environment. By default `Enabled` is false which means Sun's position is left at whatever was the default in the environment and it doesn't change over the time. If `Enabled` is true then Sun position is computed using longitude, latitude and altitude specified in `OriginGeopoint` section for the date specified in `StartDateTime` in the string format as [%Y-%m-%d %H:%M:%S](https://en.cppreference.com/w/cpp/io/manip/get_time), for example, `2018-02-12 15:20:00`. If this string is empty then current date and time is used. If `StartDateTimeDst` is true then we adjust for day light savings time. The Sun's position is then continuously updated at the interval specified in `UpdateIntervalSecs`. In some cases, it might be desirable to have celestial clock run faster or slower than simulation clock. This can be specified using `CelestialClockSpeed`, for example, value 100 means for every 1 second of simulation clock, Sun's position is advanced by 100 seconds so Sun will move in sky much faster. + +Also see [Time of Day API](apis.md#time-of-day-api). + +## OriginGeopoint +This setting specifies the latitude, longitude and altitude of the Player Start component placed in the Unreal environment. The vehicle's home point is computed using this transformation. Note that all coordinates exposed via APIs are using NED system in SI units which means each vehicle starts at (0, 0, 0) in NED system. Time of Day settings are computed for geographical coordinates specified in `OriginGeopoint`. + +## SubWindows +This setting determines what is shown in each of 3 subwindows which are visible when you press 1,2,3 keys. + +* `WindowID`: Can be 0 to 2 +* `CameraName`: is any [available camera](image_apis.md#available-cameras) on the vehicle +* `ImageType`: integer value determines what kind of image gets shown according to [ImageType enum](image_apis.md#available-imagetype-values). +* `VehicleName`: string allows you to specify the vehicle to use the camera from, used when multiple vehicles are specified in the settings. First vehicle's camera will be used if there are any mistakes such as incorrect vehicle name, or only a single vehicle. +* `Annotation`: string allows you to specify the annotation layer to use for the camera. This is only if using the Annotation camera type for `ImageType` (value is 10). + +For example, for a single car vehicle, below shows driver view, front bumper view and rear view as scene, depth and surface normals respectively. +```json + "SubWindows": [ + {"WindowID": 0, "ImageType": 0, "CameraName": "3", "Visible": true}, + {"WindowID": 1, "ImageType": 3, "CameraName": "0", "Visible": true}, + {"WindowID": 2, "ImageType": 6, "CameraName": "4", "Visible": true} + ] +``` + +In case of multiple vehicles, different vehicles can be specified as follows- + +```json + "SubWindows": [ + {"WindowID": 0, "CameraName": "0", "ImageType": 3, "VehicleName": "Car1", "Visible": false}, + {"WindowID": 1, "CameraName": "0", "ImageType": 5, "VehicleName": "Car2", "Visible": false}, + {"WindowID": 2, "CameraName": "0", "ImageType": 0, "VehicleName": "Car1", "Visible": false} + ] +``` + +## Recording +The recording feature allows you to record data such as position, orientation, velocity along with the captured image at specified intervals. You can start recording by pressing red Record button on lower right or the R key. The data is stored in the `Documents\AirSim` folder (or the folder specified using `Folder`), in a time stamped subfolder for each recording session, as tab separated file. + +* `RecordInterval`: specifies minimal interval in seconds between capturing two images. +* `RecordOnMove`: specifies that do not record frame if there was vehicle's position or orientation hasn't changed. +* `Folder`: Parent folder where timestamped subfolder with recordings are created. Absolute path of the directory must be specified. If not used, then `Documents/AirSim` folder will be used. E.g. `"Folder": "/home//Documents"` +* `Enabled`: Whether Recording should start from the beginning itself, setting to `true` will start recording automatically when the simulation starts. By default, it's set to `false` +* `Cameras`: this element controls which cameras are used to capture images. By default scene image from camera 0 is recorded as compressed png format. This setting is json array so you can specify multiple cameras to capture images, each with potentially different [image types](settings.md#capturesettings). + * When `PixelsAsFloat` is true, image is saved as [pfm](pfm.md) file instead of png file. + * `VehicleName` option allows you to specify separate cameras for individual vehicles. If the `Cameras` element isn't present, `Scene` image from the default camera of each vehicle will be recorded. + * If you don't want to record any images and just the vehicle's physics data, then specify the `Cameras` element but leave it empty, like this: `"Cameras": []` + * add the field `Annotation`, a string allowing you to specify the annotation layer to use for the camera. This is only if using the Annotation camera type for `ImageType`. +For example, the `Cameras` element below records scene & segmentation images for `Car1` & scene for `Car2`- + +```json +"Cameras": [ + { "CameraName": "0", "ImageType": 0, "PixelsAsFloat": false, "VehicleName": "Car1", "Compress": true }, + { "CameraName": "0", "ImageType": 5, "PixelsAsFloat": false, "VehicleName": "Car1", "Compress": true }, + { "CameraName": "0", "ImageType": 0, "PixelsAsFloat": false, "VehicleName": "Car2", "Compress": true } +] +``` + +Check out [Modifying Recording Data](modify_recording_data.md) for details on how to modify the kinematics data being recorded. + +## ClockSpeed +This setting allows you to set the speed of simulation clock with respect to wall clock. For example, value of 5.0 would mean simulation clock has 5 seconds elapsed when wall clock has 1 second elapsed (i.e. simulation is running faster). The value of 0.1 means that simulation clock is 10X slower than wall clock. The value of 1 means simulation is running in real time. It is important to realize that quality of simulation may decrease as the simulation clock runs faster. You might see artifacts like object moving past obstacles because collision is not detected. However slowing down simulation clock (i.e. values < 1.0) generally improves the quality of simulation. + +## Wind Settings + +This setting specifies the wind speed in World frame, in NED direction. Values are in m/s. By default, speed is 0, i.e. no wind. + +## Camera Director Settings + +This element specifies the settings used for the camera following the vehicle in the ViewPort. + +* `FollowDistance`: Distance at which camera follows the vehicle, default is -8 (8 meters) for Car, -3 for others. +* `X, Y, Z, Yaw, Roll, Pitch`: These elements allows you to specify the position and orientation of the camera relative to the vehicle. Position is in NED coordinates in SI units with origin set to Player Start location in Unreal environment. The orientation is specified in degrees. + +The `CameraDefaults` element at root level specifies defaults used for all cameras. These defaults can be overridden for individual camera in `Cameras` element inside `Vehicles` as described later. + +### Main settings +Like other sensors the pose of the sensor in the vehicle frame can be defined by X, Y, Z, Roll, Pitch, Yaw parameters. +Furthermore there are some other settings available: +* `DrawSensor`: Draw the physical sensor in the world on the vehicle with a 3D axes shown where the sensor is. +* `External`: Uncouple the sensor from the vehicle. If enabled, the position and orientation will be relative to Unreal world coordinates. Note that if `MoveWorldOrigin` in the settings.json is set to `true` the Unreal coordinates will be moved to be the same origin as the player start location and as such this may effect where the sensor will spawn. +* `ExternalLocal`: When in external mode, if this is enabled the retrieved pose of the sensor will be in Local NED coordinates(from starting position from vehicle) and not converted Unreal NED coordinates which is default. Note that if `MoveWorldOrigin` in the settings.json is set to `true` the Unreal coordinates will be moved to be the same origin as the player start location and as such this may effect what coordinates are returned if set to `false`. + +### Note on ImageType element +The `ImageType` element in JSON array determines which image type that settings applies to. The valid values are described in [ImageType section](image_apis.md#available-imagetype-values). + +For example, `CaptureSettings` element is json array so you can add settings for multiple image types easily. + +### CaptureSettings +The `CaptureSettings` in the settings.json file for either the `CameraDefaults` or specific camera settings determines how different image types such as scene, depth, disparity, surface normals and segmentation views are rendered. +The Width, Height and FOV settings should be self-explanatory. The `ProjectionMode` decides the projection used by the capture camera and can take value "perspective" (default) or "orthographic". If projection mode is "orthographic" then `OrthoWidth` determines width of projected area captured in meters. + +To disable the rendering of certain objects on specific cameras or all, use the `IgnoreMarked` boolean setting. This requires to mark individual objects that have to be ignore using an Unreal Tag called _MarkedIgnore_. + +Unreal 5 introduces Lumen lightning. Due to the cameras using scene capture components enabling Lumen for them can be costly on performance. Settings have been added specfically for the scene camera to customize the usage of Lumen for Global Illumination and Reflections. +The `LumenGIEnable` and `LumenReflectionEnable` settings enable or disable Lumen for the camera. The `LumenFinalQuality`(0.25-2) setting determines the quality of the final image. The `LumenSceneDetail`(0.25-4) setting determines the quality of the scene. The `LumenSceneLightningDetail`(0.25-2) setting determines the quality of the lightning in the scene. + +`ForceUpdate` can be enabled to force a camera (only works for scene) to update the render target every frame. This is costly on performance but can solve issues with with exposure settings not applying for example. + +Below you can find a list of all available settings and their purpose. +They are settings that are directly transferred to the post-processing settings of cameras of which more documentation can be found [here](https://dev.epicgames.com/documentation/en-us/unreal-engine/post-process-effects-in-unreal-engine). + + +#### General +* **Width**: The width of the captured image in pixels. (Default: 256) +* **Height**: The height of the captured image in pixels. (Default: 144) +* **FOV_Degrees**: The horizontal field of view of the camera in degrees. +* **ImageType**: The type of image being captured (e.g., scene, depth, etc.). (Default: 0) +* **TargetGamma**: The gamma value applied to the captured image. +* **IgnoreMarked**: Whether to ignore objects marked for a specific purpose (e.g., segmentation). (Default: false) +* **ProjectionMode**: The camera's projection mode ("Perspective" or "Orthographic"). (Default: "Perspective") +* **OrthoWidth**: The width of the orthographic view frustum. +* **ForceUpdate**: Force a camera to update the render target every frame. Costly on performance! Only works for scene camera type. (Default: false) + +#### Lumen Global Illumination and Reflections +* **LumenGIEnable**: Whether Lumen Global Illumination is enabled. (Default: false) +* **LumenReflectionEnable**: Whether Lumen Reflections are enabled. (Default: false) +* **LumenFinalQuality**: The quality of Lumen's final gather. +* **LumenSceneDetail**: Controls the size of instances that can be represented in the Lumen Scene. +* **LumenSceneLightningDetail**: The quality of Lumen Scene lighting. + +#### Camera Settings +* **CameraShutterSpeed**: The camera's shutter speed in seconds. +* **CameraISO**: The camera's sensor sensitivity (ISO). +* **CameraAperture**: The camera's aperture value (f-stop). +* **CameraMaxAperture**: The camera's maximum aperture value (minimum f-stop). +* **CameraNumBlades**: The number of blades in the camera's aperture diaphragm. + +#### Depth of Field +* **DepthOfFieldSensorWidth**: Width of the camera sensor to assume, in millimeters. +* **DepthOfFieldSqueezeFactor**: Squeeze factor for the depth of field, emulating anamorphic lenses. +* **DepthOfFieldFocalDistance**: Distance at which the depth of field effect should be sharp, in centimeters. +* **DepthOfFieldDepthBlurAmount**: Depth blur in kilometers for 50% (CircleDOF only). +* **DepthOfFieldDepthBlurRadius**: Depth blur radius in pixels at 1920x resolution (CircleDOF only). +* **DepthOfFieldUseHairDepth**: Whether to use hair depth for computing the circle of confusion size. *Not supported on UE5.2!* + +#### Exposure +* **AutoExposureMethod**: Luminance computation method. (0: Histogram, 1: Basic, 2: Manual) +* **AutoExposureCompensation**: Logarithmic adjustment for the exposure. 0: no adjustment, -1: 2x darker, -2: 4x darker, 1: 2x brighter, 2: 4x brighter, ... +* **AutoExposureApplyPhysicalCameraExposure**: Enables physical camera exposure using Shutter Speed, ISO, and Aperture. (Only affects Manual exposure mode, default=: true) +* **AutoExposureMinBrightness**: Minimum brightness for auto exposure adaptation. +* **AutoExposureMaxBrightness**: Maximum brightness for auto exposure adaptation. +* **AutoExposureSpeedUp**: Speed of exposure adaptation upwards (in f-stops per second). +* **AutoExposureSpeedDown**: Speed of exposure adaptation downwards (in f-stops per second). +* **AutoExposureLowPercent**: The lower percentage for the luminance histogram used in auto exposure. +* **AutoExposureHighPercent**: The higher percentage for the luminance histogram used in auto exposure. +* **AutoExposureHistogramLogMin**: Minimum value for the auto exposure histogram (expressed in Log2(Luminance) or EV100). +* **AutoExposureHistogramLogMax**: Maximum value for the auto exposure histogram (expressed in Log2(Luminance) or EV100). + +#### Motion Blur +* **MotionBlurAmount**: The strength of motion blur applied to the image. 0: off. +* **MotionBlurMax**: The maximum distortion caused by motion blur, in percent of the screen width. 0: off. +* **MotionBlurTargetFPS**: Defines the target FPS for motion blur. Makes motion blur independent of actual frame rate. + +#### Bloom +* **BloomIntensity**: The intensity of the bloom effect. +* **BloomThreshold**: The minimum brightness for pixels to contribute to the bloom effect. + +#### Chromatic Aberration +* **ChromaticAberrationIntensity**: The intensity of chromatic aberration. +* **ChromaticAberrationStartOffset**: A normalized distance to the center of the framebuffer where the chromatic aberration effect takes place. + +#### Lens Flare +* **LensFlareIntensity**: Brightness scale of the image-based lens flares. +* **LensFlareBokehSize**: Size of the lens blur (Bokeh) used for lens flares, as a percentage of the view width. +* **LensFlareThreshold**: Minimum brightness for lens flares to take effect. + +### NoiseSettings +The `NoiseSettings` allows to add noise to the specified image type with a goal of simulating camera sensor noise, interference and other artifacts. By default no noise is added, i.e., `Enabled: false`. If you set `Enabled: true` then following different types of noise and interference artifacts are enabled, each can be further tuned using setting. +Demo of camera noise and interference simulation: + +[![AirSim Drone Demo Video](images/camera_noise_demo.png)](https://youtu.be/1BeCEZmQyp0) + +#### Random Noise +This adds random noise blobs with the following parameters: + +* **RandContrib** (float): Blend ratio of noise pixels with image pixels. 0 means no noise, and 1 means only noise. (Default: 0.2) +* **RandSpeed** (float): How fast the noise fluctuates. 1 means no fluctuation, and higher values like 1E6 mean full fluctuation. (Default: 100000.0) +* **RandSize** (float): How coarse the noise is. 1 means every pixel has its own noise, while higher values mean more than one pixel shares the same noise value. (Default: 500.0) +* **RandDensity** (float): How many pixels out of the total will have noise. 1 means all pixels, while higher values mean fewer pixels (exponentially). (Default: 2.0) + +#### Horizontal Bump Distortion +This adds horizontal bumps/flickering/ghosting effects: + +* **HorzWaveContrib** (float): Blend ratio of distorted pixels with original image pixels. 0 means no distortion, and 1 means only distorted pixels. (Default: 0.03) +* **HorzWaveStrength** (float): Overall strength of the distortion effect. (Default: 0.08) +* **HorzWaveVertSize** (float): How many vertical pixels are affected by the effect. (Default: 1.0) +* **HorzWaveScreenSize** (float): How much of the screen is affected by the effect. (Default: 1.0) + +#### Horizontal Noise Lines +This adds regions of noise on horizontal lines: + +* **HorzNoiseLinesContrib** (float): Blend ratio of noise pixels with image pixels on the affected lines. 0 means no noise, and 1 means only noise. (Default: 1.0) +* **HorzNoiseLinesDensityY** (float): How many pixels in a horizontal line are affected by noise. (Default: 0.01) +* **HorzNoiseLinesDensityXY** (float): How many lines on the screen are affected by noise. (Default: 0.5) + + +#### Horizontal Line Distortion +This adds fluctuations to horizontal lines: + +* **HorzDistortionContrib** (float): Blend ratio of distorted pixels with original image pixels on the affected lines. 0 means no distortion, and 1 means fully distorted. (Default: 1.0) +* **HorzDistortionStrength** (float): The magnitude of the distortion. (Default: 0.002) + + +#### Radial Lens Distortion +This adds radial lens distortion to the camera sensor. Note this only applies to the scene image type, not other types like depth or segmentation. + +* **LensDistortionEnable** (bool): Enable or disable lens distortion. (Default: false) +* **LensDistortionAreaFalloff** (float): Size of the area to distort. (Default: 1.0) +* **LensDistortionAreaRadius** (float): Radius of the distortion. (Default: 1.0) +* **LensDistortionIntensity** (float): Intensity of the lens distortion. (Default: 0.5) +* **LensDistortionInvert** (bool): Set to true to invert and create 'pincushion distortion' or false for 'barrel distortion'. (Default: false) + + +#### Blur +This can add various blur effects to the camera sensor. Note this only applies to the scene image type. + +The fake motion blur can be handy when the camera is static, and you want to simulate motion blur. The radial blur can simulate centered lenses. +The Gaussian blur can simulate out-of-focus effects. + +* **FakeMotionBlurEnable** (bool): Whether fake motion blur is enabled. (Default: false) +* **FakeMotionBlurDirectionX** (float): X-component of the motion blur direction vector. (Default: 0.0) +* **FakeMotionBlurDirectionY** (float): Y-component of the motion blur direction vector. (Default: 1.0) +* **FakeMotionBlurMovementSpeed** (float): Movement speed used for the fake motion blur effect. (Default: 1.0) +* **FakeMotionBlurShutterSpeed** (float): Simulated shutter speed for the fake motion blur. (Default: 0.0167) +* **FakeMotionBlurFocalLength** (float): Focal length used in the fake motion blur calculation. (Default: 35.0) +* **FakeMotionBlurSamples** (int): Number of samples used in the fake motion blur effect. (Default: 50) +* **RadialBlurEnable** (bool): Whether radial blur is enabled. (Default: false) +* **RadialBlurDistance** (float): Distance parameter for the radial blur. (Default: 1.0) +* **RadialBlurRadius** (float): Radius parameter for the radial blur. (Default: 1.0) +* **RadialBlurDensity** (float): Density parameter for the radial blur. (Default: 4.0) +* **GuassianBlurEnable** (bool): Whether Gaussian blur is enabled. (Default: false) +* **GuassianBlurDirections** (float): Number of directions used in the Gaussian blur. (Default: 16.0) +* **GuassianBlurQuality** (float): Quality level of the Gaussian blur. (Default: 3.0) +* **GuassianBlurSize** (float): Size of the Gaussian blur kernel. (Default: 8.0) + +### Gimbal +The `Gimbal` element allows to freeze camera orientation for pitch, roll and/or yaw. This setting is ignored unless `ImageType` is -1. The `Stabilization` is defaulted to 0 meaning no gimbal i.e. camera orientation changes with body orientation on all axis. The value of 1 means full stabilization. The value between 0 to 1 acts as a weight for fixed angles specified (in degrees, in world-frame) in `Pitch`, `Roll` and `Yaw` elements and orientation of the vehicle body. When any of the angles is omitted from json or set to NaN, that angle is not stabilized (i.e. it moves along with vehicle body). + +### UnrealEngine +This element contains settings specific to the Unreal Engine. These will be ignored in the Unity project. +* `PixelFormatOverride`: This contains a list of elements that have both a `ImageType` and `PixelFormat` setting. Each element allows you to override the default pixel format of the UTextureRenderTarget2D object instantiated for the capture specified by the `ImageType` setting. Specifying this element allows you to prevent crashes caused by unexpected pixel formats (see [#4120](https://github.com/microsoft/AirSim/issues/4120) and [#4339](https://github.com/microsoft/AirSim/issues/4339) for examples of these crashes). A full list of pixel formats can be viewed [here](https://docs.unrealengine.com/4.27/en-US/API/Runtime/Core/EPixelFormat/). + +## Vehicles Settings +Each simulation mode will go through the list of vehicles specified in this setting and create the ones that has `"AutoCreate": true`. Each vehicle specified in this setting has key which becomes the name of the vehicle. If `"Vehicles"` element is missing then this list is populated with default car named "PhysXCar" and default multirotor named "SimpleFlight". + +### Common Vehicle Setting +- `VehicleType`: This could be either `PhysXCar`, `ArduRover` or `BoxCar` for the Car SimMode, `SimpleFlight`, `ArduCopter` or `PX4Multirotor` for the MultiRotor SimMode, `ComputerVision` for the ComputerVision SimMode and `CPHusky` or `Pioneer` for SkidVehicle SimMode. you can use There is no default value therefore this element must be specified. +- `PawnPath`: This allows to override the pawn blueprint to use for the vehicle. For example, you may create new pawn blueprint derived from ACarPawn for a warehouse robot in your own project outside the Cosys-AirSim code and then specify its path here. See also [PawnPaths](settings.md#pawnpaths). Note that you have to specify your custom pawn blueprint class path inside the global `PawnPaths` object using your proprietarily defined object name, and quote that name inside the `Vehicles` setting. For example, +```json + { + ... + "PawnPaths": { + "CustomPawn": {"PawnBP": "Class'/Game/Assets/Blueprints/MyPawn.MyPawn_C'"} + }, + "Vehicles": { + "MyVehicle": { + "VehicleType": ..., + "PawnPath": "CustomPawn", + ... + } + } + } +``` +- `DefaultVehicleState`: Possible value for multirotors is `Armed` or `Disarmed`. +- `AutoCreate`: If true then this vehicle would be spawned (if supported by selected sim mode). +- `RC`: This sub-element allows to specify which remote controller to use for vehicle using `RemoteControlID`. The value of -1 means use keyboard (not supported yet for multirotors). The value >= 0 specifies one of many remote controllers connected to the system. The list of available RCs can be seen in Game Controllers panel in Windows, for example. +- `X, Y, Z, Yaw, Roll, Pitch`: These elements allows you to specify the initial position and orientation of the vehicle. Position is in NED coordinates in SI units with origin set to Player Start location in Unreal environment. The orientation is specified in degrees. +- `Sensors`: This element specifies the sensors associated with the vehicle, see [Sensors](sensors.md) page for details. +- `IsFpvVehicle`: This setting allows to specify which vehicle camera will follow and the view that will be shown when ViewMode is set to Fpv. By default, Cosys-AirSim selects the first vehicle in settings as FPV vehicle. +- `Cameras`: This element specifies camera settings for vehicle. The key in this element is name of the [available camera](image_apis.md#available-cameras) and the value is same as `CameraDefaults` as described above. For example, to change FOV for the front center camera to 120 degrees, you can use this for `Vehicles` setting: + +```json +"Vehicles": { + "FishEyeDrone": { + "VehicleType": "SimpleFlight", + "Cameras": { + "front-center": { + "CaptureSettings": [ + { + "ImageType": 0, + "FOV_Degrees": 120 + } + ] + } + } + } +} +``` + +### Using PX4 +By default we use [simple_flight](simple_flight.md) so you don't have to do separate HITL or SITL setups. We also support ["PX4"](px4_setup.md) for advanced users. To use PX4 with Cosys-AirSim, you can use the following for `Vehicles` setting: + +``` +"Vehicles": { + "PX4": { + "VehicleType": "PX4Multirotor", + } +} +``` + +#### Additional PX4 Settings + +The defaults for PX4 is to enable hardware-in-loop setup. There are various other settings available for PX4 as follows with their default values: + +``` +"Vehicles": { + "PX4": { + "VehicleType": "PX4Multirotor", + "Lockstep": true, + "ControlIp": "127.0.0.1", + "ControlPortLocal": 14540, + "ControlPortRemote": 14580, + "LogViewerHostIp": "127.0.0.1", + "LogViewerPort": 14388, + "OffboardCompID": 1, + "OffboardSysID": 134, + "QgcHostIp": "127.0.0.1", + "QgcPort": 14550, + "SerialBaudRate": 115200, + "SerialPort": "*", + "SimCompID": 42, + "SimSysID": 142, + "TcpPort": 4560, + "UdpIp": "127.0.0.1", + "UdpPort": 14560, + "UseSerial": true, + "UseTcp": false, + "VehicleCompID": 1, + "VehicleSysID": 135, + "Model": "Generic", + "LocalHostIp": "127.0.0.1", + "Logs": "d:\\temp\\mavlink", + "Sensors": { + ... + } + "Parameters": { + ... + } + } +} +``` + +These settings define the MavLink SystemId and ComponentId for the Simulator (SimSysID, SimCompID), +and for the vehicle (VehicleSysID, VehicleCompID) and the node that allows remote control of the +drone from another app this is called the offboard node (OffboardSysID, OffboardCompID). + +If you want the simulator to also forward mavlink messages to your ground control app (like +QGroundControl) you can also set the UDP address for that in case you want to run that on a +different machine (QgcHostIp, QgcPort). The default is local host so QGroundControl should "just +work" if it is running on the same machine. + +You can connect the simulator to the LogViewer app, provided in this repo, by setting the UDP +address for that (LogViewerHostIp, LogViewerPort). + +And for each flying drone added to the simulator there is a named block of additional settings. In +the above you see the default name "PX4". You can change this name from the Unreal Editor when you +add a new BP_FlyingPawn asset. You will see these properties grouped under the category "MavLink". +The MavLink node for this pawn can be remote over UDP or it can be connected to a local serial port. +If serial then set UseSerial to true, otherwise set UseSerial to false. For serial connections you +also need to set the appropriate SerialBaudRate. The default of 115200 works with Pixhawk version 2 +over USB. + +When communicating with the PX4 drone over serial port both the HIL_* messages and vehicle control +messages share the same serial port. When communicating over UDP or TCP PX4 requires two separate +channels. If UseTcp is false, then UdpIp, UdpPort are used to send HIL_* messages, otherwise the +TcpPort is used. TCP support in PX4 was added in 1.9.2 with the `lockstep` feature because the +guarantee of message delivery that TCP provides is required for the proper functioning of lockstep. +Cosys-AirSim becomes a TCP server in that case, and waits for a connection from the PX4 app. The second +channel for controlling the vehicle is defined by (ControlIp, ControlPort) and is always a UDP +channel. + +The `Sensors` section can provide customized settings for simulated sensors, see +[Sensors](sensors.md). The `Parameters` section can set PX4 parameters during initialization of the +PX4 connection. See [Setting up PX4 Software-in-Loop](px4_sitl.md) for an example. + +### Using ArduPilot + +[ArduPilot](https://ardupilot.org/) Copter & Rover vehicles are supported in latest Cosys-AirSim main branch & releases `v1.3.0` and later. For settings and how to use, please see [ArduPilot SITL with Cosys-AirSim](https://ardupilot.org/dev/docs/sitl-with-airsim.html) + +## Other Settings + +### EngineSound +To turn off the engine sound use [setting](settings.md) `"EngineSound": false`. Currently this setting applies only to car. + +### PawnPaths +This allows you to specify your own vehicle pawn blueprints, for example, you can replace the default car in AirSim with your own car. Your vehicle BP can reside in Content folder of your own Unreal project (i.e. outside of AirSim plugin folder). For example, if you have a car BP located in file `Content\MyCar\MySedanBP.uasset` in your project then you can set `"DefaultCar": {"PawnBP":"Class'/Game/MyCar/MySedanBP.MySedanBP_C'"}`. The `XYZ.XYZ_C` is a special notation required to specify class for BP `XYZ`. Please note that your BP must be derived from CarPawn class. By default this is not the case but you can re-parent the BP using the "Class Settings" button in toolbar in UE editor after you open the BP and then choosing "Car Pawn" for Parent Class settings in Class Options. It is also a good idea to disable "Auto Possess Player" and "Auto Possess AI" as well as set AI Controller Class to None in BP details. Please make sure your asset is included for cooking in packaging options if you are creating binary. + +### PhysicsEngineName +For cars, we support only PhysX for now (regardless of value in this setting). For multirotors, we support `"FastPhysicsEngine"` and `"ExternalPhysicsEngine"`. `"ExternalPhysicsEngine"` allows the drone to be controlled via setVehiclePose (), keeping the drone in place until the next call. It is especially useful for moving the AirSim drone using an external simulator or on a saved path. + +### LocalHostIp Setting +Now when connecting to remote machines you may need to pick a specific Ethernet adapter to reach those machines, for example, it might be +over Ethernet or over Wi-Fi, or some other special virtual adapter or a VPN. Your PC may have multiple networks, and those networks might not +be allowed to talk to each other, in which case the UDP messages from one network will not get through to the others. + +So the LocalHostIp allows you to configure how you are reaching those machines. The default of 127.0.0.1 is not able to reach external machines, +this default is only used when everything you are talking to is contained on a single PC. + +### ApiServerPort +This setting determines the server port that used by airsim clients, default port is 41451. +By specifying different ports, the user can run multiple environments in parallel to accelerate data collection process. + +### SpeedUnitFactor +Unit conversion factor for speed related to `m/s`, default is 1. Used in conjunction with SpeedUnitLabel. This may be only used for display purposes for example on-display speed when car is being driven. For example, to get speed in `miles/hr` use factor 2.23694. + +### SpeedUnitLabel +Unit label for speed, default is `m/s`. Used in conjunction with SpeedUnitFactor. + +### PassiveEchoBeacons +For the [Echo Sensor](echo.md) one can define through the settings file passive sources directly. For more information see [here](echo.md#passive-echo-beacons). + +### WorldLights +For the [Artificial Lights](lights.md) system, one can define static world lights through the settings file directly. For more information see [here](lights.md). diff --git a/docs/settings_example.json b/docs/settings_example.json index af49f4dd1..61a7c3636 100644 --- a/docs/settings_example.json +++ b/docs/settings_example.json @@ -6,7 +6,7 @@ "ApiServerPort": 41451, "RecordUIVisible": true, "MoveWorldOrigin": false, - "InitialInstanceSegmentation": false, + "InitialInstanceSegmentation": true, "LogMessagesVisible": true, "ShowLosDebugLines": false, "ViewMode": "", diff --git a/docs/skid_steer_vehicle.md b/docs/skid_steer_vehicle.md index a9e5433a5..4e830c775 100644 --- a/docs/skid_steer_vehicle.md +++ b/docs/skid_steer_vehicle.md @@ -9,7 +9,7 @@ It is build using the Chaos engine of Unreal which does not support this vehicle ## Creating a new skid steer vehicle The steps to setup the vehicle are largely the same as a WheeledVehiclePawn with some slight adjustments. -1. Follow [this guide](https://dev.epicgames.com/documentation/en-us/unreal-engine/how-to-set-up-vehicles-in-unreal-engine?application_version=5.4) to create the skeletal mesh and physics asset. +1. Follow [this guide](https://dev.epicgames.com/documentation/en-us/unreal-engine/how-to-set-up-vehicles-in-unreal-engine?application_version=5.8) to create the skeletal mesh and physics asset. 2. For the wheels setup, the vehicle should have 4 wheels, 2 for the left side and 2 for the right side. Please use SkidWheel as the wheel class. 3. For the vehicle blueprint to create the pawn it is also largely the same as in that tutorial however as class one should use the *SkidVehiclePawn* sub-class. The vehicle setup parameters are more simplified. 4. To have animated wheels, proper physics and correct steering behavior, please take a look at how the CPHusky is configured in the AirSim plugin. The Husky is a skid steer vehicle and can be used as a reference. diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 000000000..27c3b3698 --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,55 @@ +/* + Faculty brand palette override for mkdocs-material. + Primary (header/nav bar): dark blue #002e65 + Accent (links/buttons): magenta #b10097 + Secondary (subtle highlights): lilac #e4c1db + Material's named palettes (theme.palette.primary/accent in mkdocs.yml) don't support + arbitrary hex values, so the brand colors are applied here via Material's CSS custom + properties instead, which take effect regardless of the named palette configured in + mkdocs.yml. +*/ + +[data-md-color-scheme="default"], +[data-md-color-scheme="slate"] { + --md-primary-fg-color: #002e65; + --md-primary-fg-color--light: #33578c; + --md-primary-fg-color--dark: #001d40; + --md-primary-bg-color: #ffffff; + --md-primary-bg-color--light: #ffffffb3; + + --md-accent-fg-color: #b10097; + --md-accent-fg-color--transparent: #b1009733; + --md-accent-bg-color: #ffffff; + --md-accent-bg-color--light: #ffffffb3; + + --md-typeset-a-color: #b10097; +} + +/* Secondary/lilac brand color as a subtle highlight - table header tint, marked/highlighted + text, and text selection - rather than a primary UI color. */ +.md-typeset table:not([class]) th { + background-color: #e4c1db; +} +.md-typeset mark { + background-color: #e4c1db66; +} +::selection { + background-color: #e4c1db; +} + +/* Faculty uses Calibri. It's a proprietary Microsoft font we can't legally bundle/serve, so it + is only guaranteed to render as Calibri for visitors who have it installed (e.g. via Windows + or Microsoft Office); everyone else falls back to Carlito (an open metric-compatible + substitute, present on many Linux systems/LibreOffice) and finally the system sans-serif. */ +:root { + --md-text-font: "Calibri", "Carlito", -apple-system, "Segoe UI", sans-serif; +} + +/* Code/monospace blocks intentionally keep Material's default monospace font rather than + Calibri (not a monospace typeface), so code samples stay readable/aligned. */ + +/* This site has no faculty/project logo yet, so hide the default Material placeholder icon + shown at the top-left of the header (and in the mobile drawer). */ +.md-logo { + display: none !important; +} diff --git a/docs/unreal_custenv.md b/docs/unreal_custenv.md index 3436e77e1..10275bbd3 100644 --- a/docs/unreal_custenv.md +++ b/docs/unreal_custenv.md @@ -182,7 +182,7 @@ Once you have your environment using above instructions, you should frequently u 4. Right-click on your .uproject file and chose "Generate Visual Studio project files" option. This is not required for Linux. ## Choosing Your Vehicle: Car or Multirotor -By default, AirSim prompts user for which vehicle to use. You can easily change this by setting [SimMode](settings.md#SimMode). Please see [using car](using_car.md) guide. +By default, AirSim prompts user for which vehicle to use. You can easily change this by setting [SimMode](settings.md#simmode). Please see [using car](using_car.md) guide. ## Unreal Scene camera bug Note that Unreal 5.3 and higher breaks camera scene rendering when Effects is not set to the Epic scalability preset. You can use the console command r.DetailMode 2 to fix this at runtime! diff --git a/docs/using_car.md b/docs/using_car.md index fbd610669..27a437579 100644 --- a/docs/using_car.md +++ b/docs/using_car.md @@ -1,6 +1,6 @@ # How to Use Car in Cosys-AirSim -By default Cosys-AirSim prompts user for which vehicle to use. You can easily change this by setting [SimMode](settings.md#SimMode). For example, if you want to use car instead then just set the SimMode in your [settings.json](settings.md) which you can find in your `~/Documents/AirSim` folder, like this: +By default Cosys-AirSim prompts user for which vehicle to use. You can easily change this by setting [SimMode](settings.md#simmode). For example, if you want to use car instead then just set the SimMode in your [settings.json](settings.md) which you can find in your `~/Documents/AirSim` folder, like this: ``` { @@ -21,4 +21,4 @@ You can control the car, get state and images by calling APIs in variety of clie By default camera will chase the car from the back. You can get the FPV view by pressing `F` key and switch back to chasing from back view by pressing `/` key. More keyboard shortcuts can be seen by pressing F1. ## Cameras -By default car is installed with 5 cameras: center, left and right, driver and reverse. You can chose the images from these camera by specifying [the name](image_apis.md#available_cameras). +By default car is installed with 5 cameras: center, left and right, driver and reverse. You can chose the images from these camera by specifying [the name](image_apis.md#available-cameras). diff --git a/mkdocs.yml b/mkdocs.yml index 458271c33..1ca2c497b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,14 +1,79 @@ site_name: Cosys-AirSim repo_url: https://github.com/Cosys-Lab/Cosys-AirSim -site_description: 'Cosys-AirSim is a simulator for drones, cars and more, built on Unreal Engine. We expand it with new implementations and sensor modalities.' +repo_name: Cosys-Lab/Cosys-AirSim +site_description: "Cosys-AirSim is a simulator for drones, cars and more, built on Unreal Engine. We expand it with new implementations and sensor modalities." +site_author: Cosys-Lab -theme: readthedocs +theme: + name: material + font: false + palette: + # Palette toggle for light mode + - media: "(prefers-color-scheme: light)" + scheme: default + primary: indigo + accent: indigo + toggle: + icon: material/brightness-7 + name: Switch to dark mode + # Palette toggle for dark mode + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: indigo + accent: indigo + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - navigation.instant + - navigation.instant.progress + - navigation.tracking + - navigation.tabs + - navigation.tabs.sticky + - navigation.sections + - navigation.expand + - navigation.top + - search.suggest + - search.highlight + - content.tabs.link + - content.code.annotation + - content.code.copy + icon: + repo: fontawesome/brands/github + edit: material/pencil + view: material/eye + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/Cosys-Lab/Cosys-AirSim + +extra_css: + - stylesheets/extra.css extra_javascript: - - https://polyfill.io/v3/polyfill.min.js?features=es6 - https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js -edit_uri: https://github.com/Cosys-Lab/Cosys-AirSim/edit/main/docs/ +markdown_extensions: + - admonition + - attr_list + - md_in_html + - pymdownx.details + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - pymdownx.tabbed: + alternate_style: true + - pymdownx.tasklist: + custom_checkbox: true + - toc: + permalink: true + +edit_uri: edit/main/docs/ nav: - "Home": @@ -49,7 +114,7 @@ nav: - "Distance Sensor": 'distance_sensor.md' - "ROS": - "ROS: AirSim ROS Python Wrapper": "ros_python.md" - - "ROS2: AirSim ROS C++ Wrapper": "ros_cplusplus.md" + - "ROS2: AirSim ROS C++ Wrapper": "ros2.md" - "Matlab": 'matlab.md' - "Playing Logs": 'playback.md' - "Voxel Grid Generator": "voxel_grid.md" @@ -80,6 +145,7 @@ nav: - "ArduPilot SITL Setup": "https://ardupilot.org/dev/docs/building-the-code.html" - "AirSim & ArduPilot": "https://ardupilot.org/dev/docs/sitl-with-airsim.html" - "Contributed Tutorials": + - "Overview": 'contributed_tutorials.md' - "Using Environments from Marketplace": 'https://www.youtube.com/watch?v=y09VbdQWvQY' - "Simple Collision Avoidance": 'https://github.com/simondlevy/AirSimTensorFlow' - "Autonomous Driving on Azure": 'https://aka.ms/AutonomousDrivingCookbook' diff --git a/ros/python_ws/src/airsimros/package.xml b/ros/python_ws/src/airsimros/package.xml index 3989be440..d4c147f18 100644 --- a/ros/python_ws/src/airsimros/package.xml +++ b/ros/python_ws/src/airsimros/package.xml @@ -1,7 +1,7 @@ airsimros - 3.3.0 + 3.4.0 The airsim package diff --git a/ros/python_ws/src/fm_msgs/uwb_msgs/package.xml b/ros/python_ws/src/fm_msgs/uwb_msgs/package.xml index 633d07cd4..81cdce597 100644 --- a/ros/python_ws/src/fm_msgs/uwb_msgs/package.xml +++ b/ros/python_ws/src/fm_msgs/uwb_msgs/package.xml @@ -1,7 +1,7 @@ uwb_msgs - 3.3.0 + 3.4.0 The uwb_msgs package diff --git a/ros/python_ws/src/fm_msgs/wifi_msgs/package.xml b/ros/python_ws/src/fm_msgs/wifi_msgs/package.xml index b0ffe1c3a..1ff350766 100644 --- a/ros/python_ws/src/fm_msgs/wifi_msgs/package.xml +++ b/ros/python_ws/src/fm_msgs/wifi_msgs/package.xml @@ -1,7 +1,7 @@ wifi_msgs - 3.3.0 + 3.4.0 The wifi_msgs package diff --git a/ros2/src/airsim_interfaces/package.xml b/ros2/src/airsim_interfaces/package.xml index 68f359aaf..c0c867446 100644 --- a/ros2/src/airsim_interfaces/package.xml +++ b/ros2/src/airsim_interfaces/package.xml @@ -1,7 +1,7 @@ airsim_interfaces - 3.3.0 + 3.4.0 Custom messages for the Coys-AirSim ROS Wrapper. Wouter Jansen diff --git a/ros2/src/airsim_ros_pkgs/README.md b/ros2/src/airsim_ros_pkgs/README.md index 8fa1a623c..a5cd9d649 100755 --- a/ros2/src/airsim_ros_pkgs/README.md +++ b/ros2/src/airsim_ros_pkgs/README.md @@ -1,3 +1,307 @@ # airsim_ros_pkgs -This page has moved [here](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/docs/ros_cplusplus.md). \ No newline at end of file +A ROS2 wrapper over the Cosys-AirSim C++ client library. All coordinates and data are in the right-handed coordinate frame of the ROS standard and not in NED except for geo points. +The following was tested with ROS2 Jazzy. + +## Build + +- Build Cosys-AirSim as per the instructions. + +- Make sure that you have set up the environment variables for ROS. Add the `source` command to your `.bashrc` for convenience (replace `iron` with specific version name) - +```shell +echo "source /opt/ros/iron/setup.bash" >> ~/.bashrc +source ~/.bashrc +``` + +-- Install dependencies with rosdep, if not already installed - + +```shell +apt-get install python3-rosdep +sudo rosdep init +rosdep update +cd /ros2 +rosdep install --from-paths src -y --ignore-src --skip-keys pcl --skip-keys message_runtime --skip-keys message_generation +``` + +- Build ROS package + +```shell +colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release +``` + +## Running + +```shell +source install/setup.bash +ros2 launch airsim_ros_pkgs airsim_node.launch.py +``` + +## Using Cosys-Airsim ROS wrapper + +The ROS wrapper is composed of two ROS nodes - the first is a wrapper over Cosys-AirSim's multirotor C++ client library, and the second is a simple PD position controller. +Let's look at the ROS API for both nodes: + +### Cosys-Airsim ROS Wrapper Node + +#### Publishers: +The publishers will be automatically created based on the settings in the `settings.json` file for all vehicles and the sensors. + +- `/airsim_node/VEHICLE-NAME/car_state` [airsim_interfaces::CarState](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/CarState.msg) + The state of the car if the vehicle is of this sim-mode type. + +- `/airsim_node/VEHICLE-NAME/computervision_state` [airsim_interfaces::ComputerVisionState](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/ComputerVisionState.msg) + The state of the computer vision actor if the vehicle is of this sim-mode type. + +- `/airsim_node/origin_geo_point` [airsim_interfaces::GPSYaw](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/GPSYaw.msg) + GPS coordinates corresponding to global frame. This is set in the airsim's [settings.json](https://cosys-lab.github.io/Cosys-AirSim/settings/) file under the `OriginGeopoint` key. + +- `/airsim_node/VEHICLE-NAME/global_gps` [sensor_msgs::NavSatFix](https://docs.ros.org/api/sensor_msgs/html/msg/NavSatFix.html) + This the current GPS coordinates of the drone in airsim. + +- `/airsim_node/VEHICLE-NAME/environment` [airsim_interfaces::Environment](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/Environment.msg) + +- `/airsim_node/VEHICLE-NAME/odom_local` [nav_msgs::Odometry](https://docs.ros.org/api/nav_msgs/html/msg/Odometry.html) + Odometry frame (default name: odom_local, launch name and frame type are configurable) wrt take-off point. + +- `/airsim_node/VEHICLE-NAME/CAMERA-NAME_IMAGE-TYPE/camera_info` [sensor_msgs::CameraInfo](https://docs.ros.org/api/sensor_msgs/html/msg/CameraInfo.html) + Optionally if the image type is annotation the annotation layer name is also included in the topic name. + +- `/airsim_node/VEHICLE-NAME/CAMERA-NAME_IMAGE-TYPE/image` [sensor_msgs::Image](https://docs.ros.org/api/sensor_msgs/html/msg/Image.html) + RGB or float image depending on image type requested in settings.json. Optionally if the image type is annotation the annotation layer name is also included in the topic name. + +- `/tf` [tf2_msgs::TFMessage](https://docs.ros.org/api/tf2_msgs/html/msg/TFMessage.html) + +- `/airsim_node/VEHICLE-NAME/altimeter/SENSOR_NAME` [airsim_interfaces::Altimeter](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/Altimeter.msg) + This the current altimeter reading for altitude, pressure, and [QNH](https://en.wikipedia.org/wiki/QNH) + +- `/airsim_node/VEHICLE-NAME/imu/SENSOR_NAME` [sensor_msgs::Imu](http://docs.ros.org/api/sensor_msgs/html/msg/Imu.html) + IMU sensor data. + +- `/airsim_node/VEHICLE-NAME/magnetometer/SENSOR_NAME` [sensor_msgs::MagneticField](http://docs.ros.org/api/sensor_msgs/html/msg/MagneticField.html) + Measurement of magnetic field vector/compass. + +- `/airsim_node/VEHICLE-NAME/distance/SENSOR_NAME` [sensor_msgs::Range](http://docs.ros.org/api/sensor_msgs/html/msg/Range.html) + Measurement of distance from an active ranger, such as infrared or IR + +- `/airsim_node/VEHICLE-NAME/lidar/points/SENSOR_NAME/` [sensor_msgs::PointCloud2](http://docs.ros.org/api/sensor_msgs/html/msg/PointCloud2.html) + LIDAR pointcloud + +- `/airsim_node/VEHICLE-NAME/lidar/labels/SENSOR_NAME/` [airsim_interfaces::StringArray](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/StringArray.msg) + Custom message type with an array of string that are the labels for each point in the pointcloud of the lidar sensor + +- `/airsim_node/VEHICLE-NAME/gpulidar/points/SENSOR_NAME/` [sensor_msgs::PointCloud2](http://docs.ros.org/api/sensor_msgs/html/msg/PointCloud2.html) + GPU LIDAR pointcloud. The instance segmentation/annotation color data is stored in the rgb field of the pointcloud. The intensity data is stored as well in the intensity field + +- `/airsim_node/VEHICLE-NAME/echo/active/points/SENSOR_NAME/` [sensor_msgs::PointCloud2](http://docs.ros.org/api/sensor_msgs/html/msg/PointCloud2.html) + Echo sensor pointcloud for active sensing + +- `/airsim_node/VEHICLE-NAME/echo/passive/points/SENSOR_NAME/` [sensor_msgs::PointCloud2](http://docs.ros.org/api/sensor_msgs/html/msg/PointCloud2.html) + Echo sensor pointcloud for passive sensing + +- `/airsim_node/VEHICLE-NAME/echo/active/labels/SENSOR_NAME/` [airsim_interfaces::StringArray](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/StringArray.msg) + Custom message type with an array of string that are the labels for each point in the pointcloud for the active echo pointcloud + +- `/airsim_node/VEHICLE-NAME/echo/passive/labels/SENSOR_NAME/` [airsim_interfaces::StringArray](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/StringArray.msg) + Custom message type with an array of string that are the labels for each point in the pointcloud for the passive echo pointcloud + +- `/airsim_node/instance_segmentation_labels` [airsim_interfaces::InstanceSegmentationList](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/InstanceSegmentationList.msg) + Custom message type with an array of a custom messages that are the names, color and index of the instance segmentation system for each object in the world. + +- `/airsim_node/object_transforms` [airsim_interfaces::ObjectTransformsList](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/ObjectTransformsList.msg) + Custom message type with an array of [geometry_msgs::TransformStamped](http://docs.ros.org/api/geometry_msgs/html/msg/TransformStamped.html) that are the transforms of all objects in the world, each child frame ID is the object name. + +#### Subscribers: + +- `/airsim_node/VEHICLE-NAME/vel_cmd_body_frame` [airsim_interfaces::VelCmd](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/VelCmd.msg) + +- `/airsim_node/VEHICLE-NAME/vel_cmd_world_frame` [airsim_interfaces::VelCmd](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/VelCmd.msg) + +- `/airsim_node/all_robots/vel_cmd_body_frame` [airsim_interfaces::VelCmd](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/VelCmd.msg) + Set velocity command for all drones. + +- `/airsim_node/all_robots/vel_cmd_world_frame` [airsim_interfaces::VelCmd](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/VelCmd.msg) + +- `/airsim_node/group_of_robots/vel_cmd_body_frame` [airsim_interfaces::VelCmdGroup](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/VelCmdGroup.msg) + Set velocity command for a specific set of drones. +- +- `/airsim_node/group_of_robots/vel_cmd_world_frame` [airsim_interfaces::VelCmdGroup](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/VelCmdGroup.msg) + Set velocity command for a specific set of drones. + +- `/gimbal_angle_euler_cmd` [airsim_interfaces::GimbalAngleEulerCmd](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/GimbalAngleEulerCmd.msg) + Gimbal set point in euler angles. + +- `/gimbal_angle_quat_cmd` [airsim_interfaces::GimbalAngleQuatCmd](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/GimbalAngleQuatCmd.msg) + Gimbal set point in quaternion. + +- `/airsim_node/VEHICLE-NAME/car_cmd` [airsim_interfaces::CarControls](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/CarControls.msg) +Throttle, brake, steering and gear selections for control. Both automatic and manual transmission control possible, see the [`car_joy.py`](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros/src/airsim_ros_pkgs/scripts/car_joy) script for use. + +#### Services: + +- `/airsim_node/VEHICLE-NAME/land` [airsim_interfaces::Land](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/srv/Land.html) + +- `/airsim_node/VEHICLE-NAME/takeoff` [airsim_interfaces::Takeoff](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/srv/Takeoff.html) + +- `/airsim_node/all_robots/land` [airsim_interfaces::Land](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/srv/Land.html) + land all drones + +- `/airsim_node/all_robots/takeoff` [airsim_interfaces::Takeoff](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/srv/Takeoff.html) + take-off all drones + +- `/airsim_node/group_of_robots/land` [airsim_interfaces::LandGroup](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/srv/LandGroup.html) + land a specific set of drones + +- `/airsim_node/group_of_robots/takeoff` [airsim_interfaces::TakeoffGroup](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/srv/TakeoffGroup.html) + take-off a specific set of drones + +- `/airsim_node/reset` [airsim_interfaces::Reset](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/srv/Reset.html) + Resets *all* vehicles + +- `/airsim_node/instance_segmentation_refresh` [airsim_interfaces::RefreshInstanceSegmentation](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/srv/RefreshInstanceSegmentation.html) + Refresh the instance segmentation list + +- `/airsim_node/object_transforms_refresh` [airsim_interfaces::RefreshObjectTransforms](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/srv/RefreshObjectTransforms.html) + Refresh the object transforms list + + + +#### Parameters: + +- `/airsim_node/host_ip` [string] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: localhost + The IP of the machine running the airsim RPC API server. + +- `/airsim_node/host_port` [string] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: 41451 + The port of the machine running the airsim RPC API server. + +- `/airsim_node/enable_api_control` [string] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: false + Set the API control and arm the drones on startup. If not set to true no control is available. + +- `/airsim_node/enable_object_transforms_list` [string] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: true + Retrieve the object transforms list from the airsim API at the start or with the service to refresh. If disabled this is not available but can save time on startup. + +- `/airsim_node/host_port` [string] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: 41451 + The port of the machine running the airsim RPC API server. + +- `/airsim_node/is_vulkan` [string] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: True + If using Vulkan, the image encoding is switched from rgb8 to bgr8. + +- `/airsim_node/world_frame_id` [string] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: world + +- `/airsim_node/odom_frame_id` [string] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: odom_local + +- `/airsim_node/update_airsim_control_every_n_sec` [double] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: 0.01 seconds. + Timer callback frequency for updating drone odom and state from airsim, and sending in control commands. + The current RPClib interface to unreal engine maxes out at 50 Hz. + Timer callbacks in ROS run at maximum rate possible, so it's best to not touch this parameter. + +- `/airsim_node/update_airsim_img_response_every_n_sec` [double] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: 0.01 seconds. + Timer callback frequency for receiving images from all cameras in airsim. + The speed will depend on number of images requested and their resolution. + Timer callbacks in ROS run at maximum rate possible, so it's best to not touch this parameter. + +- `/airsim_node/update_lidar_every_n_sec` [double] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: 0.01 seconds. + Timer callback frequency for receiving images from all Lidar data in airsim. + Timer callbacks in ROS run at maximum rate possible, so it's best to not touch this parameter. + + +- `/airsim_node/update_gpulidar_every_n_sec` [double] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: 0.01 seconds. + Timer callback frequency for receiving images from all GPU-Lidar data in airsim. + Timer callbacks in ROS run at maximum rate possible, so it's best to not touch this parameter. + +- `/airsim_node/update_echo_every_n_sec` [double] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: 0.01 seconds. + Timer callback frequency for receiving images from all echo sensor data in airsim. + Timer callbacks in ROS run at maximum rate possible, so it's best to not touch this parameter. + +- `/airsim_node/publish_clock` [double] + Set in: `$(airsim_ros_pkgs)/launch/airsim_node.launch` + Default: false + Will publish the ros /clock topic if set to true. + +### Simple PID Position Controller Node + +#### Parameters: + +- PD controller parameters: + * `/pd_position_node/kp_x` [double], + `/pd_position_node/kp_y` [double], + `/pd_position_node/kp_z` [double], + `/pd_position_node/kp_yaw` [double] + Proportional gains + + * `/pd_position_node/kd_x` [double], + `/pd_position_node/kd_y` [double], + `/pd_position_node/kd_z` [double], + `/pd_position_node/kd_yaw` [double] + Derivative gains + + * `/pd_position_node/reached_thresh_xyz` [double] + Threshold euler distance (meters) from current position to setpoint position + + * `/pd_position_node/reached_yaw_degrees` [double] + Threshold yaw distance (degrees) from current position to setpoint position + +- `/pd_position_node/update_control_every_n_sec` [double] + Default: 0.01 seconds + +#### Services: + +- `/airsim_node/VEHICLE-NAME/gps_goal` [Request: [airsim_interfaces::SetGPSPosition](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros/src/airsim_ros_pkgs/srv/SetGPSPosition.srv)] + Target gps position + yaw. + In **absolute** altitude. + +- `/airsim_node/VEHICLE-NAME/local_position_goal` [Request: [airsim_interfaces::SetLocalPosition](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros/src/airsim_ros_pkgs/srv/SetLocalPosition.srv)] + Target local position + yaw in global frame. + +#### Subscribers: + +- `/airsim_node/origin_geo_point` [airsim_interfaces::GPSYaw](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/GPSYaw.msg) + Listens to home geo coordinates published by `airsim_node`. + +- `/airsim_node/VEHICLE-NAME/odom_local` [nav_msgs::Odometry](https://docs.ros.org/api/nav_msgs/html/msg/Odometry.html) + Listens to odometry published by `airsim_node` + +#### Publishers: + +- `/vel_cmd_world_frame` [airsim_interfaces::VelCmd](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/VelCmd.msg) + Sends velocity command to `airsim_node` + +- `/vel_cmd_body_frame` [airsim_interfaces::VelCmd](https://github.com/Cosys-Lab/Cosys-AirSim/blob/main/ros2/src/airsim_interfaces/msg/VelCmd.msg) + Sends velocity command to `airsim_node` + +#### Global params + +- Dynamic constraints. These can be changed in `dynamic_constraints.launch`: + * `/max_vel_horz_abs` [double] + Maximum horizontal velocity of the drone (meters/second) + + * `/max_vel_vert_abs` [double] + Maximum vertical velocity of the drone (meters/second) + + * `/max_yaw_rate_degree` [double] + Maximum yaw rate (degrees/second) \ No newline at end of file diff --git a/ros2/src/airsim_ros_pkgs/include/airsim_ros_wrapper.h b/ros2/src/airsim_ros_pkgs/include/airsim_ros_wrapper.h index 0274677d9..e98f7636c 100755 --- a/ros2/src/airsim_ros_pkgs/include/airsim_ros_wrapper.h +++ b/ros2/src/airsim_ros_pkgs/include/airsim_ros_wrapper.h @@ -40,7 +40,7 @@ STRICT_MODE_OFF //todo what does this do? #include #include #include -#include +#include #include #include #include @@ -69,7 +69,7 @@ STRICT_MODE_OFF //todo what does this do? #include #include #include -#include +#include #include #include #include diff --git a/ros2/src/airsim_ros_pkgs/include/pd_position_controller_simple.h b/ros2/src/airsim_ros_pkgs/include/pd_position_controller_simple.h index b2424b27f..690dde7b7 100644 --- a/ros2/src/airsim_ros_pkgs/include/pd_position_controller_simple.h +++ b/ros2/src/airsim_ros_pkgs/include/pd_position_controller_simple.h @@ -15,7 +15,7 @@ STRICT_MODE_OFF //todo what does this do? #include #include #include -#include +#include #include #include #include diff --git a/ros2/src/airsim_ros_pkgs/include/utils.h b/ros2/src/airsim_ros_pkgs/include/utils.h index a62f691a6..bd17fac5f 100755 --- a/ros2/src/airsim_ros_pkgs/include/utils.h +++ b/ros2/src/airsim_ros_pkgs/include/utils.h @@ -1,4 +1,4 @@ -#include +#include namespace utils { inline double get_yaw_from_quat_msg(const geometry_msgs::msg::Quaternion& quat_msg) diff --git a/ros2/src/airsim_ros_pkgs/package.xml b/ros2/src/airsim_ros_pkgs/package.xml index ba55b1e2c..8d25753cb 100644 --- a/ros2/src/airsim_ros_pkgs/package.xml +++ b/ros2/src/airsim_ros_pkgs/package.xml @@ -1,7 +1,7 @@ airsim_ros_pkgs - 3.2.0 + 3.4.0 ROS Wrapper over Cosys-AirSim's C++ client library Wouter Jansen diff --git a/ros2/src/airsim_ros_pkgs/src/airsim_ros_wrapper.cpp b/ros2/src/airsim_ros_pkgs/src/airsim_ros_wrapper.cpp index a0adea937..3354afba4 100755 --- a/ros2/src/airsim_ros_pkgs/src/airsim_ros_wrapper.cpp +++ b/ros2/src/airsim_ros_pkgs/src/airsim_ros_wrapper.cpp @@ -1,6 +1,6 @@ #include #include "common/AirSimSettings.hpp" -#include +#include using namespace std::placeholders; @@ -1448,8 +1448,8 @@ rclcpp::Time AirsimROSWrapper::update_state() vehicle_ros->env_msg_ = env_msg; // convert airsim drone state to ROS msgs - vehicle_ros->curr_odom_.header.frame_id = vehicle_ros->vehicle_name_; - vehicle_ros->curr_odom_.child_frame_id = vehicle_ros->odom_frame_id_; + vehicle_ros->curr_odom_.header.frame_id = vehicle_ros->odom_frame_id_; + vehicle_ros->curr_odom_.child_frame_id = vehicle_ros->vehicle_name_; vehicle_ros->curr_odom_.header.stamp = vehicle_time; } @@ -1630,7 +1630,7 @@ void AirsimROSWrapper::append_static_vehicle_tf(VehicleROS* vehicle_ros, const V geometry_msgs::msg::TransformStamped vehicle_tf_msg; vehicle_tf_msg.header.frame_id = world_frame_id_; vehicle_tf_msg.header.stamp = nh_->now(); - vehicle_tf_msg.child_frame_id = vehicle_ros->vehicle_name_; + vehicle_tf_msg.child_frame_id = vehicle_ros->odom_frame_id_; vehicle_tf_msg.transform = get_transform_msg_from_airsim(vehicle_setting.position, vehicle_setting.rotation); convert_tf_msg_to_ros(vehicle_tf_msg); @@ -1644,7 +1644,7 @@ void AirsimROSWrapper::append_static_lidar_tf(VehicleROS* vehicle_ros, const std if(lidar_setting.external) lidar_tf_msg.header.frame_id = world_frame_id_; else - lidar_tf_msg.header.frame_id = vehicle_ros->vehicle_name_ + "/" + odom_frame_id_; + lidar_tf_msg.header.frame_id = vehicle_ros->vehicle_name_; lidar_tf_msg.child_frame_id = vehicle_ros->vehicle_name_ + "/" + lidar_name; auto lidar_data = airsim_client_lidar_.getLidarData(lidar_name, vehicle_ros->vehicle_name_); @@ -1661,7 +1661,7 @@ void AirsimROSWrapper::append_static_gpulidar_tf(VehicleROS* vehicle_ros, const if(gpulidar_setting.external) gpulidar_tf_msg.header.frame_id = world_frame_id_; else - gpulidar_tf_msg.header.frame_id = vehicle_ros->vehicle_name_ + "/" + odom_frame_id_; + gpulidar_tf_msg.header.frame_id = vehicle_ros->vehicle_name_; gpulidar_tf_msg.child_frame_id = vehicle_ros->vehicle_name_ + "/" + gpulidar_name; auto gpulidar_data = airsim_client_gpulidar_.getGPULidarData(gpulidar_name, vehicle_ros->vehicle_name_); @@ -1678,7 +1678,7 @@ void AirsimROSWrapper::append_static_echo_tf(VehicleROS* vehicle_ros, const std: if(echo_setting.external) echo_tf_msg.header.frame_id = world_frame_id_; else - echo_tf_msg.header.frame_id = vehicle_ros->vehicle_name_ + "/" + odom_frame_id_; + echo_tf_msg.header.frame_id = vehicle_ros->vehicle_name_; echo_tf_msg.child_frame_id = vehicle_ros->vehicle_name_ + "/" + echo_name; auto echo_data = airsim_client_echo_.getEchoData(echo_name, vehicle_ros->vehicle_name_); @@ -1692,22 +1692,20 @@ void AirsimROSWrapper::append_static_echo_tf(VehicleROS* vehicle_ros, const std: void AirsimROSWrapper::append_static_camera_tf(VehicleROS* vehicle_ros, const std::string& camera_name, const CameraSetting& camera_setting) { geometry_msgs::msg::TransformStamped static_cam_tf_body_msg; - if(camera_setting.external) + if(camera_setting.external){ static_cam_tf_body_msg.header.frame_id = world_frame_id_; - else - static_cam_tf_body_msg.header.frame_id = vehicle_ros->vehicle_name_ + "/" + odom_frame_id_; + auto camera_info_data = airsim_client_images_.simGetCameraInfo(camera_name, vehicle_ros->vehicle_name_); + static_cam_tf_body_msg.transform = get_transform_msg_from_airsim(camera_info_data.pose.position, camera_info_data.pose.orientation); + } + else{ + static_cam_tf_body_msg.header.frame_id = vehicle_ros->vehicle_name_; + static_cam_tf_body_msg.transform = get_transform_msg_from_airsim(camera_setting.position, camera_setting.rotation); + } static_cam_tf_body_msg.child_frame_id = vehicle_ros->vehicle_name_ + "/" + camera_name + "_body"; - auto camera_info_data = airsim_client_images_.simGetCameraInfo(camera_name, vehicle_ros->vehicle_name_); - static_cam_tf_body_msg.transform = get_transform_msg_from_airsim(camera_info_data.pose.position, camera_info_data.pose.orientation); - convert_tf_msg_to_ros(static_cam_tf_body_msg); geometry_msgs::msg::TransformStamped static_cam_tf_optical_msg = static_cam_tf_body_msg; - if(camera_setting.external) - static_cam_tf_body_msg.header.frame_id = world_frame_id_; - else - static_cam_tf_body_msg.header.frame_id = vehicle_ros->vehicle_name_ + "/" + odom_frame_id_; static_cam_tf_optical_msg.child_frame_id = vehicle_ros->vehicle_name_ + "/" + camera_name + "_optical"; static_cam_tf_optical_msg.transform = get_camera_optical_tf_from_body_tf(static_cam_tf_body_msg.transform); diff --git a/setup.sh b/setup.sh index 960334ab9..6dfd92ded 100755 --- a/setup.sh +++ b/setup.sh @@ -30,43 +30,6 @@ if [ "$(uname)" == "Darwin" ]; then # osx brew update # Update below line for newer versions brew install llvm@8 -else #linux - sudo apt-get update - sudo apt-get -y install --no-install-recommends \ - lsb-release \ - rsync \ - software-properties-common \ - wget \ - libvulkan1 \ - vulkan-tools - - #install clang and build tools - VERSION=$(lsb_release -rs | cut -d. -f1) - # Since Ubuntu 17 clang is part of the core repository - # See https://packages.ubuntu.com/search?keywords=clang-8 - # if [ "$VERSION" -lt "17" ]; then - # wget -O - http://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add - - # sudo apt-get update - # fi - if [ "$VERSION" -eq "20" ]; then - sudo add-apt-repository ppa:ubuntu-toolchain-r/test - sudo apt update - sudo apt-get install -y build-essential cmake clang clang-12 clang++-12 libc++-12-dev libc++abi-12-dev libstdc++-13-dev - - # configure update-alternatives for clang - sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-12 1000 - sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-12 1000 - sudo update-alternatives --install /usr/bin/ld.lld ld.lld /usr/bin/ld.lld-12 1000 - sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang++-12 1000 - fi - if [ "$VERSION" -eq "22" ]; then - sudo add-apt-repository ppa:ubuntu-toolchain-r/test - sudo apt update - sudo apt-get install -y build-essential cmake clang clang-14 clang++-14 libc++-14-dev libc++abi-14-dev libstdc++-13-dev - fi - if [ "$VERSION" -eq "24" ]; then - sudo apt-get install -y build-essential cmake clang clang-18 clang++-18 libc++-18-dev libc++abi-18-dev libstdc++-13-dev - fi fi if ! which cmake; then @@ -106,42 +69,7 @@ else #linux # install additional tools sudo apt-get install -y unzip - if version_less_than_equal_to $cmake_ver $MIN_CMAKE_VERSION; then - # in ubuntu 18 docker CI, avoid building cmake from scratch to save time - # ref: https://apt.kitware.com/ - if [ "$(lsb_release -rs)" == "18.04" ]; then - sudo apt-get -y install \ - apt-transport-https \ - ca-certificates \ - gnupg - wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null - sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' - sudo apt-get -y install --no-install-recommends \ - make \ - cmake - - else - # For Ubuntu 16.04, or anything else, build CMake 3.10.2 from source - if [[ ! -d "cmake_build/bin" ]]; then - echo "Downloading cmake..." - wget https://cmake.org/files/v3.10/cmake-3.10.2.tar.gz \ - -O cmake.tar.gz - tar -xzf cmake.tar.gz - rm cmake.tar.gz - rm -rf ./cmake_build - mv ./cmake-3.10.2 ./cmake_build - pushd cmake_build - ./bootstrap - make - popd - fi - fi - - else - echo "Already have good version of cmake: $cmake_ver" - fi - -fi # End USB setup, CMake install +fi # End USB setup # Download rpclib