INCUSОкружность, ровная, итераций хватает..
При анимации по кругу заметен общий люфт.
INCUS Вы анимируете вершины bezier или управляющие-handle?
Попробуйте такой вариант, пока только для вершин Corner:
Создаем один сплайн Circle и конвертируем его в Editable Spline.
Cплайн должен быть замкнутым-Closed.
Допустим нам хватает 6 итераций для сплайна.
В свитке Interpolation в поле Steps устанавливаем 0 (ноль) итераций-разбиений для сплайна.
Выделяем все сегменты-segment сплайна.
В свитке Geometry в поле Divisions устанавливаем 6 итераций-разбиений для сплайна.
Нажимаем кнопку Divide.
Выделяем все вершины сплайна и устанавливаем тип вершин Corner.
Создаем один чайник Teapot. Выделяем сплайн и чайник.
Запускаем скрипт. В новом окне нажимаем кнопку Apply.
Анимируем % Along Path чайника, который находится в начале сплайна.
Скрипт проверяет только половину длины сплайна и ищет подходящее место.
Объект Dummy и Plane являются вспомогательными и не нужно их удалять.
try (destroydialog igorznag_spline_ik) catch()
rollout igorznag_spline_ik "SplineIK"
(
--gui
spinner sp_count "Count:" range:[2,1e9,10] fieldWidth:60 type:#integer pos:[32,5]
spinner sp_spacing "Spacing:" range:[0,1e9,10] fieldWidth:60 type:#worldunits pos:[21,22]
checkbox chb_taf "Flip. Object LookAt Axis = X" pos:[5,57]
radiobuttons rb_stoa "Object Upnode Axis" labels:#("Y", "Z") pos:[5,75]
checkbox chb_stoaf "Flip" pos:[80,92]
label lbl_info "Spline Upnode Axis = Z" pos:[5,110]
button btn_apply "Apply" pos:[130,75] width:50 height:50
--events
on btn_apply pressed do
(
if(selection.count==2)then
(
spline_path=undefined; obj=undefined;
spline_types=#(SplineShape,line);cl1=classof selection[1];cl2=classof selection[2]
if(finditem spline_types cl1!=0 and finditem spline_types cl2==0)then
(spline_path=selection[1];obj=selection[2])
if(finditem spline_types cl2!=0 and finditem spline_types cl1==0)then
(spline_path=selection[2];obj=selection[1])
if(spline_path!=undefined)then
(
if numSplines spline_path==1 then
(
if isClosed spline_path 1 then
(
undo on
(
with animate off
(
len=curveLength spline_path 1
if(sp_spacing.value<len)then
(
objs_temp_a=#(); objs_count=sp_count.value
for i=1 to objs_count do
(
maxOps.cloneNodes obj cloneType:#instance newNodes:&n
append objs_temp_a n[1];
)--for i=1 to objs_count do
--
d=plane();d.name=uniquename "igorznag_splineIK";
d.width=0;d.length=0;d.widthsegs=1;d.lengthsegs=1;
d.pos.controller=Position_Constraint()
c=d.pos.controller;c.constraints.appendTarget objs_temp_a[1] 100
d_end=dummy();d_end.pos.controller=position_xyz();
--
for i=1 to objs_temp_a.count do
(
if(i==1)then
(
objs_temp_a[i].pos.controller=Path_Constraint()
c=objs_temp_a[i].pos.controller;c.path=spline_path
c.percent.controller=linear_float();
setBeforeORT c.percent.controller #cycle
setAfterORT c.percent.controller #cycle
)
if(i>1)then objs_temp_a[i].pos.controller=position_xyz();
objs_temp_a[i].rotation.controller = LookAt_Constraint();
c=objs_temp_a[i].rotation.controller
c.target_axis=0;c.lookat_vector_length=0;c.target_axisFlip=chb_taf.checked
objs_temp_a[i].rotation.controller.upnode_world = off
objs_temp_a[i].rotation.controller.pickUpNode=spline_path
c.upnode_ctrl=1;c.StoUP_axis=rb_stoa.state;c.StoUP_axisFlip=chb_stoaf.checked;
c.upnode_axis=2
if(i<objs_temp_a.count)then c.appendTarget objs_temp_a[i+1] 100
if(i==objs_temp_a.count)then c.appendTarget d_end 100
)--for i=1 to objs_temp_a.count do
--script
d.rotation.controller=rotation_script()
c=d.rotation.controller
setBeforeORT c #cycle; setAfterORT c #cycle
c.AddObject "igorznag_spline_path" spline_path
c.AddObject "igorznag_dummy_end" d_end.pos.controller
for i=1 to objs_temp_a.count do
c.AddObject ("igorznag_obj"+(i as string)) objs_temp_a[i].pos.controller
--
str=""
str+="fn sphere_segment_intersect c r o t=";str+="\n"
str+="(";str+="\n"
str+="roots_a=#(); sp_dir=normalize(t-o)";str+="\n"
str+="det=(dot sp_dir (o-c))*(dot sp_dir (o-c))- dot (o-c) (o-c)+r*r";str+="\n"
str+="if(det>=0)then";str+="\n"
str+="(";str+="\n"
str+="d1=-(dot sp_dir (o-c))+pow det 0.5; d2=-(dot sp_dir (o-c))-pow det 0.5";str+="\n"
str+="p1=o+d1*sp_dir; p2=o+d2*sp_dir";str+="\n"
str+="if(dot sp_dir (p1-o)>0 and length (p1-o) < length (t-o))then append roots_a p1";str+="\n"
str+="if(dot sp_dir (p2-o)>0 and length (p2-o) < length (t-o))then append roots_a p2";str+="\n"
str+=")--if(det>=0)then";str+="\n"
str+="roots_a";str+="\n"
str+=")--fn sphere_segment_intersect c r o t=";str+="\n"
str+="";str+="\n"
str+="with animate off ( try (";str+="\n"
str+="spacing="+(sp_spacing.value as string);str+="\n"
str+="len=curveLength igorznag_spline_path 1";str+="\n"
str+="if(len>0)then";str+="\n"
str+="(";str+="\n"
str+="percent1=igorznag_obj1.percent";str+="\n"
str+="percent1=(mod (percent1/100.0) 1.0);if(percent1<0)then percent1+=1";str+="\n"
str+="seg_legths=getSegLengths igorznag_spline_path 1 cum:true numArcSteps:0";str+="\n"
str+="segs_count=int(seg_legths.count-1)/2.0";str+="\n"
str+="seg_by_percent1=0; for i=1 to segs_count where seg_legths[i]>=percent1 do (seg_by_percent1=i;exit)";str+="\n"
str+="seg_by_percent_offset=seg_by_percent1";str+="\n"
for j=2 to objs_temp_a.count do
(
str+="for i=0 to (int(segs_count/2.0)) do";str+="\n"
str+="(";str+="\n"
str+="c=igorznag_obj"+((j-1) as string)+".value";str+="\n"
str+="r=spacing; o=undefined;";str+="\n"
str+="seg_by_percent_o=seg_by_percent_offset+i";str+="\n"
str+="if(seg_by_percent_o>segs_count)then seg_by_percent_o-=segs_count";str+="\n"
str+="o=getKnotPoint igorznag_spline_path 1 seg_by_percent_o";str+="\n"
str+="seg_by_percent_t=seg_by_percent_offset+i+1";str+="\n"
str+="if(seg_by_percent_t>segs_count)then seg_by_percent_t-=segs_count";str+="\n"
str+="t=getKnotPoint igorznag_spline_path 1 seg_by_percent_t";str+="\n"
str+="roots=sphere_segment_intersect c r o t";str+="\n"
str+="if(roots.count>0)then";str+="\n"
str+="(";str+="\n"
str+="if roots.count==1 then";str+="\n"
str+="(";str+="\n"
str+="if (dot (roots[1]-o) (roots[1]-c) >0) then";str+="\n"
str+="(";str+="\n"
str+=" igorznag_obj"+(j as string)+".value=roots[1]";str+="\n"
str+="seg_by_percent_offset=seg_by_percent_o";str+="\n"
str+="exit;";str+="\n"
str+=")";str+="\n"
str+=")";str+="\n"
str+="if roots.count==2 then";str+="\n"
str+="(";str+="\n"
str+="temp_root=roots[2]";str+="\n"
str+="if (dot (roots[1]-o) (roots[1]-c)>0)then temp_root=roots[1]";str+="\n"
str+="if (dot (roots[2]-o) (roots[2]-c)>0)then temp_root=roots[2]";str+="\n"
str+="igorznag_obj"+(j as string)+".value=temp_root";str+="\n"
str+="seg_by_percent_offset=seg_by_percent_o";str+="\n"
str+="exit;";str+="\n"
str+=")--if roots.count==2 then";str+="\n"
str+=")--if(roots.count>0)then";str+="\n"
str+=")--for i=0 to int(segs_count/2.0) do";str+="\n"
)--for i=2 to 2 do--objs_temp_a.count do
--d_end
str+="for i=0 to (int(segs_count/2.0)) do";str+="\n"
str+="(";str+="\n"
str+="c=igorznag_obj"+(objs_temp_a.count as string)+".value";str+="\n"
str+="r=spacing; o=undefined;";str+="\n"
str+="seg_by_percent_o=seg_by_percent_offset+i";str+="\n"
str+="if(seg_by_percent_o>segs_count)then seg_by_percent_o-=segs_count";str+="\n"
str+="o=getKnotPoint igorznag_spline_path 1 seg_by_percent_o";str+="\n"
str+="seg_by_percent_t=seg_by_percent_offset+i+1";str+="\n"
str+="if(seg_by_percent_t>segs_count)then seg_by_percent_t-=segs_count";str+="\n"
str+="t=getKnotPoint igorznag_spline_path 1 seg_by_percent_t";str+="\n"
str+="roots=sphere_segment_intersect c r o t";str+="\n"
str+="if(roots.count>0)then";str+="\n"
str+="(";str+="\n"
str+="if roots.count==1 then";str+="\n"
str+="(";str+="\n"
str+="if (dot (roots[1]-o) (roots[1]-c) >0) then";str+="\n"
str+="(";str+="\n"
str+="igorznag_dummy_end.value=roots[1]";str+="\n"
str+="seg_by_percent_offset=seg_by_percent_o";str+="\n"
str+="exit;";str+="\n"
str+=")";str+="\n"
str+=")";str+="\n"
str+="if roots.count==2 then";str+="\n"
str+="(";str+="\n"
str+="temp_root=roots[2]";str+="\n"
str+="if (dot (roots[1]-o) (roots[1]-c)>0)then temp_root=roots[1]";str+="\n"
str+="if (dot (roots[2]-o) (roots[2]-c)>0)then temp_root=roots[2]";str+="\n"
str+="igorznag_dummy_end.value=temp_root";str+="\n"
str+="seg_by_percent_offset=seg_by_percent_o";str+="\n"
str+="exit;";str+="\n"
str+=")--if roots.count==2 then";str+="\n"
str+=")--if(roots.count>0)then";str+="\n"
str+=")--for i=0 to int(segs_count/2.0) do";str+="\n"
--d_end
str+=")--if(len>0)then";str+="\n"
str+=")catch (quat 0 0 0 1))--try with animate off";str+="\n"
str+="quat 0 0 0 1";
c.script=str
select objs_temp_a; selectmore d; selectmore d_end
redrawViews()
)--if(sp_precision.value<len and sp_spacing.value<len)then
)--with animate off
)--undo off
)--if isClosed spline_path 1 then
)--if numSplines spline_path==1then
)--if(spline_path!=undefined)then
)--if(selection.count==2)then
)--on btn_apply pressed do
--
); createdialog igorznag_spline_ik 190 135
INCUSОкружность, ровная, итераций хватает..
При анимации по кругу заметен общий люфт.
Попробуйте такой вариант:
Создаем один сплайн Circle и конвертируем его в Editable Spline.
В свитке Interpolation в поле Steps устанавливаем нужное количество итераций, например 6.
Чем больше итераций, тем больше вычислений. Cплайн должен быть замкнутым-Closed.
Создаем один чайник Teapot. Выделяем сплайн и чайник.
Запускаем скрипт. В новом окне нажимаем кнопку Apply.
Анимируем % Along Path чайника, который находится в начале сплайна.
try (destroydialog igorznag_spline_ik) catch()
rollout igorznag_spline_ik "SplineIK"
(
--gui
spinner sp_count "Count:" range:[2,1e9,10] fieldWidth:60 type:#integer pos:[32,5]
spinner sp_spacing "Spacing:" range:[0,1e9,10] fieldWidth:60 type:#worldunits pos:[21,22]
checkbox chb_taf "Flip. Object LookAt Axis = X" pos:[5,57]
radiobuttons rb_stoa "Object Upnode Axis" labels:#("Y", "Z") pos:[5,75]
checkbox chb_stoaf "Flip" pos:[80,92]
label lbl_info "Spline Upnode Axis = Z" pos:[5,110]
button btn_apply "Apply" pos:[130,75] width:50 height:50
--events
on btn_apply pressed do
(
if(selection.count==2)then
(
spline_path=undefined; obj=undefined;
spline_types=#(SplineShape,line);cl1=classof selection[1];cl2=classof selection[2]
if(finditem spline_types cl1!=0 and finditem spline_types cl2==0)then
(spline_path=selection[1];obj=selection[2])
if(finditem spline_types cl2!=0 and finditem spline_types cl1==0)then
(spline_path=selection[2];obj=selection[1])
if(spline_path!=undefined)then
(
if numSplines spline_path==1 then
(
if isClosed spline_path 1 then
(
undo on
(
with animate off
(
len=curveLength spline_path 1
if(sp_spacing.value<len)then
(
objs_temp_a=#(); objs_count=sp_count.value
for i=1 to objs_count do
(
maxOps.cloneNodes obj cloneType:#instance newNodes:&n
append objs_temp_a n[1];
)--for i=1 to objs_count do
--
d=plane();d.name=uniquename "igorznag_splineIK";
d.width=0;d.length=0;d.widthsegs=1;d.lengthsegs=1;
d.pos.controller=Position_Constraint()
c=d.pos.controller;c.constraints.appendTarget objs_temp_a[1] 100
d_end=dummy();d_end.pos.controller=position_xyz();
--
for i=1 to objs_temp_a.count do
(
if(i==1)then
(
objs_temp_a[i].pos.controller=Path_Constraint()
c=objs_temp_a[i].pos.controller;c.path=spline_path
c.percent.controller=linear_float();
setBeforeORT c.percent.controller #cycle
setAfterORT c.percent.controller #cycle
)
if(i>1)then objs_temp_a[i].pos.controller=position_xyz();
objs_temp_a[i].rotation.controller = LookAt_Constraint();
c=objs_temp_a[i].rotation.controller
c.target_axis=0;c.lookat_vector_length=0;c.target_axisFlip=chb_taf.checked
objs_temp_a[i].rotation.controller.upnode_world = off
objs_temp_a[i].rotation.controller.pickUpNode=spline_path
c.upnode_ctrl=1;c.StoUP_axis=rb_stoa.state;c.StoUP_axisFlip=chb_stoaf.checked;
c.upnode_axis=2
if(i<objs_temp_a.count)then c.appendTarget objs_temp_a[i+1] 100
if(i==objs_temp_a.count)then c.appendTarget d_end 100
)--for i=1 to objs_temp_a.count do
--script
d.rotation.controller=rotation_script()
c=d.rotation.controller
setBeforeORT c #cycle; setAfterORT c #cycle
c.AddObject "igorznag_spline_path" spline_path
c.AddObject "igorznag_dummy_end" d_end.pos.controller
for i=1 to objs_temp_a.count do
c.AddObject ("igorznag_obj"+(i as string)) objs_temp_a[i].pos.controller
--
str=""
str+="fn sphere_segment_intersect c r o t=";str+="\n"
str+="(";str+="\n"
str+="roots_a=#(); sp_dir=normalize(t-o)";str+="\n"
str+="det=(dot sp_dir (o-c))*(dot sp_dir (o-c))- dot (o-c) (o-c)+r*r";str+="\n"
str+="if(det>=0)then";str+="\n"
str+="(";str+="\n"
str+="d1=-(dot sp_dir (o-c))+pow det 0.5; d2=-(dot sp_dir (o-c))-pow det 0.5";str+="\n"
str+="p1=o+d1*sp_dir; p2=o+d2*sp_dir";str+="\n"
str+="if(dot sp_dir (p1-o)>0 and length (p1-o) < length (t-o))then append roots_a p1";str+="\n"
str+="if(dot sp_dir (p2-o)>0 and length (p2-o) < length (t-o))then append roots_a p2";str+="\n"
str+=")--if(det>=0)then";str+="\n"
str+="roots_a";str+="\n"
str+=")--fn sphere_segment_intersect c r o t=";str+="\n"
str+="";str+="\n"
str+="with animate off ( try (";str+="\n"
str+="spacing="+(sp_spacing.value as string);str+="\n"
str+="len=curveLength igorznag_spline_path 1";str+="\n"
str+="if(len>0)then";str+="\n"
str+="(";str+="\n"
str+="percent1=igorznag_obj1.percent";str+="\n"
str+="percent1=(mod (percent1/100.0) 1.0);if(percent1<0)then percent1+=1";str+="\n"
str+="seg_points=#();n=numSegments igorznag_spline_path 1";str+="\n"
str+="for i=1 to n do for j=0 to igorznag_spline_path.steps do";str+="\n"
str+="(";str+="\n"
str+="p0=getKnotPoint igorznag_spline_path 1 i; p1=getOutVec igorznag_spline_path 1 i;p2=undefined;p3=undefined";str+="\n"
str+="if i==n then (p2=getInVec igorznag_spline_path 1 1;p3=getKnotPoint igorznag_spline_path 1 1)";str+="\n"
str+="else (p2=getInVec igorznag_spline_path 1 (i+1);p3=getKnotPoint igorznag_spline_path 1 (i+1))";str+="\n"
str+="t=1.0*j/(igorznag_spline_path.steps+1)";str+="\n"
str+="p=(1-t)*(1-t)*(1-t)*p0+3*t*(t-1)*(t-1)*p1+3*t*t*(1-t)*p2+t*t*t*p3; append seg_points p";str+="\n"
str+=")--for i=1 to n do for j=0 to igorznag_spline_path.steps do";str+="\n"
str+="seg_lengths_acc=#(); n=seg_points.count;for i=1 to n do";str+="\n"
str+="(";str+="\n"
str+="p1=seg_points[i];p2=undefined";str+="\n"
str+="if i==n then p2=seg_points[1] else p2=seg_points[i+1]";str+="\n"
str+="if i==1 then append seg_lengths_acc (distance p1 p2)";str+="\n"
str+="else append seg_lengths_acc (seg_lengths_acc[i-1]+distance p1 p2)";str+="\n"
str+=")--for i=1 to n do";str+="\n"
str+="seg_percents_acc=#();n=seg_lengths_acc.count; ";str+="\n"
str+="for i=1 to n do append seg_percents_acc (seg_lengths_acc[i]/seg_lengths_acc[n])";str+="\n"
str+="seg_by_percent1=0; for i=1 to seg_percents_acc.count where seg_percents_acc[i]>=percent1 do (seg_by_percent1=i;exit)";str+="\n"
str+="seg_by_percent_offset=seg_by_percent1";str+="\n"
for j=2 to objs_temp_a.count do
(
str+="for i=0 to (int(seg_percents_acc.count/2.0)) do";str+="\n"
str+="(";str+="\n"
str+="c=igorznag_obj"+((j-1) as string)+".value";str+="\n"
str+="r=spacing; o=undefined;";str+="\n"
str+="seg_by_percent_o=seg_by_percent_offset+i";str+="\n"
str+="if(seg_by_percent_o>seg_percents_acc.count)then seg_by_percent_o-=seg_percents_acc.count";str+="\n"
str+="o=seg_points[seg_by_percent_o]";str+="\n"
str+="seg_by_percent_t=seg_by_percent_offset+i+1";str+="\n"
str+="if(seg_by_percent_t>seg_percents_acc.count)then seg_by_percent_t-=seg_percents_acc.count";str+="\n"
str+="t=seg_points[seg_by_percent_t]";str+="\n"
str+="roots=sphere_segment_intersect c r o t";str+="\n"
str+="if(roots.count>0)then";str+="\n"
str+="(";str+="\n"
str+="if roots.count==1 then";str+="\n"
str+="(";str+="\n"
str+="if (dot (roots[1]-o) (roots[1]-c) >0) then";str+="\n"
str+="(";str+="\n"
str+=" igorznag_obj"+(j as string)+".value=roots[1]";str+="\n"
str+="seg_by_percent_offset=seg_by_percent_o";str+="\n"
str+="exit;";str+="\n"
str+=")";str+="\n"
str+=")";str+="\n"
str+="if roots.count==2 then";str+="\n"
str+="(";str+="\n"
str+="temp_root=roots[2]";str+="\n"
str+="if (dot (roots[1]-o) (roots[1]-c)>0)then temp_root=roots[1]";str+="\n"
str+="if (dot (roots[2]-o) (roots[2]-c)>0)then temp_root=roots[2]";str+="\n"
str+="igorznag_obj"+(j as string)+".value=temp_root";str+="\n"
str+="seg_by_percent_offset=seg_by_percent_o";str+="\n"
str+="exit;";str+="\n"
str+=")--if roots.count==2 then";str+="\n"
str+=")--if(roots.count>0)then";str+="\n"
str+=")--for i=0 to int(seg_percents_acc.count/2.0) do";str+="\n"
)--for i=2 to 2 do--objs_temp_a.count do
--d_end
str+="for i=0 to (int(seg_percents_acc.count/2.0)) do";str+="\n"
str+="(";str+="\n"
str+="c=igorznag_obj"+(objs_temp_a.count as string)+".value";str+="\n"
str+="r=spacing; o=undefined;";str+="\n"
str+="seg_by_percent_o=seg_by_percent_offset+i";str+="\n"
str+="if(seg_by_percent_o>seg_percents_acc.count)then seg_by_percent_o-=seg_percents_acc.count";str+="\n"
str+="o=seg_points[seg_by_percent_o]";str+="\n"
str+="seg_by_percent_t=seg_by_percent_offset+i+1";str+="\n"
str+="if(seg_by_percent_t>seg_percents_acc.count)then seg_by_percent_t-=seg_percents_acc.count";str+="\n"
str+="t=seg_points[seg_by_percent_t]";str+="\n"
str+="roots=sphere_segment_intersect c r o t";str+="\n"
str+="if(roots.count>0)then";str+="\n"
str+="(";str+="\n"
str+="if roots.count==1 then";str+="\n"
str+="(";str+="\n"
str+="if (dot (roots[1]-o) (roots[1]-c) >0) then";str+="\n"
str+="(";str+="\n"
str+="igorznag_dummy_end.value=roots[1]";str+="\n"
str+="seg_by_percent_offset=seg_by_percent_o";str+="\n"
str+="exit;";str+="\n"
str+=")";str+="\n"
str+=")";str+="\n"
str+="if roots.count==2 then";str+="\n"
str+="(";str+="\n"
str+="temp_root=roots[2]";str+="\n"
str+="if (dot (roots[1]-o) (roots[1]-c)>0)then temp_root=roots[1]";str+="\n"
str+="if (dot (roots[2]-o) (roots[2]-c)>0)then temp_root=roots[2]";str+="\n"
str+="igorznag_dummy_end.value=temp_root";str+="\n"
str+="seg_by_percent_offset=seg_by_percent_o";str+="\n"
str+="exit;";str+="\n"
str+=")--if roots.count==2 then";str+="\n"
str+=")--if(roots.count>0)then";str+="\n"
str+=")--for i=0 to int(segs_count/2.0) do";str+="\n"
--d_end
str+=")--if(len>0)then";str+="\n"
str+=")catch (quat 0 0 0 1))--try with animate off";str+="\n"
str+="quat 0 0 0 1";
c.script=str
select objs_temp_a; selectmore d; selectmore d_end
redrawViews()
)--if(sp_precision.value<len and sp_spacing.value<len)then
)--with animate off
)--undo off
)--if isClosed spline_path 1 then
)--if numSplines spline_path==1then
)--if(spline_path!=undefined)then
)--if(selection.count==2)then
)--on btn_apply pressed do
--
); createdialog igorznag_spline_ik 190 135
Вещь!!
Удивительно, но это работает !!!
Запустил сто траков гусеницы, и они так шустренько поехали как миленькие.
Спасибо большое тебе, igorznaq, очень полезная штука получилась.
извиняюсь, не его, а ее (модель ). но это зависит какая у вас модель. но мы этого не знаем. INCUS - если для Вас принципиально нужно сделать это именно костями, то я бы предложил такой вариант. Создаете обычный ИК (Hi Solver) на каждый сегмент цепочки костей. Т.е. если в цепи 10 костей ( не считая end point) то получится 10 HI Solver - ов. потом path constrain пускаете по сплайну эти ик солверы . Придется вручную их позиционировать на сплайне потом, потому-что все они будут пригать к началу сплайна, и не забыть удалить анимацию созданную автоматически. Дальше нужно LookAT констрейном для каждой кости указать дочерную кость , ли сам ик солвер который стои впереди кости. Ну и парамтр Along path констрейна всех ик солверов нужно привязать к какому-нибудь параметру, через wire parameters , либо скопировать как Instance трек в track view .
Если у вас модель - прямая цепочка как в видео туторе, и не обязательно делать кастями, то можно просто на просто использовать PathDeform модификатор .
Доступ к резюме доступен только по пакетному доступу HR менеджерам зарегистрированных компаний. Узнать о вариантах корпоративных пакетов можно по ссылке.
igorznag
Попробуйте такой вариант, пока только для вершин Corner:
Создаем один сплайн Circle и конвертируем его в Editable Spline.
Cплайн должен быть замкнутым-Closed.
Допустим нам хватает 6 итераций для сплайна.
В свитке Interpolation в поле Steps устанавливаем 0 (ноль) итераций-разбиений для сплайна.
Выделяем все сегменты-segment сплайна.
В свитке Geometry в поле Divisions устанавливаем 6 итераций-разбиений для сплайна.
Нажимаем кнопку Divide.
Выделяем все вершины сплайна и устанавливаем тип вершин Corner.
Создаем один чайник Teapot. Выделяем сплайн и чайник.
Запускаем скрипт. В новом окне нажимаем кнопку Apply.
Анимируем % Along Path чайника, который находится в начале сплайна.
Скрипт проверяет только половину длины сплайна и ищет подходящее место.
Объект Dummy и Plane являются вспомогательными и не нужно их удалять.
try (destroydialog igorznag_spline_ik) catch() rollout igorznag_spline_ik "SplineIK" ( --gui spinner sp_count "Count:" range:[2,1e9,10] fieldWidth:60 type:#integer pos:[32,5] spinner sp_spacing "Spacing:" range:[0,1e9,10] fieldWidth:60 type:#worldunits pos:[21,22] checkbox chb_taf "Flip. Object LookAt Axis = X" pos:[5,57] radiobuttons rb_stoa "Object Upnode Axis" labels:#("Y", "Z") pos:[5,75] checkbox chb_stoaf "Flip" pos:[80,92] label lbl_info "Spline Upnode Axis = Z" pos:[5,110] button btn_apply "Apply" pos:[130,75] width:50 height:50 --events on btn_apply pressed do ( if(selection.count==2)then ( spline_path=undefined; obj=undefined; spline_types=#(SplineShape,line);cl1=classof selection[1];cl2=classof selection[2] if(finditem spline_types cl1!=0 and finditem spline_types cl2==0)then (spline_path=selection[1];obj=selection[2]) if(finditem spline_types cl2!=0 and finditem spline_types cl1==0)then (spline_path=selection[2];obj=selection[1]) if(spline_path!=undefined)then ( if numSplines spline_path==1 then ( if isClosed spline_path 1 then ( undo on ( with animate off ( len=curveLength spline_path 1 if(sp_spacing.value<len)then ( objs_temp_a=#(); objs_count=sp_count.value for i=1 to objs_count do ( maxOps.cloneNodes obj cloneType:#instance newNodes:&n append objs_temp_a n[1]; )--for i=1 to objs_count do -- d=plane();d.name=uniquename "igorznag_splineIK"; d.width=0;d.length=0;d.widthsegs=1;d.lengthsegs=1; d.pos.controller=Position_Constraint() c=d.pos.controller;c.constraints.appendTarget objs_temp_a[1] 100 d_end=dummy();d_end.pos.controller=position_xyz(); -- for i=1 to objs_temp_a.count do ( if(i==1)then ( objs_temp_a[i].pos.controller=Path_Constraint() c=objs_temp_a[i].pos.controller;c.path=spline_path c.percent.controller=linear_float(); setBeforeORT c.percent.controller #cycle setAfterORT c.percent.controller #cycle ) if(i>1)then objs_temp_a[i].pos.controller=position_xyz(); objs_temp_a[i].rotation.controller = LookAt_Constraint(); c=objs_temp_a[i].rotation.controller c.target_axis=0;c.lookat_vector_length=0;c.target_axisFlip=chb_taf.checked objs_temp_a[i].rotation.controller.upnode_world = off objs_temp_a[i].rotation.controller.pickUpNode=spline_path c.upnode_ctrl=1;c.StoUP_axis=rb_stoa.state;c.StoUP_axisFlip=chb_stoaf.checked; c.upnode_axis=2 if(i<objs_temp_a.count)then c.appendTarget objs_temp_a[i+1] 100 if(i==objs_temp_a.count)then c.appendTarget d_end 100 )--for i=1 to objs_temp_a.count do --script d.rotation.controller=rotation_script() c=d.rotation.controller setBeforeORT c #cycle; setAfterORT c #cycle c.AddObject "igorznag_spline_path" spline_path c.AddObject "igorznag_dummy_end" d_end.pos.controller for i=1 to objs_temp_a.count do c.AddObject ("igorznag_obj"+(i as string)) objs_temp_a[i].pos.controller -- str="" str+="fn sphere_segment_intersect c r o t=";str+="\n" str+="(";str+="\n" str+="roots_a=#(); sp_dir=normalize(t-o)";str+="\n" str+="det=(dot sp_dir (o-c))*(dot sp_dir (o-c))- dot (o-c) (o-c)+r*r";str+="\n" str+="if(det>=0)then";str+="\n" str+="(";str+="\n" str+="d1=-(dot sp_dir (o-c))+pow det 0.5; d2=-(dot sp_dir (o-c))-pow det 0.5";str+="\n" str+="p1=o+d1*sp_dir; p2=o+d2*sp_dir";str+="\n" str+="if(dot sp_dir (p1-o)>0 and length (p1-o) < length (t-o))then append roots_a p1";str+="\n" str+="if(dot sp_dir (p2-o)>0 and length (p2-o) < length (t-o))then append roots_a p2";str+="\n" str+=")--if(det>=0)then";str+="\n" str+="roots_a";str+="\n" str+=")--fn sphere_segment_intersect c r o t=";str+="\n" str+="";str+="\n" str+="with animate off ( try (";str+="\n" str+="spacing="+(sp_spacing.value as string);str+="\n" str+="len=curveLength igorznag_spline_path 1";str+="\n" str+="if(len>0)then";str+="\n" str+="(";str+="\n" str+="percent1=igorznag_obj1.percent";str+="\n" str+="percent1=(mod (percent1/100.0) 1.0);if(percent1<0)then percent1+=1";str+="\n" str+="seg_legths=getSegLengths igorznag_spline_path 1 cum:true numArcSteps:0";str+="\n" str+="segs_count=int(seg_legths.count-1)/2.0";str+="\n" str+="seg_by_percent1=0; for i=1 to segs_count where seg_legths[i]>=percent1 do (seg_by_percent1=i;exit)";str+="\n" str+="seg_by_percent_offset=seg_by_percent1";str+="\n" for j=2 to objs_temp_a.count do ( str+="for i=0 to (int(segs_count/2.0)) do";str+="\n" str+="(";str+="\n" str+="c=igorznag_obj"+((j-1) as string)+".value";str+="\n" str+="r=spacing; o=undefined;";str+="\n" str+="seg_by_percent_o=seg_by_percent_offset+i";str+="\n" str+="if(seg_by_percent_o>segs_count)then seg_by_percent_o-=segs_count";str+="\n" str+="o=getKnotPoint igorznag_spline_path 1 seg_by_percent_o";str+="\n" str+="seg_by_percent_t=seg_by_percent_offset+i+1";str+="\n" str+="if(seg_by_percent_t>segs_count)then seg_by_percent_t-=segs_count";str+="\n" str+="t=getKnotPoint igorznag_spline_path 1 seg_by_percent_t";str+="\n" str+="roots=sphere_segment_intersect c r o t";str+="\n" str+="if(roots.count>0)then";str+="\n" str+="(";str+="\n" str+="if roots.count==1 then";str+="\n" str+="(";str+="\n" str+="if (dot (roots[1]-o) (roots[1]-c) >0) then";str+="\n" str+="(";str+="\n" str+=" igorznag_obj"+(j as string)+".value=roots[1]";str+="\n" str+="seg_by_percent_offset=seg_by_percent_o";str+="\n" str+="exit;";str+="\n" str+=")";str+="\n" str+=")";str+="\n" str+="if roots.count==2 then";str+="\n" str+="(";str+="\n" str+="temp_root=roots[2]";str+="\n" str+="if (dot (roots[1]-o) (roots[1]-c)>0)then temp_root=roots[1]";str+="\n" str+="if (dot (roots[2]-o) (roots[2]-c)>0)then temp_root=roots[2]";str+="\n" str+="igorznag_obj"+(j as string)+".value=temp_root";str+="\n" str+="seg_by_percent_offset=seg_by_percent_o";str+="\n" str+="exit;";str+="\n" str+=")--if roots.count==2 then";str+="\n" str+=")--if(roots.count>0)then";str+="\n" str+=")--for i=0 to int(segs_count/2.0) do";str+="\n" )--for i=2 to 2 do--objs_temp_a.count do --d_end str+="for i=0 to (int(segs_count/2.0)) do";str+="\n" str+="(";str+="\n" str+="c=igorznag_obj"+(objs_temp_a.count as string)+".value";str+="\n" str+="r=spacing; o=undefined;";str+="\n" str+="seg_by_percent_o=seg_by_percent_offset+i";str+="\n" str+="if(seg_by_percent_o>segs_count)then seg_by_percent_o-=segs_count";str+="\n" str+="o=getKnotPoint igorznag_spline_path 1 seg_by_percent_o";str+="\n" str+="seg_by_percent_t=seg_by_percent_offset+i+1";str+="\n" str+="if(seg_by_percent_t>segs_count)then seg_by_percent_t-=segs_count";str+="\n" str+="t=getKnotPoint igorznag_spline_path 1 seg_by_percent_t";str+="\n" str+="roots=sphere_segment_intersect c r o t";str+="\n" str+="if(roots.count>0)then";str+="\n" str+="(";str+="\n" str+="if roots.count==1 then";str+="\n" str+="(";str+="\n" str+="if (dot (roots[1]-o) (roots[1]-c) >0) then";str+="\n" str+="(";str+="\n" str+="igorznag_dummy_end.value=roots[1]";str+="\n" str+="seg_by_percent_offset=seg_by_percent_o";str+="\n" str+="exit;";str+="\n" str+=")";str+="\n" str+=")";str+="\n" str+="if roots.count==2 then";str+="\n" str+="(";str+="\n" str+="temp_root=roots[2]";str+="\n" str+="if (dot (roots[1]-o) (roots[1]-c)>0)then temp_root=roots[1]";str+="\n" str+="if (dot (roots[2]-o) (roots[2]-c)>0)then temp_root=roots[2]";str+="\n" str+="igorznag_dummy_end.value=temp_root";str+="\n" str+="seg_by_percent_offset=seg_by_percent_o";str+="\n" str+="exit;";str+="\n" str+=")--if roots.count==2 then";str+="\n" str+=")--if(roots.count>0)then";str+="\n" str+=")--for i=0 to int(segs_count/2.0) do";str+="\n" --d_end str+=")--if(len>0)then";str+="\n" str+=")catch (quat 0 0 0 1))--try with animate off";str+="\n" str+="quat 0 0 0 1"; c.script=str select objs_temp_a; selectmore d; selectmore d_end redrawViews() )--if(sp_precision.value<len and sp_spacing.value<len)then )--with animate off )--undo off )--if isClosed spline_path 1 then )--if numSplines spline_path==1then )--if(spline_path!=undefined)then )--if(selection.count==2)then )--on btn_apply pressed do -- ); createdialog igorznag_spline_ik 190 135igorznag
Создаем один сплайн Circle и конвертируем его в Editable Spline.
В свитке Interpolation в поле Steps устанавливаем нужное количество итераций, например 6.
Чем больше итераций, тем больше вычислений. Cплайн должен быть замкнутым-Closed.
Создаем один чайник Teapot. Выделяем сплайн и чайник.
Запускаем скрипт. В новом окне нажимаем кнопку Apply.
Анимируем % Along Path чайника, который находится в начале сплайна.
try (destroydialog igorznag_spline_ik) catch() rollout igorznag_spline_ik "SplineIK" ( --gui spinner sp_count "Count:" range:[2,1e9,10] fieldWidth:60 type:#integer pos:[32,5] spinner sp_spacing "Spacing:" range:[0,1e9,10] fieldWidth:60 type:#worldunits pos:[21,22] checkbox chb_taf "Flip. Object LookAt Axis = X" pos:[5,57] radiobuttons rb_stoa "Object Upnode Axis" labels:#("Y", "Z") pos:[5,75] checkbox chb_stoaf "Flip" pos:[80,92] label lbl_info "Spline Upnode Axis = Z" pos:[5,110] button btn_apply "Apply" pos:[130,75] width:50 height:50 --events on btn_apply pressed do ( if(selection.count==2)then ( spline_path=undefined; obj=undefined; spline_types=#(SplineShape,line);cl1=classof selection[1];cl2=classof selection[2] if(finditem spline_types cl1!=0 and finditem spline_types cl2==0)then (spline_path=selection[1];obj=selection[2]) if(finditem spline_types cl2!=0 and finditem spline_types cl1==0)then (spline_path=selection[2];obj=selection[1]) if(spline_path!=undefined)then ( if numSplines spline_path==1 then ( if isClosed spline_path 1 then ( undo on ( with animate off ( len=curveLength spline_path 1 if(sp_spacing.value<len)then ( objs_temp_a=#(); objs_count=sp_count.value for i=1 to objs_count do ( maxOps.cloneNodes obj cloneType:#instance newNodes:&n append objs_temp_a n[1]; )--for i=1 to objs_count do -- d=plane();d.name=uniquename "igorznag_splineIK"; d.width=0;d.length=0;d.widthsegs=1;d.lengthsegs=1; d.pos.controller=Position_Constraint() c=d.pos.controller;c.constraints.appendTarget objs_temp_a[1] 100 d_end=dummy();d_end.pos.controller=position_xyz(); -- for i=1 to objs_temp_a.count do ( if(i==1)then ( objs_temp_a[i].pos.controller=Path_Constraint() c=objs_temp_a[i].pos.controller;c.path=spline_path c.percent.controller=linear_float(); setBeforeORT c.percent.controller #cycle setAfterORT c.percent.controller #cycle ) if(i>1)then objs_temp_a[i].pos.controller=position_xyz(); objs_temp_a[i].rotation.controller = LookAt_Constraint(); c=objs_temp_a[i].rotation.controller c.target_axis=0;c.lookat_vector_length=0;c.target_axisFlip=chb_taf.checked objs_temp_a[i].rotation.controller.upnode_world = off objs_temp_a[i].rotation.controller.pickUpNode=spline_path c.upnode_ctrl=1;c.StoUP_axis=rb_stoa.state;c.StoUP_axisFlip=chb_stoaf.checked; c.upnode_axis=2 if(i<objs_temp_a.count)then c.appendTarget objs_temp_a[i+1] 100 if(i==objs_temp_a.count)then c.appendTarget d_end 100 )--for i=1 to objs_temp_a.count do --script d.rotation.controller=rotation_script() c=d.rotation.controller setBeforeORT c #cycle; setAfterORT c #cycle c.AddObject "igorznag_spline_path" spline_path c.AddObject "igorznag_dummy_end" d_end.pos.controller for i=1 to objs_temp_a.count do c.AddObject ("igorznag_obj"+(i as string)) objs_temp_a[i].pos.controller -- str="" str+="fn sphere_segment_intersect c r o t=";str+="\n" str+="(";str+="\n" str+="roots_a=#(); sp_dir=normalize(t-o)";str+="\n" str+="det=(dot sp_dir (o-c))*(dot sp_dir (o-c))- dot (o-c) (o-c)+r*r";str+="\n" str+="if(det>=0)then";str+="\n" str+="(";str+="\n" str+="d1=-(dot sp_dir (o-c))+pow det 0.5; d2=-(dot sp_dir (o-c))-pow det 0.5";str+="\n" str+="p1=o+d1*sp_dir; p2=o+d2*sp_dir";str+="\n" str+="if(dot sp_dir (p1-o)>0 and length (p1-o) < length (t-o))then append roots_a p1";str+="\n" str+="if(dot sp_dir (p2-o)>0 and length (p2-o) < length (t-o))then append roots_a p2";str+="\n" str+=")--if(det>=0)then";str+="\n" str+="roots_a";str+="\n" str+=")--fn sphere_segment_intersect c r o t=";str+="\n" str+="";str+="\n" str+="with animate off ( try (";str+="\n" str+="spacing="+(sp_spacing.value as string);str+="\n" str+="len=curveLength igorznag_spline_path 1";str+="\n" str+="if(len>0)then";str+="\n" str+="(";str+="\n" str+="percent1=igorznag_obj1.percent";str+="\n" str+="percent1=(mod (percent1/100.0) 1.0);if(percent1<0)then percent1+=1";str+="\n" str+="seg_points=#();n=numSegments igorznag_spline_path 1";str+="\n" str+="for i=1 to n do for j=0 to igorznag_spline_path.steps do";str+="\n" str+="(";str+="\n" str+="p0=getKnotPoint igorznag_spline_path 1 i; p1=getOutVec igorznag_spline_path 1 i;p2=undefined;p3=undefined";str+="\n" str+="if i==n then (p2=getInVec igorznag_spline_path 1 1;p3=getKnotPoint igorznag_spline_path 1 1)";str+="\n" str+="else (p2=getInVec igorznag_spline_path 1 (i+1);p3=getKnotPoint igorznag_spline_path 1 (i+1))";str+="\n" str+="t=1.0*j/(igorznag_spline_path.steps+1)";str+="\n" str+="p=(1-t)*(1-t)*(1-t)*p0+3*t*(t-1)*(t-1)*p1+3*t*t*(1-t)*p2+t*t*t*p3; append seg_points p";str+="\n" str+=")--for i=1 to n do for j=0 to igorznag_spline_path.steps do";str+="\n" str+="seg_lengths_acc=#(); n=seg_points.count;for i=1 to n do";str+="\n" str+="(";str+="\n" str+="p1=seg_points[i];p2=undefined";str+="\n" str+="if i==n then p2=seg_points[1] else p2=seg_points[i+1]";str+="\n" str+="if i==1 then append seg_lengths_acc (distance p1 p2)";str+="\n" str+="else append seg_lengths_acc (seg_lengths_acc[i-1]+distance p1 p2)";str+="\n" str+=")--for i=1 to n do";str+="\n" str+="seg_percents_acc=#();n=seg_lengths_acc.count; ";str+="\n" str+="for i=1 to n do append seg_percents_acc (seg_lengths_acc[i]/seg_lengths_acc[n])";str+="\n" str+="seg_by_percent1=0; for i=1 to seg_percents_acc.count where seg_percents_acc[i]>=percent1 do (seg_by_percent1=i;exit)";str+="\n" str+="seg_by_percent_offset=seg_by_percent1";str+="\n" for j=2 to objs_temp_a.count do ( str+="for i=0 to (int(seg_percents_acc.count/2.0)) do";str+="\n" str+="(";str+="\n" str+="c=igorznag_obj"+((j-1) as string)+".value";str+="\n" str+="r=spacing; o=undefined;";str+="\n" str+="seg_by_percent_o=seg_by_percent_offset+i";str+="\n" str+="if(seg_by_percent_o>seg_percents_acc.count)then seg_by_percent_o-=seg_percents_acc.count";str+="\n" str+="o=seg_points[seg_by_percent_o]";str+="\n" str+="seg_by_percent_t=seg_by_percent_offset+i+1";str+="\n" str+="if(seg_by_percent_t>seg_percents_acc.count)then seg_by_percent_t-=seg_percents_acc.count";str+="\n" str+="t=seg_points[seg_by_percent_t]";str+="\n" str+="roots=sphere_segment_intersect c r o t";str+="\n" str+="if(roots.count>0)then";str+="\n" str+="(";str+="\n" str+="if roots.count==1 then";str+="\n" str+="(";str+="\n" str+="if (dot (roots[1]-o) (roots[1]-c) >0) then";str+="\n" str+="(";str+="\n" str+=" igorznag_obj"+(j as string)+".value=roots[1]";str+="\n" str+="seg_by_percent_offset=seg_by_percent_o";str+="\n" str+="exit;";str+="\n" str+=")";str+="\n" str+=")";str+="\n" str+="if roots.count==2 then";str+="\n" str+="(";str+="\n" str+="temp_root=roots[2]";str+="\n" str+="if (dot (roots[1]-o) (roots[1]-c)>0)then temp_root=roots[1]";str+="\n" str+="if (dot (roots[2]-o) (roots[2]-c)>0)then temp_root=roots[2]";str+="\n" str+="igorznag_obj"+(j as string)+".value=temp_root";str+="\n" str+="seg_by_percent_offset=seg_by_percent_o";str+="\n" str+="exit;";str+="\n" str+=")--if roots.count==2 then";str+="\n" str+=")--if(roots.count>0)then";str+="\n" str+=")--for i=0 to int(seg_percents_acc.count/2.0) do";str+="\n" )--for i=2 to 2 do--objs_temp_a.count do --d_end str+="for i=0 to (int(seg_percents_acc.count/2.0)) do";str+="\n" str+="(";str+="\n" str+="c=igorznag_obj"+(objs_temp_a.count as string)+".value";str+="\n" str+="r=spacing; o=undefined;";str+="\n" str+="seg_by_percent_o=seg_by_percent_offset+i";str+="\n" str+="if(seg_by_percent_o>seg_percents_acc.count)then seg_by_percent_o-=seg_percents_acc.count";str+="\n" str+="o=seg_points[seg_by_percent_o]";str+="\n" str+="seg_by_percent_t=seg_by_percent_offset+i+1";str+="\n" str+="if(seg_by_percent_t>seg_percents_acc.count)then seg_by_percent_t-=seg_percents_acc.count";str+="\n" str+="t=seg_points[seg_by_percent_t]";str+="\n" str+="roots=sphere_segment_intersect c r o t";str+="\n" str+="if(roots.count>0)then";str+="\n" str+="(";str+="\n" str+="if roots.count==1 then";str+="\n" str+="(";str+="\n" str+="if (dot (roots[1]-o) (roots[1]-c) >0) then";str+="\n" str+="(";str+="\n" str+="igorznag_dummy_end.value=roots[1]";str+="\n" str+="seg_by_percent_offset=seg_by_percent_o";str+="\n" str+="exit;";str+="\n" str+=")";str+="\n" str+=")";str+="\n" str+="if roots.count==2 then";str+="\n" str+="(";str+="\n" str+="temp_root=roots[2]";str+="\n" str+="if (dot (roots[1]-o) (roots[1]-c)>0)then temp_root=roots[1]";str+="\n" str+="if (dot (roots[2]-o) (roots[2]-c)>0)then temp_root=roots[2]";str+="\n" str+="igorznag_dummy_end.value=temp_root";str+="\n" str+="seg_by_percent_offset=seg_by_percent_o";str+="\n" str+="exit;";str+="\n" str+=")--if roots.count==2 then";str+="\n" str+=")--if(roots.count>0)then";str+="\n" str+=")--for i=0 to int(segs_count/2.0) do";str+="\n" --d_end str+=")--if(len>0)then";str+="\n" str+=")catch (quat 0 0 0 1))--try with animate off";str+="\n" str+="quat 0 0 0 1"; c.script=str select objs_temp_a; selectmore d; selectmore d_end redrawViews() )--if(sp_precision.value<len and sp_spacing.value<len)then )--with animate off )--undo off )--if isClosed spline_path 1 then )--if numSplines spline_path==1then )--if(spline_path!=undefined)then )--if(selection.count==2)then )--on btn_apply pressed do -- ); createdialog igorznag_spline_ik 190 135INCUS
Удивительно, но это работает !!!
Запустил сто траков гусеницы, и они так шустренько поехали как миленькие.
Спасибо большое тебе, igorznaq, очень полезная штука получилась.
Amar3
INCUS
Можно поподробней ?
Amar3
Amar3