Fix for stroke rendering instability with stroke geometry shaders.

* Stroke::Resample(int nPoints) was not properly working when a wrong
value was returned from Stroke::getLength2D(), resulting in repeated
warning messages "Warning: incorrect points number" during stroke
rendering.  The main cause was that stroke geometry shaders did not
update the two-dimensional (2D) length (also referred to as curvilinear
abscissa) after they modified the 2D points of stroke vertices.  Now
all stroke geometry shaders make explicit calls for Stroke::UpdateLength()
that has been introduced for recomputing the 2D length.  Many thanks to
Josef who reported the problem together with sample .blend files for
reproducing the issue.

* Missing Python wrapper of Stroke::getLength2D() was added.
This commit is contained in:
Tamito Kajiyama 2011-10-30 16:00:35 +00:00
parent 1f25228857
commit f0acdcf135
5 changed files with 46 additions and 24 deletions

@ -449,6 +449,7 @@ class SinusDisplacementShader(StrokeShader):
u = v.u() u = v.u()
n = n * self._amplitude * math.cos(distance / self._wavelength * 2 * math.pi + self._phase) n = n * self._amplitude * math.cos(distance / self._wavelength * 2 * math.pi + self._phase)
v.setPoint(p + n) v.setPoint(p + n)
stroke.UpdateLength()
class PerlinNoise1DShader(StrokeShader): class PerlinNoise1DShader(StrokeShader):
def __init__(self, freq = 10, amp = 10, oct = 4, angle = 45, seed = -1): def __init__(self, freq = 10, amp = 10, oct = 4, angle = 45, seed = -1):
@ -468,6 +469,7 @@ class PerlinNoise1DShader(StrokeShader):
nres = self.__noise.turbulence1(v.u(), self.__freq, self.__amp, self.__oct) nres = self.__noise.turbulence1(v.u(), self.__freq, self.__amp, self.__oct)
v.setPoint(v.getPoint() + nres * self.__dir) v.setPoint(v.getPoint() + nres * self.__dir)
it.increment() it.increment()
stroke.UpdateLength()
class PerlinNoise2DShader(StrokeShader): class PerlinNoise2DShader(StrokeShader):
def __init__(self, freq = 10, amp = 10, oct = 4, angle = 45, seed = -1): def __init__(self, freq = 10, amp = 10, oct = 4, angle = 45, seed = -1):
@ -488,6 +490,7 @@ class PerlinNoise2DShader(StrokeShader):
nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct) nres = self.__noise.turbulence2(vec, self.__freq, self.__amp, self.__oct)
v.setPoint(v.getPoint() + nres * self.__dir) v.setPoint(v.getPoint() + nres * self.__dir)
it.increment() it.increment()
stroke.UpdateLength()
# Predicates and helper functions # Predicates and helper functions

