Skip to content

Commit 78f09cb

Browse files
authored
Merge pull request #13 from Uralstech/unstable
UXR.QuestCamera v4.0.0
2 parents f5fb077 + 84d1c17 commit 78f09cb

160 files changed

Lines changed: 4707 additions & 5100 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Documentation/DocSource/AdvancedSamples.md

Lines changed: 90 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -4,169 +4,161 @@ This page contains some samples for advanced use-cases, like custom texture conv
44

55
## Custom Texture Converters
66

7-
The texture converter in `CapturePipeline<T>.TextureConverter` allows you to easily change the conversion compute shader to custom
8-
ones. All you have to do is set `CapturePipeline<T>.TextureConverter.Shader` to your shader. You can also change the compute shader
9-
for all new capture sessions by changing `UCameraManager.YUVToRGBAComputeShader`.
7+
The texture converter in `CapturePipeline<T>.Converter` allows you to easily change the conversion compute shader to custom
8+
ones. All you have to do is assign a new `ComputeShaderKernel` to `Converter.ShaderKernel`. `ComputeShaderKernel` references
9+
the compute shader and the name of the shader kernel to use.
10+
11+
You can also change the compute shader for all new capture sessions by changing `QuestCameraManager.ConversionKernel`.
1012

1113
For example, the following compute shader ignores the U and V values of the YUV stream to provide a Luminance-only image:
1214

1315
```hlsl
1416
#pragma kernel CSMain
1517
16-
// Input buffers (read-only)
18+
// ---------------- YUVConverter *required* parameters ----------------
19+
20+
// Camera frame
1721
ByteAddressBuffer YBuffer;
1822
ByteAddressBuffer UBuffer;
1923
ByteAddressBuffer VBuffer;
2024
21-
// Row strides
22-
uint YRowStride;
23-
uint UVRowStride;
25+
cbuffer StrideParams {
26+
// Row strides
27+
uint YRowStride;
28+
uint UVRowStride;
2429
25-
// Pixel strides
26-
uint UVPixelStride;
27-
28-
// Image dimensions
29-
uint TargetWidth;
30-
uint TargetHeight;
30+
// Pixel strides
31+
uint UVPixelStride;
32+
uint StrideParamsPadding;
33+
}
3134
32-
// Output texture (read-write)
35+
uniform uint OutputTextureWidth;
36+
uniform uint OutputTextureHeight;
3337
RWTexture2D<float4> OutputTexture;
3438
35-
// Helper function to get a byte from a ByteAddressBuffer.
36-
// buffer: The ByteAddressBuffer.
37-
// byteIndex: The *byte* index (offset) into the buffer.
38-
uint GetByteFromBuffer(ByteAddressBuffer buffer, uint byteIndex)
39-
{
40-
// Calculate the 32-bit word offset (each word is 4 bytes).
41-
uint wordOffset = byteIndex / 4;
42-
43-
// Load the 32-bit word containing the byte.
44-
uint word = buffer.Load(wordOffset * 4); // MUST multiply by 4 for ByteAddressBuffer.Load()
39+
// ---------------- End of required parameters ----------------
4540
46-
// Calculate the byte position *within* the word (0, 1, 2, or 3).
47-
uint byteInWord = byteIndex % 4;
41+
// Converts byte array indexing to ByteAddressBuffer indexing and returns the value
42+
uint GetByteFromBuffer(const ByteAddressBuffer buffer, const uint byteIndex) {
43+
44+
const uint word = buffer.Load(byteIndex & ~3);
45+
const uint byteInWord = byteIndex & 3;
4846
49-
// Extract the correct byte using bit shifts and masking.
5047
return (word >> (byteInWord * 8)) & 0xFF;
5148
}
5249
5350
[numthreads(8, 8, 1)]
54-
void CSMain(uint3 id : SV_DispatchThreadID)
55-
{
56-
if (id.x >= TargetWidth || id.y >= TargetHeight)
51+
void CSMain(uint3 id : SV_DispatchThreadID) {
52+
53+
if (id.x >= OutputTextureWidth || id.y >= OutputTextureHeight)
5754
return;
58-
55+
5956
// The YUV stream is flipped, so we have to un-flip it.
60-
uint flippedY = TargetHeight - 1 - id.y;
57+
const uint flippedY = OutputTextureHeight - 1 - id.y;
6158
6259
// Index of Y value in buffer.
63-
uint yIndex = flippedY * YRowStride + id.x;
64-
uint yValue = GetByteFromBuffer(YBuffer, yIndex);
60+
const uint yIndex = flippedY * YRowStride + id.x;
61+
62+
// Get the Y (luminance) value.
63+
const uint y = GetByteFromBuffer(YBuffer, yIndex);
6564
66-
float3 luminance = float3(yValue, yValue, yValue) / 255.0;
67-
OutputTexture[id.xy] = float4(luminance.rgb, 1.0);
65+
// Convert the value from 0-255 to 0-1 and set the output texture.
66+
const float3 color = float3(y, y, y) / 255.0;
67+
OutputTexture[id.xy] = float4(color, 1.0);
6868
}
6969
```
7070

