|
|
|
Return to Scripting Issues
by Neon22 » Thu May 24, 2012 4:47 pm
I'm new to Panda3D and I'm trying to get this project done. Follows is the description and then several possible solutions. I would greatly appreciate it if anyone can advise me as to which mechanism is best suited to architecture of Panda3D.
Description:
Classic tunnelware but flexible.
- cylindrical tunnel leads away from user into distance. - tunnel is flexible - controlled by bspline. - tunnel has animated texture map on it. - (Actually several concentric tunnels travelling at different speeds, revealed using alpha maps). Solutions:Simple model based - tried adapting tunnel demo to have separately rotated objects but tunnel sections cannot be joined wihout seams. - adandoned Procedural manual transform - create classic procedural multislice cylinder - loop over each ring doing manual transforms and UV edit - OR use UvScrollNode to do UV animation (possibly slow) Procedural auto transform - create classic procedural multislice cylinder - however each ring of verts goes into its own array and is also used to create separate ring objects. - These standalone ring objects are manipulated using setPos, setHpr node based manipulations. Because they share verts the cylinder moves as a side effect. (is this even possible) Rope style - Use Rope primitive and somehow get animated UVs onto the setRenderMode(RopeNode.RMTube) style. - Camera inside the Rope. (is this even possible)
Some other way ?
I'm using 1.7.2 as 1.8 is marked unstable on download page. Is it OK to use ?
numpy is fast for array manipulations. Is numpy able to be mapped onto panda3D's structures ? Should I bother ?
Any responses and guidance is greatly appreciated.
-

Neon22
-
- Posts: 27
- Joined: Thu May 24, 2012 5:50 am
by Neon22 » Sat May 26, 2012 12:43 am
so it looks like the choice above entitled "Procedural auto transform" is not possible.
I created a GeomVertexData array holding my cylinder vertices. (vdata)
Then I created the GeomTriangles(Geom.UHStatic) for all of them.
I also made GeomLines(Geom.UHStatic)for a single ring in the cyclinder, indexing into the same array.
So I was hoping they were sharing the same vdata.
But the calls to create the Geom nodes seem to have split them apart.
- Code: Select all
self.cylGeom = Geom(vdata) for p in tubeprims: self.cylGeom.addPrimitive(p) # self.ring1Geom = Geom(vdata) for p in ringprims: self.ring1Geom.addPrimitive(p) # self.tunnelA = GeomNode('TunnelA') self.tunnelA.addGeom(self.cylGeom) c = render.attachNewNode(self.tunnelA) # self.ring1 = GeomNode('Ring1') self.ring1.addGeom(self.ring1Geom) d = render.attachNewNode(self.ring1)
So subsequent calls to (say) d.setPos do not move the vertices in the cylinder object
Oh well next plan on the list.
Can anyone save me some time and tell me what else won't work ?
-

Neon22
-
- Posts: 27
- Joined: Thu May 24, 2012 5:50 am
by Bradamante » Sun May 27, 2012 6:13 pm
Not sure if I understand your intentions correctly, but maybe this relates to the first question I ever asked on this forum: http://www.panda3d.org/forums/viewtopic.php?p=43381
However my solution involving LerpTexOffsetInterval applied to some uniform cylinder, not a more dynamic, irregular shape you seem to descibe. I guess what you want would require a shader or whatever.
iMac (2009), Mac OS X.8.1 - MacBookPro (2007), Mac OS X.8.2
@ YouTube
-

