Thank you both for helping me. It’s very much appreciated. So I’ve got sort of a hybrid setup now using a mix of the two suggestions. For testing purposes I’ve got my left wall using the extrude method and the floor and right wall using the other method. They seem to be getting placed in the same spot with either method, however I’m noticing that the smaller I set my film size the more the walls move inward toward the center of the screen. I’m not sure how to keep the walls perfectly at the edge as I want the film size to be around 20.
I’m thinking it may be due to my setting up my orthographic lens slightly different than what is shown in Epihaius’ example because when I tried to copy it exactly I could not longer see my bullet objects anywhere. I’m very new to Panda3D and coding so it’s likely I’m doing something wrong with where I’m rendering things but I’m not sure.
In Epihaius’ example the smileys seem to always land exactly on the edge of the screen regardless of the film size, which is not how my adaptation is working.
Here’s is my current code.
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from panda3d.core import Vec4, Vec3, Vec2, Point3, LVector3, LColor, Material, BitMask32, OrthographicLens, AmbientLight, Spotlight, WindowProperties, Lens, CollisionRay
from panda3d.bullet import BulletWorld, BulletPlaneShape, BulletSphereShape, BulletRigidBodyNode, BulletDebugNode
import sys, random
staticObjects = []
marbleActors = []
marbleCount = 0
maxObstacleCount = 3
maxMarbleCount = 500
class MyApp(ShowBase):
def __init__(self):
ShowBase.__init__(self)
# Escape quits.
self.accept("escape", sys.exit)
screenWidth = int(self.pipe.getDisplayWidth())
screenHeight = int(self.pipe.getDisplayHeight())
windowProperties = WindowProperties()
windowProperties.setSize(screenWidth,screenHeight)
windowProperties.setForeground(1)
windowProperties.set_undecorated(True)
windowProperties.setTitle("Marbles")
windowProperties.set_icon_filename("Icons\Window_Icon.ico")
self.win.requestProperties(windowProperties)
self.setBackgroundColor((0, 0, 0, 1))
#"""
# Disables the camera controls.
self.disableMouse()
self.lens = OrthographicLens()
self.lens.setNearFar(-10, 10)
self.camLens.change_event = "lens-event"
self.accept("lens-event", self.__handle_lens_event)
#"""
debugNode = BulletDebugNode('Debug')
debugNode.showWireframe(True)
debugNode.showConstraints(True)
debugNode.showBoundingBoxes(False)
debugNode.showNormals(True)
debugNP = self.cam.attachNewNode(debugNode)
debugNP.show()
# World
self.world = BulletWorld()
self.world.setGravity(Vec3(0, 0, -9.81))
self.world.setDebugNode(debugNP.node())
# Floor
floorShape = BulletPlaneShape(Vec3(0, 0, 1), 1)
floorNode = BulletRigidBodyNode('floor')
floorNode.addShape(floorShape)
floorNode.setRestitution(0.6)
floorNode.setFriction(100)
self.floorNP = self.cam.attachNewNode(floorNode)
self.floorNP.reparent_to(self.cam)
self.world.attachRigidBody(floorNode)
# Left Wall
leftWallShape = BulletPlaneShape(Vec3(1, 0, 0), 1)
leftWallNode = BulletRigidBodyNode('Left Wall')
leftWallNode.addShape(leftWallShape)
leftWallNode.setRestitution(1)
leftWallNode.setFriction(10)
self.world.attachRigidBody(leftWallNode)
self.leftWallNP = self.cam.attachNewNode(leftWallNode)
self.leftWallNP.reparent_to(self.cam)
# Right Wall
rightWallShape = BulletPlaneShape(Vec3(-1, 0, 0), 1)
rightWallNode = BulletRigidBodyNode('Right Wall')
rightWallNode.addShape(rightWallShape)
rightWallNode.setRestitution(1)
rightWallNode.setFriction(10)
self.world.attachRigidBody(rightWallNode)
self.rightWallNP = self.cam.attachNewNode(rightWallNode)
self.rightWallNP.reparent_to(self.cam)
# Load all models.
# Marble Model
self.marble = loader.loadModel('Models/Marble')
#self.marble.setColor(LColor(1, 1, 1, 1) ** 5)
# Load all textures.
# Marble Textures
marbleTextures = ["Models/Textures/Marble_1.png", "Models/Textures/Marble_2.png", "Models/Textures/Marble_3.png", "Models/Textures/Marble_4.png"]
self.marbleTextureObjects = []
for texture in marbleTextures:
self.marbleTextureObjects.append(self.loader.loadTexture(texture))
self.taskMgr.add(self.createMarble, "Create Marble")
self.taskMgr.add(self.updatePhysics, 'Update Physics')
def __handle_lens_event(self, lens):
self.aspect_ratio = self.get_aspect_ratio(self.win)
self.filmSize = 20
self.lens.film_size = (self.filmSize, self.filmSize / self.aspect_ratio)
self.cam.node().setLens(self.lens)
# These will contain the results of the "extrude" method
nearPt = Point3()
farPt = Point3()
# Here use whatever lens you are employing,
# whether that's your own or base.camLens.
#
# The point (-1, 0) corresponds to the middle of the left-hand
# side of the screen, I believe.
self.lens.extrude(Vec2(-1, 0), nearPt, farPt)
# With a perspective lens this next step gets a little more
# complicated, but thankfully with an orthographic lens we can
# just grab the x- and y- coordinates and set the z- coordinate as
# we please! ^_^
self.leftWallNP.setPos(nearPt.x, nearPt.y, 0)
self.floorNP.setPos(0, 0, -self.filmSize * 0.5 / self.aspect_ratio)
#self.leftWallNP.setPos(-self.filmSize * 0.5, 0, 0)
self.rightWallNP.setPos(self.filmSize * 0.5, 0, 0)
# Create all static objects and obstacles.
for x in range(maxObstacleCount):
# Generic Sphere Obstacle
# Hpr affects rotation.
self.marble.setHpr(random.randint(0, 360), random.randint(0, 360), random.randint(0, 360))
randomScale = round(random.uniform(0.5, 0.5), 2)
self.marble.setScale(randomScale, randomScale, randomScale)
self.marble.setTexture(random.choice(self.marbleTextureObjects))
material = Material()
# Adjusts the colors of the reflection off the marble. (R, G, B, A)
material.setSpecular((1, 1, 1, 1))
material.setShininess(90)
#material.setEmission((0, 0, 0, 0)) #Make this material max brightness regardless of lighting.
self.marble.setMaterial(material, 1)
marbleCollisionShape = BulletSphereShape(randomScale)
marbleNode = BulletRigidBodyNode('Marble')
marbleNode.setMass(0)
marbleNode.setRestitution(0.5)
marbleNode.setFriction(0)
marbleNode.addShape(marbleCollisionShape)
marbleNodePath = self.cam.attachNewNode(marbleNode)
marbleNodePath.setPos(random.uniform((-self.filmSize * 0.5), (self.filmSize * 0.5)), 0, random.uniform((-self.filmSize * 0.5 / self.aspect_ratio), (self.filmSize * 0.5 / self.aspect_ratio)))
# Make sure there are no collisions happening with the obstacles.
while (self.world.contactTest(marbleNode)).getNumContacts() > 0:
marbleNodePath.setPos(random.uniform((-self.filmSize * 0.5), (self.filmSize * 0.5)), 0, random.uniform((-self.filmSize * 0.5 / self.aspect_ratio), (self.filmSize * 0.5 / self.aspect_ratio)))
self.world.attachRigidBody(marbleNode)
self.marble.copyTo(marbleNodePath)
staticObjects.append(marbleNodePath)
# Attach a point light to the camera so that the marbles are always lit.
spotLight = Spotlight("Spot Light")
spotLight.setLens(PerspectiveLens())
spotLightNodePath = self.cam.attachNewNode(spotLight)
spotLightNodePath.setPos(random.uniform(-40, 40), -30, 40)
spotLightNodePath.lookAt(self.floorNP)
self.cam.setLight(spotLightNodePath)
# Add ambient lighting to the scene.
ambientLight = AmbientLight("Ambient Light")
ambientLight.setColor(Vec4(0.2, 0.2, 0.2, 1))
ambientLightNodePath = self.cam.attachNewNode(ambientLight)
self.cam.setLight(ambientLightNodePath)
self.cam.setShaderAuto()
# This task runs every 2 seconds.
def createMarble(self, task):
global marbleCount
if task.time < 2.0:
return Task.cont
if marbleCount < maxMarbleCount:
marbleCount = marbleCount + 1
# Set rotation. (X, Y, Z)
self.marble.setHpr(random.randint(0, 360), random.randint(0, 360), random.randint(0, 360))
#marble.flattenLight()
# Randomize the scale of the model.
randomScale = round(random.uniform(0.2, 0.2), 2)
self.marble.setScale(randomScale, randomScale, randomScale)
# Set a random texture for the marble.
self.marble.setTexture(random.choice(self.marbleTextureObjects))
# This section deals with adding a specular highlight to the ball to make it look shiny. Normally, this is specified in the .egg file.
material = Material()
# Adjusts the collors of the reflection off the marble. (R, G, B, A)
material.setSpecular((1, 1, 1, 1))
material.setShininess(90)
self.marble.setMaterial(material, 1)
marbleCollisionShape = BulletSphereShape(randomScale)
marbleNode = BulletRigidBodyNode('Marble')
marbleNode.linear_factor = LVector3(1, 0, 1)
marbleNode.setMass(3.0)
marbleNode.setRestitution(0.55)
marbleNode.setFriction(0.5)
marbleNode.addShape(marbleCollisionShape)
marbleNodePath = self.cam.attachNewNode(marbleNode)
marbleNodePath.setPos(random.uniform((-self.filmSize * 0.5), (self.filmSize * 0.5)), 0, random.uniform((self.filmSize * 0.5 / self.aspect_ratio + 5), (self.filmSize * 0.5 / self.aspect_ratio + 10)))
marbleNodePath.setColor(1,1,1,1)
self.world.attachRigidBody(marbleNode)
self.marble.copyTo(marbleNodePath)
marbleActors.append(marbleNode)
return Task.again
# Update Physics
def updatePhysics(self, task):
dt = globalClock.getDt()
self.world.doPhysics(dt)
return Task.cont
app = MyApp()
app.run()