Code archives/3D Graphics - Mesh/Bezier Patches - Editable 3D surfaces.

This code has been declared by its author to be Public Domain code.

Download source code

Bezier Patches - Editable 3D surfaces. by Jeppe Nielsen2005
Shows how bezier patches can be created, example demonstrates an interactive 3d surface.
;*****************************************************
;*               Bezier Patch example                *
;*****************************************************
;*              By Jeppe Nielsen 2005                *
;*****************************************************
;*                jeppe@gameart.dk                   *
;*****************************************************

Graphics3D 800,600

segments=10

b.bezierpatch = BezierPatchNew()

patch=BezierPatchMesh(b,segments,segments)

patchtexture=CreateTexture(32,32)
SetBuffer TextureBuffer(patchtexture)
	ClsColor 255,0,0
	Cls
	Color 255,255,255
	Rect 0,0,16,16,True
	Rect 16,16,16,16,True
	
SetBuffer BackBuffer()

ScaleTexture patchtexture,0.25,0.25
EntityTexture patch,patchtexture

Global camera,camerarx#,camerary#

CameraInit

light=CreateLight(2)
PositionEntity light,0,10,0
LightRange light,5



plane=CreatePlane()
EntityPickMode plane,2
EntityAlpha plane,0

selectedpoint=-1

Repeat

cameraupdate 0.1

