blender-uv-texturing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBlender UV Texturing
Blender UV纹理处理
This skill fills the gap between “assign a material” and “the supplied texture pack actually fits the model.” It is mandatory for template/atlas-driven assets.
此技能填补了“分配材质”与“提供的纹理包真正适配模型”之间的空白。对于基于模板/图集的资产来说,这是必不可少的步骤。
Decision tree
决策树
What does the texture represent?
├── Whole object from front/reference → Project-from-View style UVs from the validation camera
├── Atlas with separate parts → crop/map each part to its own UV island/rectangle
├── Repeating material → generated/object coords or tiled UVs
├── Face/expression decal → alpha material plane or projected UV island; no black background
├── Roughness/bump/normal map → Non-Color data, correct node type
└── Lightmap → separate UV/lightmap channel or optional multiply helper; not emission纹理代表什么?
├── 从正面/参考图看的完整对象 → 从验证相机生成“从视图投影”风格的UV
├── 包含独立部件的图集 → 将每个部件裁剪/映射到对应的UV岛/矩形区域
├── 可重复材质 → 使用生成/对象坐标或 tiled UV
├── 面部/表情贴花 → 使用带alpha的材质平面或投影UV岛;无黑色背景
├── 粗糙度/凹凸/法线贴图 → 非颜色数据,使用正确的节点类型
└── 光照贴图 → 使用独立的UV/光照贴图通道或可选的乘法辅助节点;不使用发光材质Non-negotiable rules
不可违反的规则
- Image textures need a material node setup to render/export; viewport UV display alone is not enough.
- Basecolor/albedo = sRGB. Roughness, metallic, bump, normal, AO/lightmap = Non-Color.
- Atlas textures must be mapped by region. Never apply a full atlas to every mesh part.
- Alpha decals must use alpha-connected material settings (,
BLEND, orAlpha Hashed) and a keyed/correct PNG. Do not leave black planes.Alpha Clip - For GLB, keep to exporter-recognized nodes where possible: Principled BSDF with Image Texture inputs, UVs, normals, tangents.
- Validate with a checker texture or overlay render before final material tuning.
- 图像纹理需要材质节点设置才能渲染/导出;仅在视口显示UV是不够的。
- 基础色/反照率 = sRGB。粗糙度、金属度、凹凸、法线、AO/光照贴图 = 非颜色(Non-Color)。
- 图集纹理必须按区域映射。绝不能将整张图集应用到每个网格部件。
- Alpha贴花必须使用连接alpha的材质设置(、
BLEND或Alpha Hashed),并使用抠图正确的PNG图片。不能保留黑色平面。Alpha Clip - 针对GLB格式,尽可能使用导出器可识别的节点:带图像纹理输入、UV、法线、切线的Principled BSDF。
- 在最终材质调整前,使用棋盘格纹理或叠加渲染进行验证。
Recipes
操作方案
Create front-projected UVs from world X/Z bounds
从世界X/Z边界创建正面投影UV
python
import bpy
def assign_front_projected_uv(obj_name, uv_name='UV_front_projected'):
obj = bpy.data.objects[obj_name]
mesh = obj.data
uv = mesh.uv_layers.get(uv_name) or mesh.uv_layers.new(name=uv_name)
mesh.uv_layers.active = uv
xs = [v.co.x for v in mesh.vertices]
zs = [v.co.z for v in mesh.vertices]
minx, maxx = min(xs), max(xs)
minz, maxz = min(zs), max(zs)
dx = max(maxx - minx, 1e-8)
dz = max(maxz - minz, 1e-8)
for poly in mesh.polygons:
for li in poly.loop_indices:
co = mesh.vertices[mesh.loops[li].vertex_index].co
uv.data[li].uv = ((co.x - minx) / dx, (co.z - minz) / dz)
mesh.update()python
import bpy
def assign_front_projected_uv(obj_name, uv_name='UV_front_projected'):
obj = bpy.data.objects[obj_name]
mesh = obj.data
uv = mesh.uv_layers.get(uv_name) or mesh.uv_layers.new(name=uv_name)
mesh.uv_layers.active = uv
xs = [v.co.x for v in mesh.vertices]
zs = [v.co.z for v in mesh.vertices]
minx, maxx = min(xs), max(xs)
minz, maxz = min(zs), max(zs)
dx = max(maxx - minx, 1e-8)
dz = max(maxz - minz, 1e-8)
for poly in mesh.polygons:
for li in poly.loop_indices:
co = mesh.vertices[mesh.loops[li].vertex_index].co
uv.data[li].uv = ((co.x - minx) / dx, (co.z - minz) / dz)
mesh.update()Map a mesh to a rectangle in an atlas
将网格映射到图集的矩形区域
Atlas rectangle is in normalized UV coordinates. Use this after creating local 0–1 UVs.
[u0, v0, u1, v1]python
def remap_uv_rect(obj_name, rect, uv_name=None):
obj = bpy.data.objects[obj_name]
layer = obj.data.uv_layers.get(uv_name) if uv_name else obj.data.uv_layers.active
u0, v0, u1, v1 = rect
for item in layer.data:
u, v = item.uv
item.uv = (u0 + u * (u1-u0), v0 + v * (v1-v0))
obj.data.update()图集矩形在归一化UV坐标中为。在创建本地0–1 UV后使用此方法。
[u0, v0, u1, v1]python
def remap_uv_rect(obj_name, rect, uv_name=None):
obj = bpy.data.objects[obj_name]
layer = obj.data.uv_layers.get(uv_name) if uv_name else obj.data.uv_layers.active
u0, v0, u1, v1 = rect
for item in layer.data:
u, v = item.uv
item.uv = (u0 + u * (u1-u0), v0 + v * (v1-v0))
obj.data.update()Image texture material with correct color spaces
带正确色彩空间的图像纹理材质
python
import bpy
def image(path, colorspace):
img = bpy.data.images.load(path, check_existing=True)
img.colorspace_settings.name = colorspace
return img
def make_pbr_texture_material(name, basecolor, roughness=None, normal_or_bump=None, alpha=False):
mat = bpy.data.materials.new(name)
mat.use_nodes = True
nt = mat.node_tree
bsdf = nt.nodes.get('Principled BSDF')
tex = nt.nodes.new('ShaderNodeTexImage')
tex.image = image(basecolor, 'sRGB')
nt.links.new(tex.outputs['Color'], bsdf.inputs['Base Color'])
if alpha and 'Alpha' in bsdf.inputs:
nt.links.new(tex.outputs['Alpha'], bsdf.inputs['Alpha'])
mat.blend_method = 'BLEND'
if roughness:
r = nt.nodes.new('ShaderNodeTexImage')
r.image = image(roughness, 'Non-Color')
nt.links.new(r.outputs['Color'], bsdf.inputs['Roughness'])
if normal_or_bump:
btex = nt.nodes.new('ShaderNodeTexImage')
btex.image = image(normal_or_bump, 'Non-Color')
bump = nt.nodes.new('ShaderNodeBump')
bump.inputs['Strength'].default_value = 0.02
nt.links.new(btex.outputs['Color'], bump.inputs['Height'])
nt.links.new(bump.outputs['Normal'], bsdf.inputs['Normal'])
return matpython
import bpy
def image(path, colorspace):
img = bpy.data.images.load(path, check_existing=True)
img.colorspace_settings.name = colorspace
return img
def make_pbr_texture_material(name, basecolor, roughness=None, normal_or_bump=None, alpha=False):
mat = bpy.data.materials.new(name)
mat.use_nodes = True
nt = mat.node_tree
bsdf = nt.nodes.get('Principled BSDF')
tex = nt.nodes.new('ShaderNodeTexImage')
tex.image = image(basecolor, 'sRGB')
nt.links.new(tex.outputs['Color'], bsdf.inputs['Base Color'])
if alpha and 'Alpha' in bsdf.inputs:
nt.links.new(tex.outputs['Alpha'], bsdf.inputs['Alpha'])
mat.blend_method = 'BLEND'
if roughness:
r = nt.nodes.new('ShaderNodeTexImage')
r.image = image(roughness, 'Non-Color')
nt.links.new(r.outputs['Color'], bsdf.inputs['Roughness'])
if normal_or_bump:
btex = nt.nodes.new('ShaderNodeTexImage')
btex.image = image(normal_or_bump, 'Non-Color')
bump = nt.nodes.new('ShaderNodeBump')
bump.inputs['Strength'].default_value = 0.02
nt.links.new(btex.outputs['Color'], bump.inputs['Height'])
nt.links.new(bump.outputs['Normal'], bsdf.inputs['Normal'])
return matBake target setup
烘焙目标设置
Blender baking requires a UV map and an active Image Texture node or color attribute as the bake target. Use Cycles for baking.
python
import bpy
obj = bpy.data.objects['GEO-target']
bpy.context.scene.render.engine = 'CYCLES'
img = bpy.data.images.new('BAKE_target', 2048, 2048, alpha=True)
mat = obj.data.materials[0]
mat.use_nodes = True
node = mat.node_tree.nodes.new('ShaderNodeTexImage')
node.image = img
mat.node_tree.nodes.active = node
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.bake(type='DIFFUSE', pass_filter={'COLOR'}, margin=16)
img.filepath_raw = '/tmp/bake_target.png'
img.file_format = 'PNG'
img.save()Blender烘焙需要UV贴图和活动的图像纹理节点或颜色属性作为烘焙目标。使用Cycles进行烘焙。
python
import bpy
obj = bpy.data.objects['GEO-target']
bpy.context.scene.render.engine = 'CYCLES'
img = bpy.data.images.new('BAKE_target', 2048, 2048, alpha=True)
mat = obj.data.materials[0]
mat.use_nodes = True
node = mat.node_tree.nodes.new('ShaderNodeTexImage')
node.image = img
mat.node_tree.nodes.active = node
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.bake(type='DIFFUSE', pass_filter={'COLOR'}, margin=16)
img.filepath_raw = '/tmp/bake_target.png'
img.file_format = 'PNG'
img.save()Closed/extruded surface coverage gate
闭合/挤压曲面覆盖检查
For closed or extruded assets, do not stop at front projection. Use to verify front cap, back cap, and sidewall material/UV/generated coverage separately. Back/side curve overlays are accents, not texture fill.
closed-surface-uv-coverage对于闭合或挤压的资产,不能仅停留在正面投影。使用分别验证正面盖、背面盖和侧壁的材质/UV/生成覆盖情况。背面/侧面曲线叠加是装饰,而非纹理填充。
closed-surface-uv-coverageValidation checklist
验证清单
- UV layer exists and is active.
- Checker texture shows no obvious stretching on front-facing parts.
- Atlas rectangles are per-part, not whole-atlas everywhere.
- Roughness/bump/normal/lightmap color spaces are Non-Color.
- Alpha material has blend mode set and no black backing plane.
- Base GLB embeds/exports expected images and excludes reference planes.
- A front overlay render confirms the texture aligns with the source template.
- UV层已存在且处于活动状态。
- 棋盘格纹理显示正面部件无明显拉伸。
- 图集矩形按部件分配,而非整张图集应用到所有部件。
- 粗糙度/凹凸/法线/光照贴图的色彩空间为非颜色(Non-Color)。
- Alpha材质已设置混合模式,无黑色背景平面。
- 基础GLB文件嵌入/导出预期图像,排除参考平面。
- 正面叠加渲染确认纹理与源模板对齐。
Sources distilled
参考来源
- Blender Manual: UV/Image texture workflow requires material nodes for rendered texture output.
- Blender Manual: Image Texture node uses active UV map when Vector is unconnected.
- Blender Manual: Cycles baking requires a UV map and active Image Texture/Color Attribute target.
- Blender Manual: glTF exporter supports meshes, UVs, textures, and materials based mainly on Principled BSDF.
- Khronos glTF PBR: base color, metallic/roughness, normals and related maps are core concepts for realtime transfer.
- Blender手册:UV/图像纹理工作流需要材质节点才能输出可渲染的纹理。
- Blender手册:当Vector未连接时,图像纹理节点使用活动UV贴图。
- Blender手册:Cycles烘焙需要UV贴图和活动的图像纹理/颜色属性目标。
- Blender手册:glTF导出器主要支持基于Principled BSDF的网格、UV、纹理和材质。
- Khronos glTF PBR:基础色、金属度/粗糙度、法线及相关贴图是实时传输的核心概念。