edit: I've worked through the problems I originally posted about, and of course have some new ones :)
move the white points around (click and drag) and see if you can give me a hint why its doubling up the points when my code only creates 4
setcolor.bb:
bez.bb:
bezier.bb:
move the white points around (click and drag) and see if you can give me a hint why its doubling up the points when my code only creates 4
setcolor.bb:
Global SetColorTexture = LoadTexture("purewhite.png") Global SetColorBrush = CreateBrush(255,255,255) BrushAlpha SetColorBrush, 1 BrushShininess SetColorBrush, 0 BrushTexture SetColorBrush, SetColorTexture Function SetColor(mesh,r,g,b) For k=1 To CountSurfaces(mesh) PaintSurface(GetSurface(mesh,k), SetColorBrush) Next For k=1 To CountChildren(mesh) SetColor(GetChild(mesh, k), r,g,b) Next EntityColor mesh, r,g,b End Function
bez.bb:
Type bez Field x#, y#, z# ; point coords Field pa#, ya# ; pitch and yaw of control vector Field len# ; length of control vector Field sec% ; sections to next point Field pt ; point entity (sphere) Field cyl ; control line (cylinder) Field cp1, cp2 ; fwd and back control points Field piv ; pivot containing curve segments End Type Function BezierNew.bez(x#,y#,z#,pa#,ya#,Len#) tmp.bez = New bez tmp\x = x tmp\y = y tmp\z = z tmp\pa = pa tmp\ya = ya tmp\Len = Len tmp\pt = 0 tmp\cyl = 0 tmp\cp1 = 0 tmp\cp2 = 0 tmp\piv = 0 tmp\sec = 8 Return tmp; End Function Function BezierAdd.bez(blist.bez, b.bez) blist.bez = New bez blist\x = b\x blist\y = b\y blist\z = b\z blist\pa = b\pa blist\ya = b\ya blist\Len = b\Len blist\sec = b\sec Return blist End Function Function BezierInit() spline.bez = Last bez pt2.bez = spline.bez If pt2\pt = 0 BezierCreatePoint(pt2) EndIf For spline.bez = Each bez pt1.bez = pt2.bez pt2.bez = spline.bez If pt2\pt = 0 BezierCreatePoint(pt2) EndIf BezierUpdateSegment(pt1,pt2) Next End Function Function IsBezierPoint(ent) For spline.bez = Each bez If spline\pt = ent Return True Next Return False End Function Function BezierListIndex(ent) ndx = 0 For spline.bez = Each bez If spline\pt = ent Return ndx EndIf If spline\cp1 = ent Return ndx EndIf If spline\cp2 = ent Return ndx EndIf ndx = ndx + 1 Next Return -1 End Function Function BezierControlIndex(ent) For spline.bez = Each bez If spline\cp1 = ent Return 1 EndIf If spline\cp2 = ent Return 2 EndIf Next Return -1 End Function Function BezierMovePoint(ndx, x#, y#, z#) cnt = 0 spline.bez = Last bez pre.bez = spline.bez For spline.bez = Each bez If cnt = ndx ; update point spline\x = spline\x + x spline\y = spline\y + y spline\z = spline\z + z BezierUpdatePoint(spline.bez) cur.bez = spline.bez spline = After spline If spline = Null spline.bez = First bez EndIf BezierUpdateSegment(pre, cur) BezierUpdateSegment(cur, spline.bez) Return EndIf pre.bez = spline.bez cnt = cnt + 1 Next End Function Function BezierMoveControl(ndx, ctrl, x#, y#, z#) cnt = 0 spline.bez = Last bez pre.bez = spline.bez For spline.bez = Each bez If cnt = ndx ; update control If ctrl = 1 ; update cp1 x = x + EntityX(spline\cp1) y = y + EntityY(spline\cp1) z = z + EntityZ(spline\cp1) MoveEntity(spline\cp1, x, y, z) nx# = EntityX(spline\cp1) ny# = EntityY(spline\cp1) nz# = EntityZ(spline\cp1) p# = VectorPitch(nx,ny,nz) y# = VectorYaw(nx,ny,nz) d# = Sqr(nx*nx + ny*ny + nz*nz) spline\pa = p spline\ya = y + 90.0 spline\Len = d Else ; update cp2 x = x + EntityX(spline\cp2) y = y + EntityY(spline\cp2) z = z + EntityZ(spline\cp2) MoveEntity(spline\cp2, x, y, z) nx# = -EntityX(spline\cp2) ny# = -EntityY(spline\cp2) nz# = -EntityZ(spline\cp2) p# = VectorPitch(nx,ny,nz) y# = VectorYaw(nx,ny,nz) d# = Sqr(nx*nx + ny*ny + nz*nz) spline\pa = p spline\ya = y + 90.0 spline\Len = d EndIf BezierUpdatePoint(spline.bez) cur.bez = spline.bez spline = After spline If spline = Null spline.bez = First bez EndIf BezierUpdateSegment(pre, cur) BezierUpdateSegment(cur, spline.bez) Return EndIf pre.bez = spline.bez cnt = cnt + 1 Next End Function Function BezierCreatePoint(pt.bez) pt\pt = CreateSphere(8) ScaleMesh(pt\pt,0.07,0.07,0.07) EntityPickMode pt\pt, 2 pt\cyl = CreateCylinder(8,1,pt\pt) ScaleMesh(pt\cyl,0.02,1,0.02) pt\cp1 = CreateSphere(8,pt\pt) ScaleMesh(pt\cp1,0.05,0.05,0.05) EntityPickMode pt\cp1, 2 pt\cp2 = CreateSphere(8,pt\pt) ScaleMesh(pt\cp2,0.05,0.05,0.05) EntityPickMode pt\cp2, 2 SetColor(pt\pt, 255, 255, 255) SetColor(pt\cp1, 255, 255, 0) SetColor(pt\cp2, 255, 0, 255) SetColor(pt\cyl, 0, 255, 0) EntityFX pt\pt,5 pt\piv = CreatePivot(pt\pt) For i=1 To pt\sec sec = CreateCylinder(8,1,pt\piv) SetColor(sec, 0, 0, 255) ScaleMesh(sec,0.02,1,0.02) Next BezierUpdatePoint(pt) End Function Function BezierUpdatePoint(pt.bez) RotateEntity(pt\cyl, pt\pa, pt\ya, 90) ScaleEntity(pt\cyl,1,pt\Len/2.0,1) cpz# = (pt\Len/2.0) * Sin(pt\ya) * Cos(pt\pa) cpy# = (pt\Len/2.0) * Sin(pt\pa) cpx# = (pt\Len/2.0) * Cos(pt\ya) * Cos(pt\pa) PositionEntity(pt\cp1, cpx#, cpy#, cpz#) PositionEntity(pt\cp2, -cpx#, -cpy#, -cpz#) PositionEntity(pt\pt, pt\x, pt\y, pt\z) End Function Function BezierUpdateSegment(pt1.bez, pt2.bez) Local lx#, ly#, lz# ; last point coords Local inc#, t#, sec% ; loop control Local nt#, nt2#, nt3# ; precomputed (1-t) factors Local t2#, t3# ; precomputed (t) factors Local p1px#, p1py#, p1pz# ; pt1 x/y/z Local p1cx#, p1cy#, p1cz# ; pt1 control x/y/z Local p2px#, p2py#, p2pz# ; pt2 x/y/z Local p2cx#, p2cy#, p2cz# ; pt2 control x/y/z Local x#, y#, z# ; bezier results Local dx#, dy#, dz# ; distance from last point to current Local dist# ; distance vector magnitude Local pit#, yaw# ; pitch and yaw of segment Local px#, py#, pz# ; centerpoint of current segment Local nx#, ny#, nz# ; center point relative to base point DebugLog "" DebugLog "starting " + pt1\pt + " " + pt2\pt lx = pt1\x ly = pt1\y lz = pt1\z inc = 1.0 / pt1\sec t = inc sec = 1 While t<=1.0 nt = 1.0-t nt2 = nt * nt nt3 = nt2 * nt t2 = t * t t3 = t2 * t p1px = pt1\x p1py = pt1\y p1pz = pt1\z p1cx = EntityX(pt1\cp1) + p1px p1cy = EntityY(pt1\cp1) + p1py p1cz = EntityZ(pt1\cp1) + p1pz ;DebugLog "Pt1(x,y,z) Pc1(x,y,z) = " +p1px+" "+p1py+" "+p1pz+" "+p1cx+" "+p1cy+" "+p1cz p2px = pt2\x p2py = pt2\y p2pz = pt2\z p2cx = EntityX(pt2\cp2) + p2px p2cy = EntityY(pt2\cp2) + p2py p2cz = EntityZ(pt2\cp2) + p2pz ;DebugLog "Pt2(x,y,z) Pc2(x,y,z) = " +p2px+" "+p2py+" "+p2pz+" "+p2cx+" "+p2cy+" "+p2cz x = p1px*nt3 + 3.0*p1cx*nt2*t + 3.0*p2cx*nt*t2 + p2px*t3 y = p1py*nt3 + 3.0*p1cy*nt2*t + 3.0*p2cy*nt*t2 + p2py*t3 z = p1pz*nt3 + 3.0*p1cz*nt2*t + 3.0*p2cz*nt*t2 + p2pz*t3 ;DebugLog "t x y z = " + t + " " + x + " " + y + " " + z dx = x - lx dy = y - ly dz = z - lz ;DebugLog "dx dy dz = " + dx + " " + dy + " " + dz dist = Sqr(dx*dx + dy*dy + dz*dz) pit = VectorPitch(dx,dy,dz) yaw = VectorYaw(dx,dy,dz) ;DebugLog "dist / pitch / yaw = " + dist + " / " + pit + " / " + yaw px = lx + dx/2.0 py = ly + dy/2.0 pz = lz + dz/2.0 ;DebugLog "px py pz = " + px + " " + py + " " + pz nx = px-p1px ny = py-p1py nz = pz-p1pz ;DebugLog "sec / nx ny nz = " + sec + " / " + nx + " " + ny + " " + nz seg = GetChild(pt1\piv, sec) PositionEntity(seg, nx, ny, nz) ScaleEntity(seg, 1, dist/2.0, 1) RotateEntity(seg, pit+90, yaw, 0) lx=x ly=y lz=z t = t + inc sec = sec + 1 Wend End Function
bezier.bb:
;************************************************** ;* 3D Bezier Spline by John Barrett 2004 * ;************************************************** ;* Email: john@... * ;************************************************** ;* Based on Jeppe Nielson's 2D Bezier code * ;* Based on Wedoe´s bezier function * ;************************************************** Graphics3D 800,600,16,2 SetBuffer BackBuffer() ; Setup the lighting... AmbientLight 255,255,255 ; CAMERA PIVOT Global camera_pivot= CreatePivot() EntityRadius camera_pivot,0.1 ; Setup the camera. Global camera = CreateCamera(camera_pivot) PositionEntity(camera_pivot, 0, 0, 0) PositionEntity(camera, 0, 10, 0) RotateEntity(camera, 90,0,0) Color 255, 255, 255 Include "setcolor.bb" Include "bez.bb" Global spline.bez pt1.bez = BezierNew(0,0,-1,0,0,1.5) pt2.bez = BezierNew(1,0,0,0,90,1.5) pt3.bez = BezierNew(0,0,1,0,180,1.5) pt4.bez = BezierNew(-1,0,0,0,270,1.5) BezierAdd(spline,pt1) BezierAdd(spline,pt2) BezierAdd(spline,pt3) BezierAdd(spline,pt4) BezierInit() ; mouse x to view translation matrix mxtx = 1: mxty = 0: mxtz = 0 ; mouse y to view translation matrix mytx = 0: myty = 0: mytz = -1 curbpt = -1 curcpt = -1 Repeat If KeyHit(33) ; f=front PositionEntity(camera, 0, 0, -10) RotateEntity(camera, 0,0,0) mxtx = 1: mxty = 0: mxtz = 0 mytx = 0: myty = -1: mytz = 0 EndIf If KeyHit(38) ; l=left PositionEntity(camera, -10, 0, 0) RotateEntity(camera, 0,270,0) mxtx = 0: mxty = 0: mxtz = -1 mytx = 0: myty = -1: mytz = 0 EndIf If KeyHit(19) ; r=right PositionEntity(camera, 10, 0, 0) RotateEntity(camera, 0,90,0) mxtx = 0: mxty = 0: mxtz = 1 mytx = 0: myty = -1: mytz = 0 EndIf If KeyHit(20) ; t=top PositionEntity(camera, 0, 10, 0) RotateEntity(camera, 90,0,0) mxtx = 1: mxty = 0: mxtz = 0 mytx = 0: myty = 0: mytz = -1 EndIf If MouseDown(1) If curbpt = -1 And curcpt = -1 ; find out what is being clicked mx = MouseX() my = MouseY() ent = CameraPick(camera, mx, my) ent = PickedEntity() If ent <> 0 If IsBezierPoint(ent) curbpt = BezierListIndex(ent) Else curbpt = BezierListindex(ent) curcpt = BezierControlIndex(ent) EndIf ; setup to track movement next frame MouseXSpeed() MouseYSpeed() EndIf Else ; move currently clicked entity mx = MouseXSpeed() my = MouseYSpeed() tx = mxtx * mx + mytx * my ty = mxty * mx + myty * my tz = mxtz * mx + mytz * my If curcpt = -1 ; moving point BezierMovePoint(curbpt, tx*0.025, ty*0.025, tz*0.025) Else ; moving control BezierMoveControl(curbpt, curcpt, tx*0.025, ty*0.025, tz*0.025) EndIf EndIf Else curbpt = -1 curcpt = -1 EndIf RenderWorld Flip Until KeyDown(1) End