Skip to content

Commit 081cb87

Browse files
authored
Merge pull request #114741 from FlorianBorn71/CppCodeExamples
Add C++ flavor to all code samples
2 parents 7023b9b + b38e599 commit 081cb87

18 files changed

+631
-63
lines changed

articles/remote-rendering/concepts/components.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,20 @@ lightComponent.Destroy();
3434
lightComponent = null;
3535
```
3636

37+
```cpp
38+
// create a point light component
39+
ApiHandle<AzureSession> session = GetCurrentlyConnectedSession();
40+
41+
ApiHandle<PointLightComponent> lightComponent = session->Actions()->CreateComponent(ObjectType::PointLightComponent, ownerEntity)->as<PointLightComponent>();
42+
43+
// ...
44+
45+
// destroy the component
46+
lightComponent->Destroy();
47+
lightComponent = nullptr;
48+
```
49+
50+
3751
A component is attached to an entity at creation time. It cannot be moved to another entity afterwards. Components are explicitly deleted with `Component.Destroy()` or automatically when the component's owner entity is destroyed.
3852
3953
Only one instance of each component type may be added to an entity at a time.

articles/remote-rendering/concepts/entities.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ CutPlaneComponent cutplane = (CutPlaneComponent)entity.FindComponentOfType(Objec
3636
CutPlaneComponent cutplane = entity.FindComponentOfType<CutPlaneComponent>();
3737
```
3838

39+
```cpp
40+
ApiHandle<CutPlaneComponent> cutplane = entity->FindComponentOfType(ObjectType::CutPlaneComponent)->as<CutPlaneComponent>();
41+
42+
// or alternatively:
43+
ApiHandle<CutPlaneComponent> cutplane = *entity->FindComponentOfType<CutPlaneComponent>();
44+
```
45+
3946
### Querying transforms
4047
4148
Transform queries are synchronous calls on the object. It is important to note that transforms queried through the API are local space transforms, relative to the object's parent. Exceptions are root objects, for which local space and world space are identical.
@@ -49,6 +56,13 @@ Double3 translation = entity.Position;
4956
Quaternion rotation = entity.Rotation;
5057
```
5158

59+
```cpp
60+
// local space transform of the entity
61+
Double3 translation = *entity->Position();
62+
Quaternion rotation = *entity->Rotation();
63+
```
64+
65+
5266
### Querying spatial bounds
5367

5468
Bounds queries are asynchronous calls that operate on a full object hierarchy, using one entity as a root. See the dedicated chapter about [object bounds](object-bounds.md).
@@ -74,6 +88,21 @@ metaDataQuery.Completed += (MetadataQueryAsync query) =>
7488
};
7589
```
7690

91+
```cpp
92+
ApiHandle<MetadataQueryAsync> metaDataQuery = *entity->QueryMetaDataAsync();
93+
metaDataQuery->Completed([](const ApiHandle<MetadataQueryAsync>& query)
94+
{
95+
if (query->IsRanToCompletion())
96+
{
97+
ApiHandle<ObjectMetaData> metaData = *query->Result();
98+
ApiHandle<ObjectMetaDataEntry> entry = *metaData->GetMetadataByName("MyInt64Value");
99+
int64_t intValue = *entry->AsInt64();
100+
101+
// ...
102+
}
103+
});
104+
```
105+
77106
The query will succeed even if the object does not hold any metadata.
78107
79108
## Next steps

