@@ -15,137 +15,154 @@ public class RhinoMaterialUnpacker
15
15
{
16
16
private readonly ILogger < RhinoMaterialUnpacker > _logger ;
17
17
18
+ /// <summary>
19
+ /// For send operations
20
+ /// </summary>
21
+ private Dictionary < string , RenderMaterialProxy > RenderMaterialProxies { get ; } = new ( ) ;
22
+
18
23
public RhinoMaterialUnpacker ( ILogger < RhinoMaterialUnpacker > logger )
19
24
{
20
25
_logger = logger ;
21
26
}
22
27
23
- public List < RenderMaterialProxy > UnpackRenderMaterial ( List < RhinoObject > atomicObjects )
28
+ /// <summary>
29
+ /// Processes an object's material and adds the object id to a material proxy in <see cref="RenderMaterialProxies"/> if object color is set ByObject or ByParent.
30
+ /// </summary>
31
+ /// <param name="objId"></param>
32
+ private void ProcessObjectMaterial (
33
+ string objId ,
34
+ RenderMaterial ? renderMaterial ,
35
+ Material ? material ,
36
+ ObjectMaterialSource source
37
+ )
38
+ {
39
+ switch ( source )
40
+ {
41
+ case ObjectMaterialSource . MaterialFromObject :
42
+ AddObjectIdToRenderMaterialProxy ( objId , renderMaterial , material ) ;
43
+ break ;
44
+
45
+ // POC: skip if object material source is *not* by object. we don't support render material inheritance atm bc alex disagrees with the concept
46
+ default :
47
+ break ;
48
+ }
49
+ }
50
+
51
+ private void AddObjectIdToRenderMaterialProxy ( string objectId , RenderMaterial ? renderMaterial , Material ? material )
24
52
{
25
- Dictionary < string , RenderMaterialProxy > renderMaterialProxies = new ( ) ;
26
- Dictionary < string , Layer > usedLayerMap = new ( ) ;
53
+ string ? renderMaterialId = renderMaterial ? . Id . ToString ( ) ?? material ? . Id . ToString ( ) ;
27
54
28
- // Stage 1: unpack materials from objects, and collect their uniqe layers in the process
29
- foreach ( RhinoObject rhinoObject in atomicObjects )
55
+ if ( renderMaterialId is not null )
30
56
{
31
- try
57
+ if ( RenderMaterialProxies . TryGetValue ( renderMaterialId , out RenderMaterialProxy ? proxy ) )
32
58
{
33
- var layer = RhinoDoc . ActiveDoc . Layers [ rhinoObject . Attributes . LayerIndex ] ;
34
- usedLayerMap [ layer . Id . ToString ( ) ] = layer ;
35
-
36
- if ( rhinoObject . Attributes . MaterialSource != ObjectMaterialSource . MaterialFromObject )
59
+ proxy . objects . Add ( objectId ) ;
60
+ }
61
+ else
62
+ {
63
+ if (
64
+ ConvertMaterialToRenderMaterialProxy ( renderMaterialId , renderMaterial , material )
65
+ is RenderMaterialProxy newRenderMaterial
66
+ )
37
67
{
38
- continue ; // TODO: will not catch layer materials
68
+ newRenderMaterial . objects . Add ( objectId ) ;
69
+ RenderMaterialProxies [ renderMaterialId ] = newRenderMaterial ;
39
70
}
71
+ }
72
+ }
73
+ }
40
74
41
- var rhinoRenderMaterial = rhinoObject . GetRenderMaterial ( true ) ;
42
- var rhinoMaterial = rhinoObject . GetMaterial ( true ) ;
43
- var rhinoMaterialId = rhinoRenderMaterial ? . Id . ToString ( ) ?? rhinoMaterial ? . Id . ToString ( ) ;
75
+ private RenderMaterialProxy ? ConvertMaterialToRenderMaterialProxy (
76
+ string materialId ,
77
+ RenderMaterial ? renderMaterial ,
78
+ Material ? material
79
+ )
80
+ {
81
+ // TY Rhino api for being a bit confused about materials 💖
82
+ SpeckleRenderMaterial ? myMaterial = null ;
83
+ if ( renderMaterial is not null )
84
+ {
85
+ myMaterial = ConvertRenderMaterialToSpeckle ( renderMaterial ) ;
86
+ }
87
+ else if ( material is not null )
88
+ {
89
+ RenderMaterial convertedRender = ConvertMaterialToRenderMaterial ( material ) ;
90
+ myMaterial = ConvertRenderMaterialToSpeckle ( convertedRender ) ;
91
+ }
44
92
45
- if ( rhinoMaterialId == null )
46
- {
47
- continue ;
48
- }
93
+ if ( myMaterial is null )
94
+ {
95
+ return null ;
96
+ }
49
97
50
- if ( renderMaterialProxies . TryGetValue ( rhinoMaterialId , out RenderMaterialProxy ? value ) )
51
- {
52
- value . objects . Add ( rhinoObject . Id . ToString ( ) ) ;
53
- }
54
- else
55
- {
56
- // TY Rhino api for being a bit confused about materials 💖
57
- SpeckleRenderMaterial ? myMaterial = null ;
58
- if ( rhinoRenderMaterial is not null )
59
- {
60
- myMaterial = ConvertRenderMaterialToSpeckle ( rhinoRenderMaterial ) ;
61
- }
62
- else if ( rhinoMaterial is not null )
63
- {
64
- RenderMaterial convertedRender = ConvertMaterialToRenderMaterial ( rhinoMaterial ) ;
65
- myMaterial = ConvertRenderMaterialToSpeckle ( convertedRender ) ;
66
- }
67
-
68
- if ( myMaterial is not null )
69
- {
70
- renderMaterialProxies [ rhinoMaterialId ] = new RenderMaterialProxy ( )
71
- {
72
- value = myMaterial ,
73
- objects = [ rhinoObject . Id . ToString ( ) ]
74
- } ;
75
- }
76
- }
98
+ RenderMaterialProxy renderMaterialProxy =
99
+ new ( )
100
+ {
101
+ value = myMaterial ,
102
+ applicationId = materialId ,
103
+ objects = new ( )
104
+ } ;
105
+
106
+ // POC: we are not attaching source information here, since we do not support material inheritance
107
+ return renderMaterialProxy ;
108
+ }
109
+
110
+ /// <summary>
111
+ /// Iterates through a given set of rhino objects and layers to collect render materials.
112
+ /// </summary>
113
+ /// <param name="atomicObjects">atomic root objects, including instance objects</param>
114
+ /// <param name="layers">the layers corresponding to collections on the root collection</param>
115
+ /// <returns></returns>
116
+ public List < RenderMaterialProxy > UnpackRenderMaterials ( List < RhinoObject > atomicObjects , List < Layer > layers )
117
+ {
118
+ var currentDoc = RhinoDoc . ActiveDoc ; // POC: too much right now to interface around
119
+
120
+ // Stage 1: unpack materials from objects
121
+ foreach ( RhinoObject rootObj in atomicObjects )
122
+ {
123
+ // materials are confusing in rhino. we need both render material and material because objects can have either assigned
124
+ RenderMaterial ? rhinoRenderMaterial = rootObj . GetRenderMaterial ( true ) ;
125
+ Material ? rhinoMaterial = rootObj . GetMaterial ( true ) ;
126
+
127
+ try
128
+ {
129
+ ProcessObjectMaterial (
130
+ rootObj . Id . ToString ( ) ,
131
+ rhinoRenderMaterial ,
132
+ rhinoMaterial ,
133
+ rootObj . Attributes . MaterialSource
134
+ ) ;
77
135
}
78
136
catch ( Exception ex ) when ( ! ex . IsFatal ( ) )
79
137
{
80
- _logger . LogError ( ex , "Failed to unpack render material from RhinoObject " ) ;
138
+ _logger . LogError ( ex , "Failed to unpack material from Rhino Object " ) ;
81
139
}
82
140
}
83
141
84
142
// Stage 2: make sure we collect layer materials as well
85
- foreach ( var layer in usedLayerMap . Values )
143
+ foreach ( Layer layer in layers )
86
144
{
145
+ // materials are confusing in rhino. we will first try to get layer render material and then material by index if null
146
+ RenderMaterial ? rhinoRenderMaterial = layer . RenderMaterial ;
147
+ Material ? rhinoMaterial =
148
+ layer . RenderMaterialIndex == - 1 ? null : currentDoc . Materials [ layer . RenderMaterialIndex ] ;
149
+
87
150
try
88
151
{
89
- // 1. Try to create from RenderMaterial
90
- var renderMaterial = layer . RenderMaterial ;
91
- if ( renderMaterial is not null )
92
- {
93
- if ( renderMaterialProxies . TryGetValue ( renderMaterial . Id . ToString ( ) , out RenderMaterialProxy ? value ) )
94
- {
95
- value . objects . Add ( layer . Id . ToString ( ) ) ;
96
- }
97
- else
98
- {
99
- renderMaterialProxies [ renderMaterial . Id . ToString ( ) ] = new RenderMaterialProxy ( )
100
- {
101
- value = ConvertRenderMaterialToSpeckle ( renderMaterial ) ,
102
- objects = [ layer . Id . ToString ( ) ]
103
- } ;
104
- }
105
-
106
- continue ;
107
- }
108
-
109
- // 2. As fallback, try to create from index
110
- // ON RECEIVE: when creating a layer on receive we cannot set RenderMaterial to layer. (RhinoCommon API limitation, it tested)
111
- // We can only set render material index of layer. So for the second send, we also need to check its index!
112
- var renderMaterialIndex = layer . RenderMaterialIndex ;
113
- if ( renderMaterialIndex == - 1 )
114
- {
115
- continue ;
116
- }
117
-
118
- var renderMaterialFromIndex = RhinoDoc . ActiveDoc . Materials [ renderMaterialIndex ] ;
119
- if ( renderMaterialFromIndex is null )
120
- {
121
- continue ;
122
- }
123
-
124
- if (
125
- renderMaterialProxies . TryGetValue (
126
- renderMaterialFromIndex . Id . ToString ( ) ,
127
- out RenderMaterialProxy ? renderMaterialProxy
128
- )
129
- )
130
- {
131
- renderMaterialProxy . objects . Add ( layer . Id . ToString ( ) ) ;
132
- }
133
- else
134
- {
135
- renderMaterialProxies [ renderMaterialFromIndex . Id . ToString ( ) ] = new RenderMaterialProxy ( )
136
- {
137
- value = ConvertRenderMaterialToSpeckle ( ConvertMaterialToRenderMaterial ( renderMaterialFromIndex ) ) ,
138
- objects = [ layer . Id . ToString ( ) ]
139
- } ;
140
- }
152
+ ProcessObjectMaterial (
153
+ layer . Id . ToString ( ) ,
154
+ rhinoRenderMaterial ,
155
+ rhinoMaterial ,
156
+ ObjectMaterialSource . MaterialFromObject
157
+ ) ;
141
158
}
142
159
catch ( Exception ex ) when ( ! ex . IsFatal ( ) )
143
160
{
144
- _logger . LogError ( ex , "Failed to unpack render material from Rhino Layer" ) ;
161
+ _logger . LogError ( ex , "Failed to unpack materials from Rhino Layer" ) ;
145
162
}
146
163
}
147
164
148
- return renderMaterialProxies . Values . ToList ( ) ;
165
+ return RenderMaterialProxies . Values . ToList ( ) ;
149
166
}
150
167
151
168
// converts a rhino material to a rhino render material
0 commit comments