71-
## Multiple Streams From One Camera
71+
## Multiple Streams from One Camera
7272

7373
By adding multiple texture converters to the same request, you can emulate the effect of having more than one image stream from a
7474
single camera. For example, you can have one converter stream the camera image as-is, and another streaming with a simple Sepia
7575
post-processing effect:
7676

77-
```csharp
78-
// Create a capture session with the camera, at the chosen resolution.
79-
CapturePipeline<ContinuousCaptureSession> capturePipeline = camera.CreateContinuousCaptureSession(highestResolution);
80-
if (capturePipeline == null...
81-
82-
yield return capturePipeline.CaptureSession.WaitForInitialization();
83-
84-
// Check if it opened successfully.
85-
if (capturePipeline.CaptureSession.CurrentState...
77+
> [!WARNING]
78+
> This is not the best way to do this! Creating multiple `YUVConverter`s duplicates almost all conversion resources for each instance!
79+
>
80+
> Each `YUVConverter` allocates its own:
81+
> - CPU-side `NativeArray` copy buffers
82+
> - GPU-side `GraphicsBuffer`s
83+
> - Output `RenderTexture`
84+
> - Conversion `CommandBuffer`
85+
>
86+
> The CPU-side copy buffers and GPU-side graphics buffers are each approximately the size of one frame of
87+
> YUV image data. The output `RenderTexture` size depends on the selected texture format, but is usually
88+
> larger than an equivalent YUV texture.
89+
>
90+
> Please implement a custom converter which shares the above data between different consumers.
8691
87-
// Set the image texture.
88-
_rawImage.texture = capturePipeline.TextureConverter.FrameRenderTexture;
92+
```csharp
93+
// Create the session.
94+
_session = _camera.CreateContinuousSession(highestResolution, CaptureTemplate.Preview, useCase);
95+
if (!await _session.WaitForInitializationAsync())
96+
{
97+
await _session.DisposeAsync();
98+
await _camera.DisposeAsync();
99+
return;
100+
}
89101

90-
// Create a new YUVToRGBAConverter.
91-
YUVToRGBAConverter secondary = new YUVToRGBAConverter(highestResolution);
102+
// Primary converter, defaults to the shader set in QuestCameraManager.
103+
_primaryConverter = new YUVConverter(highestResolution);
92104

93-
// Assign it a different shader.
94-
secondary.Shader = _postProcessShader;
105+
// Secondary converter with the sepia effect, ComputeShaderKernel uses "CSMain" by default.
106+
_secondaryConverter = new YUVConverter(highestResolution, new ComputeShaderKernel(_sepiaShader));
95107

96-
// Link the capture session and the converter.
97-
capturePipeline.CaptureSession.OnFrameReady += secondary.OnFrameReady;
108+
// Register converters to session.
109+
_session.NativeProxy.OnFrameReady += _primaryConverter.OnFrameReady;
110+
_session.NativeProxy.OnFrameReady += _secondaryConverter.OnFrameReady;
98111

