Code archives/Miscellaneous/Render Tweening

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

Download source code

Render Tweening by John Blackledge2005
I just got my head around Render Tweening!
- at least enough to know what I've been doing wrong, and how I should really be using it.
And many thanks to all the Blitzers who replied to my cries for help, but especially to those who effectively smacked me around the head and said "Mark's code works! - Check YOURS!"
So I felt it was time to pay some back, and write a little tutorial.

Ignoring the external functions for the moment (which is why I wrote them as separate) there are two areas that need to be looked at:

1) UPDATEWORLD:
What I didn't realise (despite all explanations) was that this is the work horse of tweening code and yet another example of Mark Sibly's brilliance.
Suppose that I have created a little man whose movement frames are such that at 'Const FPS = 30' he will walk at a normal pace across the terrain. Suppose also that I have a dog-slow graphics card which (due to all the other clutter, village huts etc) is NEVER going to be actually able to render 30 frames per second to the screen.
Mark's code effectively says 'I know your graphics card may be slow, but at least I can recalculate, on the fly, how much to change the little man's animations so that at least (a) the leg movements happen at the correct speed, and (b) he travels from point 1 to point 2 as you designed'. In other words the correct speed of animation does NOT depend on how fast the final images are flung at the screen by the graphics card.

2) RENDERWORLD:
Of course all the frame counting code I was using was telling me that I was getting as low as 5 frames per second being rendered to the screen (the previously mentioned dog-slow graphics card) and I was saying 'Oh, no. My animation speeds are all over the place!'
NOT SO. Internally Mark's code was still keeping all animations smooth and predictable, based on 'Const FPS = 30'.
How fast the final images are flung at the screen is not Mark's problem, but the graphics card's problem.

So I wrote the demo code above using two different counters, the UpdateWorldCounter to confirm that Mark's tweening style DOES work as designed, and then the RenderWorldCounter(s) to show me how often my graphics card is actually updating the screen.
Sounds obvious when written down, but for a long time I was confusing the two concepts.

SOME FINAL THOUGHTS:

[1] A Big Mistake:
Someone suggested that the variable 'ticks' might sometimes be zero, and that this would be a bad idea.
So I added:

If ticks<1 Then ticks = 1

before

For k=1 To ticks

Do NOT do this! I think that this was the reason for my characters 'speed-walking' every so often.
As soon as I removed it the problem went away. I guess it's a case of 'trust Mark's code'.

[2] Other Methods:
There are other methods of timing, notably Delta Timing (search in the forums for 'Tweening' or 'Delta') which may give a higher fps for Quake style games, but my understanding is that the above tweening method produces the kind of 'sublety' that I need for my slow walking animations, i.e. a village full of people and huts seen at very close quarters, and individual characters who talk to the camera.

