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