articles/remote-rendering/concepts/graphics-bindings.md

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,26 +30,46 @@ The only other relevant part for Unity is accessing the [basic binding](#access)
3030

3131
To select a graphics binding, take the following two steps: First, the graphics binding has to be statically initialized when the program is initialized:
3232

33-
``` cs
33+
```cs
3434
RemoteRenderingInitialization managerInit = new RemoteRenderingInitialization;
3535
managerInit.graphicsApi = GraphicsApiType.WmrD3D11;
3636
managerInit.connectionType = ConnectionType.General;
3737
managerInit.right = ///...
3838
RemoteManagerStatic.StartupRemoteRendering(managerInit);
3939
```
4040

41+
```cpp
42+
RemoteRenderingInitialization managerInit;
43+
managerInit.graphicsApi = GraphicsApiType::WmrD3D11;
44+
managerInit.connectionType = ConnectionType::General;
45+
managerInit.right = ///...
46+
StartupRemoteRendering(managerInit); // static function in namespace Microsoft::Azure::RemoteRendering
47+
```
48+
4149
The call above is necessary to initialize Azure Remote Rendering into the holographic APIs. This function must be called before any holographic API is called and before any other Remote Rendering APIs are accessed. Similarly, the corresponding de-init function `RemoteManagerStatic.ShutdownRemoteRendering();` should be called after no holographic APIs are being called anymore.
4250
4351
## <span id="access">Accessing graphics binding
4452
4553
Once a client is set up, the basic graphics binding can be accessed with the `AzureSession.GraphicsBinding` getter. As an example, the last frame statistics can be retrieved like this:
4654
47-
``` cs
48-
AzureSession currentSesson = ...;
49-
if (currentSesson.GraphicsBinding)
55+
```cs
56+
AzureSession currentSession = ...;
57+
if (currentSession.GraphicsBinding)
58+
{
59+
FrameStatistics frameStatistics;
60+
if (currentSession.GraphicsBinding.GetLastFrameStatistics(out frameStatistics) == Result.Success)
61+
{
62+
...
63+
}
64+
}
65+
```
66+
67+
```cpp
68+
ApiHandle<AzureSession> currentSession = ...;
69+
if (ApiHandle<GraphicsBinding> binding = currentSession->GetGraphicsBinding())
5070
{
5171
FrameStatistics frameStatistics;
52-
if (session.GraphicsBinding.GetLastFrameStatistics(out frameStatistics) == Result.Success)
72+
if (*binding->GetLastFrameStatistics(&frameStatistics) == Result::Success)
5373
{
5474
...
5575
}
@@ -69,26 +89,43 @@ There are two things that need to be done to use the WMR binding:
6989

7090
#### Inform Remote Rendering of the used coordinate system
7191

72-
``` cs
73-
AzureSession currentSesson = ...;
92+
```cs
93+
AzureSession currentSession = ...;
7494
IntPtr ptr = ...; // native pointer to ISpatialCoordinateSystem
7595
GraphicsBindingWmrD3d11 wmrBinding = (currentSession.GraphicsBinding as GraphicsBindingWmrD3d11);
76-
if (binding.UpdateUserCoordinateSystem(ptr) == Result.Success)
96+
if (wmrBinding.UpdateUserCoordinateSystem(ptr) == Result.Success)
7797
{
7898
...
7999
}
80100
```
81101

102+
```cpp
103+
ApiHandle<AzureSession> currentSession = ...;
104+
void* ptr = ...; // native pointer to ISpatialCoordinateSystem
105+
ApiHandle<GraphicsBindingWmrD3d11> wmrBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingWmrD3d11>();
106+
if (*wmrBinding->UpdateUserCoordinateSystem(ptr) == Result::Success)
107+
{
108+
//...
109+
}
110+
```
111+
112+
82113
Where the above `ptr` must be a pointer to a native `ABI::Windows::Perception::Spatial::ISpatialCoordinateSystem` object that defines the world space coordinate system in which coordinates in the API are expressed in.
83114
84115
#### Render remote image
85116
86117
At the start of each frame the remote frame needs to be rendered into the back buffer. This is done by calling `BlitRemoteFrame`, which will fill both color and depth information into the currently bound render target. Thus it is important that this is done after binding the back buffer as a render target.
87118
88-
``` cs
89-
AzureSession currentSesson = ...;
119+
```cs
120+
AzureSession currentSession = ...;
90121
GraphicsBindingWmrD3d11 wmrBinding = (currentSession.GraphicsBinding as GraphicsBindingWmrD3d11);
91-
binding.BlitRemoteFrame();
122+
wmrBinding.BlitRemoteFrame();
123+
```
124+
125+
```cpp
126+
ApiHandle<AzureSession> currentSession = ...;
127+
ApiHandle<GraphicsBindingWmrD3d11> wmrBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingWmrD3d11>();
128+
wmrBinding->BlitRemoteFrame();
92129
```
93130

94131
### Simulation
@@ -101,8 +138,8 @@ The setup is a bit more involved and works as follows:
101138
Remote and local content needs to be rendered to an offscreen color / depth render target called 'proxy' using
102139
the proxy camera data provided by the `GraphicsBindingSimD3d11.Update` function. The proxy must match the resolution of the back buffer. Once a session is ready, `GraphicsBindingSimD3d11.InitSimulation` needs to be called before connecting to it:
103140

104-
``` cs
105-
AzureSession currentSesson = ...;
141+
```cs
142+
AzureSession currentSession = ...;
106143
IntPtr d3dDevice = ...; // native pointer to ID3D11Device
107144
IntPtr color = ...; // native pointer to ID3D11Texture2D
108145
IntPtr depth = ...; // native pointer to ID3D11Texture2D
@@ -113,6 +150,18 @@ GraphicsBindingSimD3d11 simBinding = (currentSession.GraphicsBinding as Graphics
113150
simBinding.InitSimulation(d3dDevice, depth, color, refreshRate, flipBlitRemoteFrameTextureVertically, flipReprojectTextureVertically);
114151
```
115152

153+
```cpp
154+
ApiHandle<AzureSession> currentSession = ...;
155+
void* d3dDevice = ...; // native pointer to ID3D11Device
156+
void* color = ...; // native pointer to ID3D11Texture2D
157+
void* depth = ...; // native pointer to ID3D11Texture2D
158+
float refreshRate = 60.0f; // Monitor refresh rate up to 60hz.
159+
bool flipBlitRemoteFrameTextureVertically = false;
160+
bool flipReprojectTextureVertically = false;
161+
ApiHandle<GraphicsBindingSimD3d11> simBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingSimD3d11>();
162+
simBinding->InitSimulation(d3dDevice, depth, color, refreshRate, flipBlitRemoteFrameTextureVertically, flipReprojectTextureVertically);
163+
```
164+
116165
The init function needs to be provided with pointers to the native d3d-device as well as to the color and depth texture of the proxy render target. Once initialized, `AzureSession.ConnectToRuntime` and `DisconnectFromRuntime` can be called multiple times but when switching to a different session, `GraphicsBindingSimD3d11.DeinitSimulation` needs to be called first on the old session before `GraphicsBindingSimD3d11.InitSimulation` can be called on another session.
117166
118167
#### Render loop update
@@ -124,8 +173,8 @@ If the returned proxy update `SimulationUpdate.frameId` is null, there is no rem
124173
1. The application should now bind the proxy render target and call `GraphicsBindingSimD3d11.BlitRemoteFrameToProxy`. This will fill the remote color and depth information into the proxy render target. Any local content can now be rendered onto the proxy using the proxy camera transform.
125174
1. Next, the back buffer needs to be bound as a render target and `GraphicsBindingSimD3d11.ReprojectProxy` called at which point the back buffer can be presented.
126175
127-
``` cs
128-
AzureSession currentSesson = ...;
176+
```cs
177+
AzureSession currentSession = ...;
129178
GraphicsBindingSimD3d11 simBinding = (currentSession.GraphicsBinding as GraphicsBindingSimD3d11);
130179
SimulationUpdate update = new SimulationUpdate();
131180
// Fill out camera data with current camera data
@@ -150,6 +199,33 @@ else
150199
}
151200
```
152201

202+
```cpp
203+
ApiHandle<AzureSession> currentSession;
204+
ApiHandle<GraphicsBindingSimD3d11> simBinding = currentSession->GetGraphicsBinding().as<GraphicsBindingSimD3d11>();
205+
206+
SimulationUpdate update;
207+
// Fill out camera data with current camera data
208+
...
209+
SimulationUpdate proxyUpdate;
210+
simBinding->Update(update, &proxyUpdate);
211+
// Is the frame data valid?
212+
if (proxyUpdate.frameId != 0)
213+
{
214+
// Bind proxy render target
215+
simBinding->BlitRemoteFrameToProxy();
216+
// Use proxy camera data to render local content
217+
...
218+
// Bind back buffer
219+
simBinding->ReprojectProxy();
220+
}
221+
else
222+
{
223+
// Bind back buffer
224+
// Use current camera data to render local content
225+
...
226+
}
227+
```
228+
153229
## Next steps
154230
155231
* [Tutorial: Setting up a Unity project from scratch](../tutorials/unity/project-setup.md)

articles/remote-rendering/concepts/materials.md

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ During conversion multiple materials with the same properties and textures are a
3838

3939
All materials provided by the API derive from the base class `Material`. Their type can be queried through `Material.MaterialSubType` or by casting them directly:
4040

41-
``` cs
41+
```cs
4242
void SetMaterialColorToGreen(Material material)
4343
{
4444
if (material.MaterialSubType == MaterialType.Color)
@@ -49,15 +49,34 @@ void SetMaterialColorToGreen(Material material)
4949
}
5050

5151
PbrMaterial pbrMat = material as PbrMaterial;
52-
if( pbrMat!= null )
52+
if (pbrMat != null)
5353
{
54-
PbrMaterial pbrMaterial = material.PbrMaterial.Value;
55-
pbrMaterial.AlbedoColor = new Color4(0, 1, 0, 1);
54+
pbrMat.AlbedoColor = new Color4(0, 1, 0, 1);
5655
return;
5756
}
5857
}
5958
```
6059