@ -223,6 +223,29 @@ static PyObject * Stroke_RemoveVertex( BPy_Stroke *self, PyObject *args ) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static char Stroke_UpdateLength___doc__[] =
".. method:: UpdateLength()\n"
"\n"
" Updates the 2D length of the Stroke.\n";
static PyObject * Stroke_UpdateLength( BPy_Stroke *self ) {
self->s->UpdateLength();
Py_RETURN_NONE;
}
static char Stroke_getLength2D___doc__[] =
".. method:: getLength2D()\n"
"\n"
" Returns the 2D length of the Stroke.\n"
"\n"
" :return: the 2D length of the Stroke.\n"
" :rtype: float\n";
static PyObject * Stroke_getLength2D( BPy_Stroke *self ) {
return PyFloat_FromDouble( self->s->getLength2D() );
}
static char Stroke_getMediumType___doc__[] = static char Stroke_getMediumType___doc__[] =
".. method:: getMediumType()\n" ".. method:: getMediumType()\n"
"\n" "\n"
@ -415,6 +438,8 @@ static PyMethodDef BPy_Stroke_methods[] = {
{"Resample", ( PyCFunction ) Stroke_Resample, METH_VARARGS, Stroke_Resample___doc__}, {"Resample", ( PyCFunction ) Stroke_Resample, METH_VARARGS, Stroke_Resample___doc__},
{"RemoveVertex", ( PyCFunction ) Stroke_RemoveVertex, METH_VARARGS, Stroke_RemoveVertex___doc__}, {"RemoveVertex", ( PyCFunction ) Stroke_RemoveVertex, METH_VARARGS, Stroke_RemoveVertex___doc__},
{"InsertVertex", ( PyCFunction ) Stroke_InsertVertex, METH_VARARGS, Stroke_InsertVertex___doc__}, {"InsertVertex", ( PyCFunction ) Stroke_InsertVertex, METH_VARARGS, Stroke_InsertVertex___doc__},
{"UpdateLength", ( PyCFunction ) Stroke_UpdateLength, METH_NOARGS, Stroke_UpdateLength___doc__},
{"getLength2D", ( PyCFunction ) Stroke_getLength2D, METH_NOARGS, Stroke_getLength2D___doc__},
{"getMediumType", ( PyCFunction ) Stroke_getMediumType, METH_NOARGS, Stroke_getMediumType___doc__}, {"getMediumType", ( PyCFunction ) Stroke_getMediumType, METH_NOARGS, Stroke_getMediumType___doc__},
{"getTextureId", ( PyCFunction ) Stroke_getTextureId, METH_NOARGS, Stroke_getTextureId___doc__}, {"getTextureId", ( PyCFunction ) Stroke_getTextureId, METH_NOARGS, Stroke_getTextureId___doc__},
{"hasTips", ( PyCFunction ) Stroke_hasTips, METH_NOARGS, Stroke_hasTips___doc__}, {"hasTips", ( PyCFunction ) Stroke_hasTips, METH_NOARGS, Stroke_hasTips___doc__},

@ -586,6 +586,8 @@ namespace StrokeShaders {
(v0)->setPoint(newFirst[0], newFirst[1]); (v0)->setPoint(newFirst[0], newFirst[1]);
Vec2d newLast(last+_amount*dn); Vec2d newLast(last+_amount*dn);
(vn)->setPoint(newLast[0], newLast[1]); (vn)->setPoint(newLast[0], newLast[1]);
stroke.UpdateLength();
return 0; return 0;
} }
@ -611,6 +613,7 @@ namespace StrokeShaders {
sv->setPoint(newPoint[0], newPoint[1]); sv->setPoint(newPoint[0], newPoint[1]);
++it; ++it;
} }
stroke.UpdateLength();
return 0; return 0;
} }
@ -726,6 +729,7 @@ namespace StrokeShaders {
++it; ++it;
++n; ++n;
} }
stroke.UpdateLength();
return 0; return 0;
} }
@ -844,6 +848,7 @@ namespace StrokeShaders {
++p; ++p;
++n; ++n;
} }
stroke.UpdateLength();
// Deal with extra vertices: // Deal with extra vertices:
if(nExtraVertex == 0) if(nExtraVertex == 0)
@ -931,6 +936,7 @@ namespace StrokeShaders {
sv->setPoint(newPoint[0], newPoint[1]); sv->setPoint(newPoint[0], newPoint[1]);
++it; ++it;
} }
stroke.UpdateLength();
return 0; return 0;
} }
@ -1038,6 +1044,7 @@ namespace StrokeShaders {
// u.normalize(); // u.normalize();
// (*a)->setPoint((*a)->x()-u.x()*10, (*a)->y()-u.y()*10); // (*a)->setPoint((*a)->x()-u.x()*10, (*a)->y()-u.y()*10);
} }
stroke.UpdateLength();
// delete stuff // delete stuff
for(cp=_results.begin(), cpend=_results.end(); for(cp=_results.begin(), cpend=_results.end();
@ -1076,6 +1083,7 @@ namespace StrokeShaders {
{ {
v->setPoint(piece.A.x()+v->u()*u.x()+n.x()*offset, piece.A.y()+v->u()*u.y()+n.y()*offset); v->setPoint(piece.A.x()+v->u()*u.x()+n.x()*offset, piece.A.y()+v->u()*u.y()+n.y()*offset);
} }
stroke.UpdateLength();
return 0; return 0;
} }

@ -674,28 +674,7 @@ void Stroke::RemoveVertex(StrokeVertex *iVertex)
break; break;
} }
} }
// recompute various values (length, curvilign abscissa) UpdateLength();
float curvabsc = 0.f;
it=_Vertices.begin();
itend=_Vertices.end();
vertex_container::iterator previous=it;
for(;
(it!=itend);
++it)
{
if(it != previous)
curvabsc += ((*it)->point2d()-(*previous)->point2d()).norm();
(*it)->setCurvilinearAbscissa(curvabsc);
previous = it;
}
_Length = curvabsc;
it=_Vertices.begin();
for(;
(it!=itend);
++it)
{
(*it)->setStrokeLength(_Length);
}
} }
void Stroke::InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next) void Stroke::InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next)
@ -704,10 +683,14 @@ void Stroke::InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIte
vertex_container::iterator itnext = next.getIt(); vertex_container::iterator itnext = next.getIt();
_Vertices.insert(itnext, iVertex); _Vertices.insert(itnext, iVertex);
UpdateLength();
}
void Stroke::UpdateLength()
{
// recompute various values (length, curvilign abscissa) // recompute various values (length, curvilign abscissa)
float curvabsc = 0.f; float curvabsc = 0.f;
it=_Vertices.begin(); vertex_container::iterator it=_Vertices.begin(), itend=_Vertices.end();
itend=_Vertices.end();
vertex_container::iterator previous=it; vertex_container::iterator previous=it;
for(; for(;
(it!=itend); (it!=itend);

@ -466,6 +466,9 @@ public:
*/ */
void InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next); void InsertVertex(StrokeVertex *iVertex, StrokeInternal::StrokeVertexIterator next);
/*! Updates the 2D length of the Stroke */
void UpdateLength();
/* Render method */ /* Render method */
void Render(const StrokeRenderer *iRenderer ); void Render(const StrokeRenderer *iRenderer );
void RenderBasic(const StrokeRenderer *iRenderer ); void RenderBasic(const StrokeRenderer *iRenderer );