Skip to content

Commit 452291c

Browse files
Add depth map support for camera sensor
1 parent a66ffbf commit 452291c

File tree

11 files changed

+202
-35
lines changed

11 files changed

+202
-35
lines changed

com.unity.ml-agents/Editor/CameraSensorComponentEditor.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public override void OnInspectorGUI()
2424
EditorGUILayout.PropertyField(so.FindProperty("m_Width"), true);
2525
EditorGUILayout.PropertyField(so.FindProperty("m_Height"), true);
2626
EditorGUILayout.PropertyField(so.FindProperty("m_Grayscale"), true);
27+
EditorGUILayout.PropertyField(so.FindProperty("m_RGBD"), true);
2728
EditorGUILayout.PropertyField(so.FindProperty("m_ObservationStacks"), true);
2829
EditorGUILayout.PropertyField(so.FindProperty("m_ObservationType"), true);
2930
}

com.unity.ml-agents/Runtime/Resources.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
Shader "Custom/DepthShader"
2+
{
3+
Properties
4+
{
5+
_MainTex ("Texture", 2D) = "white" {}
6+
}
7+
SubShader
8+
{
9+
Pass
10+
{
11+
CGPROGRAM
12+
#pragma vertex vert
13+
#pragma fragment frag
14+
15+
#include "UnityCG.cginc"
16+
17+
struct appdata
18+
{
19+
float4 vertex : POSITION;
20+
float2 uv : TEXCOORD0;
21+
};
22+
23+
struct v2f
24+
{
25+
float2 uv : TEXCOORD0;
26+
float4 vertex : SV_POSITION;
27+
float4 screenPos: TEXTCOORD1;
28+
};
29+
30+
v2f vert (appdata v)
31+
{
32+
v2f o;
33+
o.vertex = UnityObjectToClipPos(v.vertex);
34+
o.screenPos = ComputeScreenPos(o.vertex);
35+
o.uv = v.uv;
36+
return o;
37+
}
38+
39+
sampler2D _MainTex, _CameraDepthTexture;
40+
41+
float4 frag (v2f i) : SV_Target
42+
{
43+
// Extract color from texture
44+
float4 color = tex2D(_MainTex, i.uv);
45+
46+
// Extract depth from camera depth texture
47+
float depth = LinearEyeDepth(tex2D(_CameraDepthTexture, i.screenPos.xy));
48+
49+
// Clip depth to far plane
50+
float farPlane = _ProjectionParams.z;
51+
if (depth > farPlane) depth = 0;
52+
53+
// Convert color from linear to sRGB
54+
color.rgb = LinearToGammaSpace(saturate(color.rgb));
55+
56+
// Store depth in alpha channel
57+
color.a = depth;
58+
59+
return color;
60+
}
61+
ENDCG
62+
}
63+
}
64+
}

com.unity.ml-agents/Runtime/Resources/DepthShader.shader.meta

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

com.unity.ml-agents/Runtime/Sensors/CameraSensor.cs

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,19 @@ public class CameraSensor : ISensor, IBuiltInSensor, IDisposable
1313
int m_Width;
1414
int m_Height;
1515
bool m_Grayscale;
16+
bool m_RGBD;
1617
string m_Name;
1718
private ObservationSpec m_ObservationSpec;
1819
SensorCompressionType m_CompressionType;
1920
Texture2D m_Texture;
2021

22+
/// <summary>
23+
/// Indicates wether or not the Render method is being executed by CameraSensor.
24+
/// This boolean is checked in CameraSensorComponent.OnRenderImage method to avoid
25+
/// applying the depth shader outside of the camera sensor scope.
26+
/// </summary>
27+
public bool m_InCameraSensorRender { get; private set; }
28+
2129
/// <summary>
2230
/// The Camera used for rendering the sensor observations.
2331
/// </summary>
@@ -47,17 +55,19 @@ public SensorCompressionType CompressionType
4755
/// <param name="compression">The compression to apply to the generated image.</param>
4856
/// <param name="observationType">The type of observation.</param>
4957
public CameraSensor(
50-
Camera camera, int width, int height, bool grayscale, string name, SensorCompressionType compression, ObservationType observationType = ObservationType.Default)
58+
Camera camera, int width, int height, bool grayscale, bool rgbd, string name, SensorCompressionType compression, ObservationType observationType = ObservationType.Default)
5159
{
5260
m_Camera = camera;
5361
m_Width = width;
5462
m_Height = height;
5563
m_Grayscale = grayscale;
64+
m_RGBD = rgbd;
5665
m_Name = name;
57-
var channels = grayscale ? 1 : 3;
66+
var channels = rgbd ? 4 : grayscale ? 1 : 3; // RGBD has priority over Grayscale
5867
m_ObservationSpec = ObservationSpec.Visual(channels, height, width, observationType);
5968
m_CompressionType = compression;
60-
m_Texture = new Texture2D(width, height, TextureFormat.RGB24, false);
69+
m_Texture = new Texture2D(width, height, rgbd ? TextureFormat.RGBAFloat : TextureFormat.RGB24, false);
70+
m_InCameraSensorRender = false;
6171
}
6272

