forked from StereoKit/StereoKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDemoPointCloud.cs
More file actions
188 lines (163 loc) · 5.63 KB
/
Copy pathDemoPointCloud.cs
File metadata and controls
188 lines (163 loc) · 5.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// SPDX-License-Identifier: MIT
// The authors below grant copyright rights under the MIT license:
// Copyright (c) 2019-2023 Nick Klingensmith
// Copyright (c) 2023 Qualcomm Technologies, Inc.
using StereoKit;
using System;
using System.Linq;
using System.Runtime.InteropServices;
public class PointCloud
{
// Each point becomes a camera-facing quad, so per-vertex cost is x4!
// 16 bytes to Vertex's 36, the shader derives corners from vertex id.
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct PointVert
{
[VertComponent(VertSemantic.Position, VertFmt.F32, 3)]
public Vec3 pos;
[VertComponent(VertSemantic.Color, VertFmt.U8Normalized, 4)]
public Color32 col;
public PointVert(Vec3 position, Color32 color) { pos = position; col = color; }
}
Material mat;
PointVert[] verts;
Mesh mesh;
bool distanceIndependant;
float pointSize;
public bool DistanceIndependantSize { get => distanceIndependant; set { mat["screen_size"] = value?1.0f:0.0f; distanceIndependant = value; } }
public float PointSize { get => pointSize; set { mat["point_size" ] = value; pointSize = value; } }
public PointCloud(float pointSizeMeters = 0.01f)
{
mat = new Material(Shader.FromFile("point_cloud.hlsl"));
PointSize = pointSizeMeters;
}
public PointCloud(float pointSizeMeters, Mesh fromMesh)
: this (pointSizeMeters) => SetPoints(fromMesh);
public PointCloud(float pointSizeMeters, Vertex[] fromVerts)
: this(pointSizeMeters) => SetPoints(fromVerts);
public PointCloud(float pointSizeMeters, Model fromModel)
: this(pointSizeMeters) => SetPoints(fromModel);
public void Draw(Matrix transform) => mesh?.Draw(mat, transform);
public void SetPoints(Vertex[] points)
{
if (verts == null)
verts = new PointVert[points.Length*4];
if (verts.Length != points.Length * 4)
{
Log.Err("You can re-use a point cloud, but the number of points should stay the same!");
return;
}
for (int i = 0; i < points.Length; i++)
{
Vertex p = points[i];
PointVert vert = new PointVert(p.pos, p.col);
int idx = i*4;
verts[idx ] = vert;
verts[idx+1] = vert;
verts[idx+2] = vert;
verts[idx+3] = vert;
}
if (mesh == null) {
uint[] inds = new uint[points.Length*6];
for (uint i = 0; i < points.Length; i++)
{
uint ind = i*6;
uint vert = i*4;
inds[ind ] = vert+2;
inds[ind+1] = vert+1;
inds[ind+2] = vert+0;
inds[ind+3] = vert+3;
inds[ind+4] = vert+2;
inds[ind+5] = vert+0;
}
mesh = new Mesh();
mesh.SetVerts(verts);
mesh.SetInds (inds);
}
else
{
mesh.SetVerts(verts);
}
}
public void SetPoints(Mesh fromMeshVerts)
=> SetPoints(fromMeshVerts.GetVerts());
public void SetPoints(Model fromModelVerts)
=> SetPoints(fromModelVerts.Visuals
.SelectMany(v => TransformVerts(v.ModelTransform, v.Mesh.GetVerts()))
.ToArray ());
private static Vertex[] TransformVerts(Matrix mat, Vertex[] verts)
{
for (int i = 0; i < verts.Length; i++)
verts[i].pos = mat.Transform(verts[i].pos);
return verts;
}
}
class DemoPointCloud : ITest
{
string title = "Point Clouds";
string description = "Point clouds are not a built-in feature of StereoKit, but it's not hard to do this yourself! Check out the code for this demo for a class that'll help you do this directly from data, or from a Model. It's also a nice example of pairing a custom vertex format with a custom shader, point clouds only need a fraction of the data regular meshes use!";
Pose cloudPose = (Matrix.T(0.2f,-0.1f,0) * Demo.contentPose).Pose;
float cloudScale = 1;
PointCloud cloud;
Pose settingsPose = (Matrix.T(-0.2f,0,0) * Demo.contentPose).Pose;
float pointSize = 0.01f;
public void Initialize()
{
// Generate colored points in the shape of a UV sphere! Vertex is
// just a convenient carrier here, see PointCloud.SetPoints.
const int xCount = 24;
const int yCount = 16;
Vertex[] points = new Vertex[xCount*yCount];
for (int y = 0; y < yCount; y++)
{
for (int x = 0; x < xCount; x++)
{
float u = x / (float)xCount;
float v = y / (float)yCount;
int i = x + y * xCount;
float theta = u * (float)Math.PI * 2.0f;
float phi = (v - 0.5f) * (float)Math.PI;
float c = SKMath.Cos(phi);
points[i].pos = V.XYZ(c * SKMath.Cos(theta), SKMath.Sin(phi), c * SKMath.Sin(theta))*0.2f;
points[i].col = Color.HSV(u, v, 1).ToLinear();
}
}
// Make a point cloud out of the points!
cloud = new PointCloud(pointSize, points);
cloudScale = 1;
}
public void Shutdown()
{
}
public void Step()
{
cloud.Draw(cloudPose.ToMatrix(cloudScale));
UI.WindowBegin("Point Cloud", ref settingsPose);
{
if (UI.Button("Load Model"))
{
Platform.FilePicker(PickerMode.Open, (file) => {
Model model = Model.FromFile(file);
cloud = new PointCloud(pointSize, model);
cloudScale = 0.5f / model.Bounds.dimensions.Length;
}, null, Assets.ModelFormats);
}
UI.HSlider("Cloud Scale", ref cloudScale, 0.001f, 2, 0);
UI.PanelBegin();
UI.Label("Point Cloud Settings");
UI.HSeparator();
UI.Label("Mode:", V.XY(.04f, 0));
UI.SameLine();
if (UI.Radio("Fixed", cloud.DistanceIndependantSize)) cloud.DistanceIndependantSize = true;
UI.SameLine();
if (UI.Radio("Perspective", !cloud.DistanceIndependantSize)) cloud.DistanceIndependantSize = false;
UI.Label("Size:", V.XY(.04f, 0));
UI.SameLine();
if (UI.HSlider("Point Size", ref pointSize, 0.001f, 0.1f, 0))
cloud.PointSize = pointSize;
UI.PanelEnd();
}
UI.WindowEnd();
Demo.ShowSummary(title, description, new Bounds(V.XY0(0,-0.1f), V.XYZ(.8f, .5f, 0.5f)));
}
}