写了一个C4D的点对齐脚本——Alignment_V1.0

北京/设计爱好者/2年前/155浏览
写了一个C4D的点对齐脚本——Alignment_V1.0

最近要做一些板式家具小模型,碰到点对齐的问题。可以实现像SketchUp那样快速地对齐点和面。文末附脚本下载方式

最近要做一些板式家具小模型,碰到点对齐的问题。横板与竖板顶上,用吸附来回切换视图太麻烦,所以写了这个脚本,可以实现像SketchUp那样快速地对齐点和面。文末附下载链接

  使用方法  

-1.选中C掉的对象面或者点。

-2.选择要对齐的轴-x或者其他轴即可对齐。需要注意的一点是这里的轴方向是指世界轴的方向,不是选集轴的方向。点选集会自动按选中轴的方向贴合。

另外一个例子,选集点只有一半对齐到了面:

当选择的轴方向上没有面可以对齐,点选集会对齐到物体自身的边界框。如下图所示:

-3.如果Fixed to window没有勾选,则窗口在执行完命令会自动关闭。

  脚本实现方法  

在选中的点对象上,发射一条指定方向的射线。这条射线如果与自己的面相交,那么把交点的坐标记录下来,以此作为目标位置移动到这里。

好在C4D中已经有这个类和相关的方法了,可以直接拿来用。

ge = c4d.utils.GeRayCollider()ge.Init(op, force=False)
_ = ge.Intersect(pos + vector * 0.001, vector, d, only_test=False)
z = ge.GetNearestIntersection()

我这里pos + vector * 0.001是在pos位置的vector方向上做了0.1%的偏移,因为测试时发现产生的射线会跟自己的发射点有碰撞(无语)。z会返回一些碰撞的信息,可以参考C4D的文档:

intersection["face_id"]  # The polygon index, int
intersection["tri_face_id"] # If first half of quad or triangle face_id + 1, else -(face_id + 1), int
intersection["hitpos"] # Position of the intersection, c4d.Vector
intersection["distance"] # Distance to the intersection, float
intersection["s_normal"] # Same as f_normal (reserved for phong normal at the intersection (Not normalized)), c4d.Vector
intersection["f_normal"] # Face normal (Not normalized), c4d.Vector
intersection["barrycoords"] # Barycentric coordinates of the intersection (x = u, y = v, z = d), c4d.Vector
intersection["backface"] # True if the intersected face's normal points away from the camera, otherwise False, bool

如果射线没有碰撞到任何面会返回None,我这里还通过intersection["backface"]排除掉了点选集对自己的碰撞结果。在多个点发射射线的情况下找到一个最小距离,然后将最小距离分别设置给选集中的点向量即可。除此之外,如果所有点选集发射的射线的返回结果都为None,那么将对齐到选中对象自己的BBox边界值,可以实现与自身外轮廓对齐的效果。



class Align(c4d.gui.GeDialog):
def __init__(self):
pass    
#创建发射器,并获得碰撞点信息设置给目标的
def shot(self,op, vector, d=99999):
if op.GetRealType() == 5100:
c4d.CallCommand(12139)
ge = c4d.utils.GeRayCollider()
ge.Init(op, force=False)
points = op.GetPointS()
sel = points.GetAll(op.GetPointCount())
dis = []
selections = []
pos_list = []
for index, selected in enumerate(sel):
if not selected:
continue
pos = op.GetPoint(index)
pos_list.append(pos)
_ = ge.Intersect(pos + vector * 0.001, vector, d, only_test=False)
z = ge.GetNearestIntersection()
selections.append(index)
if z:
# hitpos = z['hitpos']
if not z['backface']:
distance = z['distance'] + 0.001
dis.append(distance)
try:
if len(dis):
min_dis = min(dis)
else:
level,d = self.get_dis(op,vector,pos_list)
min_dis = abs(level - d)
except ValueError:
min_dis = 0
if min_dis > 0:
doc.StartUndo()
for i in selections:
op.SetPoint(i, op.GetPoint(i) + vector * min_dis)
doc.AddUndo(c4d.UNDOTYPE_CHANGE, op)
doc.EndUndo()
c4d.EventAdd()
return min_dis
else:
c4d.gui.MessageDialog("Please select the point of the c4d.polygonObject!")
return False
#获取最值点
def get_dis(self,op,vector,pos_list):
all_pos = op.GetAllPoints()
if vector[0] > 0:
return max([dec[0] for dec in all_pos]),max([vec[0] for vec in pos_list])
elif vector[0] < 0:
return min([dec[0] for dec in all_pos]),min([vec[0] for vec in pos_list])
elif vector[1] > 0:
return max([dec[1] for dec in all_pos]),max([vec[1] for vec in pos_list])
elif vector[1] < 0:
return min([dec[1] for dec in all_pos]),min([vec[1] for vec in pos_list])
elif vector[2] > 0:
return max([dec[2] for dec in all_pos]),max([vec[2] for vec in pos_list])
elif vector[2] < 0:
return min([dec[2] for dec in all_pos]),min([vec[2] for vec in pos_list])

  【下载方式】  

关注【西技大神】微信公众号,后台留言【10008】,即可获得下载链接。原创不易,欢迎打赏。

2
Report
|
收藏
Share
相关推荐
评论
in to comment
Add emoji
喜欢TA的作品吗?喜欢就快来夸夸TA吧!
推荐素材
You may like
相关收藏夹
ip形象设计+表情包
ip形象设计+表情包
ip形象设计+表情包
ip形象设计+表情包
精选收藏夹
作品收藏夹
企业展厅/文化墙 参考
企业展厅/文化墙 参考
企业展厅/文化墙 参考
企业展厅/文化墙 参考
精选收藏夹
作品收藏夹
小家电
小家电
小家电
小家电
精选收藏夹
作品收藏夹
企业展厅
企业展厅
企业展厅
企业展厅
精选收藏夹
作品收藏夹
IP形象及IP内容
IP形象及IP内容
IP形象及IP内容
IP形象及IP内容
精选收藏夹
作品收藏夹
IP形象——动物类
IP形象——动物类
IP形象——动物类
IP形象——动物类
精选收藏夹
作品收藏夹
大家都在看
Log in