6373
/// <summary>
@@ -90,8 +100,11 @@ public byte[] GetCompressedObservation()
90100
using (TimerStack.Instance.Scoped("CameraSensor.GetCompressedObservation"))
91101
{
92102
// TODO support more types here, e.g. JPG
93-
var compressed = m_Texture.EncodeToPNG();
94-
return compressed;
103+
if (m_CompressionType == SensorCompressionType.OPENEXR)
104+
{
105+
return m_Texture.EncodeToEXR();
106+
}
107+
return m_Texture.EncodeToPNG();
95108
}
96109
}
97110

@@ -104,7 +117,7 @@ public int Write(ObservationWriter writer)
104117
{
105118
using (TimerStack.Instance.Scoped("CameraSensor.WriteToTensor"))
106119
{
107-
var numWritten = writer.WriteTexture(m_Texture, m_Grayscale);
120+
var numWritten = writer.WriteTexture(m_Texture, m_Grayscale, m_RGBD);
108121
return numWritten;
109122
}
110123
}
@@ -131,7 +144,7 @@ public CompressionSpec GetCompressionSpec()
131144
/// <param name="texture2D">Texture2D to render to.</param>
132145
/// <param name="width">Width of resulting 2D texture.</param>
133146
/// <param name="height">Height of resulting 2D texture.</param>
134-
public static void ObservationToTexture(Camera obsCamera, Texture2D texture2D, int width, int height)
147+
public void ObservationToTexture(Camera obsCamera, Texture2D texture2D, int width, int height)
135148
{
136149
if (SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null)
137150
{
@@ -140,9 +153,9 @@ public static void ObservationToTexture(Camera obsCamera, Texture2D texture2D, i
140153

141154
var oldRec = obsCamera.rect;
142155
obsCamera.rect = new Rect(0f, 0f, 1f, 1f);
143-
var depth = 24;
144-
var format = RenderTextureFormat.Default;
145-
var readWrite = RenderTextureReadWrite.Default;
156+
var depth = m_RGBD ? 32 : 24;
157+
var format = m_RGBD ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.Default;
158+
var readWrite = m_RGBD ? RenderTextureReadWrite.Linear : RenderTextureReadWrite.Default;
146159

147160
var tempRt =
148161
RenderTexture.GetTemporary(width, height, depth, format, readWrite);
@@ -154,8 +167,12 @@ public static void ObservationToTexture(Camera obsCamera, Texture2D texture2D, i
154167
RenderTexture.active = tempRt;
155168
obsCamera.targetTexture = tempRt;
156169

170+
m_InCameraSensorRender = true;
171+
157172
obsCamera.Render();
158173

174+
m_InCameraSensorRender = false;
175+
159176
texture2D.ReadPixels(new Rect(0, 0, texture2D.width, texture2D.height), 0, 0);
160177

161178
obsCamera.targetTexture = prevCameraRt;

com.unity.ml-agents/Runtime/Sensors/CameraSensorComponent.cs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,26 @@ public int Height
6767
bool m_Grayscale;
6868

6969
/// <summary>
70-
/// Whether to generate grayscale images or color.
70+
/// Whether to generate grayscale images or color. Disable RGBD to use it.
7171
/// Note that changing this after the sensor is created has no effect.
7272
/// </summary>
7373
public bool Grayscale
7474
{
7575
get { return m_Grayscale; }
76-
set { m_Grayscale = value; }
76+
set { m_Grayscale = value; UpdateSensor(); }
77+
}
78+
79+
[HideInInspector, SerializeField, FormerlySerializedAs("rgbd")]
80+
bool m_RGBD;
81+
82+
/// <summary>
83+
/// Whether to generate color+depth images. RGBD has priority over Grayscale.
84+
/// Note that changing this after the sensor is created has no effect.
85+
/// </summary>
86+
public bool RGBD
87+
{
88+
get { return m_RGBD; }
89+
set { m_RGBD = value; UpdateSensor(); }
7790
}
7891

7992
[HideInInspector, SerializeField]
@@ -130,9 +143,15 @@ public int ObservationStacks
130143
set { m_ObservationStacks = value; }
131144
}
132145

146+
/// <summary>
147+
/// The material used to render the depth image.
148+
/// </summary>
149+
private Material m_DepthMaterial;
150+
133151
void Start()
134152
{
135153
UpdateSensor();
154+
m_DepthMaterial = new Material(Shader.Find("Custom/DepthShader"));
136155
}
137156

138157
/// <summary>
@@ -142,7 +161,7 @@ void Start()
142161
public override ISensor[] CreateSensors()
143162
{
144163
Dispose();
145-
m_Sensor = new CameraSensor(m_Camera, m_Width, m_Height, Grayscale, m_SensorName, m_Compression, m_ObservationType);
164+
m_Sensor = new CameraSensor(m_Camera, m_Width, m_Height, Grayscale, RGBD, m_SensorName, m_Compression, m_ObservationType);
146165

147166
if (ObservationStacks != 1)
148167
{
@@ -158,6 +177,14 @@ internal void UpdateSensor()
158177
{
159178
if (m_Sensor != null)
160179
{
180+
// Update depth settings before camera settings because m_Compression might change
181+
if (m_RGBD)
182+
{
183+
m_Grayscale = false;
184+
m_Compression = SensorCompressionType.OPENEXR;
185+
}
186+
187+
// Update camera settings
161188
m_Sensor.Camera = m_Camera;
162189
m_Sensor.CompressionType = m_Compression;
163190
m_Sensor.Camera.enabled = m_RuntimeCameraEnable;
@@ -175,5 +202,20 @@ public void Dispose()
175202
m_Sensor = null;
176203
}
177204
}
205+
206+
/// <summary>
207+
/// Apply the depth material to the camera image if the sensor is set to RGBD.
208+
/// </summary>
209+
void OnRenderImage(RenderTexture src, RenderTexture dest)
210+
{
211+
if (m_RGBD && m_Sensor != null && m_Sensor.m_InCameraSensorRender)
212+
{
213+
Graphics.Blit(src, dest, m_DepthMaterial);
214+
}
215+
else
216+
{
217+
Graphics.Blit(src, dest);
218+
}
219+
}
178220
}
179221
}

com.unity.ml-agents/Runtime/Sensors/CompressionSpec.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ public enum SensorCompressionType
1414
/// <summary>
1515
/// PNG format. Data will be stored in binary format.
1616
/// </summary>
17-
PNG
17+
PNG,
18+
19+
/// <summary>
20+
/// OpenEXR format.
21+
/// </summary>
22+
OPENEXR
1823
}
1924

2025
/// <summary>

com.unity.ml-agents/Runtime/Sensors/ObservationWriter.cs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ public static class ObservationWriterExtension
296296
public static int WriteTexture(
297297
this ObservationWriter obsWriter,
298298
Texture2D texture,
299-
bool grayScale)
299+
bool grayScale,
300+
bool rgbd = false)
300301
{
301302
if (texture.format == TextureFormat.RGB24)
302303
{
@@ -306,7 +307,7 @@ public static int WriteTexture(
306307
var width = texture.width;
307308
var height = texture.height;
308309

309-
var texturePixels = texture.GetPixels32();
310+
var texturePixels = texture.GetPixels();
310311

311312
// During training, we convert from Texture to PNG before sending to the trainer, which has the
312313
// effect of flipping the image. We need another flip here at inference time to match this.
@@ -316,22 +317,25 @@ public static int WriteTexture(
316317
{
317318
var currentPixel = texturePixels[(height - h - 1) * width + w];
318319

319-
if (grayScale)
320+
if (grayScale && !rgbd)
320321
{
321322
obsWriter[0, h, w] =
322-
(currentPixel.r + currentPixel.g + currentPixel.b) / 3f / 255.0f;
323+
(currentPixel.r + currentPixel.g + currentPixel.b) / 3f;
323324
}
324325
else
325326
{
326-
// For Color32, the r, g and b values are between 0 and 255.
327-
obsWriter[0, h, w] = currentPixel.r / 255.0f;
328-
obsWriter[1, h, w] = currentPixel.g / 255.0f;
329-
obsWriter[2, h, w] = currentPixel.b / 255.0f;
327+
obsWriter[0, h, w] = currentPixel.r;
328+
obsWriter[1, h, w] = currentPixel.g;
329+
obsWriter[2, h, w] = currentPixel.b;
330+
if (rgbd)
331+
{
332+
obsWriter[3, h, w] = currentPixel.a;
333+
}
330334
}
331335
}
332336
}
333337

334-
return height * width * (grayScale ? 1 : 3);
338+
return height * width * (rgbd ? 4 : grayScale ? 1 : 3);
335339
}
336340

337341
internal static int WriteTextureRGB24(

0 commit comments

Comments
 (0)