forked from bartvdbraak/blender
28cc31ba11
The instability considered here is due to a persistent failure of the getFEdge() method in the Interface0D class and its subclasses in the presence of smooth FEdges. When the Face Smoothness option is enabled, the view map is populated with not only sharp FEdges (i.e., edges in the original meshes) but also smooth FEdges (i.e., newly built edges lying on triangular surfaces). The failure of getFEdge() caused many related issues because the method is widely used in other predicates and functions that rely on it. The most prominent example of related user-visible problems is a constant failure of the built-in MaterialF0D. The main issue and related problems were addressed as follows: * A bug in the construction of smooth FEdges was fixed. Individual smooth FEdges, even when they were detected as a series of smooth FEdges that constitute one smooth ViewEdge, may have some irregular geometry in the form of non-uniform OWXFaceLayer::order values. The OWXFaceLayer::order values were used in an inappropriate way, so that resulting smooth ViewEdges may have an FEdge between two subsequent SVertices that were indeed the same SVertex object. This was an unexpected situation that getFEdge() could not handle. * Another issue in the construction of smooth FEdges was resolved. When sharp FEdges are constructed, two SVertices at both ends of an FEdge are generated only when no SVertex exists in a given 3D position (this way, the original mesh topology is reconstructed from a bunch of independent triangles that the BlenderFileLoader class passes to the view map creation process). This sharing of SVertices was used also for the generation of SVertices at the two ends of each smooth FEdge, causing the getFEdge() failure in the presence of smooth FEdges. The workaround implemented here is to simply suppress the sharing of generated SVertices when smooth FEdges are created. * In the Parameter Editor mode, the built-in MaterialF0D was replaced with a better implementation that works well with Curves and Strokes. MaterialF0D does not work with these 1D data types.
93 lines
3.1 KiB
Python
Executable File
93 lines
3.1 KiB
Python
Executable File
from freestyle_init import *
|
|
|
|
class CurveMaterialF0D(UnaryFunction0DMaterial):
|
|
# A replacement of the built-in MaterialF0D for stroke creation.
|
|
# MaterialF0D does not work with Curves and Strokes.
|
|
def getName(self):
|
|
return "CurveMaterialF0D"
|
|
def __call__(self, inter):
|
|
cp = inter.getObject()
|
|
assert(isinstance(cp, CurvePoint))
|
|
fe = cp.A().getFEdge(cp.B())
|
|
assert(fe is not None)
|
|
return fe.material() if fe.isSmooth() else fe.bMaterial()
|
|
|
|
class pyInverseCurvature2DAngleF0D(UnaryFunction0DDouble):
|
|
def getName(self):
|
|
return "InverseCurvature2DAngleF0D"
|
|
|
|
def __call__(self, inter):
|
|
func = Curvature2DAngleF0D()
|
|
c = func(inter)
|
|
return (3.1415 - c)
|
|
|
|
class pyCurvilinearLengthF0D(UnaryFunction0DDouble):
|
|
def getName(self):
|
|
return "CurvilinearLengthF0D"
|
|
|
|
def __call__(self, inter):
|
|
i0d = inter.getObject()
|
|
s = i0d.getExactTypeName()
|
|
if (string.find(s, "CurvePoint") == -1):
|
|
print("CurvilinearLengthF0D: not implemented yet for", s)
|
|
return -1
|
|
cp = castToCurvePoint(i0d)
|
|
return cp.t2d()
|
|
|
|
## estimate anisotropy of density
|
|
class pyDensityAnisotropyF0D(UnaryFunction0DDouble):
|
|
def __init__(self,level):
|
|
UnaryFunction0DDouble.__init__(self)
|
|
self.IsoDensity = ReadCompleteViewMapPixelF0D(level)
|
|
self.d0Density = ReadSteerableViewMapPixelF0D(0, level)
|
|
self.d1Density = ReadSteerableViewMapPixelF0D(1, level)
|
|
self.d2Density = ReadSteerableViewMapPixelF0D(2, level)
|
|
self.d3Density = ReadSteerableViewMapPixelF0D(3, level)
|
|
def getName(self):
|
|
return "pyDensityAnisotropyF0D"
|
|
def __call__(self, inter):
|
|
c_iso = self.IsoDensity(inter)
|
|
c_0 = self.d0Density(inter)
|
|
c_1 = self.d1Density(inter)
|
|
c_2 = self.d2Density(inter)
|
|
c_3 = self.d3Density(inter)
|
|
cMax = max( max(c_0,c_1), max(c_2,c_3))
|
|
cMin = min( min(c_0,c_1), min(c_2,c_3))
|
|
if ( c_iso == 0 ):
|
|
v = 0
|
|
else:
|
|
v = (cMax-cMin)/c_iso
|
|
return (v)
|
|
|
|
## Returns the gradient vector for a pixel
|
|
## l
|
|
## the level at which one wants to compute the gradient
|
|
class pyViewMapGradientVectorF0D(UnaryFunction0DVec2f):
|
|
def __init__(self, l):
|
|
UnaryFunction0DVec2f.__init__(self)
|
|
self._l = l
|
|
self._step = pow(2,self._l)
|
|
def getName(self):
|
|
return "pyViewMapGradientVectorF0D"
|
|
def __call__(self, iter):
|
|
p = iter.getObject().getPoint2D()
|
|
gx = ReadCompleteViewMapPixelCF(self._l, int(p.x()+self._step), int(p.y()))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
|
|
gy = ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()+self._step))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
|
|
return Vector([gx, gy])
|
|
|
|
class pyViewMapGradientNormF0D(UnaryFunction0DDouble):
|
|
def __init__(self, l):
|
|
UnaryFunction0DDouble.__init__(self)
|
|
self._l = l
|
|
self._step = pow(2,self._l)
|
|
def getName(self):
|
|
return "pyViewMapGradientNormF0D"
|
|
def __call__(self, iter):
|
|
p = iter.getObject().getPoint2D()
|
|
gx = ReadCompleteViewMapPixelCF(self._l, int(p.x()+self._step), int(p.y()))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
|
|
gy = ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()+self._step))- ReadCompleteViewMapPixelCF(self._l, int(p.x()), int(p.y()))
|
|
grad = Vector([gx, gy])
|
|
return grad.length
|
|
|
|
|