99-
// Set the second image to the post processed RenderTexture.
100-
_rawImagePostProcessed.texture = secondary.FrameRenderTexture;
112+
_rawImagePrimary.texture = _primaryConverter.Texture;
113+
_rawImageSecondary.texture = _secondaryConverter.Texture;
101114
```
102115

103116
### YUV To RGBA Converter With Sepia Effect
104117

105118
```hlsl
106119
#pragma kernel CSMain
107120
108-
// Input buffers (read-only)
109121
ByteAddressBuffer YBuffer;
110122
ByteAddressBuffer UBuffer;
111123
ByteAddressBuffer VBuffer;
112124
113-
// Row strides
114-
uint YRowStride;
115-
uint UVRowStride;
116-
117-
// Pixel strides
118-
uint UVPixelStride;
125+
cbuffer StrideParams {
126+
uint YRowStride;
127+
uint UVRowStride;
119128
120-
// Image dimensions
121-
uint TargetWidth;
122-
uint TargetHeight;
129+
uint UVPixelStride;
130+
uint StrideParamsPadding;
131+
}
123132
124-
// Output texture (read-write)
133+
uniform uint OutputTextureWidth;
134+
uniform uint OutputTextureHeight;
125135
RWTexture2D<float4> OutputTexture;
126136
127-
// Helper function to get a byte from a ByteAddressBuffer.
128-
// buffer: The ByteAddressBuffer.
129-
// byteIndex: The *byte* index (offset) into the buffer.
130-
uint GetByteFromBuffer(ByteAddressBuffer buffer, uint byteIndex)
131-
{
132-
// Calculate the 32-bit word offset (each word is 4 bytes).
133-
uint wordOffset = byteIndex / 4;
134-
135-
// Load the 32-bit word containing the byte.
136-
uint word = buffer.Load(wordOffset * 4); // MUST multiply by 4 for ByteAddressBuffer.Load()
137-
138-
// Calculate the byte position *within* the word (0, 1, 2, or 3).
139-
uint byteInWord = byteIndex % 4;
137+
uint GetByteFromBuffer(const ByteAddressBuffer buffer, const uint byteIndex) {
138+
139+
const uint word = buffer.Load(byteIndex & ~3);
140+
const uint byteInWord = byteIndex & 3;
140141
141-
// Extract the correct byte using bit shifts and masking.
142142
return (word >> (byteInWord * 8)) & 0xFF;
143143
}
144144
145145
[numthreads(8, 8, 1)]
146-
void CSMain(uint3 id : SV_DispatchThreadID)
147-
{
148-
if (id.x >= TargetWidth || id.y >= TargetHeight)
146+
void CSMain(uint3 id : SV_DispatchThreadID) {
147+
148+
if (id.x >= OutputTextureWidth || id.y >= OutputTextureHeight)
149149
return;
150-
151-
// The YUV stream is flipped, so we have to un-flip it.
152-
uint flippedY = TargetHeight - 1 - id.y;
153150
154-
// Index of Y value in buffer.
155-
uint yIndex = flippedY * YRowStride + id.x;
156-
uint yValue = GetByteFromBuffer(YBuffer, yIndex);
157-
158-
float3 luminance = float3(yValue, yValue, yValue) / 255.0;
151+
const uint flippedY = OutputTextureHeight - 1 - id.y;
152+
const uint yIndex = flippedY * YRowStride + id.x;
159153
160-
// --- Post-processing (Sepia Tone) ---
161-
float4 color = float4(luminance.rgb, 1.0);
154+
const uint y = GetByteFromBuffer(YBuffer, yIndex);
155+
const float3 color = float3(y, y, y) / 255.0;
162156
163-
//Simple Sepia. Could also do a vignette, bloom, etc. here.
164-
float4 sepiaColor;
157+
float3 sepiaColor;
165158
sepiaColor.r = dot(color.rgb, float3(0.393, 0.769, 0.189));
166159
sepiaColor.g = dot(color.rgb, float3(0.349, 0.686, 0.168));
167160
sepiaColor.b = dot(color.rgb, float3(0.272, 0.534, 0.131));
168-
sepiaColor.a = 1.0;
169161
170-
OutputTexture[id.xy] = sepiaColor;
162+
OutputTexture[id.xy] = float4(sepiaColor, 1.0);
171163
}
172164
```

0 commit comments

Comments
 (0)