5
$\begingroup$

Geometry nodes uses vertices as points by default so when i feed the mesh to Point Instance it instances the selected object across the vertices. How do you switch to the centers of faces?enter image description here

enter image description here enter image description here enter image description here

$\endgroup$
4
$\begingroup$

There is a pure GeoNodes workaround..

Please see below for GN (Fields) update.

Compare the original mesh to a 1-level subdivision of itself. Points on the subdivided version which are sufficiently distant from the edges of the original are in the middle of the original's faces, and can be separated out:

enter image description here

There has to be a tiny Epsilon in the Greater Than node to account for floating-point errors.. in this case, 0.0001.

GN(Fields) Update:

Just in case some have found some of this as counter-intuitive as I have, here is a route to one instance per face, aligned to normal:

enter image description here

..here shown with GN-modified mesh and instances together:

enter image description here

(Blender 3.0b)

$\endgroup$
2
  • $\begingroup$ This is a pretty smart sollution! GeoNodes still don't let us do it so ellegantly but your method will work about 100% of the time so it's alright. $\endgroup$ Sep 3 at 9:21
  • $\begingroup$ Re: update.. I'm finding it very difficult to work out which branch of geometry callbacks like 'Position' are being called on... :( $\endgroup$ Nov 13 at 13:44
2
$\begingroup$

i think this is not possible with the current version of geometry nodes.

But you could do it with the help of this python script:

import bpy
import bmesh
from mathutils import Vector

print("*" * 50)

obj = bpy.context.object

prevMode = obj.mode

# Will need to be in object mode
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)

# Create a bmesh access
bm = bmesh.new()
bm.from_mesh( obj.data )

# Get faces access
bm.faces.ensure_lookup_table()

# Identify the wanted faces
faces = [f for f in bm.faces]
faceNormals = [f.normal for f in bm.faces]

newVerts = []

for eachFace in faces:
#    print("new face:")
    x = 0
    y = 0
    z = 0
    for eachVertex in eachFace.verts:
#        print("vert:",eachVertex.co)
        x = eachVertex.co.x + x
        y = eachVertex.co.y + y
        z = eachVertex.co.z + z
        
    noOfVertsInFace = len(eachFace.verts)
           
    avgX = x / noOfVertsInFace
    avgY = y / noOfVertsInFace
    avgZ = z / noOfVertsInFace
       
    newVerts.append((avgX, avgY, avgZ))
       
verts = [v for v in bm.verts]       

bmesh.ops.delete( bm, geom = faces, context = 'FACES_ONLY' )
bmesh.ops.delete( bm, geom = verts)

for v in newVerts:
    bm.verts.new(v) 
    
bm.to_mesh( obj.data )

# Back to the initial mode
bpy.ops.object.mode_set(mode=prevMode, toggle=False)

how can you use it?

  1. select your object which you want to use (better make a copy of it and save that because your original object/mesh will be changed)
  2. run the script
  3. now you can use geometry nodes with that changed object

what does the script?

The script iterates over each face. For each face it iterates over all vertices and calculates the average point ("center"). It then deletes all existing faces and vertices and creates vertices at these centers.

$\endgroup$
2
  • $\begingroup$ Thank you! It's a pity they haven't yet implemented that into blender tho $\endgroup$ Aug 30 at 13:28
  • 1
    $\begingroup$ +1, ... It's not really my area, but I think you could crunch your code quite a lot by using bmesh.ops.poke(), which will pop a vertex in the middle of all faces in a given list. If you keep a record of the original verts, you can then delete those. $\endgroup$ Aug 30 at 19:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.