1
$\begingroup$

I'd like to use a python script to transfer normals to a new uv layer. Here is my first attempt:

import bpy

ob = bpy.context.object

for loop in ob.data.loops:
    normal = ob.data.vertices[loop.vertex_index].normal
    ob.data.uv_layers["XY"].data[loop.index].uv = (normal.x, normal.y)
    ob.data.uv_layers["ZW"].data[loop.index].uv = (normal.z, 0)

What I eventually want the script to be able to do is read custom split normals. I heard this was possible through the use of this script. The normal section underneath is supposed to calculate the normals using calc_normals_split or calc_tangents. However every time I try to incorporate this into my script I keep getting error messages or the result comes out as just one color. If anyone could help me to make it work would be much appreciated.

$\endgroup$
2
  • $\begingroup$ your url points to the man page for MeshLoop, but there's no script there. Did you mean to point to an example? $\endgroup$ Commented Oct 13, 2021 at 20:12
  • 1
    $\begingroup$ Yeah, that's correct. After using ob.data.calc_normals_split() you access the normals with loop.normal. What error message are you getting? Make sure you are in object mode and not edit mode when you run the script. $\endgroup$
    – scurest
    Commented Oct 13, 2021 at 23:34

1 Answer 1

4
$\begingroup$

MeshLoop.normal

As commented by @scurest

After using ob.data.calc_normals_split() you access the normals with loop.normal. What error message are you getting? Make sure you are in object mode and not edit mode when you run the script.

Look at the loop normal, rather than the vertex normal to get the custom split normal values.

Test script, using foreach set to set the UV values rather than directly looping over them.

import bpy
import numpy as np

context = bpy.context

ob = context.object
me = ob.data

# get or create uv layers
xy_layer = me.uv_layers.get("XY") or me.uv_layers.new(name="XY")
zw_layer = me.uv_layers.get("ZW") or me.uv_layers.new(name="ZW")

# calc split nomrals
me.calc_normals_split()

norms = np.empty(3 * len(me.loops))
me.loops.foreach_get("normal", norms)
nx, ny, nz = norms.reshape((-1, 3)).T
nw = np.zeros(len(nz))
xy_layer.data.foreach_set("uv", np.array([nx, ny]).T.ravel())
zw_layer.data.foreach_set("uv", np.array([nz, nw]).T.ravel())
$\endgroup$
2
  • 1
    $\begingroup$ Here is what it looks like when I run the script and extract the uv coordinates in the shader editor ibb.co/T0szQtm and here is how it should look ibb.co/bFdCM3F I think something is going wrong when It transfers the normals to uv coordinates. $\endgroup$ Commented Oct 14, 2021 at 17:32
  • 1
    $\begingroup$ Whoops, Required a transpose before the ravel. $\endgroup$
    – batFINGER
    Commented Oct 15, 2021 at 6:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .