You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Blender Python导入HGHT格式时顶点坐标错误问题求助

问题分析与解决方案

核心问题诊断

你的脚本存在两个关键问题导致右上角顶点Z值始终为0.0:

  1. Z-order相邻块计算错误:当前位运算逻辑无法正确获取正上方和右侧的相邻块,导致从错误的块中读取顶点数据,这些块的对应顶点Z值可能未正确导入(默认0.0)。
  2. 顶点依赖时序问题:右上角顶点对应的相邻块顶点本身属于边缘顶点,若相邻块未被提前处理,其Z值仍为初始的0.0,导致当前块无法获取正确值。

修复步骤

1. 替换错误的Z-order相邻块计算逻辑

当前位运算方式无法正确计算Z-order曲线的相邻块,应先将Z-order值解码为(x,y)坐标,修改坐标后重新编码:

def z_order_to_xy(z):
    """将32位Z-order值解码为(x,y)坐标"""
    x = 0
    y = 0
    for i in range(16):
        # 提取x的第i位:Z-order的偶数位
        x |= ((z >> (2 * i)) & 1) << i
        # 提取y的第i位:Z-order的奇数位
        y |= ((z >> (2 * i + 1)) & 1) << i
    return x, y

def xy_to_z_order(x, y):
    """将(x,y)坐标编码为32位Z-order值"""
    z = 0
    for i in range(16):
        # 将x的第i位放入Z-order的偶数位
        z |= ((x >> i) & 1) << (2 * i)
        # 将y的第i位放入Z-order的奇数位
        z |= ((y >> i) & 1) << (2 * i + 1)
    return z

在脚本中使用这两个函数获取相邻块:

z = int(obj.name[2:], base=16)
x, y = z_order_to_xy(z)
# 上方块:y坐标减1
top = xy_to_z_order(x, y - 1)
# 右侧块:x坐标加1
right = xy_to_z_order(x + 1, y)

# 简化块名称生成
top_tile_name = f"{obj.name[:2]}{top:08X}"
right_tile_name = f"{obj.name[:2]}{right:08X}"

2. 优化相邻块查找效率

提前创建块名称到对象的字典,避免每次遍历所有对象:

# 循环外构建字典
obj_dict = {obj.name: obj for obj in objects}

# 循环内查找相邻块
if top_tile_name in obj_dict:
    top_tile_obj = obj_dict[top_tile_name]
    # ...后续处理

3. 分阶段处理顶点,解决依赖问题

右上角顶点对应的相邻块顶点均为边缘顶点,需分两轮处理:

  • 第一轮:处理所有非角落边缘顶点,这些顶点可从相邻块的内部顶点获取有效值。
  • 第二轮:处理所有块的角落顶点,取相邻块已处理的边缘顶点值(若都存在则取平均值)。

4. 释放Bmesh资源

每次使用bmesh.new()创建对象后,调用bm.free()释放内存,避免泄漏。

完整修复后的脚本

def z_order_to_xy(z):
    x = 0
    y = 0
    for i in range(16):
        x |= ((z >> (2 * i)) & 1) << i
        y |= ((z >> (2 * i + 1)) & 1) << i
    return x, y

def xy_to_z_order(x, y):
    z = 0
    for i in range(16):
        z |= ((x >> i) & 1) << (2 * i)
        z |= ((y >> i) & 1) << (2 * i + 1)
    return z

# 提前构建块名称字典
obj_dict = {obj.name: obj for obj in objects}

# 第一轮:处理非角落边缘顶点
for obj in objects:
    z = int(obj.name[2:], base=16)
    x, y = z_order_to_xy(z)
    
    top = xy_to_z_order(x, y - 1)
    right = xy_to_z_order(x + 1, y)
    
    top_tile_name = f"{obj.name[:2]}{top:08X}"
    right_tile_name = f"{obj.name[:2]}{right:08X}"
    
    mesh = bmesh.new()
    mesh.from_mesh(obj.data)
    mesh.verts.ensure_lookup_table()
    
    # 处理顶部边缘(排除右上角)
    if top_tile_name in obj_dict:
        top_tile = bmesh.new()
        top_tile.from_mesh(obj_dict[top_tile_name].data)
        top_tile.verts.ensure_lookup_table()
        
        for x_coord in range(256):
            curr_vert_idx = x_coord + 256 * 257
            top_vert_idx = x_coord
            mesh.verts[curr_vert_idx].co.z = top_tile.verts[top_vert_idx].co.z
        
        top_tile.free()
    
    # 处理右侧边缘(排除右上角)
    if right_tile_name in obj_dict:
        right_tile = bmesh.new()
        right_tile.from_mesh(obj_dict[right_tile_name].data)
        right_tile.verts.ensure_lookup_table()
        
        for y_coord in range(256):
            curr_vert_idx = 256 + y_coord * 257
            right_vert_idx = y_coord * 257
            mesh.verts[curr_vert_idx].co.z = right_tile.verts[right_vert_idx].co.z
        
        right_tile.free()
    
    mesh.to_mesh(obj.data)
    obj.data.update()
    mesh.free()

# 第二轮:处理所有块的右上角顶点
for obj in objects:
    z = int(obj.name[2:], base=16)
    x, y = z_order_to_xy(z)
    
    top = xy_to_z_order(x, y - 1)
    right = xy_to_z_order(x + 1, y)
    
    top_tile_name = f"{obj.name[:2]}{top:08X}"
    right_tile_name = f"{obj.name[:2]}{right:08X}"
    
    mesh = bmesh.new()
    mesh.from_mesh(obj.data)
    mesh.verts.ensure_lookup_table()
    
    corner_idx = 256 + 256 * 257
    z_candidates = []
    
    # 从上方块取右边缘顶点值
    if top_tile_name in obj_dict:
        top_tile = bmesh.new()
        top_tile.from_mesh(obj_dict[top_tile_name].data)
        top_tile.verts.ensure_lookup_table()
        top_corner_idx = 256 + 0 * 257
        val = top_tile.verts[top_corner_idx].co.z
        if val != 0.0:
            z_candidates.append(val)
        top_tile.free()
    
    # 从右侧块取顶部边缘顶点值
    if right_tile_name in obj_dict:
        right_tile = bmesh.new()
        right_tile.from_mesh(obj_dict[right_tile_name].data)
        right_tile.verts.ensure_lookup_table()
        right_corner_idx = 0 + 256 * 257
        val = right_tile.verts[right_corner_idx].co.z
        if val != 0.0:
            z_candidates.append(val)
        right_tile.free()
    
    # 取有效候选值的平均值
    if z_candidates:
        mesh.verts[corner_idx].co.z = sum(z_candidates) / len(z_candidates)
    
    mesh.to_mesh(obj.data)
    obj.data.update()
    mesh.free()

内容的提问来源于stack exchange,提问作者guiguig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 13:07:02