Cesium for Unity 1.20.0
Loading...
Searching...
No Matches
CesiumPointCloudRenderer.cs
Go to the documentation of this file.
1using UnityEngine;
2using UnityEngine.Rendering;
3
4#if ENABLE_XR_MODULE
5using UnityEngine.XR;
6#endif
7
8#if UNITY_EDITOR
9using UnityEditor;
10#endif
11
12namespace CesiumForUnity
13{
14 internal struct Cesium3DTileInfo
15 {
16 public bool usesAdditiveRefinement;
17 public float geometricError;
18 public Vector3 dimensions;
19 public bool isTranslucent;
20 }
21
22 [ExecuteInEditMode]
23 [AddComponentMenu("")]
24 internal class CesiumPointCloudRenderer : MonoBehaviour
25 {
26 private Cesium3DTileset _tileset;
27
28 private Mesh _mesh;
29 private MeshFilter _meshFilter;
30 private MeshRenderer _meshRenderer;
31 private GraphicsBuffer _meshVertexBuffer;
32
33 private int _pointCount = 0;
34 private Material _pointMaterial;
35
36 private Bounds _bounds;
37
38 private Vector4 _attenuationParameters;
39 private Vector4 _constantColor;
40
41 private Cesium3DTileInfo _tileInfo;
42
43 public Cesium3DTileInfo tileInfo
44 {
45 set => this._tileInfo = value;
46 }
47
48 void OnEnable()
49 {
50 this._tileset = this.gameObject.GetComponentInParent<Cesium3DTileset>();
51
52 this._meshFilter = this.gameObject.GetComponent<MeshFilter>();
53 this._mesh = this._meshFilter.sharedMesh;
54 this._meshRenderer = this.gameObject.GetComponent<MeshRenderer>();
55
56 this._pointCount = this._mesh.vertexCount;
57 this._pointMaterial = UnityEngine.Object.Instantiate(
58 Resources.Load<Material>("CesiumPointCloudShadingMaterial"));
59
60 GraphicsBuffer sourceBuffer = this._mesh.GetVertexBuffer(0);
61
62 bool usingDirect11 = SystemInfo.graphicsDeviceType == GraphicsDeviceType.Direct3D11;
63 if (usingDirect11)
64 {
65 this._meshVertexBuffer = new GraphicsBuffer(
66 GraphicsBuffer.Target.Structured | GraphicsBuffer.Target.CopyDestination,
67 sourceBuffer.count,
68 sourceBuffer.stride);
69 Graphics.CopyBuffer(sourceBuffer, this._meshVertexBuffer);
70 sourceBuffer.Release();
71 } else
72 {
73 this._mesh.vertexBufferTarget |= GraphicsBuffer.Target.Structured;
74 this._meshVertexBuffer = sourceBuffer;
75 }
76
77 if (this._mesh.HasVertexAttribute(VertexAttribute.Color))
78 {
79 this._pointMaterial.EnableKeyword("HAS_POINT_COLORS");
80 }
81 else
82 {
83 Material material = this._meshRenderer.sharedMaterial;
84
85 if (material.HasColor("_Color"))
86 {
87 this._constantColor = material.color;
88 }
89 else if (material.HasVector("_baseColorFactor"))
90 {
91 this._constantColor = material.GetVector("_baseColorFactor");
92 }
93 else
94 {
95 this._constantColor = Color.gray;
96 }
97 }
98
99 if (this._mesh.HasVertexAttribute(VertexAttribute.Normal))
100 {
101 this._pointMaterial.EnableKeyword("HAS_POINT_NORMALS");
102 }
103
104#if ENABLE_XR_MODULE
105 if (XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePassInstanced ||
106 XRSettings.stereoRenderingMode == XRSettings.StereoRenderingMode.SinglePassMultiview)
107 {
108 this._pointMaterial.EnableKeyword("INSTANCING_ON");
109 }
110#endif
111 }
112
113 private float GetGeometricError(CesiumPointCloudShading pointCloudShading)
114 {
115 float geometricError = this._tileInfo.geometricError;
116 if (geometricError > 0.0f)
117 {
118 return geometricError;
119 }
120
121 if (pointCloudShading.baseResolution > 0.0f)
122 {
123 return pointCloudShading.baseResolution;
124 }
125
126 // Estimate the geometric error.
127 Vector3 dimensions = this._tileInfo.dimensions;
128 float volume = dimensions.x * dimensions.y * dimensions.z;
129 return Mathf.Pow(volume / this._pointCount, 1.0f / 3.0f);
130 }
131
132 private void UpdateAttenuationParameters()
133 {
134 float maximumPointSize =
135 this._tileInfo.usesAdditiveRefinement ?
136 5.0f :
137 this._tileset.maximumScreenSpaceError;
138
139 CesiumPointCloudShading pointCloudShading = this._tileset.pointCloudShading;
140
141 if (pointCloudShading.maximumAttenuation > 0.0f)
142 {
143 maximumPointSize = this._tileset.pointCloudShading.maximumAttenuation;
144 }
145
146 if (Screen.dpi > 0)
147 {
148 // Approximation of device pixel ratio
149 maximumPointSize *= Screen.dpi / 150;
150 }
151
152 float geometricError = this.GetGeometricError(pointCloudShading);
153 geometricError *= pointCloudShading.geometricErrorScale;
154
155 // Depth multiplier
156 Camera camera = Camera.main;
157 float sseDenominator = 2.0f * Mathf.Tan(0.5f * Mathf.Deg2Rad * camera.fieldOfView);
158 float depthMultplier = camera.scaledPixelHeight / sseDenominator;
159
160 this._attenuationParameters =
161 new Vector4(maximumPointSize, geometricError, depthMultplier, 0);
162 }
163
164 private Vector3[] positionsScratch = new Vector3[3];
165
166 private void UpdateBounds()
167 {
168 Matrix4x4 transformMatrix = this.gameObject.transform.localToWorldMatrix;
169
170 Bounds localBounds = this._mesh.bounds;
171 positionsScratch[0] = localBounds.center;
172 positionsScratch[1] = localBounds.min;
173 positionsScratch[2] = localBounds.max;
174
175 this._bounds = GeometryUtility.CalculateBounds(positionsScratch, transformMatrix);
176 }
177
178 private void DestroyResources()
179 {
180 if (this._meshVertexBuffer != null)
181 {
182 this._meshVertexBuffer.Release();
183 this._meshVertexBuffer = null;
184 }
185
186 if (this._pointMaterial != null)
187 {
188#if UNITY_EDITOR
189 if (!EditorApplication.isPlaying) {
190 DestroyImmediate(this._pointMaterial);
191 return;
192 }
193#endif
194 Destroy(this._pointMaterial);
195 }
196 }
197
198 private void UpdateMaterial()
199 {
200 this._pointMaterial.SetBuffer("_inPoints", this._meshVertexBuffer);
201 this._pointMaterial.SetMatrix("_worldTransform", this.gameObject.transform.localToWorldMatrix);
202 this._pointMaterial.SetVector("_attenuationParameters", this._attenuationParameters);
203 this._pointMaterial.SetVector("_constantColor", this._constantColor);
204
205 if (this._tileInfo.isTranslucent || this._constantColor.w < 1.0f)
206 {
207 this._pointMaterial.SetOverrideTag("RenderType", "Transparent");
208 this._pointMaterial.renderQueue = (int)RenderQueue.Transparent;
209 this._pointMaterial.SetInt("_SrcBlend", (int)BlendMode.SrcAlpha);
210 this._pointMaterial.SetInt("_DstBlend", (int)BlendMode.OneMinusSrcAlpha);
211 }
212 else
213 {
214 this._pointMaterial.SetInt("_SrcBlend", (int)BlendMode.One);
215 this._pointMaterial.SetInt("_DstBlend", (int)BlendMode.Zero);
216 }
217 }
218
219 private void DrawPointsWithAttenuation()
220 {
221 this.UpdateBounds();
222 this.UpdateAttenuationParameters();
223 this.UpdateMaterial();
224
225 Graphics.DrawProcedural(
226 this._pointMaterial,
227 this._bounds,
228 MeshTopology.Triangles,
229 this._pointCount * 6,
230 1);
231 }
232
233 void Update()
234 {
235 CesiumPointCloudShading pointCloudShading = this._tileset.pointCloudShading;
236 if (pointCloudShading != null && pointCloudShading.attenuation)
237 {
238 this.DrawPointsWithAttenuation();
239 this._meshRenderer.enabled = false;
240 }
241 else
242 {
243 this._meshRenderer.enabled = true;
244 }
245 }
246
247 void OnDisable()
248 {
249 this.DestroyResources();
250 }
251 }
252}