[3] Improving Speed (1):
Several people have suggested that care should be taken to keep the number of entities visible to a minimum.
In the case of furniture and houses (where you don't need to access separate child parts) the best way to do this is to merge (in your modeller) all the parts of an entity into one, as the final production model.
And even, if possible, to merge all of THOSE entities into one final entity, which is your 'level'.
It's my belief that this is why 'Morrowind' is so fast - the opening village is literally one entity - all the houses are really only external shells, and are merged with the terrain as one model.

[4] Improving Speed (2):
A nice tip I was given was the following:
After UpdateWorld() do:

For z = 1 To nNumObjs
ShowEntity obj(z)\hobj
Next

and just before RenderWorld tween# do:

For z = 1 To nNumObjs
If Not EntityInView(obj(z)\hobj, camera) Then HideEntity obj(z)\hobj
Next
RenderWorld frameTween#

This DOES add quite a few frames to the final fps being rendered to the screen.

[5] Improving Speed (3):
If (like me) you want a huge terrain with many villages and people, then the ONLY way you are going to achieve this is by making different areas HIDE or SHOW when needed, otherwise the system just start to grind to a halt after you've added village number two.
This was obviously quite a gut-wrenching rewrite to a system that I had been working on for nearly a year, but the difference it made was phenomenal. I had almost given up on the project, and suddenly it became viable again.
There's no easy way to describe such a system (or give a code example) but if I just say that the essence is to keep a list of named rectangles

[Areas]
1=Village1
2=Village2


then other lists for objects and people, each of which contains a reference to an area which it it is linked to.

[Man1]
type = man.b3d
pos = 100,10,100
area = Village1


Then write a piece of code which detects the camera movement into and out of different areas, and run down your list of people and objects showing and hiding entities as appropriate.
At first I thought that I'd end up with that horrible Morrowind-style message 'Loading area' with a blank screen for 5 seconds, but in actual fact Blitz can SHOW or HIDE a hundred entities literally in the blink of an eye, and the effect is virtually unnoticeable, Yay, Blitz!

[6] Improving Speed (4):
Change the VWAIT command to:

VWait
Flip False

This change is still open to discussion and you should search the forums for 'Vwait' to read different people's opinions.

FINALLY:
Once again thanks to all the people who reacted to my cries for help, and helped out by providing fps counter code, HIDE and SHOW advice etc .
Thanks to you all. This really is a GREAT community.

Cheers,
John
;--------------------------------------------
; TweenTest.bb
; John Blackledge 20/9/03
; john@tla-data.co.uk
;--------------------------------------------

; --- Set Graphics mode, create a camera, create a light.
Graphics3D 800,600,0,2
camera = CreateCamera()
PositionEntity camera,0,0,-15
light = CreateLight()
PositionEntity light,20,20,40

; --- Set the Tweening/timer constants and initial variables.
Const FPS=30
period=1000/FPS
time=MilliSecs()-period

; --- Create an big entity of 1000 spheres parented to a piv.
piv=CreatePivot()
PositionEntity piv,0,0,0
For cnt = 1 To 1000
	cube = CreateSphere(16,piv)
	PositionEntity cube,Float(Rnd(-5,+5)),Float(Rnd(-5,+5)),Float(Rnd(-5,+5)),False
	EntityColor cube,Rnd(0,255),Rnd(0,255),Rnd(0,255)
Next

; --- The main loop start - based on Mark's Castle Demo code..
While Not KeyHit(1)
	Repeat
		elapsed=MilliSecs()-time
	Until elapsed
	ticks=elapsed/period	;how many 'frames' have elapsed	
	tween#=Float(elapsed Mod period)/Float(period)	;fractional remainder
	For k=1 To ticks
		time=time+period
		If k=ticks Then CaptureWorld

		; --- Rotate our big spheres entity.
		; --- This will stress the system, especially windowed.
		TurnEntity piv,1,2,3
		; ----------------------------------------

		UpdateWorld

		; --- Count the internal updates per second.
		; --- This will show what sort of progress is actually happening as regards
		; --- the updating of animated figures, water lapping etc?
		UpdateWorldCounter()
		; ----------------------------------------

	Next
	RenderWorld tween#

	; --- Count the number of updates per second being sent to the screen.
	; --- This is actually what people are referring to 
	; --- when they talk about frames per second.
	RenderWorldCounter1()
	RenderWorldCounter2()
	CounterDisplay()
	; ----------------------------------------

	Flip
Wend
End

; --- I've kept the counters and displays as external functions
; --- (rather than embedded in the code) so as to simplify the
; --- reading of both areas.
Global UWcurTime,UWcheckTime,UWcurFPS,UWcounter
Function UpdateWorldCounter()
	UWcurTime = MilliSecs()
	If UWcurTime => UWcheckTime Then
		UWcheckTime = UWcurTime + 1000
		UWcurFPS = UWcounter
		UWcounter = 0
	Else
		UWcounter = UWcounter + 1
	End If
End Function

Global RW1curTime,RW1checkTime,RW1curFPS,RW1fpscounter
Function RenderWorldCounter1()
	RW1curTime = MilliSecs()
	If RW1curTime > RW1checkTime Then
		RW1checkTime = RW1curTime + 1000
		RW1curFPS = RW1fpscounter
		RW1fpscounter = 0
	Else
		RW1fpscounter = RW1fpscounter + 1
	End If
End Function

Global RW2counter,RW2time,RW2framerate
; --- This is a different fps counter that I came across
; --- so I thought I'd add it in as a contrast.
Function RenderWorldCounter2()
	RW2counter = RW2counter+1
	If RW2time=0 Then RW2time=MilliSecs()
	If RW2time+1001 < MilliSecs()
		RW2framerate = RW2counter
		RW2counter=0
		RW2time=MilliSecs()
	EndIf
End Function

Function CounterDisplay()
	Color 0,0,0
	Rect 0,0,300,100,1
	Color 255,255,255
	Text 0, 0,"Const FPS " + FPS + " "
	Text 0,20,"UpdateWorld() / sec " + UWcurFPS + " "
	Text 0,40,"RenderWorld() / sec 1st method " + RW1curFPS + " "
	Text 0,60,"RenderWorld() / sec 2nd method "+RW2framerate
End Function

Comments

Plantagenet2005
Top notch John, thanks a lot :)


John Blackledge2005
Cheers.
There has been a bit a discussion (pros and cons) about this method on another thread.
For me the important thing was to get my head around the the whole method that some people are so off-hand about.
Personally, this sort of code gives me a headache.

If it can be improved, or better described, then feel free to do it, and we'll re-upload it.


puki2007
"Vorderman" had problems with RenderTweening with his Blitz Rally project. He and "Eurhythmy" were discussing it.

"Vorderman" had been using "James Boyd's" interpretation of RenderTweening: http://www.blitzbasic.com/codearcs/codearcs.php?code=9

"Eurhythmy" had advised "Vorderman" to use the RenderTweening as per the castle demo. Anyway, it is all contained in here: http://www.blitzmax.com/Community/posts.php?topic=44275


Sanosake12009
Hey, if you add or subtract the from "Constant FPS" , will it effectively make EVERY THING faster or slower?


John Blackledge2009
No. The FPS constant merely says "We're aiming for this many frames per second, if the system can do it." But the overall speed of an animation (the hypothetical little man walking) will be constant.

When I started with Blitz3D 30 was a respectable framerate.


Mikorians2014
Hm. My renderworld is faster than my updateworld.


Species2015
wouldnt it be easier just using the castle demo that came with blitz? Just remove all the functions and entities and junk and tweening is in its raw basic form.


Code Archives Forum