Select state

	Case 0
	
		If MouseDown(1)
			selectedpoint=BezierPatchGetPoint(b,camera,MouseX(),MouseY())
			If selectedpoint<>-1
				state=1
				PositionEntity plane,b\px[selectedpoint],b\py[selectedpoint],b\pz[selectedpoint]
			EndIf
		EndIf
		
	Case 1
	
		If MouseDown(1)
			
			CameraPick(camera,MouseX(),MouseY())
		
			BezierPatchSetPoint(b,selectedpoint,PickedX#(),PickedY#(),PickedZ#())
			If patch<>0
				FreeEntity patch
				patch=0
			EndIf
			
			patch=BezierPatchMesh(b,segments,segments)
			EntityTexture patch,patchtexture
				
		Else
		
			state=0
			
		EndIf
		
End Select

If selectedpoint<>-1
	
	If KeyDown(201)
	
		b\py[selectedpoint]=b\py[selectedpoint]+0.5
		If patch<>0
			FreeEntity patch
			patch=0
		EndIf
		
		patch=BezierPatchMesh(b,segments,segments)
		EntityTexture patch,patchtexture

	
	ElseIf KeyDown(209)	
	
		b\py[selectedpoint]=b\py[selectedpoint]-0.5
		If patch<>0
			FreeEntity patch
			patch=0
		EndIf
		
		patch=BezierPatchMesh(b,segments,segments)
		EntityTexture patch,patchtexture


	EndIf
	

EndIf

If KeyHit(78)

	segments=segments+1
	If patch<>0
		FreeEntity patch
		patch=0
	EndIf
	
	patch=BezierPatchMesh(b,segments,segments)
	EntityTexture patch,patchtexture


ElseIf KeyHit(74)	

	segments=segments-1
	If segments<1
		segments=1
	EndIf
	If patch<>0
		FreeEntity patch
		patch=0
	EndIf
	
	patch=BezierPatchMesh(b,segments,segments)
	EntityTexture patch,patchtexture

EndIf

If KeyHit(57)

	wire=1-wire
	WireFrame wire

EndIf


RenderWorld

Color 0,0,255
BezierPatchDraw(b,camera,selectedpoint)

Color 0,0,0
Text 401,11,"Bezier Patch example by Jeppe Nielsen, 2005",True
Text 401,31,"Left mouse button to move control points",True
Text 401,51,"Right mouse button & mouse to rotate camera, cursor keys to move camera",True
Text 401,71,"Page Up/down to move selected control point up/down",True
Text 401,91,"+ / - to adjust polygon segments : "+segments,True
Text 401,111,"Space to toggle wireframe",True

Color 0,128,255
Text 400,10,"Bezier Patch example by Jeppe Nielsen, 2005",True
Text 400,30,"Left mouse button to move control points",True
Text 401,51,"Right mouse button & mouse to rotate camera, cursor keys to move camera",True
Text 400,70,"Page Up/down to move selected control point up/down",True
Text 400,90,"+ / - to adjust polygon segments : "+segments,True
Text 400,110,"Space to toggle wireframe",True

x=MouseX()
y=MouseY()

Color 255,255,255

Rect x-6,y,13,1
Rect x,y-6,1,13


Flip

Until KeyDown(1)
End


Type bezierpatch

Field px#[15]
Field py#[15]
Field pz#[15]

End Type

Function BezierPatchNew.bezierpatch()

b.bezierpatch=New bezierpatch

For u=0 To 3
	
	For v=0 To 3
	
		b\px[u+v*4]=u*3
		b\py[u+v*4]=0
		b\pz[u+v*4]=v*3
		
	Next
	
Next

Return b
End Function

Function BezierPatchSetPoint(b.bezierpatch,point,x#,y#,z#)

	b\px[point]=x
	b\py[point]=y
	b\pz[point]=z

End Function

Function BezierPatchGetPoint(b.bezierpatch,cam,x,y,size=15)

sizesq=size*size

For n=0 To 15
	
	CameraProject cam,b\px[n],b\py[n],b\pz[n]
	
	dx=x-ProjectedX()
	dy=y-ProjectedY()

	dist=dx*dx+dy*dy

	If dist<=sizesq
		Return n
	EndIf
	
Next

Return -1
End Function

Function BezierPatchMesh(b.bezierpatch,useg=10,vseg=10)

mesh=CreateMesh()

surf=CreateSurface(mesh)

usegstep#=1/Float(useg)
vsegstep#=1/Float(vseg)

v#=0

While v<0.99

	u#=0

	While u<0.99
	
		uu#=u
		
		px1#=b\px[0]*(1-uu)^3 + b\px[1]*3*(1-uu)^2*uu + b\px[2]*3*(1-uu)*uu*uu + b\px[3]*uu^3
		py1#=b\py[0]*(1-uu)^3 + b\py[1]*3*(1-uu)^2*uu + b\py[2]*3*(1-uu)*uu*uu + b\py[3]*uu^3
		pz1#=b\pz[0]*(1-uu)^3 + b\pz[1]*3*(1-uu)^2*uu + b\pz[2]*3*(1-uu)*uu*uu + b\pz[3]*uu^3
		
		px2#=b\px[4]*(1-uu)^3 + b\px[5]*3*(1-uu)^2*uu + b\px[6]*3*(1-uu)*uu*uu + b\px[7]*uu^3
		py2#=b\py[4]*(1-uu)^3 + b\py[5]*3*(1-uu)^2*uu + b\py[6]*3*(1-uu)*uu*uu + b\py[7]*uu^3
		pz2#=b\pz[4]*(1-uu)^3 + b\pz[5]*3*(1-uu)^2*uu + b\pz[6]*3*(1-uu)*uu*uu + b\pz[7]*uu^3
		
		px3#=b\px[8]*(1-uu)^3 + b\px[9]*3*(1-uu)^2*uu + b\px[10]*3*(1-uu)*uu*uu + b\px[11]*uu^3
		py3#=b\py[8]*(1-uu)^3 + b\py[9]*3*(1-uu)^2*uu + b\py[10]*3*(1-uu)*uu*uu + b\py[11]*uu^3
		pz3#=b\pz[8]*(1-uu)^3 + b\pz[9]*3*(1-uu)^2*uu + b\pz[10]*3*(1-uu)*uu*uu + b\pz[11]*uu^3
		
		px4#=b\px[12]*(1-uu)^3 + b\px[13]*3*(1-uu)^2*uu + b\px[14]*3*(1-uu)*uu*uu + b\px[15]*uu^3
		py4#=b\py[12]*(1-uu)^3 + b\py[13]*3*(1-uu)^2*uu + b\py[14]*3*(1-uu)*uu*uu + b\py[15]*uu^3
		pz4#=b\pz[12]*(1-uu)^3 + b\pz[13]*3*(1-uu)^2*uu + b\pz[14]*3*(1-uu)*uu*uu + b\pz[15]*uu^3
		
		vv#=v
		
		x1# = px1*(1-vv)^3 + 3*px2*(1-vv)^2*vv + 3*px3*(1-vv)*vv*vv + px4*vv^3
		y1# = py1*(1-vv)^3 + 3*py2*(1-vv)^2*vv + 3*py3*(1-vv)*vv*vv + py4*vv^3
		z1# = pz1*(1-vv)^3 + 3*pz2*(1-vv)^2*vv + 3*pz3*(1-vv)*vv*vv + pz4*vv^3
		
		uu#=u+usegstep
		
		px1#=b\px[0]*(1-uu)^3 + b\px[1]*3*(1-uu)^2*uu + b\px[2]*3*(1-uu)*uu*uu + b\px[3]*uu^3
		py1#=b\py[0]*(1-uu)^3 + b\py[1]*3*(1-uu)^2*uu + b\py[2]*3*(1-uu)*uu*uu + b\py[3]*uu^3
		pz1#=b\pz[0]*(1-uu)^3 + b\pz[1]*3*(1-uu)^2*uu + b\pz[2]*3*(1-uu)*uu*uu + b\pz[3]*uu^3
		
		px2#=b\px[4]*(1-uu)^3 + b\px[5]*3*(1-uu)^2*uu + b\px[6]*3*(1-uu)*uu*uu + b\px[7]*uu^3
		py2#=b\py[4]*(1-uu)^3 + b\py[5]*3*(1-uu)^2*uu + b\py[6]*3*(1-uu)*uu*uu + b\py[7]*uu^3
		pz2#=b\pz[4]*(1-uu)^3 + b\pz[5]*3*(1-uu)^2*uu + b\pz[6]*3*(1-uu)*uu*uu + b\pz[7]*uu^3
		
		px3#=b\px[8]*(1-uu)^3 + b\px[9]*3*(1-uu)^2*uu + b\px[10]*3*(1-uu)*uu*uu + b\px[11]*uu^3
		py3#=b\py[8]*(1-uu)^3 + b\py[9]*3*(1-uu)^2*uu + b\py[10]*3*(1-uu)*uu*uu + b\py[11]*uu^3
		pz3#=b\pz[8]*(1-uu)^3 + b\pz[9]*3*(1-uu)^2*uu + b\pz[10]*3*(1-uu)*uu*uu + b\pz[11]*uu^3
		
		px4#=b\px[12]*(1-uu)^3 + b\px[13]*3*(1-uu)^2*uu + b\px[14]*3*(1-uu)*uu*uu + b\px[15]*uu^3
		py4#=b\py[12]*(1-uu)^3 + b\py[13]*3*(1-uu)^2*uu + b\py[14]*3*(1-uu)*uu*uu + b\py[15]*uu^3
		pz4#=b\pz[12]*(1-uu)^3 + b\pz[13]*3*(1-uu)^2*uu + b\pz[14]*3*(1-uu)*uu*uu + b\pz[15]*uu^3
		
		vv#=v
		
		x2# = px1*(1-vv)^3 + 3*px2*(1-vv)^2*vv + 3*px3*(1-vv)*vv*vv + px4*vv^3
		y2# = py1*(1-vv)^3 + 3*py2*(1-vv)^2*vv + 3*py3*(1-vv)*vv*vv + py4*vv^3
		z2# = pz1*(1-vv)^3 + 3*pz2*(1-vv)^2*vv + 3*pz3*(1-vv)*vv*vv + pz4*vv^3
		
		uu#=u
		
		px1#=b\px[0]*(1-uu)^3 + b\px[1]*3*(1-uu)^2*uu + b\px[2]*3*(1-uu)*uu*uu + b\px[3]*uu^3
		py1#=b\py[0]*(1-uu)^3 + b\py[1]*3*(1-uu)^2*uu + b\py[2]*3*(1-uu)*uu*uu + b\py[3]*uu^3
		pz1#=b\pz[0]*(1-uu)^3 + b\pz[1]*3*(1-uu)^2*uu + b\pz[2]*3*(1-uu)*uu*uu + b\pz[3]*uu^3
		
		px2#=b\px[4]*(1-uu)^3 + b\px[5]*3*(1-uu)^2*uu + b\px[6]*3*(1-uu)*uu*uu + b\px[7]*uu^3
		py2#=b\py[4]*(1-uu)^3 + b\py[5]*3*(1-uu)^2*uu + b\py[6]*3*(1-uu)*uu*uu + b\py[7]*uu^3
		pz2#=b\pz[4]*(1-uu)^3 + b\pz[5]*3*(1-uu)^2*uu + b\pz[6]*3*(1-uu)*uu*uu + b\pz[7]*uu^3
		
		px3#=b\px[8]*(1-uu)^3 + b\px[9]*3*(1-uu)^2*uu + b\px[10]*3*(1-uu)*uu*uu + b\px[11]*uu^3
		py3#=b\py[8]*(1-uu)^3 + b\py[9]*3*(1-uu)^2*uu + b\py[10]*3*(1-uu)*uu*uu + b\py[11]*uu^3
		pz3#=b\pz[8]*(1-uu)^3 + b\pz[9]*3*(1-uu)^2*uu + b\pz[10]*3*(1-uu)*uu*uu + b\pz[11]*uu^3
		
		px4#=b\px[12]*(1-uu)^3 + b\px[13]*3*(1-uu)^2*uu + b\px[14]*3*(1-uu)*uu*uu + b\px[15]*uu^3
		py4#=b\py[12]*(1-uu)^3 + b\py[13]*3*(1-uu)^2*uu + b\py[14]*3*(1-uu)*uu*uu + b\py[15]*uu^3
		pz4#=b\pz[12]*(1-uu)^3 + b\pz[13]*3*(1-uu)^2*uu + b\pz[14]*3*(1-uu)*uu*uu + b\pz[15]*uu^3
		
		vv#=v+vsegstep
		
		x3# = px1*(1-vv)^3 + 3*px2*(1-vv)^2*vv + 3*px3*(1-vv)*vv*vv + px4*vv^3
		y3# = py1*(1-vv)^3 + 3*py2*(1-vv)^2*vv + 3*py3*(1-vv)*vv*vv + py4*vv^3
		z3# = pz1*(1-vv)^3 + 3*pz2*(1-vv)^2*vv + 3*pz3*(1-vv)*vv*vv + pz4*vv^3
		
		uu#=u+usegstep
		
		px1#=b\px[0]*(1-uu)^3 + b\px[1]*3*(1-uu)^2*uu + b\px[2]*3*(1-uu)*uu*uu + b\px[3]*uu^3
		py1#=b\py[0]*(1-uu)^3 + b\py[1]*3*(1-uu)^2*uu + b\py[2]*3*(1-uu)*uu*uu + b\py[3]*uu^3
		pz1#=b\pz[0]*(1-uu)^3 + b\pz[1]*3*(1-uu)^2*uu + b\pz[2]*3*(1-uu)*uu*uu + b\pz[3]*uu^3
		
		px2#=b\px[4]*(1-uu)^3 + b\px[5]*3*(1-uu)^2*uu + b\px[6]*3*(1-uu)*uu*uu + b\px[7]*uu^3
		py2#=b\py[4]*(1-uu)^3 + b\py[5]*3*(1-uu)^2*uu + b\py[6]*3*(1-uu)*uu*uu + b\py[7]*uu^3
		pz2#=b\pz[4]*(1-uu)^3 + b\pz[5]*3*(1-uu)^2*uu + b\pz[6]*3*(1-uu)*uu*uu + b\pz[7]*uu^3
		
		px3#=b\px[8]*(1-uu)^3 + b\px[9]*3*(1-uu)^2*uu + b\px[10]*3*(1-uu)*uu*uu + b\px[11]*uu^3
		py3#=b\py[8]*(1-uu)^3 + b\py[9]*3*(1-uu)^2*uu + b\py[10]*3*(1-uu)*uu*uu + b\py[11]*uu^3
		pz3#=b\pz[8]*(1-uu)^3 + b\pz[9]*3*(1-uu)^2*uu + b\pz[10]*3*(1-uu)*uu*uu + b\pz[11]*uu^3
		
		px4#=b\px[12]*(1-uu)^3 + b\px[13]*3*(1-uu)^2*uu + b\px[14]*3*(1-uu)*uu*uu + b\px[15]*uu^3
		py4#=b\py[12]*(1-uu)^3 + b\py[13]*3*(1-uu)^2*uu + b\py[14]*3*(1-uu)*uu*uu + b\py[15]*uu^3
		pz4#=b\pz[12]*(1-uu)^3 + b\pz[13]*3*(1-uu)^2*uu + b\pz[14]*3*(1-uu)*uu*uu + b\pz[15]*uu^3
		
		vv#=v+vsegstep
		
		x4# = px1*(1-vv)^3 + 3*px2*(1-vv)^2*vv + 3*px3*(1-vv)*vv*vv + px4*vv^3
		y4# = py1*(1-vv)^3 + 3*py2*(1-vv)^2*vv + 3*py3*(1-vv)*vv*vv + py4*vv^3
		z4# = pz1*(1-vv)^3 + 3*pz2*(1-vv)^2*vv + 3*pz3*(1-vv)*vv*vv + pz4*vv^3
		
		
		vert=AddVertex(surf,x1,y1,z1,u,v)
		     AddVertex(surf,x2,y2,z2,u+usegstep,v)
		     AddVertex(surf,x3,y3,z3,u,v+vsegstep)
		     AddVertex(surf,x4,y4,z4,u+usegstep,v+vsegstep)
		
			AddTriangle surf,vert+0,vert+3,vert+1
			AddTriangle surf,vert+0,vert+2,vert+3
		
		u=u+usegstep

	Wend

	v=v+vsegstep

Wend

UpdateNormals mesh

Return mesh
End Function

Function BezierPatchDraw(b.bezierpatch,cam,selectedpoint)

Local projx[15],projy[15]

For n=0 To 15
	
	CameraProject cam,b\px[n],b\py[n],b\pz[n]
	
	projx[n]=ProjectedX()
	projy[n]=ProjectedY()
	
	If selectedpoint=n
	
		Color 255,255,0
	
	Else
	
		Color 0,0,255
	
	EndIf
	
	Oval projx[n]-5,projy[n]-5,10,10,True
	
	
Next

Color 0,255,0

For u=0 To 3
	
	For v=0 To 3
		If u<3
		Line projx[u+v*4],projy[u+v*4],projx[u+v*4+1],projy[u+v*4+1]
		EndIf
		If v<3
		Line projx[u+v*4],projy[u+v*4],projx[u+v*4+4],projy[u+v*4+4]
		EndIf
		
	Next
	
Next

End Function

Function CameraInit(r=0,g=0,b=0,x#=12,y#=10,z#=12,px#=0,py#=0,pz#=0)

	camera=CreateCamera()
	CameraClsColor camera,r,g,b
	PositionEntity camera,x,y,z
	p=CreatePivot()
	PositionEntity p,px,py,pz
	PointEntity camera,p
	FreeEntity p
	MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
	camerarx=EntityPitch(camera)
	camerary=EntityYaw(camera)
		
End Function

Function CameraClear()

	If camera<>0 Then FreeEntity camera	: camera=0
	
End Function

Function CameraUpdate(speed#=1)

		
	If MouseHit(2)
	
	MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
		
	EndIf
	
	If MouseDown(2)

		camerarx#=camerarx#+MouseYSpeed()*0.5
		camerary#=camerary#-MouseXSpeed()*0.5
		If camerarx#>89
			camerarx#=89
		ElseIf camerarx#<-89
			camerarx#=-89
		EndIf
		RotateEntity camera,camerarx,camerary,0
		MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
		
	EndIf
	
	If KeyDown(200) Or KeyDown(17) Then MoveEntity camera,0,0,speed#
	If KeyDown(208) Or KeyDown(31) Then MoveEntity camera,0,0,-speed#
	If KeyDown(203) Or KeyDown(30) Then MoveEntity camera,-speed#,0,0
	If KeyDown(205) Or KeyDown(32) Then MoveEntity camera,speed#,0,0
	
End Function

Comments

BlitzSupport2005
Very cool indeed -- only thing is you have to run windowed as there's no pointer in full-screen mode! The resulting meshes look great though.


Jeppe Nielsen2005
Yes I forgot to include a pointer as I was creating this in windowed mode :-)

I have updated the code now.


Barliesque2005
Looking forward to seeing this when I get home to my own computer... for now, I'm wondering if this might be a basis for supporting models from Hash Animation:Master--which is patch-based.


WarpZone2005
Wow. This is great. This explains all those terrain programs that suddenly appeared simultaneously. =) Now if only I UNDERSTOOD enough of what was going on here to make it *scalable.*


Code Archives Forum