Catmull-Rom code

Blitz3D Forums/Blitz3D Programming/Catmull-Rom code

Axel Wheeler(Posted 2011) [#1]
Here's my Catmull-Rom code.

Use it to produce interpolated values better (but slower) than cosine interpolation does.

It has the following three functions.

catmullrom#(v0#,v1#,v2#,v3#,x#)

You need five values: v0-3 and x. You are looking for a value somewhere between v1 and v2. How far between? x far between. x is a value 0-1 representing that distance. The function will return an interpolated value at that point (you can think of it as v1.x).

Why do you need v0 and v3? They affect the slope of the curve at v1 and v2, which affects your result. That's the idea behind Catmull-Rom and what makes it better than cosine.

catmullrom3d#(v00#,v01#,v02#,v03#,v10#,v11#,v12#,v13#,v20#,v21#,v22#,v23#,v30#,v31#,v32#,v33#,xdist#,zdist#)

Ok, this is daunting but bear with me. If you need a smoothly curving surface (a terrain, for example), you can feed this function all 16 values (4x4) around a given location, and also the distance across the middle square your point is (in both directions). It will give you back the interpolated value at that point. Think smoothly sloping hills from random points.


crterrainy#(terrainname,x#,z#)

Let's say you have an actual blitz terrain. Why put all that effort into identifying all 16 points when you can just feed this function the terrain name and the two points and let it figure it out. I haven't tested this in awhile; the terrain may need to be at 0,0 for this to work.

Function crterrainy#(terrainname,x#,z#)
	Local lx=Floor(x#)
	Local lz=Floor(z#)
	
	Local x0=lx-1:If x0<0 Then x0=0
	Local x1=lx
	Local x2=lx+1
	Local x3=lx+2:If x3>TerrainSize(terrainname)-1 Then x3=x2
	
	Local z0=lz-1:If z0<0 Then z0=0
	Local z1=lz
	Local z2=lz+1
	Local z3=lz+2:If z3>TerrainSize(terrainname)-1 Then z3=z2
	
	Local v00#=TerrainY(terrainname,x0,1,z0)
	Local v01#=TerrainY(terrainname,x1,1,z0)
	Local v02#=TerrainY(terrainname,x2,1,z0)
	Local v03#=TerrainY(terrainname,x3,1,z0)
	
	Local v10#=TerrainY(terrainname,x0,1,z1)
	Local v11#=TerrainY(terrainname,x1,1,z1)
	Local v12#=TerrainY(terrainname,x2,1,z1)
	Local v13#=TerrainY(terrainname,x3,1,z1)
	
	Local v20#=TerrainY(terrainname,x0,1,z2)
	Local v21#=TerrainY(terrainname,x1,1,z2)
	Local v22#=TerrainY(terrainname,x2,1,z2)
	Local v23#=TerrainY(terrainname,x3,1,z2)
	
	Local v30#=TerrainY(terrainname,x0,1,z3)
	Local v31#=TerrainY(terrainname,x1,1,z3)
	Local v32#=TerrainY(terrainname,x2,1,z3)
	Local v33#=TerrainY(terrainname,x3,1,z3)
	
	Local xdist#=x#-lx
	Local zdist#=z#-lz
	
	Local result#=catmullrom3d(v00#,v01#,v02#,v03#,v10#,v11#,v12#,v13#,v20#,v21#,v22#,v23#,v30#,v31#,v32#,v33#,xdist#,zdist#)
	
	Return(result)
	
End Function

Function catmullrom3d#(v00#,v01#,v02#,v03#,v10#,v11#,v12#,v13#,v20#,v21#,v22#,v23#,v30#,v31#,v32#,v33#,xdist#,zdist#)
	;This function calculates the Catmull-Rom interpolated height given the heights of the 16 surrounding vertexes and the x and z distances across the center square.  You're welcome.
	fv0#=catmullrom(v00#,v01#,v02#,v03#,xdist#)
	fv1#=catmullrom(v10#,v11#,v12#,v13#,xdist#)
	fv2#=catmullrom(v20#,v21#,v22#,v23#,xdist#)
	fv3#=catmullrom(v30#,v31#,v32#,v33#,xdist#)
	newvalue#=catmullrom(fv0#,fv1#,fv2#,fv3#,zdist#)
	Return newvalue#
End Function

Function catmullrom#(v0#,v1#,v2#,v3#,x#)
	v0#=0.5*(v2#-v0#)
	v3#=0.5*(v3#-v1#)
	
	;The above two lines apparently convert from regular Hermite interpolation (which isn't generally useful) to Catmull-Rom (which is).
	
	p#=2.0*(x^3.0)-3.0*(x^2.0) + 1.0
	q#=-2.0*(x^3.0)+3.0*(x^2.0)
	r#=x^3.0-2.0*(x^2.0)+x
	s#=x^3.0-x^2.0
	Return p*v1+q*v2+r*v0+s*v3
End Function



Edit: The code in catmullrom() was extracted from some c code in an article on Catmull-Rom that I can't find now. If I do I'll post a link.

Last edited 2011