Updating Normals & some Vector questions

I have a plane with lots of vertices that randomly move up and down. However, the normals don’t get updated, and that makes the plane shaded flat. I have found codes that update the normals, however, they look a bit weird as instead of shading the whole polygon flat, the make a part around the vertex darker, following the edges.

I believe there’s two ways to finding the normal of a polygon:

  1. mathutils.geometry.normal
  2. cross product of two vectors of two edges or vectors of the triangle.

I’d like to try the 2nd method as I can learn from it, but I don’t exactly know how to code it.
First, I need the vectors. getVectTo won’t work as you need an object’s origin as the start point, not an XYZ point.
Then, I need to find the cross product, somehow like this:

a1 = firstvertex.XYZ()
a2 = secondvertex.XYZ()
a3 = thirdvertex.XYZ()
vec1 = vector from a1 to a2
vec2 = vector from a1 to a3
polyNormal = crossproduct(vec1 and vec2)

Finding the cross product would be something like this:

vec1.cross(vec2)

However, I don’t know the Python code, and that’s where I need help.
The first method probably is just a shortcut of the second method…

Once I have the normal, I need a way to set the normal of the polygon, not the vertex.

to get the vector from one position vector (in this case the position of a vertex) to another you just substract the two position vectors (destination - origin), so you could do getVectTo once for each vertex and then substract properly to get what you are looking for

and i think cross product in blender python is done by doing vec1.cross(vec2), it should work as long a you import the mathutils library like so


import Blender
from Blender import Mathutils
from Blender.Mathutils import *

An object position is a vector, all collums of orientations are vectors.


v1 = own.getVectTo(something)
v2 = own.getVectTo(something) - v1

v1.cross(v2)

import Blenderfrom Blender import Mathutils from Blender.Mathutils import *

why are you importing that?

import mathutils as mat

is enough.

then you can use vec = mat.vector(1.0,1.0,1.0)
but most things dont need mathutils and you can just use [0.0,0.0,0.0] as a vector

But the vector shouldn’t have its origin at the object’s origin, but rather at a vertex’s position that can be defined as an XYZ coordinate.

if you have the vertex position(s) simply do something like

start_point = [vertex.x, vertex.y ,vertex.z]
vec = start_point.getVecto(next point)

Allright, I got it working, it does the same as the first method… :yes: But atleast I learned something. I understand vectors (mostly) now, sorry for saying stupid things earlier.

Mathutils has an calculate normals function…

Yes, that’s the first method, or the shortcut…

If I hear you right, you’re trying to do flat shaded after moving verts, but it’s com8ng out smooth shaded?
This likely isn’t an issue with the normal calculation, instead it is probable that the mesh is smooth shaded to begin with.

In BGE (and most game engines) a vertex has only a single normal. As a result, when things are flat shaded, you need multiple vertices for each intersection of edges. Because of this, if the mesh in blender is smooth shaded, attempting to make it flat shaded by recalculating normals will not work - their aren’t enough vertices to store the information.
To prove this, print out how many vertices are in a cube - once in smooth shaded (8) and once in flat shaded (24).

Now, even if your mesh is flat shaded, BGE may try and be clever and reduce the number of vertices by making flat flat-shaded faces vertices share data. If your plane is flat shaded, and still doesn’t appear so in BGE, try using an edge split modifier after marking all edges as sharp. This will split all the faces in the mesh so the vertices are definitely separate.

Finally, you don;t need get vect to. Simply:
mathutils.Vector([vert1.x, vert1.y, vert1.z]) - mathutils.Vector([vert2.x, vert2.y, vert2.z]) will work.
(I can’t remember the format of vert.XYZ(), it may already come as a mathutils.Vector in which case vert1.XYZ() - vert2.XYZ() is sufficient.)

Vectors do not have a position. They have a direction and a length. They can be anywhere in space.

Special vectors are positional or location vectors. They are placed at the space origin (in object space it is the object origin). The vector to a vertex is the location vector (in object space from object origin).

Normal vectors have no origin at all. For simpler imagination they are typically draws at the vertex location. They do not need that. The “normal” attribute defines:

  • they have a length of 1.0 (the bge does not require that)
  • they are orthogonal to something (here -> orthogonal to the polygon that spans between the two edges)

Hmmm, yes, I got it working before all these new replies. Turns out that positions aren’t just a list, but a 3D vector… Anyway, maybe for shading the polygons flat I shoud use the normal calculated with the Python code, pass it over to OpenGL somehow, and set the normal there. However, I don’t know almost any OpenGL or how to use it in BGE, so it’s going to be hard… Can you set a polygon’s ​normal with Python?

https://docs.blender.org/api/blender_python_api_2_67_1/bge.types.KX_MeshProxy.html

https://docs.blender.org/api/blender_python_api_2_67_1/bge.types.KX_MeshProxy.html#bge.types.KX_MeshProxy.getPolygon

and I think
vertex.normal = Vector([x,y,z]) works

This is what I’m getting: (first 2)

This is what I want: (last)

Attachments




as sayd sdfgeoff, something change if the mesh starts in blender as smooth or flat, but is not the number of vertex(still the same), anyhow if the mesh starts as flat this seem that work … pretty (in reality should not :smiley: because the triangles are not counted)

......

def remake_normals_flat(mesh):
    # check that the mesh is "flat" in blender otherwise not work 
    for p in [mesh.getPolygon(index) for index in range(mesh.numPolygons)]:
        vertexes = [p.getMesh().getVertex(p.getMaterialIndex(),p.getVertexIndex(vn)) for vn in range(p.getNumVertex())]
        normal = mathutils.geometry.normal(*[v.XYZ for v in vertexes])
        for v in vertexes:
            v.normal = normal