Tanoda
LeapMesherBase.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
9using System;
10using System.Collections.Generic;
11using UnityEngine;
12using UnityEngine.Rendering;
13using UnityEngine.Assertions;
14#if UNITY_EDITOR
15using UnityEditor;
16using UnityEditor.Sprites;
17#endif
18using Leap.Unity.Query;
20
22
23 public abstract class LeapMesherBase : LeapRenderingMethod<LeapMeshGraphicBase>,
24 ISupportsFeature<LeapTextureFeature>,
25 ISupportsFeature<LeapSpriteFeature>,
26 ISupportsFeature<LeapRuntimeTintFeature>,
27 ISupportsFeature<LeapBlendShapeFeature>,
28 ISupportsFeature<CustomFloatChannelFeature>,
29 ISupportsFeature<CustomVectorChannelFeature>,
30 ISupportsFeature<CustomColorChannelFeature>,
31 ISupportsFeature<CustomMatrixChannelFeature> {
32
33 [Serializable]
34 private class JaggedRects : JaggedArray<Rect> {
35 public JaggedRects(int length) : base(length) { }
36 }
37
38 public const string MESH_ASSET_NAME = "Mesh Data";
39 public const string TEXTURE_ASSET_NAME = "Texture Data";
40
41 public const string UV_0_FEATURE = LeapGraphicRenderer.FEATURE_PREFIX + "VERTEX_UV_0";
42 public const string UV_1_FEATURE = LeapGraphicRenderer.FEATURE_PREFIX + "VERTEX_UV_1";
43 public const string UV_2_FEATURE = LeapGraphicRenderer.FEATURE_PREFIX + "VERTEX_UV_2";
44 public const string UV_3_FEATURE = LeapGraphicRenderer.FEATURE_PREFIX + "VERTEX_UV_3";
45 public const string COLORS_FEATURE = LeapGraphicRenderer.FEATURE_PREFIX + "VERTEX_COLORS";
46 public const string NORMALS_FEATURE = LeapGraphicRenderer.FEATURE_PREFIX + "VERTEX_NORMALS";
47
48 public static string GetUvFeature(UVChannelFlags flags) {
49 switch (flags) {
50 case UVChannelFlags.UV0:
51 return UV_0_FEATURE;
52 case UVChannelFlags.UV1:
53 return UV_1_FEATURE;
54 case UVChannelFlags.UV2:
55 return UV_2_FEATURE;
56 case UVChannelFlags.UV3:
57 return UV_3_FEATURE;
58 default:
59 throw new InvalidOperationException();
60 }
61 }
62
63 public Action<Texture2D, AtlasUvs> OnPostProcessAtlas;
64
65 #region INSPECTOR FIELDS
66 //BEGIN MESH SETTINGS
67 [Tooltip("Should this renderer include uv0 coordinates in the generated meshes.")]
68 [EditTimeOnly, SerializeField, HideInInspector]
69 private bool _useUv0 = true;
70
71 [Tooltip("Should this renderer include uv1 coordinates in the generated meshes.")]
72 [EditTimeOnly, SerializeField, HideInInspector]
73 private bool _useUv1 = false;
74
75 [Tooltip("Should this renderer include uv2 coordinates in the generated meshes.")]
76 [EditTimeOnly, SerializeField, HideInInspector]
77 private bool _useUv2 = false;
78
79 [Tooltip("Should this renderer include uv3 coordinates in the generated meshes.")]
80 [EditTimeOnly, SerializeField, HideInInspector]
81 private bool _useUv3 = false;
82
83 [Tooltip("Should this renderer include vertex colors in the generated meshes.")]
84 [EditTimeOnly, SerializeField, HideInInspector]
85 private bool _useColors = true;
86
87 [Tooltip("Multiply all vertex colors for all graphics by this color.")]
88 [EditTimeOnly, SerializeField, HideInInspector]
89 private Color _bakedTint = Color.white;
90
91 [Tooltip("Should this renderer include normals in the generated meshes.")]
92 [EditTimeOnly, SerializeField, HideInInspector]
93 private bool _useNormals = false;
94
95 //BEGIN RENDERING SETTINGS
96 [Tooltip("Shader to use to display the graphics.")]
97 [EditTimeOnly, SerializeField]
98 protected Shader _shader;
99
100 [Tooltip("The layer that the visual representation of the graphics. It is independent from the layer the graphics occupy.")]
101 [SerializeField]
102 private SingleLayer _visualLayer = 0;
103
104 [Tooltip("The atlas combines multiple textures into a single texture automatically, allowing each graphic to have a different " +
105 "texture but still allow the graphics as a whole to render efficiently.")]
106 [SerializeField]
107 private AtlasBuilder _atlas = new AtlasBuilder();
108 #endregion
109
111
112 //Internal cache of requirements
113 protected bool _doesRequireColors;
114 protected bool _doesRequireNormals;
115 protected bool _doesRequireVertInfo;
116 protected List<UVChannelFlags> _requiredUvChannels = new List<UVChannelFlags>();
117
118 //Feature lists
119 protected List<LeapTextureFeature> _textureFeatures = new List<LeapTextureFeature>();
120 protected List<LeapSpriteFeature> _spriteFeatures = new List<LeapSpriteFeature>();
121 protected List<LeapRuntimeTintFeature> _tintFeatures = new List<LeapRuntimeTintFeature>();
122 protected List<LeapBlendShapeFeature> _blendShapeFeatures = new List<LeapBlendShapeFeature>();
123 protected List<CustomFloatChannelFeature> _floatChannelFeatures = new List<CustomFloatChannelFeature>();
124 protected List<CustomVectorChannelFeature> _vectorChannelFeatures = new List<CustomVectorChannelFeature>();
125 protected List<CustomColorChannelFeature> _colorChannelFeatures = new List<CustomColorChannelFeature>();
126 protected List<CustomMatrixChannelFeature> _matrixChannelFeatures = new List<CustomMatrixChannelFeature>();
127
128 //### Generated Data ###
129 [SerializeField]
130 protected Material _material;
131 [SerializeField]
133 [SerializeField]
135
136 //#### Sprite/Texture Remapping ####
137 [SerializeField]
138 private AtlasUvs _atlasUvs = default(AtlasUvs);
139 [NonSerialized]
140 protected MaterialPropertyBlock _spriteTextureBlock;
141
142 //#### Tinting ####
143 protected const string TINTS_PROPERTY = LeapGraphicRenderer.PROPERTY_PREFIX + "Tints";
144 protected List<Vector4> _tintColors = new List<Vector4>();
145
146 //#### Blend Shapes ####
147 protected const string BLEND_SHAPE_AMOUNTS_PROPERTY = LeapGraphicRenderer.PROPERTY_PREFIX + "BlendShapeAmounts";
148 protected List<float> _blendShapeAmounts = new List<float>();
149
150 //#### Custom Channels ####
151 public const string CUSTOM_CHANNEL_KEYWORD = LeapGraphicRenderer.FEATURE_PREFIX + "ENABLE_CUSTOM_CHANNELS";
152 protected List<float> _customFloatChannelData = new List<float>();
153 protected List<Vector4> _customVectorChannelData = new List<Vector4>();
154 protected List<Color> _customColorChannelData = new List<Color>();
155 protected List<Matrix4x4> _customMatrixChannelData = new List<Matrix4x4>();
156
157 public Material material {
158 get {
159 return _material;
160 }
161 }
162
163#if UNITY_EDITOR
164 public virtual bool IsAtlasDirty {
165 get {
166 return _atlas.isDirty;
167 }
168 }
169
170 public virtual void RebuildAtlas(ProgressBar progress) {
171 Undo.RecordObject(renderer, "Rebuilt atlas");
172
173 progress.Begin(2, "Rebuilding Atlas", "", () => {
174 Texture2D[] packedTextures;
175
176 group.GetSupportedFeatures(_textureFeatures);
178 _atlas.RebuildAtlas(progress, out packedTextures, out _atlasUvs);
179
180 progress.Begin(3, "", "", () => {
181 progress.Step("Post-Process Atlas");
182 if (OnPostProcessAtlas != null) {
183 for (int i = 0; i < packedTextures.Length; i++) {
184 try {
185 OnPostProcessAtlas(packedTextures[i], _atlasUvs);
186 } catch (Exception e) {
187 Debug.LogException(e);
188 }
189 }
190 }
191 progress.Step("Saving To Asset");
192
193 //Now that all post-process has finished, finally mark no longer readable
194 //Don't change the mipmaps because a post process might have uploaded custom data
195 for (int i = 0; i < packedTextures.Length; i++) {
196 packedTextures[i].Apply(updateMipmaps: false, makeNoLongerReadable: true);
197 }
198
199 _packedTextures.AssignTextures(packedTextures, _textureFeatures.Query().Select(f => f.propertyName).ToArray());
200
201 progress.Begin(_textureFeatures.Count, "", "Loading Into Scene", () => {
202 foreach (var feature in _textureFeatures) {
203 _material.SetTexture(feature.propertyName, _packedTextures.GetTexture(feature.propertyName));
204 }
205 });
206 });
207 });
208 }
209#endif
210
211 public virtual void GetSupportInfo(List<LeapTextureFeature> features, List<SupportInfo> info) {
212 for (int i = 0; i < features.Count; i++) {
213 var feature = features[i];
214 if (group.features.Query().OfType<LeapSpriteFeature>().Any(s => s.channel == feature.channel)) {
215 info[i] = info[i].OrWorse(SupportInfo.Error("Texture features cannot currently share uvs with sprite features."));
216 }
217 }
218 }
219
220 public virtual void GetSupportInfo(List<LeapSpriteFeature> features, List<SupportInfo> info) {
221 SupportUtil.OnlySupportFirstFeature<LeapSpriteFeature>(info);
222
223#if UNITY_EDITOR
224 #if !UNITY_2020_1_OR_NEWER
225 if (!Application.isPlaying) {
226 Packer.RebuildAtlasCacheIfNeeded(EditorUserBuildSettings.activeBuildTarget);
227 }
228 #endif
229
230 for (int i = 0; i < features.Count; i++) {
231 var feature = features[i];
232
233 if (!feature.AreAllSpritesPacked()) {
234 info[i] = SupportInfo.Error("Not all sprites are packed.");
235 }
236
237 if (!feature.AreAllSpritesOnSameTexture()) {
238 info[i] = SupportInfo.Error("Not all sprites are packed into same atlas.");
239 }
240 }
241#endif
242
243 for (int i = 0; i < features.Count; i++) {
244 var feature = features[i];
245 if (group.features.Query().OfType<LeapTextureFeature>().Any(s => s.channel == feature.channel)) {
246 info[i] = info[i].OrWorse(SupportInfo.Error("Sprite features cannot currently share uvs with texture features."));
247 }
248 }
249 }
250
251 public virtual void GetSupportInfo(List<LeapRuntimeTintFeature> features, List<SupportInfo> info) {
252 SupportUtil.OnlySupportFirstFeature<LeapRuntimeTintFeature>(info);
253 }
254
255 public virtual void GetSupportInfo(List<LeapBlendShapeFeature> features, List<SupportInfo> info) {
256 SupportUtil.OnlySupportFirstFeature<LeapBlendShapeFeature>(info);
257 }
258
259 //Full unconditional support for all custom channels
260 public virtual void GetSupportInfo(List<CustomFloatChannelFeature> features, List<SupportInfo> info) { }
261 public virtual void GetSupportInfo(List<CustomVectorChannelFeature> features, List<SupportInfo> info) { }
262 public virtual void GetSupportInfo(List<CustomColorChannelFeature> features, List<SupportInfo> info) { }
263 public virtual void GetSupportInfo(List<CustomMatrixChannelFeature> features, List<SupportInfo> info) { }
264
265 public override void OnEnableRenderer() {
266 loadAllSupportedFeatures();
267 prepareMaterial();
268
269 //Sprite textures cannot be accessed at edit time, so we need to make sure
270 //to upload them to the material right as the renderer is enabled
271 if (_spriteFeatures != null) {
272 uploadSpriteTextures();
273 }
274 }
275
276 public override void OnDisableRenderer() { }
277
278 public override void OnUpdateRenderer() {
279 if (_material == null) {
280 prepareMaterial();
281 }
282
283 updateTinting();
284 updateBlendShapes();
285 updateCustomChannels();
286 }
287
288#if UNITY_EDITOR
289 public override void OnDisableRendererEditor() {
290 base.OnDisableRendererEditor();
291 }
292
293 public override void OnUpdateRendererEditor() {
294 base.OnUpdateRendererEditor();
295
296 _meshes.Validate(this);
297 _packedTextures.Validate(this);
298
299 setupForBuilding();
300
301 PreventDuplication(ref _material);
302
303 buildMesh();
304 }
305#endif
306
307 #region UPDATE
308 protected virtual void updateTinting() {
309 foreach (var tintFeature in _tintFeatures) {
310 if (!tintFeature.isDirtyOrEditTime) continue;
311
312 using (new ProfilerSample("Update Tinting")) {
313 if (QualitySettings.activeColorSpace == ColorSpace.Linear) {
314 tintFeature.featureData.Query().Select(d => (Vector4)d.color.linear).FillList(_tintColors);
315 } else {
316 tintFeature.featureData.Query().Select(d => (Vector4)d.color).FillList(_tintColors);
317 }
318 _material.SetVectorArraySafe(TINTS_PROPERTY, _tintColors);
319 }
320 }
321 }
322
323 protected virtual void updateBlendShapes() {
324 foreach (var blendShapeFeature in _blendShapeFeatures) {
325 if (!blendShapeFeature.isDirtyOrEditTime) continue;
326
327 using (new ProfilerSample("Update Blend Shapes")) {
328 blendShapeFeature.featureData.Query().Select(d => d.amount).FillList(_blendShapeAmounts);
329 _material.SetFloatArraySafe(BLEND_SHAPE_AMOUNTS_PROPERTY, _blendShapeAmounts);
330 }
331 }
332 }
333
334 protected virtual void updateCustomChannels() {
335 using (new ProfilerSample("Update Custom Channels")) {
336 foreach (var floatChannelFeature in _floatChannelFeatures) {
337 if (!floatChannelFeature.isDirtyOrEditTime) continue;
338
339 floatChannelFeature.featureData.Query().Select(d => d.value).FillList(_customFloatChannelData);
340 _material.SetFloatArraySafe(floatChannelFeature.channelName, _customFloatChannelData);
341 }
342
343 foreach (var vectorChannelFeature in _vectorChannelFeatures) {
344 if (!vectorChannelFeature.isDirtyOrEditTime) continue;
345
346 vectorChannelFeature.featureData.Query().Select(d => d.value).FillList(_customVectorChannelData);
347 _material.SetVectorArraySafe(vectorChannelFeature.channelName, _customVectorChannelData);
348 }
349
350 foreach (var colorChannelFeature in _colorChannelFeatures) {
351 if (!colorChannelFeature.isDirtyOrEditTime) continue;
352
353 colorChannelFeature.featureData.Query().Select(d => d.value).FillList(_customColorChannelData);
354 _material.SetColorArraySafe(colorChannelFeature.channelName, _customColorChannelData);
355 }
356
357 foreach (var matrixChannelFeature in _matrixChannelFeatures) {
358 if (!matrixChannelFeature.isDirty) continue;
359
360 matrixChannelFeature.featureData.Query().Select(d => d.value).FillList(_customMatrixChannelData);
361 _material.SetMatrixArraySafe(matrixChannelFeature.channelName, _customMatrixChannelData);
362 }
363 }
364 }
365 #endregion
366
367 #region GENERATION SETUP
368 protected virtual void setupForBuilding() {
369 using (new ProfilerSample("Mesh Setup")) {
370 MeshCache.Clear();
371 loadAllSupportedFeatures();
372 prepareMeshes();
373 prepareMaterial();
374
375 if (_textureFeatures.Count != 0) {
376 _atlas.UpdateTextureList(_textureFeatures);
377 }
378
379 if (_spriteFeatures.Count != 0) {
380#if UNITY_EDITOR && !UNITY_2020_1_OR_NEWER
381 Packer.RebuildAtlasCacheIfNeeded(EditorUserBuildSettings.activeBuildTarget);
382#endif
383 extractSpriteRects();
384 uploadSpriteTextures();
385 }
386 }
387 }
388
389 protected virtual void loadAllSupportedFeatures() {
390 using (new ProfilerSample("Load All Supported Features")) {
391 group.GetSupportedFeatures(_textureFeatures);
392 group.GetSupportedFeatures(_spriteFeatures);
393 group.GetSupportedFeatures(_tintFeatures);
394 group.GetSupportedFeatures(_blendShapeFeatures);
395
396 group.GetSupportedFeatures(_floatChannelFeatures);
397 group.GetSupportedFeatures(_vectorChannelFeatures);
398 group.GetSupportedFeatures(_colorChannelFeatures);
399 group.GetSupportedFeatures(_matrixChannelFeatures);
400
401 _doesRequireColors = doesRequireMeshColors();
402 _doesRequireNormals = doesRequireMeshNormals();
403 _doesRequireVertInfo = doesRequireVertInfo();
404
405 _requiredUvChannels.Clear();
406 foreach (var channel in MeshUtil.allUvChannels) {
407 if (channel == UVChannelFlags.UV3 && _doesRequireVertInfo) continue;
408
409 if (doesRequireUvChannel(channel)) {
410 _requiredUvChannels.Add(channel);
411 }
412 }
413 }
414 }
415
416 protected virtual void prepareMeshes() {
417 _meshes.Clear();
418 _generation.Reset();
419 }
420
421 protected virtual void prepareMaterial() {
422 if (_material == null) {
423 _material = new Material(_shader);
424 }
425
426#if UNITY_EDITOR
427 Undo.RecordObject(_material, "Touched material");
428#endif
429
430 _material.shader = _shader;
431 _material.name = "Procedural Graphic Material";
432
433 foreach (var keyword in _material.shaderKeywords) {
434 _material.DisableKeyword(keyword);
435 }
436
437 if (_spriteTextureBlock == null) {
438 _spriteTextureBlock = new MaterialPropertyBlock();
439 }
440 _spriteTextureBlock.Clear();
441
442 if (_doesRequireColors) {
443 _material.EnableKeyword(COLORS_FEATURE);
444 }
445
446 if (_doesRequireNormals) {
447 _material.EnableKeyword(NORMALS_FEATURE);
448 }
449
450 foreach (var channel in _requiredUvChannels) {
451 _material.EnableKeyword(GetUvFeature(channel));
452 }
453
454 if (_customColorChannelData.Count > 0 ||
455 _customFloatChannelData.Count > 0 ||
456 _customVectorChannelData.Count > 0 ||
457 _customMatrixChannelData.Count > 0) {
458 _material.EnableKeyword(CUSTOM_CHANNEL_KEYWORD);
459 }
460
461 if (_textureFeatures.Count != 0) {
462 foreach (var feature in _textureFeatures) {
463 _material.SetTexture(feature.propertyName, _packedTextures.GetTexture(feature.propertyName));
464 }
465 }
466
467 if (_tintFeatures.Count != 0) {
468 _material.EnableKeyword(LeapRuntimeTintFeature.FEATURE_NAME);
469 }
470
471 if (_blendShapeFeatures.Count != 0) {
472 _material.EnableKeyword(LeapBlendShapeFeature.FEATURE_NAME);
473 }
474 }
475
476 protected virtual void extractSpriteRects() {
477 using (new ProfilerSample("Extract Sprite Rects")) {
478 foreach (var spriteFeature in _spriteFeatures) {
479 for (int i = 0; i < spriteFeature.featureData.Count; i++) {
480 var dataObj = spriteFeature.featureData[i];
481 var sprite = dataObj.sprite;
482 if (sprite == null) continue;
483
484 Rect rect;
485 if (SpriteAtlasUtil.TryGetAtlasedRect(sprite, out rect)) {
486 _atlasUvs.SetRect(spriteFeature.channel.Index(), sprite, rect);
487 } else {
488 _atlasUvs.SetRect(spriteFeature.channel.Index(), sprite, default(Rect));
489 }
490 }
491 }
492 }
493 }
494
495 protected virtual void uploadSpriteTextures() {
496 using (new ProfilerSample("Upload Sprite Textures")) {
497 foreach (var spriteFeature in _spriteFeatures) {
498 var tex = spriteFeature.featureData.Query().
499 Select(d => d.sprite).
500 Where(s => s != null).
501#if UNITY_EDITOR
502 Select(s => SpriteUtility.GetSpriteTexture(s, getAtlasData: true)).
503#else
504 Select(s => s.texture).
505#endif
506 FirstOrDefault();
507
508 if (tex != null) {
509#if UNITY_EDITOR
510 if (!Application.isPlaying) {
511 _spriteTextureBlock.SetTexture(spriteFeature.propertyName, tex);
512 } else
513#endif
514 {
515 _material.SetTexture(spriteFeature.propertyName, tex);
516 }
517 }
518 }
519 }
520 }
521 #endregion
522
523 #region MESH GENERATION
524 protected virtual void buildMesh() {
525 using (new ProfilerSample("Build Mesh")) {
526 beginMesh();
527
528 for (_generation.graphicIndex = 0;
529 _generation.graphicIndex < group.graphics.Count;
530 _generation.graphicIndex++) {
531 //For re-generation of everything, graphicIndex == graphicId
532 _generation.graphicId = _generation.graphicIndex;
533 _generation.graphic = group.graphics[_generation.graphicIndex] as LeapMeshGraphicBase;
534 buildGraphic();
535 }
536
537 if (_generation.isGenerating) {
538 finishAndAddMesh();
539 }
540 }
541
542 _meshes.ClearPool();
543 }
544
545 protected virtual void buildGraphic() {
546 using (new ProfilerSample("Build Graphic")) {
547 refreshMeshData();
548 if (_generation.graphic.mesh == null) return;
549
550 buildTopology();
551
552 if (_doesRequireColors) {
553 buildColors();
554 }
555
556 foreach (var channel in _requiredUvChannels) {
557 buildUvs(channel);
558 }
559
560 if (_doesRequireVertInfo) {
561 buildVertInfo();
562 }
563
564 foreach (var blendShapeFeature in _blendShapeFeatures) {
565 buildBlendShapes(blendShapeFeature.featureData[_generation.graphicIndex]);
566 }
567
568 _generation.graphic.isRepresentationDirty = false;
569 }
570 }
571
572 protected virtual void refreshMeshData() {
573 using (new ProfilerSample("Refresh Mesh Data")) {
574 _generation.graphic.RefreshMeshData();
575 }
576 }
577
578 protected virtual void buildTopology() {
579 using (new ProfilerSample("Build Topology")) {
580 var topology = MeshCache.GetTopology(_generation.graphic.mesh);
581
582 int vertOffset = _generation.verts.Count;
583 for (int i = 0; i < topology.tris.Length; i++) {
584 _generation.tris.Add(topology.tris[i] + vertOffset);
585 }
586
587 if (_doesRequireNormals) {
588 var normals = MeshCache.GetNormals(_generation.graphic.mesh);
589 for (int i = 0; i < topology.verts.Length; i++) {
590 Vector3 meshVert;
591 Vector3 meshNormal;
592 graphicVertNormalToMeshVertNormal(topology.verts[i], normals[i], out meshVert, out meshNormal);
593
594 _generation.verts.Add(meshVert);
595 _generation.normals.Add(meshNormal);
596 }
597 } else {
598 for (int i = 0; i < topology.verts.Length; i++) {
599 _generation.verts.Add(graphicVertToMeshVert(topology.verts[i]));
600 }
601 }
602 }
603 }
604
605 protected virtual void buildColors() {
606 using (new ProfilerSample("Build Colors")) {
607 Color totalTint;
608 if (QualitySettings.activeColorSpace == ColorSpace.Linear) {
609 totalTint = _bakedTint.linear * _generation.graphic.vertexColor.linear;
610 } else {
611 totalTint = _bakedTint * _generation.graphic.vertexColor;
612 }
613
614 var colors = MeshCache.GetColors(_generation.graphic.mesh);
615 if (QualitySettings.activeColorSpace == ColorSpace.Linear) {
616 for (int i = 0; i < colors.Length; i++) {
617 _generation.colors.Add(colors[i].linear * totalTint);
618 }
619 } else {
620 for (int i = 0; i < colors.Length; i++) {
621 _generation.colors.Add(colors[i] * totalTint);
622 }
623 }
624 }
625 }
626
627 protected virtual void buildUvs(UVChannelFlags channel) {
628 using (new ProfilerSample("Build Uvs")) {
629 var uvs = MeshCache.GetUvs(_generation.graphic.mesh, channel);
630 var targetList = _generation.uvs[channel.Index()];
631
632 targetList.AddRange(uvs);
633
634 //If we cannot remap this channel, just return
635 if ((_generation.graphic.remappableChannels & channel) == 0) {
636 return;
637 }
638
639 UnityEngine.Object key;
640 if (_textureFeatures.Count > 0) {
641 key = _textureFeatures[0].featureData[_generation.graphicIndex].texture;
642 } else if (_spriteFeatures.Count > 0) {
643 key = _spriteFeatures[0].featureData[_generation.graphicIndex].sprite;
644 } else {
645 return;
646 }
647
648 Rect rect = _atlasUvs.GetRect(channel.Index(), key);
649 MeshUtil.RemapUvs(targetList, rect, uvs.Count);
650 }
651 }
652
653 protected virtual void buildVertInfo() {
654 using (new ProfilerSample("Build Special Uv3")) {
655 _generation.vertInfo.Append(_generation.graphic.mesh.vertexCount,
656 new Vector4(0, 0, 0, _generation.graphicId));
657 }
658 }
659
660 protected virtual void buildBlendShapes(LeapBlendShapeData blendShapeData) {
661 using (new ProfilerSample("Build Blend Shapes")) {
662 List<Vector3> blendVerts = Pool<List<Vector3>>.Spawn();
663
664 try {
665 if (!blendShapeData.TryGetBlendShape(blendVerts)) {
666 return;
667 }
668
669 int offset = _generation.verts.Count - blendVerts.Count;
670 for (int i = 0; i < blendVerts.Count; i++) {
671 Vector3 shapeVert = blendVerts[i];
672 Vector3 delta = blendShapeDelta(shapeVert, _generation.verts[i + offset]);
673
674 Vector4 currVertInfo = _generation.vertInfo[i + offset];
675 currVertInfo.x = delta.x;
676 currVertInfo.y = delta.y;
677 currVertInfo.z = delta.z;
678 _generation.vertInfo[i + offset] = currVertInfo;
679 }
680 } finally {
681 blendVerts.Clear();
682 Pool<List<Vector3>>.Recycle(blendVerts);
683 }
684 }
685 }
686
687 protected virtual Vector3 blendShapeDelta(Vector3 shapeVert, Vector3 originalVert) {
688 return graphicVertToMeshVert(shapeVert) - originalVert;
689 }
690
691 protected virtual void beginMesh(Mesh mesh = null) {
692 Assert.IsNull(_generation.mesh, "Cannot begin a new mesh without finishing the current mesh.");
693
694 _generation.Reset();
695
696 if (mesh == null) {
697 mesh = _meshes.GetMeshFromPoolOrNew();
698 } else {
699 mesh.Clear(keepVertexLayout: false);
700 }
701
702 mesh.name = "Procedural Graphic Mesh";
703 mesh.hideFlags = HideFlags.None;
704
705 _generation.mesh = mesh;
706 }
707
708 protected virtual void finishMesh(bool deleteEmptyMeshes = true) {
709 using (new ProfilerSample("Finish Mesh")) {
710
711 if (_generation.verts.Count == 0 && deleteEmptyMeshes) {
712 if (!Application.isPlaying) {
713 UnityEngine.Object.DestroyImmediate(_generation.mesh, allowDestroyingAssets: true);
714 }
715 _generation.mesh = null;
716 return;
717 }
718
719 _generation.mesh.SetVertices(_generation.verts);
720 _generation.mesh.SetTriangles(_generation.tris, 0);
721
722 if (_generation.normals.Count == _generation.verts.Count) {
723 _generation.mesh.SetNormals(_generation.normals);
724 }
725
726 if (_generation.vertInfo.Count == _generation.verts.Count) {
727 _generation.mesh.SetTangents(_generation.vertInfo);
728 }
729
730 if (_generation.colors.Count == _generation.verts.Count) {
731 _generation.mesh.SetColors(_generation.colors);
732 }
733
734 foreach (var channel in _requiredUvChannels) {
735 _generation.mesh.SetUVs(channel.Index(), _generation.uvs[channel.Index()]);
736 }
737
738 postProcessMesh();
739 }
740 }
741
742 protected virtual void finishAndAddMesh(bool deleteEmptyMeshes = true) {
743 finishMesh(deleteEmptyMeshes);
744
745 if (_generation.mesh != null) {
746 _meshes.AddMesh(_generation.mesh);
747 _generation.mesh = null;
748 }
749 }
750
751 protected virtual void postProcessMesh() { }
752
753 protected struct GenerationState {
755 public int graphicIndex;
756 public int graphicId;
757 public Mesh mesh;
758
759 public List<Vector3> verts;
760 public List<Vector3> normals;
761 public List<Vector4> vertInfo;
762 public List<int> tris;
763 public List<Color> colors;
764 public List<Vector4>[] uvs;
765
766 public bool isGenerating {
767 get {
768 return mesh != null;
769 }
770 }
771
773 GenerationState state = new GenerationState();
774
775 state.verts = new List<Vector3>();
776 state.normals = new List<Vector3>();
777 state.vertInfo = new List<Vector4>();
778 state.tris = new List<int>();
779 state.colors = new List<Color>();
780 state.uvs = new List<Vector4>[4] {
781 new List<Vector4>(),
782 new List<Vector4>(),
783 new List<Vector4>(),
784 new List<Vector4>()
785 };
786
787 return state;
788 }
789
790 public void Reset() {
791 verts.Clear();
792 normals.Clear();
793 vertInfo.Clear();
794 tris.Clear();
795 colors.Clear();
796 for (int i = 0; i < 4; i++) {
797 uvs[i].Clear();
798 }
799 }
800 }
801 #endregion
802
803 #region UTILITY
804
805 protected IEnumerable<UVChannelFlags> enabledUvChannels {
806 get {
807 if (_useUv0) yield return UVChannelFlags.UV0;
808 if (_useUv1) yield return UVChannelFlags.UV1;
809 if (_useUv2) yield return UVChannelFlags.UV2;
810 if (_useUv3) yield return UVChannelFlags.UV3;
811 }
812 }
813
814 protected virtual bool doesRequireMeshColors() {
815 return _useColors;
816 }
817
818 protected virtual bool doesRequireMeshNormals() {
819 return _useNormals;
820 }
821
822 protected virtual bool doesRequireUvChannel(UVChannelFlags channel) {
823 switch (channel) {
824 case UVChannelFlags.UV0:
825 return _useUv0;
826 case UVChannelFlags.UV1:
827 return _useUv1;
828 case UVChannelFlags.UV2:
829 return _useUv2;
830 case UVChannelFlags.UV3:
831 return _useUv3;
832 default:
833 throw new ArgumentException("Invalid channel argument.");
834 }
835 }
836
837 protected void drawMesh(Mesh mesh, Matrix4x4 transform) {
838#if UNITY_EDITOR
839 if (!Application.isPlaying) {
840 Graphics.DrawMesh(mesh, transform, _material, _visualLayer, null, 0, _spriteTextureBlock);
841 } else
842#endif
843 {
844 Graphics.DrawMesh(mesh, transform, _material, _visualLayer);
845 }
846 }
847
848 protected virtual bool doesRequireVertInfo() {
849 return _tintFeatures.Count != 0 ||
850 _blendShapeFeatures.Count != 0 ||
851 _customFloatChannelData.Count != 0 ||
852 _customVectorChannelData.Count != 0 ||
853 _customMatrixChannelData.Count != 0 ||
854 _customColorChannelData.Count != 0;
855 }
856
857 protected abstract Vector3 graphicVertToMeshVert(Vector3 vertex);
858 protected abstract void graphicVertNormalToMeshVertNormal(Vector3 vertex, Vector3 normal, out Vector3 meshVert, out Vector3 meshNormal);
859 #endregion
860 }
861}
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
UnityEngine.Color Color
Definition: TestScript.cs:32
void RebuildAtlas(ProgressBar progress, out Texture2D[] packedTextures, out AtlasUvs channelMapping)
Actually perform the build for the atlas. This method outputs the atlas textures, and the atlas uvs t...
bool isDirty
Returns whether or not the results built by this atlas have become invalid.
void UpdateTextureList(List< LeapTextureFeature > textureFeatures)
Updates the internal list of textures given some texture features to build an atlas for....
A class that contains mapping information that specifies how a texture is packed into an atlas.
Definition: AtlasBuilder.cs:23
bool TryGetBlendShape(List< Vector3 > blendVerts)
Returns the blended vertices based on the current mesh this blend shape is attached to....
bool isRepresentationDirty
An internal flag that returns true if the visual representation of this graphic needs to be updated....
Definition: LeapGraphic.cs:64
This class is a base class for all graphics that can be represented by a mesh object.
abstract void RefreshMeshData()
When this method is called, the mesh property and the remappableChannels property must be assigned to...
Mesh mesh
Returns the mesh that represents this graphic. It can have any topology, any number of uv channels,...
UVChannelFlags remappableChannels
Returns an enum mask that represents the union of all channels that are allowed to be remapped for th...
virtual bool doesRequireUvChannel(UVChannelFlags channel)
virtual void GetSupportInfo(List< CustomVectorChannelFeature > features, List< SupportInfo > info)
virtual void finishMesh(bool deleteEmptyMeshes=true)
virtual void buildBlendShapes(LeapBlendShapeData blendShapeData)
override void OnUpdateRenderer()
Called from LateUpdate during runtime. Use this to update the renderer using any changes made to duri...
override void OnEnableRenderer()
Called when the renderer is enabled at runtime.
List< CustomFloatChannelFeature > _floatChannelFeatures
abstract Vector3 graphicVertToMeshVert(Vector3 vertex)
virtual void GetSupportInfo(List< LeapBlendShapeFeature > features, List< SupportInfo > info)
List< CustomVectorChannelFeature > _vectorChannelFeatures
virtual void GetSupportInfo(List< LeapSpriteFeature > features, List< SupportInfo > info)
static string GetUvFeature(UVChannelFlags flags)
virtual void buildUvs(UVChannelFlags channel)
Action< Texture2D, AtlasUvs > OnPostProcessAtlas
List< LeapTextureFeature > _textureFeatures
virtual void finishAndAddMesh(bool deleteEmptyMeshes=true)
virtual void GetSupportInfo(List< LeapRuntimeTintFeature > features, List< SupportInfo > info)
virtual void GetSupportInfo(List< CustomFloatChannelFeature > features, List< SupportInfo > info)
List< CustomColorChannelFeature > _colorChannelFeatures
override void OnDisableRenderer()
Called when the renderer is disabled at runtime.
virtual void GetSupportInfo(List< CustomMatrixChannelFeature > features, List< SupportInfo > info)
virtual Vector3 blendShapeDelta(Vector3 shapeVert, Vector3 originalVert)
List< LeapBlendShapeFeature > _blendShapeFeatures
virtual void GetSupportInfo(List< CustomColorChannelFeature > features, List< SupportInfo > info)
abstract void graphicVertNormalToMeshVertNormal(Vector3 vertex, Vector3 normal, out Vector3 meshVert, out Vector3 meshNormal)
List< CustomMatrixChannelFeature > _matrixChannelFeatures
void drawMesh(Mesh mesh, Matrix4x4 transform)
List< LeapRuntimeTintFeature > _tintFeatures
virtual void GetSupportInfo(List< LeapTextureFeature > features, List< SupportInfo > info)
virtual void beginMesh(Mesh mesh=null)
LeapGraphicGroup group
Gets the group this rendering method is attached to.
LeapGraphicRenderer renderer
Gets the renderer this rendering method is attached to.
void Validate(LeapRenderingMethod renderingMethod)
void Validate(LeapRenderingMethod renderingMethod)
void AssignTextures(Texture2D[] textures, string[] propertyNames)
This class allows you to easily give feedback of an action as it completes.
Definition: ProgressBar.cs:66
void Begin(int sections, string title, string info, Action action)
Begins a new chunk. If this call is made from within a chunk it will generate a sub-chunk that repres...
Definition: ProgressBar.cs:109
void Step(string infoString="")
Steps through one section of the current chunk. You can provide an optional info string that will be ...
Definition: ProgressBar.cs:147
The support info class provides a very basic way to notify that something is fully supported,...
Definition: SupportInfo.cs:21
static SupportInfo Error(string message)
Helper getter to return a struct that signifies no support with an error message.
Definition: SupportInfo.cs:42
SupportInfo OrWorse(SupportInfo other)
Helper method that returns either the current support info struct, or the argument support info struc...
Definition: SupportInfo.cs:51
A utility struct for ease of use when you want to wrap a piece of code in a Profiler....
An object you can use to represent a single Unity layer as a dropdown in the inspector....
Definition: SingleLayer.cs:20