60+
```cpp
61+
void SetMaterialColorToGreen(ApiHandle<Material> material)
62+
{
63+
if (*material->MaterialSubType() == MaterialType::Color)
64+
{
65+
ApiHandle<ColorMaterial> colorMaterial = material.as<ColorMaterial>();
66+
colorMaterial->AlbedoColor({ 0, 1, 0, 1 });
67+
return;
68+
}
69+
70+
if (*material->MaterialSubType() == MaterialType::Pbr)
71+
{
72+
ApiHandle<PbrMaterial> pbrMat = material.as<PbrMaterial>();
73+
pbrMat->AlbedoColor({ 0, 1, 0, 1 });
74+
return;
75+
}
76+
}
77+
```
78+
79+
6180
## Next steps
6281
6382
* [PBR materials](../overview/features/pbr-materials.md)

articles/remote-rendering/concepts/models.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,28 @@ async void LoadModel(AzureSession session, Entity modelParent, string modelUri)
5353
}
5454
```
5555

56+
```cpp
57+
ApiHandle<LoadModelAsync> LoadModel(ApiHandle<AzureSession> session, ApiHandle<Entity> modelParent, std::string modelUri)
58+
{
59+
LoadModelFromSASParams modelParams;
60+
modelParams.ModelUrl = modelUri;
61+
modelParams.Parent = modelParent;
62+
63+
ApiHandle<LoadModelAsync> loadOp = *session->Actions()->LoadModelFromSASAsync(modelParams);
64+
65+
loadOp->Completed([](const ApiHandle<LoadModelAsync>& async)
66+
{
67+
printf("Loading: finished.");
68+
});
69+
loadOp->ProgressUpdated([](float progress)
70+
{
71+
printf("Loading: %.1f%%", progress*100.f);
72+
});
73+
74+
return loadOp;
75+
}
76+
```
77+
5678
If you want to load a model by directly using its blob storage parameters, use code similar to the following snippet:
5779
5880
```csharp
@@ -72,6 +94,20 @@ async void LoadModel(AzureSession session, Entity modelParent, string storageAcc
7294
}
7395
```
7496

97+
```cpp
98+
ApiHandle<LoadModelAsync> LoadModel(ApiHandle<AzureSession> session, ApiHandle<Entity> modelParent, std::string storageAccount, std::string containerName, std::string assetFilePath)
99+
{
100+
LoadModelParams modelParams;
101+
modelParams.Parent = modelParent;
102+
modelParams.Blob.StorageAccountName = std::move(storageAccount);
103+
modelParams.Blob.BlobContainerName = std::move(containerName);
104+
modelParams.Blob.AssetPath = std::move(assetFilePath);
105+
106+
ApiHandle<LoadModelAsync> loadOp = *session->Actions()->LoadModelAsync(modelParams);
107+
// ... (identical to the SAS URI snippet above)
108+
}
109+
```
110+
75111
Afterwards you can traverse the entity hierarchy and modify the entities and components. Loading the same model multiple times creates multiple instances, each with their own copy of the entity/component structure. Since meshes, materials, and textures are [shared resources](../concepts/lifetime.md), their data will not be loaded again, though. Therefore instantiating a model more than once incurs relatively little memory overhead.
76112
77113
> [!CAUTION]

articles/remote-rendering/concepts/object-bounds.md

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ It's possible to compute the bounds of an entire object hierarchy this way, but
1919

2020
A better way is to call `QueryLocalBoundsAsync` or `QueryWorldBoundsAsync` on an entity. The computation is then offloaded to the server and returned with minimal delay.
2121

22-
``` cs
22+
```cs
2323
private BoundsQueryAsync _boundsQuery = null;
2424

2525
public void GetBounds(Entity entity)
@@ -37,6 +37,22 @@ public void GetBounds(Entity entity)
3737
}
3838
```
3939

40+
```cpp
41+
void GetBounds(ApiHandle<Entity> entity)
42+
{
43+
ApiHandle<BoundsQueryAsync> boundsQuery = *entity->QueryWorldBoundsAsync();
44+
boundsQuery->Completed([](ApiHandle<BoundsQueryAsync> bounds)
45+
{
46+
if (bounds->IsRanToCompletion())
47+
{
48+
Double3 aabbMin = bounds->Result()->min;
49+
Double3 aabbMax = bounds->Result()->max;
50+
// ...
51+
}
52+
});
53+
}
54+
```
55+
4056
## Next steps
4157
4258
* [Spatial queries](../overview/features/spatial-queries.md)

articles/remote-rendering/concepts/sessions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ You can [extend the lease time](../how-tos/session-rest-api.md#update-a-session)
7777

7878
The code below shows a simple implementation of starting a session, waiting for the *ready* state, connecting, and then disconnecting and shutting down again.
7979

80-
``` cs
80+
```cs
8181
RemoteRenderingInitialization init = new RemoteRenderingInitialization();
8282
// fill out RemoteRenderingInitialization parameters...
8383

0 commit comments

Comments
 (0)