I’m having a bit of trouble getting shading from procedural geometry to work. I am fairly certain that I am setting the normal vectors correctly, but I keep getting flat shading for the added VRObject. The VRBox environment seems to be working correctly, however. Is it something with how I am attaching them to self.render? Lots of code below:
from panda3d.core import loadPrcFileData, Vec2D, rad2Deg, Mat4, Vec3, AmbientLight, DirectionalLight, VBase4, deg2Rad, NodePath, Material
loadPrcFileData("", """#side-by-side-stereo 1
#undecorated 1
win-origin 15 15
win-size 640 480""")
import math
from VRBox import VRBox
from VRObjects import VRObject
from direct.showbase.ShowBase import ShowBase
class World(ShowBase):
def __init__(self):
ShowBase.__init__(self)
scnsz = Vec2D(0.31,0.2325)
scndist = 0.52
wkspsz = scnsz
wkspdp = 2*0.12
IOD = 0.3
Desired_CD = scndist
self.disableMouse()
self.setBackgroundColor(.5,0,0)
# Mirror the display (vertical) for task room & correct aspect ratio for stereo
#self.setAspectRatio(scnsz.x/(2*scnsz.y))
self.win.setInverted(True)
# Position the camera
self.camera.setPos(0,0,1*scndist)
self.camera.setHpr(0,-90,0)
# Setup the camera lens
self.camLens.setNear(0.001)
self.camLens.setFar(100)
Xang = rad2Deg(2.*math.atan(scnsz.x/(2.*scndist)))
Yang = rad2Deg(2.*math.atan(scnsz.y/(2.*scndist)))
CD_Hack = Desired_CD*math.tan(deg2Rad(Xang)/2)/(IOD*2)
self.camLens.setFov(Xang,Yang)
self.camLens.setInterocularDistance(IOD)
self.camLens.setConvergenceDistance(CD_Hack)
# Add the VRBox
self.box = VRBox().generate(Vec3(0,0,-.06),wkspsz.x,wkspsz.y,wkspdp/2)
# Add checker pattern to the box
checkers = loader.loadTexture("textures/checker.bmp")
checkers.setMagfilter(checkers.FTNearest)
self.box.setTexture(checkers)
self.boxmat = Material()
self.boxmat.setShininess(6.)
self.box.setMaterial(self.boxmat)
self.box.reparentTo(self.render)
# Add a directional light
dlight = DirectionalLight('dlight')
dlight.setColor(VBase4(0.8, 0.8, 0.8, 1))
dlnp = self.render.attachNewNode(dlight)
dlnp.lookAt(1,-1,-1)
self.render.setLight(dlnp)
# Add an ambient light
alight = AmbientLight('alight')
alight.setColor(VBase4(0.3, 0.3, 0.3, 1))
alnp = self.render.attachNewNode(alight)
self.render.setLight(alnp)
# Add a cursor
self.cursor = VRObject('cylinder', scnsz.y, Vec3(0.1,0.1,0.2))
self.cursor.getNodePath().reparentTo(self.render)
self.cursor.getNodePath().setHpr(0,110,0)
W = World()
W.run()
from pandac.PandaModules import GeomVertexFormat, GeomVertexData, GeomVertexWriter, GeomTriangles, Geom, GeomNode, NodePath, GeomPoints, Vec3, Vec2
class VRBox:
def generate(self,cent,w,h,d):
format = GeomVertexFormat.getV3n3t2()
boxData = GeomVertexData("box", format, Geom.UHStatic)
vertexWriter = GeomVertexWriter(boxData,'vertex')
normWriter = GeomVertexWriter(boxData,'normal')
uvWriter = GeomVertexWriter(boxData,'texcoord')
d2 = d/w
coords = [Vec3(w, h, -d), Vec3(-w, h, -d), Vec3(-w, -h, -d), Vec3(w, -h, -d), # Back
Vec3(-w, h, -d), Vec3(-w, h, d), Vec3(-w, -h, d), Vec3(-w, -h, -d), # Left
Vec3(w, h, d), Vec3(w, h, -d), Vec3(w,-h,-d), Vec3(w, -h, d), # Right
Vec3(-w, h, -d), Vec3(w, h, -d), Vec3(w, h, d), Vec3(-w, h, d), # Top
Vec3(w, -h, -d), Vec3(-w, -h, -d), Vec3(-w, -h, d), Vec3(w, -h, d)] # Bottom
norms = [Vec3(0, 0, 1), Vec3(0, 0, 1), Vec3(0, 0, 1), Vec3(0, 0, 1), # Back
Vec3(1, 0, 0), Vec3(1, 0, 0), Vec3(1, 0, 0), Vec3(1, 0, 0), # Left
Vec3(-1, 0, 0), Vec3(-1, 0, 0), Vec3(-1, 0, 0), Vec3(-1, 0, 0), # Right
Vec3(0, -1, 0), Vec3(0, -1, 0), Vec3(0, -1, 0), Vec3(0, -1, 0), # Top
Vec3(0, 1, 0), Vec3(0, 1, 0), Vec3(0, 1, 0), Vec3(0, 1, 0)] # Bottom
texts = [Vec2(1, 1), Vec2(0, 1), Vec2(0, 0), Vec2(1, 0), # Back
Vec2(0, 0), Vec2(0, d2), Vec2(1, d2), Vec2(1, 0), # Left
Vec2(0, d2), Vec2(0, 0), Vec2(1, 0), Vec2(1, d2), # Right
Vec2(0, 0), Vec2(1, 0), Vec2(1, d2), Vec2(0, d2), # Top
Vec2(1, 0), Vec2(0, 0), Vec2(0, d2), Vec2(1, d2)] # Bottom
for pos, norm, tex in zip(coords, norms, texts):
vertexWriter.addData3f((pos/2)+cent)
normWriter.addData3f(norm)
uvWriter.addData2f(tex)
triangles = GeomTriangles(Geom.UHStatic)
def addQuad(v0, v1, v2, v3):
triangles.addVertices(v0, v1, v2)
triangles.addVertices(v0, v2, v3)
triangles.closePrimitive()
for i in range(0,5):
addQuad(i*4,i*4+1,i*4+2,i*4+3)
triangles.closePrimitive()
geom = Geom(boxData)
geom.addPrimitive(triangles)
node = GeomNode("checkerbox")
node.addGeom(geom)
return NodePath(node)
from pandac.PandaModules import GeomVertexFormat, GeomVertexData, GeomVertexWriter, GeomTriangles, Geom, GeomNode, NodePath, GeomPoints, Vec3, Material, VBase4
from math import sin, cos, pi, fmod
class VRObject:
def __init__(self,type='sphere',wrldsz=0.2325, sz=Vec3(0.1,0.1,0.1)):
self.DEF_LATS = 30
self.DEF_LONGS = 30
self.wrldsz = wrldsz
self.sz = sz
self.type = type
self.material = Material()
self.material.setShininess(0)
self.material.setAmbient(VBase4(0, 1, 0, 1))
self.material.setDiffuse(VBase4(0, 0, 1, 1))
self.material.setSpecular(VBase4(1, 1, 0, 1))
self.material.setEmission(VBase4(0, 0, 0, 1))
self.rootNodePath = NodePath('object')
format = GeomVertexFormat.getV3n3()
self.objectData = GeomVertexData('object', format, Geom.UHStatic)
self.vertex = GeomVertexWriter(self.objectData,'vertex')
self.normals = GeomVertexWriter(self.objectData,'normal')
self.triangles = GeomTriangles(Geom.UHStatic)
self.createandaddcoords(type)
self.geom = Geom(self.objectData)
self.geom.addPrimitive(self.triangles)
self.geomnode = GeomNode('object')
self.geomnode.addGeom(self.geom)
NodePath(self.geomnode).reparentTo(self.rootNodePath)
self.rootNodePath.setMaterial(self.material)
self.rootNodePath.setScale(self.sz*self.wrldsz)
def getNodePath(self):
return self.rootNodePath
def setColor(self,R,G,B):
self.material.setAmbient(VBase4(R,G,B,1))
self.material.setDiffuse(VBase4(R,G,B,1))
def createandaddcoords(self,type):
if type=='sphere':
coords = [None]*(self.DEF_LATS*self.DEF_LONGS+2)
coords[0] = Vec3(0,0,-1)
for i in range(0,self.DEF_LATS):
vertang = pi*(i+1)/(self.DEF_LATS+1)-pi/2
z = sin(vertang)
hzrad = cos(vertang)
for j in range(0,self.DEF_LONGS):
idx = i*self.DEF_LONGS+j+1
hrzang = 2*pi*j/self.DEF_LONGS
x = hzrad*cos(hrzang)
y = hzrad*sin(hrzang)
coords[idx] = Vec3(x,y,z)
endidx = self.DEF_LATS*self.DEF_LONGS+1
coords[endidx] = Vec3(0,0,1)
norms = coords
elif type=='cylinder':
coords = [None]*(self.DEF_LONGS*4+2)
norms = [None]*(self.DEF_LONGS*4+2)
coords[0] = Vec3(0,0,-1)
norms[0] = Vec3(0,0,-1)
for i in range(0, self.DEF_LONGS):
for j in range(0,4):
idx = i+self.DEF_LONGS*j+1
x = cos(2*pi*i/self.DEF_LONGS)
y = sin(2*pi*i/self.DEF_LONGS)
norms[idx] = Vec3(x,y,0)
if j<2:
coords[idx] = Vec3(x,y,-1)
else:
coords[idx] = Vec3(x,y,1)
if j==0:
norms[idx] = Vec3(0,0,-1)
elif j==3:
norms[idx] = Vec3(0,0,1)
endidx = self.DEF_LONGS*4+1
coords[endidx] = Vec3(0,0,1)
norms[endidx] = Vec3(0,0,1)
for pos, norm in zip(coords, norms):
self.vertex.addData3f(pos)
self.normals.addData3f(norm.normalize())
if type=='sphere':
self.addCap('bottom')
for i in range(1,self.DEF_LATS):
self.addLatitudes(i)
self.addCap('top')
elif type=='cylinder':
self.addCylEnd('bottom')
self.addLatitudes(2)
self.addCylEnd('top')
def addCap(self,whatend):
if whatend=='bottom':
for i in range(0,self.DEF_LONGS):
idx1 = i+1
idx2 = int(fmod(i+1,self.DEF_LONGS)+1)
self.triangles.addVertices(0,idx2,idx1)
self.triangles.closePrimitive()
elif whatend=='top':
endidx = self.DEF_LATS*self.DEF_LONGS+1
startspot = 1+self.DEF_LONGS*(self.DEF_LATS-1)
for i in range(0,self.DEF_LONGS):
idx1 = i+startspot
idx2 = int(fmod(i+1,self.DEF_LONGS)+startspot)
self.triangles.addVertices(endidx,idx1,idx2)
self.triangles.closePrimitive()
def addLatitudes(self,level):
strtpt1 = 1+(level-1)*self.DEF_LONGS
strtpt2 = 1+level*self.DEF_LONGS
for i in range(0,self.DEF_LONGS):
nextpt1 = int(fmod(i+1,self.DEF_LONGS)+strtpt1)
nextpt2 = int(fmod(i+1,self.DEF_LONGS)+strtpt2)
self.addQuad(i+strtpt1,nextpt1,nextpt2,i+strtpt2)
def addCylEnd(self,whatend):
if whatend=='bottom':
for i in range(0,self.DEF_LONGS):
idx1 = i+1
idx2 = int(fmod(i+1,self.DEF_LONGS)+1)
self.triangles.addVertices(0,idx2,idx1)
self.triangles.closePrimitive()
elif whatend=='top':
for i in range(0,self.DEF_LONGS):
idx1 = i+1+self.DEF_LONGS*3
idx2 = int(fmod(i+1,self.DEF_LONGS)+1+self.DEF_LONGS*3)
self.triangles.addVertices(self.DEF_LONGS*4+1,idx1,idx2)
self.triangles.closePrimitive()
def addQuad(self, v0, v1, v2, v3):
self.triangles.addVertices(v0, v1, v2)
self.triangles.closePrimitive()
self.triangles.addVertices(v0, v2, v3)
self.triangles.closePrimitive()
def changeSize(self, newsize):
self.sz = newsize
self.rootNodePath.setScale(self.sz*self.wrldsz)