Bradamante
-
- Posts: 303
- Joined: Tue Nov 25, 2008 10:58 am
- Location: Leipzig, Germany
by Neon22 » Sun May 27, 2012 7:03 pm
Thanks for the feedback Bradamante. Great thread. I will look into LerpTex and friends. Any ideas on UvScrollNode ?
Here I have implemented my "Procedural manual transform" and The tunnel behaves usefully and looks to be calculating fast enough. So I guess I'll go with that.
Next is this issue of animating the uvs (which I could also do manually within 'turn' but I want it as efficient as possible.
- Code: Select all
###
# do fullscreen etc first from panda3d.core import loadPrcFileData #loadPrcFileData('', 'fullscreen 1')
import math import direct.directbase.DirectStart from panda3d.core import Fog, Texture, GeomNode from panda3d.core import TextNode from panda3d.core import Light,Spotlight,AmbientLight,DirectionalLight from panda3d.core import Vec3,Vec4,Point3, Mat4, VBase3 from panda3d.core import lookAt from panda3d.core import GeomVertexFormat, GeomVertexData from panda3d.core import Geom, GeomTriangles, GeomLines, GeomVertexWriter from direct.gui.OnscreenText import OnscreenText from direct.showbase.DirectObject import DirectObject from direct.interval.MetaInterval import Sequence from direct.interval.LerpInterval import LerpFunc from direct.interval.FunctionInterval import Func from direct.task.Task import Task import sys
# tunnel defs [radius, length, ringsteps, lengthsteps, texturefile] tunneldefs = [[12,60,16,8, "models/tunnel.jpg"], [20,60,16,5, "models/wood.jpg"] ]
#A simple function to make sure a value is in a given range, -1 to 1 by default def restrain(i, mn = -1, mx = 1): return min(max(i, mn), mx)
class World(DirectObject): def __init__(self): #base.disableMouse() #disable mouse control so that we can place the camera base.oobe() #base.oobeCull #camera.setPosHpr(0,0,10, 0, -90, 0) camera.setPosHpr(0,0,0, 0, 0 , 0) # define for 35mm lenses base.camLens.setFilmSize(24, 36) base.camLens.setFocalLength(24) # set the background color to black base.setBackgroundColor(0,0,0) # setup task to control tunnel taskMgr.add(self.turn, "turn") ###World specific-code
#Define the keyboard input #Escape closes the demo self.accept('escape', sys.exit) self.accept('1', self.inc_fov, [-2]) self.accept('2', self.inc_fov, [2])
#Load the tunel and start the tunnel self.tunnels = [] # [[node, initialV, vdata], tunneldef] for t in tunneldefs: self.tunnels.append([self.init_tube(t[0], t[1], t[2], t[3], t[4]), t]) self.show_tunnels()
def show_tunnels(self): i = 0 for t in self.tunnels: print "tunnel", i print " [0][0] Node=",t[0][0] print " [0][1] initialV has", len(t[0][1]), "vertices" print " [0][2] vdata has", repr(t[0][2]) print " [1] defs = [radius, length, ringsteps, tubesteps]]" print " [1] defs =", t[1]
def myNormalize(self, myVec): # can't normalise in-place myVec.normalize() return myVec
def circle(self, radius, steps): """ Generate a single ring to be used for each ring in cylinder """ pos = [] norm = [] angle = math.pi*2/steps cos = math.cos(angle) sin = math.sin(angle) xn, zn = radius, 0 for i in range(steps): nf = 1/(xn*xn+zn*zn)**0.5 norm.append((xn*nf, zn*nf)) pos.append((xn,zn)) xt = xn xn = cos*xn - sin*zn zn = sin*xt + cos*zn # do last one (duplicate of first to close) norm.append(norm[0]) pos.append(pos[0]) return pos,norm
def init_tube(self, radius, length, ringsteps, tubesteps, texture="models/tunnel.jpg"): # length = length tubesteps = tubesteps ringsteps = ringsteps initialV = [] form = GeomVertexFormat.getV3n3t2()#getV3n3cpt2() vdata = GeomVertexData('cyl', form, Geom.UHDynamic) vertex = GeomVertexWriter(vdata, 'vertex') normal = GeomVertexWriter(vdata, 'normal') #color = GeomVertexWriter(vdata, 'color') texcoord = GeomVertexWriter(vdata, 'texcoord') # ring, normals = self.circle(radius, ringsteps) ustep = 1.0/ringsteps vstep = 1.0/(tubesteps-1) ystep = float(length) / (tubesteps-1) y = 0 v = 0 for i in range(tubesteps): u=0 for j in range(ringsteps+1): # same as len(ring) p = ring[j] n = normals[j] vertex.addData3f(p[0], y, p[1]) initialV.append(VBase3(p[0], y, p[1])) normal.addData3f(self.myNormalize(Vec3(n[0],0,n[1]))) #color.addData4f(0.5, 1.0*j/ringsteps, 1.0*i/tubesteps, 1.0) texcoord.addData2f(u, v) u += ustep # y += ystep v += vstep # vdata now defined print len(initialV), "Vertices in tunnel" #print self.vdata # make triangles tris = [] for i in range(tubesteps-1): for j in range(0,ringsteps): idx = j+i*(ringsteps+1) #print idx, [idx,idx+1,idx+ringsteps+1], [idx+ringsteps+1, idx+1, idx+1+ringsteps+1] tris.append([idx,idx+1,idx+ringsteps+1]) # 1/2 quad tris.append([idx+ringsteps+1, idx+1, idx+1+ringsteps+1]) # 2nd 1/2 quad # have list make triangles into prims #print "\n",tris tubeprims = [] # make tube triangles for t in tris: prim = GeomTriangles(Geom.UHStatic) prim.addVertices(t[0],t[1],t[2]) prim.closePrimitive() tubeprims.append(prim) # finalise cylGeom = Geom(vdata) for p in tubeprims: cylGeom.addPrimitive(p) # tunnelA = GeomNode('TunnelA') tunnelA.addGeom(cylGeom) c = render.attachNewNode(tunnelA) # texture tex = loader.loadTexture(texture) tex.setWrapU(1) tex.setWrapV(1) c.setTexture(tex) return (c, initialV, vdata)
def turn(self, task): """ Based on mouse input (later to be replaced) bend tubes progressively into distance. Would prefer a bspline here and to set each tube ring to position/orientation of bspline """ #Check to make sure the mouse is readable if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() #Here we multiply the values to get the amount of degrees to turn screenYrot = restrain(mpos.getX()) * 150 screenXrot = restrain(mpos.getY()) * 200 Zaxis = Vec3( 0, 0, -1 ) # up vector Xaxis = Vec3( 1, 0, 0 ) for tunnels in self.tunnels: verts = GeomVertexWriter(tunnels[0][2], 'vertex') tubesteps = tunnels[1][3] length = tunnels[1][1] # make up one mat per ring to move those ring's vertices newmats = range(tubesteps) pos = VBase3(0,0,0) zangle = 0 xangle = 0 for i in range(tubesteps): #print i,zangle, pos scalefact = 1.1-float(i)/(tubesteps-1) newmats[i] = Mat4.scaleMat(scalefact, 1, scalefact) * Mat4.rotateMat( xangle, Xaxis ) * Mat4.rotateMat( zangle, Zaxis )# * Mat4.translateMat( pos) # calc next ring's values #pos[1] += float(length)/(tubesteps-1) # ! using initial tube values zangle += float(screenYrot)/(tubesteps -1) xangle += float(screenXrot)/(tubesteps -1) # Move the verts by writing new ones i = 0 rstep = tunnels[1][2] + 1 # ringsteps initialV = tunnels[0][1] # initial tube verts in VBase3 format while not verts.isAtEnd(): ringidx = i/rstep mat = newmats[ringidx] #print i, ringidx newv = mat.xformPoint(initialV[i]) #if i == 0: print " ",self.initialV[i],newv verts.setData3f(newv) i+=1 return task.cont #Task continues infinitely
def inc_fov(self, change): base.camLens.setFocalLength(base.camLens.getFocalLength()+change) print"focal = ", base.camLens.getFocalLength()+change self.fxtask.start() status = self.mySound.status() self.musicBoxSound.play()
#End Class World
w = World() run()
-

Neon22
-
- Posts: 27
- Joined: Thu May 24, 2012 5:50 am
Return to Scripting Issues
Who is online
Users browsing this forum: No registered users and 1 guest
| | |