물 영상 정식 3D 기준·끝점·31개 컷 제작
This commit is contained in:
@@ -19,6 +19,7 @@ def containment(scene):
|
||||
evaluated = body.evaluated_get(deps)
|
||||
mesh = evaluated.to_mesh()
|
||||
water = np.array([tuple(evaluated.matrix_world @ v.co) for v in mesh.vertices])
|
||||
faces=[list(face.vertices) for face in mesh.polygons]
|
||||
evaluated.to_mesh_clear()
|
||||
low, high = water.min(axis=0), water.max(axis=0)
|
||||
# 실제 물 표시 mesh에서 경계를 얻고 중심·별도 메타데이터만으로 판정하지 않는다.
|
||||
@@ -26,6 +27,7 @@ def containment(scene):
|
||||
projection = np.array([tuple(world_to_camera_view(scene,scene.camera,Vector(b))-origin)[:2] for b in ((1,0,0),(0,1,0),(0,0,1))])
|
||||
offset = np.array(tuple(origin)[:2])
|
||||
screen = (water @ projection + offset) * (1080,1920)
|
||||
face_polygons=[screen[face] for face in faces]
|
||||
points = sorted(set(map(tuple,screen)))
|
||||
def cross(a,b,c):
|
||||
return (b[0]-a[0])*(c[1]-a[1])-(b[1]-a[1])*(c[0]-a[0])
|
||||
@@ -57,6 +59,19 @@ def containment(scene):
|
||||
minimum = np.minimum(minimum,margin)
|
||||
projected = (vertices @ projection + offset) * (1080,1920)
|
||||
assert (projected.min(axis=0)>0).all() and (projected.max(axis=0)<(1080,1920)).all(), '분자 화면 잘림'
|
||||
covered=np.zeros(len(projected),dtype=bool)
|
||||
for polygon in face_polygons:
|
||||
following=np.roll(polygon,-1,axis=0)
|
||||
area=sum(a[0]*b[1]-b[0]*a[1] for a,b in zip(polygon,following))
|
||||
if abs(area)<.001:
|
||||
continue
|
||||
inside=np.ones(len(projected),dtype=bool)
|
||||
for a,b in zip(polygon,following):
|
||||
edge=b-a
|
||||
signed=(edge[0]*(projected[:,1]-a[1])-edge[1]*(projected[:,0]-a[0]))*(1 if area>0 else -1)
|
||||
inside &= signed>=-.001
|
||||
covered |= inside
|
||||
assert covered.all(), f'실제 파란 절개 면 투영 밖: F{logical} {obj.name}'
|
||||
for a,b in zip(hull,np.roll(hull,-1,axis=0)):
|
||||
edge = b-a
|
||||
distance = (edge[0]*(projected[:,1]-a[1])-edge[1]*(projected[:,0]-a[0]))/np.linalg.norm(edge)
|
||||
@@ -68,13 +83,13 @@ def containment(scene):
|
||||
for face in body.data.polygons:
|
||||
points=np.array([tuple(body.matrix_world @ body.data.vertices[i].co) for i in face.vertices])
|
||||
assert not np.allclose(points[:,1],low[1]) and not np.allclose(points[:,2],high[2]), '앞면·윗면 절개가 닫힘'
|
||||
return dict(logical_frame_start=2468,logical_frame_end=3172,frames=705,water_bounds=[low.tolist(),high.tolist()],minimum_axis_margin=minimum.tolist(),minimum_projected_margin_px=pixel_margin,evaluated_vertices=vertex_count,mesh_roles=['atom','covalent','active_hydrogen_bond'],open_faces=['front','top'])
|
||||
return dict(logical_frame_start=2468,logical_frame_end=3172,frames=705,water_bounds=[low.tolist(),high.tolist()],minimum_axis_margin=minimum.tolist(),minimum_projected_margin_px=pixel_margin,evaluated_vertices=vertex_count,mesh_roles=['atom','covalent','active_hydrogen_bond'],open_faces=['front','top'],projection_check='actual_face_union_and_outer_hull')
|
||||
|
||||
|
||||
def verify(source):
|
||||
def verify(source, expected=None):
|
||||
assert source.is_file(), "원본 파일 없음"
|
||||
bpy.ops.wm.open_mainfile(filepath=str(source))
|
||||
expected = {"BondPair": (905, 1637), "Interface": (2469, 3173), "DropletStretch": (3173, 4077)}
|
||||
expected = expected or {"BondPair": (905, 1637), "Interface": (2469, 3173), "DropletStretch": (3173, 4077)}
|
||||
assert set(bpy.data.scenes) and set(s.name for s in bpy.data.scenes) == set(expected), "대표 Scene 누락/혼입"
|
||||
assert not any(d.library for d in bpy.data.objects), "외부 객체"
|
||||
assert not bpy.data.images and not bpy.data.fonts and not bpy.data.movieclips, "외부 자산"
|
||||
|
||||
Reference in New Issue
Block a user