Smoothing vertex map
On 15/12/2017 at 08:00, xxxxxxxx wrote:
In a ObjectData plugin, I create a vertex map from a polygon selection and put that in a vertex map tag.
No problem so far, except that all the weights are set to 0% or 100%. There is no smoothing!
So, how can I smooth the weights in the vertex map tag?
I tried to do it using the paint tool, see below, but that gave me the warning "RuntimeError: illegal operation, invalid cross-thread call".
Is there another way to smooth the vertex map?
tool = c4d.plugins.FindPlugin(doc.GetAction(), c4d.PLUGINTYPE_TOOL) if tool is not None: tool[c4d.ID_BRUSH_BASE_TOOL_STRENGTH] = 1.0 tool[c4d.ID_CA_PAINT_TOOL_MODE] = c4d.ID_CA_PAINT_TOOL_MODE_SMOOTH #smooth c4d.CallButton(tool, c4d.ID_CA_PAINT_TOOL_APPLY_ALL)
On 15/12/2017 at 08:22, xxxxxxxx wrote:
I guess you already know, but for peoples who get here, I told it .But it fail cause you are using c4d.CallButton from a threaded function (probably GetVirtualObject in your case).
A workaround could be to use Message function explain here. But I'm really not sure it will work since it's a tool and not a NodeData in your case.
But it's maybe time for asking how SendModelingCommand work? ^^
On 15/12/2017 at 08:35, xxxxxxxx wrote:
Thanks for the reply.
I considered SendModelingCommand, but I could not see how to use the paint tool and SendModelingCommand.
Hopefully the guys from Maxon can explain.
On 18/12/2017 at 12:25, xxxxxxxx wrote:
As gr4ph0s already told you, it's not allowed to interact with a tool from an object plugin. Also the Paint Tool can't be used with SendModelingCommand().
The solution is to manually smooth the weights just like the Paint Tool does when clicking the Apply buttons.
Don't be afraid, the needed code isn't complex.
You can find a script below. It first initializes the selected points with a weight of 1.0. Then it performs the smoothing with the average of the neighboring points weight.
Code works with a polygon object which has polygons selected.
Note if you'll be using this code in a generator, then don't call SetBit(c4d.BIT_ACTIVE) on the vertex map tag and EventAdd().
These functions are forbidden there and also it would not make sense to call these as the vertex map tag is used virtually.
import c4d def main() : # Requirements if op is None: return if op.GetType() != c4d.Opolygon: return if doc.GetMode() != c4d.Mpolygons: return # Retrieve polygon object information allPolys = op.GetAllPolygons() polyCount = op.GetPolygonCount() if len(allPolys) != polyCount: return polySel = op.GetPolygonS() # Select points from polygon selection pointSel = c4d.BaseSelect() for polyIdx in xrange(polyCount) : if not polySel.IsSelected(polyIdx) : continue pointSel.Select(allPolys[polyIdx].a) pointSel.Select(allPolys[polyIdx].b) pointSel.Select(allPolys[polyIdx].c) pointSel.Select(allPolys[polyIdx].d) # Add vertex map tag to polygon object pointCount = op.GetPointCount() vmapTag = op.MakeVariableTag(c4d.Tvertexmap, pointCount) if vmapTag is None: return # Initialize vertex map for selected points with 1.0 weight vmapData = vmapTag.GetAllHighlevelData() for pointIdx in xrange(pointCount) : if not pointSel.IsSelected(pointIdx) : continue vmapData[pointIdx] = 1.0 # Create list for the new vertex map data newData = [0.0] * pointCount # Strength of weight application (Opacity in Paint Tool) applyStrength = 1.0 # Create neighbor to obtain information on neighboring polygons for each point nb = c4d.utils.Neighbor() if not nb.Init(op) : return # Smooth calculation loop for pointIdx in xrange(pointCount) : if not pointSel.IsSelected(pointIdx) : continue # Get neighboring polygons polys = nb.GetPointPolys(pointIdx) if len(polys) == 0: newData[pointIdx] = vmapData[pointIdx] continue # Select points from neighboring polygons sel = c4d.BaseSelect() for poly in polys: sel.Select(allPolys[poly].a) sel.Select(allPolys[poly].b) sel.Select(allPolys[poly].c) sel.Select(allPolys[poly].d) weight = 0.0 num = 0 # Calculate average weight from neighboring points segCount = sel.GetSegments() for segIdx in xrange(segCount) : first, last = sel.GetRange(segIdx, pointCount) for idx in range(first, last+1) : weight += vmapData[idx] num += 1 if num > 0: weight /= float(num) # Blend weight data = vmapData[idx] value = data + (weight - data) * applyStrength # Set new weight newData[pointIdx] = c4d.utils.ClampValue(value, 0.0, 1.0) # Finally set the new vertex map data vmapTag.SetAllHighlevelData(newData) # Update polygon object op.Message(c4d.MSG_UPDATE) vmapTag.SetBit(c4d.BIT_ACTIVE) c4d.EventAdd() if __name__=='__main__': main()
On 18/12/2017 at 13:07, xxxxxxxx wrote:
Great, thank you!