Jump to content
magneto

How to add a Normal attribute in a Python SOP?

Recommended Posts

I know how to add attributes in Python but it doesn't work for the normal attribute. I add it using this line:

att = geo.addAttrib ( hou.attribType.Point, "N", ( 0.0, 1.0, 0.0 ) )

but when I do this, I can't see the normals in the viewport (show normals toggle on).

I then added a normal attribute using the Point SOP, and now I have 2 N[3] which the detail view show as follows:

N[0] N[1] N[2] N[x] N[y] N[z]

where mines are the first 3, and Point SOP added the last 3.

The docs say Houdini supports attributes with the same name but different type but I am not sure how to set the right type of the normal attribute through Python.

Any ideas?

Thanks :)

Share this post


Link to post
Share on other sites

Thanks Graham, it works awesome. I saw it in the docs but thought that was something else :)

Share this post


Link to post
Share on other sites

Also should I ensure the values I store are normalized or would the scale be important for potential other tasks?

I have seen a nurbs curve modified by VEX where the length of the point normals vary by the distance between the points.

Which one would be more preferred?

Share this post


Link to post
Share on other sites

It depends on what you want to do with them I guess. I'd say default to normalized values unless there's other info you want to encode in there.

  • Like 1

Share this post


Link to post
Share on other sites

It's really up to you what you want to put in there. In the case of 'N', while it is generally a normalized value there is nothing stopping you from scaling it up or down using any of many tools in Houdini. It all depends on what you want to do with it later, if anything. Really all the option means is that it will transform the vector when you transform the geometry, as opposed to not doing anything at all if it is just a 3 float attribute.

Share this post


Link to post
Share on other sites

Really all the option means is that it will transform the vector when you transform the geometry, as opposed to not doing anything at all if it is just a 3 float attribute.

Interesting. I had the impression that the following applies here:

float[3] doesn't get transformed

vectors[3] get transformed

normals get transformed, but differently and that's what this option is for.

Normal vectors don't transform in the same way as vertices, or position vectors. Mathematically, it's better to think of normal vectors not as vectors, but as planes perpendicular to those vectors. Then, the transformation rules for normal vectors are described by the transformation rules for perpendicular planes.

http://fly.cc.fer.hr/~unreal/theredbook/appendixg.html

Like transformVOP allows you to specify how to interpret the data:

How to treat the values in the 3D entity value parameter: as a position, direction vector, or normal.

Share this post


Link to post
Share on other sites

In Houdini 11, all vector attributes will be transformed as a normal and there no way to differentiate between a vector and a normal.

From the HDK docs:

GB_ATTRIB_VECTOR

This attribute is stored as 3 single precision floats. The difference between this and a GB_ATTRIB_FLOAT of 3 floats is that a GB_ATTRIB_VECTOR attribute will be transformed as a normal when the geometry has a transform applied.

http://www.sidefx.com/docs/hdk11.1/hdk_geometry_intro.html#HDK_Geometry_Intro_Attribute_Types

  • Like 1

Share this post


Link to post
Share on other sites

Thanks guys, I went with the normalized. Also in my case the vectors are already unit vectors, so I didn't have to normalize.

But if I did, I would have to create intermediate hou.Vector3 values from my nx, ny, nz and then normalize it, and then create a tuple from the members of this vector, right?

setAttribValue doesn't seem to accept hou.Vector3 values according to docs.

Just thought this would be alot of overhead, if I could just pass my vectors. But this is a theoretical question because I don't need to do this right now :D

Share this post


Link to post
Share on other sites

You can pass a hou.Vector3 if you have one. For cases where it wants multiple values, a tuple, list or a hou.Vector object at all valid. Something like this:

v = hou.Vector3(point.attribValue("N"))
v = v.normalized()
point.setAttribValue("N", v)

Edited by graham
  • Like 1

Share this post


Link to post
Share on other sites

Thanks Graham, that's sweet. Also I noticed in your last line you pass the attribute as a string. Is it safe to do that? I assume you still have to create an attribute for N before that. But if there are 2 N attributes; one as floats and the other as a vector, would that call know which to set?

Anyway was just curious :D

Share this post


Link to post
Share on other sites

Yes, that assumes you have an 'N' point attribute.

A better method would be to to pass a hou.Attrib instead of the string name.

normal_attr = geo.findPointAttrib("N")
v = hou.Vector3(point.attribValue(normal_attr))
v = v.normalized()
point.setAttribValue(normal_attr, v)

While this gives the same result as before, using the actual object can be quicker if you are doing the operation over many points/prims/vertices, as it doesn't need to find the attribute from the name every time.

As to what would happen if you had 2 'N' attributes, I can't say exactly. My suggestion would be to not have 2 of them so there is no doubt.

Edited by graham
  • Like 1

Share this post


Link to post
Share on other sites

Thanks man, gotcha, yeah I don't do that kind of shady stuff (having 2 attributes with the same name) :D

But Houdini allowing this confused me when I saw 2 N's :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×