Custom Geometry not being lit by point light

I’m sure this is a simple question but I’m having trouble lightning a custom geometry I’m making. I’ve gotten down to this simple panda3d app but my model is still not being lit. I’m sure its due to incorrect normal’s or light placement but I’m having trouble debugging it. Here is my example (I have not included my vertices/faces due to size)


from direct.showbase.ShowBase import ShowBase
from panda3d.core import Geom, GeomNode, GeomVertexFormat, \
    GeomVertexData, GeomTriangles, GeomVertexWriter, GeomVertexReader, TextureStage, TexGenAttrib
from panda3d.core import NodePath, Spotlight
from panda3d.core import AmbientLight, PointLight, DirectionalLight
from panda3d.core import VBase4, Vec3, Vec4
from direct.task import Task
import sys
import random
from math import sqrt, sin, cos, pi

#to large to be included
vertices = []
faces = []

import cv2
import mediapipe as mp
import numpy as np

class BrownianBlender(ShowBase):
    def __init__(self):
        # Basics
        ShowBase.__init__(self)
        base.disableMouse()
        self.render.setShaderAuto()
        self.render.setTwoSided(True)

        self.accept("escape", sys.exit)


        # Create the geometry
        self.geom_node = self.create_geom()
        self.face_model_np = NodePath(self.geom_node)
        self.face_model_np.setColor(1,1,0,1,1)

        #update rendering settings
        self.face_model_np.setDepthOffset(1)
        self.face_model_np.reparent_to(self.render)



        # Light
        light = PointLight('light')
        light_np = self.render.attachNewNode(light)
        light_np.set_pos(0, 5, -5)
        light_np.look_at(0, 0, 0)
        # Model-light interaction
        #light.setShadowCaster(True)
        self.render.setLight(light_np)
        

        self.camera.set_pos(0, 0, -2)
        self.camera.look_at(0,0,0)


    def create_geom(self):
        
        #bpy.ops.mesh.primitive_cube_add()
        vertex_format = GeomVertexFormat.getV3()
        vdata = GeomVertexData('face_vertex_data', vertex_format, Geom.UHDynamic)
        vdata.setNumRows(len(vertices))

        #create vertex writer and add vertices
        vertex_writer = GeomVertexWriter(vdata, 'vertex')
        
        landmark_x = np.array([])
        landmark_y = np.array([])
        landmark_z = np.array([])
        for landmark in vertices:
            landmark_x = np.append(landmark_x, landmark[0])
            landmark_y = np.append(landmark_y, landmark[1])
            landmark_z = np.append(landmark_z, landmark[2])


        #center locations in 3d space
        self.average_x = np.mean(landmark_x)
        self.average_y = np.mean(landmark_y)
        self.average_z = np.mean(landmark_z)

        centered_pos_x = landmark_x - self.average_x  
        centered_pos_y = landmark_y - self.average_y
        centered_pos_z = landmark_z - self.average_z

        for i in range(len(vertices)):
            vertex_writer.addData3(centered_pos_x[i], centered_pos_y[i], centered_pos_z[i])
        #    texcoord_writer.addData2(*uv_map[i])

        geom = Geom(vdata)

        for face in faces:
            if(len(face) != 3):
                print("bad face")

            prim = GeomTriangles(Geom.UHStatic)
            prim.addVertices(*face)
            prim.closePrimitive()
            geom.addPrimitive(prim)

        # Create the actual node
        node = GeomNode('gnode')
        node.addGeom(geom)
        
        self.vdata = vdata
        
        return node

   
demo = BrownianBlender()
demo.run()

Thank you for any help and I’m sorry if this is to simple of a question.

Yes, your problem has a simple solution, you forgot to add vertex normals. To calculate the lighting, the direction of the polygon in space is required, which is described as a vector.

Okay thank you! I knew it was something simple like that. Since I’m generating this model in real time is it possible to procedural generate normals? I’ve be looking through this documentation to little success.

Also I assumed panda3d generated default normal’s which should have been visible due to self.render.setTwoSided(True). It also works when using AmbientLight just not Point or Directional

Of course you can generate normals, the procedural-cube example shows how to do it.