fixed xynova texture generation problem
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
"""Blender adapter for evaluated, camera-local loop-triangle fragments."""
|
||||
from patch_geometry import cell_fragments, interpolate_uv
|
||||
|
||||
|
||||
def build_patch_geometry(obj, cam, scene, depsgraph, uv_names, nx, ny, edge_sample_grid):
|
||||
from mathutils import Vector
|
||||
if cam.data.type not in {'PERSP', 'ORTHO'}:
|
||||
raise ValueError('Patch projection requires a perspective or orthographic camera')
|
||||
camera = cam.evaluated_get(depsgraph)
|
||||
evaluated = obj.evaluated_get(depsgraph)
|
||||
mesh = evaluated.to_mesh(preserve_all_data_layers=True, depsgraph=depsgraph)
|
||||
try:
|
||||
mesh.calc_loop_triangles()
|
||||
layers = {name: mesh.uv_layers.get(name) for name in uv_names}
|
||||
if any(layer is None for layer in layers.values()):
|
||||
raise ValueError('An evaluated mesh UV layer is missing')
|
||||
render = scene.render
|
||||
projection = camera.calc_matrix_camera(
|
||||
depsgraph, x=render.resolution_x, y=render.resolution_y,
|
||||
scale_x=render.pixel_aspect_x, scale_y=render.pixel_aspect_y)
|
||||
view = camera.matrix_world.normalized().inverted()
|
||||
clip_matrix = projection @ view
|
||||
origin = camera.matrix_world.translation
|
||||
forward = camera.matrix_world.to_quaternion() @ Vector((0, 0, -1))
|
||||
output = {name: {'mesh': [], 'patches': []} for name in uv_names}
|
||||
ray_count = 0
|
||||
for triangle in mesh.loop_triangles:
|
||||
world = [evaluated.matrix_world @ mesh.vertices[i].co for i in triangle.vertices]
|
||||
clips = [tuple(clip_matrix @ p.to_4d()) for p in world]
|
||||
uvs = {name: [tuple(layer.data[i].uv) for i in triangle.loops]
|
||||
for name, layer in layers.items()}
|
||||
for name in uv_names:
|
||||
output[name]['mesh'].append(uvs[name])
|
||||
cache = {}
|
||||
|
||||
def visible(weights):
|
||||
nonlocal ray_count
|
||||
key = tuple(round(w, 12) for w in weights)
|
||||
if key in cache:
|
||||
return cache[key]
|
||||
point = sum((p * w for p, w in zip(world, weights)), Vector())
|
||||
depth = -(view @ point).z
|
||||
ray_origin = origin if camera.data.type == 'PERSP' else point - forward * depth
|
||||
direction = point - ray_origin
|
||||
distance = direction.length
|
||||
# Relative hit-position tolerance in world units; never rely on
|
||||
# original/evaluated polygon indices (modifiers can change them).
|
||||
tolerance = max(1e-7, distance * 2e-5)
|
||||
if distance <= tolerance:
|
||||
cache[key] = False
|
||||
return False
|
||||
direction.normalize()
|
||||
hit, location, normal, index, hit_obj, matrix = scene.ray_cast(
|
||||
depsgraph, ray_origin, direction, distance=distance + tolerance)
|
||||
ray_count += 1
|
||||
same_object = hit_obj is not None and getattr(hit_obj, 'original', hit_obj) == obj.original
|
||||
result = bool(hit and same_object and (location - point).length <= tolerance)
|
||||
cache[key] = result
|
||||
return result
|
||||
|
||||
for i, j, fragment in cell_fragments(clips, nx, ny, visible, edge_sample_grid):
|
||||
for name in uv_names:
|
||||
polygon = [interpolate_uv(p, uvs[name]) for p in fragment]
|
||||
output[name]['patches'].append((i, j, polygon))
|
||||
print(f'Evaluated {len(mesh.loop_triangles)} loop triangles; {ray_count} visibility rays; '
|
||||
f'{len(output[uv_names[0]]["patches"])} local fragments per UV target')
|
||||
print(f'Visibility sampling: seven probes per fragment; uniformly probed '
|
||||
f'fragments are accepted or dropped whole, mixed boundary fragments '
|
||||
f'refine to 1/4 cell or depth 6 and unresolved leaves are rejected. '
|
||||
f'Sub-sample occluders may be missed; hit tolerance max(1e-7, distance*2e-5).')
|
||||
return output
|
||||
finally:
|
||||
evaluated.to_mesh_clear()
|
||||
Reference in New Issue
Block a user