real time wall mirror

Blitz3D Forums/Blitz3D Programming/real time wall mirror

Midimaster(Posted 2009) [#1]
I searched for a real time wall mirror, but I only found terrible pseudo code, which was not working correct.

Now I started to build a "wall mirror class" project, which will enable everybody a free to position, free rotation mirror, which is able to mirror all scenes, including free moving camera aspects.

this is a first code, which is correct as long as the mirror in standing vertical on the floor.



(all textures and object in this image are code based and help only to understand the method. in nice rooms the mirror shows nice mirror image)

this is the code:

; Definitionin of the mirror
Global Mirror
Global MirrorCamera
Global MirrorTexture
Global MirrorPlan






; this part constructs only a simple virtual room for the demo 

	Graphics3D 1024,768,32,2
	
	AntiAlias 1
	
	; Licht
		AmbientLight 111,111,111
		Licht= CreateLight(1)
		MoveEntity licht, -5,10,10  
		RotateEntity licht, 45,45,0
		LightColor Licht, 255,222,222
		Licht2= CreateLight(1)
		MoveEntity licht2, 5,10,10  
		RotateEntity licht2, 45,-45,0
		LightColor Licht2, 222,222,252
		
		
		licht3=CreateLight(3)
		LightRange licht3,1090
		RotateEntity licht3,270,270,0
		MoveEntity licht3,-2,-2,-4
	
	;Camera
		Global Camera=CreateCamera()
		kommode=CreatePivot()
		SeedRnd MilliSecs()
		MaterialBreite#=0.02
		MoveEntity kommode, 0,0,0
		PositionEntity Camera, -2,1,-5
		RotateEntity Camera, 0,0,0
		CameraViewport Camera,20,20,620,620
		
	
	
	; Der Raum
		Raum=CreateCube()
		FlipMesh raum
		EntityColor Raum,115,82,42
		MoveEntity raum, 1,2.82,-4.47
		ScaleEntity raum,6,4,5
	
	
	; Die Kommode
		Dim Wand(99)
		Dim Fuss(99)
		Dim Schub(99)
		
		TexName$="holz.png"
		Holz=LoadTexture(TexName)
		If holz=0 Then
			Holz=CreateTexture(256,256,0)
			SetBuffer TextureBuffer(holz)
			Color 102,61,4
			Rect 0,0,256,256
			Color 112,71,24
			For i=0 To 1000
				Oval Rand(0,255),Rand(0,255),2,50
			Next 
			SetBuffer BackBuffer()
			
		EndIf
		RotateTexture Holz, 90
		
		ScaleTexture  Holz,1,0.3
		; linke wand
		Wand(0)=CreateCube (Kommode)
		ScaleEntity wand(0),MaterialBreite,1,0.5
		MoveEntity wand(0), -1.5,0,0
		EntityColor Wand(0),211,211,211
		EntityTexture Wand(0),Holz
		
		; rechte wand
		Wand(1)=CreateCube (Kommode)
		ScaleEntity wand(1),MaterialBreite,1,0.5
		MoveEntity wand(1), 1.5,0,0
		EntityColor Wand(1),191,191,191
		EntityTexture Wand(1),Holz
		
		; oben
		Wand(2)=CreateCube (Kommode)
		ScaleEntity wand(2),1.6,2*MaterialBreite,0.55
		MoveEntity wand(2), 0,1,-0.05
		EntityTexture Wand(2),Holz
		
		
		; unten
		Wand(3)=CreateCube (Kommode)
		ScaleEntity wand(3),1.55,MaterialBreite,0.51
		MoveEntity wand(3), 0,-1,0
		;EntityColor Wand(3),Rand(100,255),Rand(100,255),Rand(100,255)
		EntityColor Wand(3),111,111,111
		EntityTexture Wand(3),Holz
		
		
		; hinten
		Wand(4)=CreateCube (Kommode)
		ScaleEntity wand(4),1.50,0.97,MaterialBreite
		MoveEntity wand(4), 0,0,0.5
		;EntityColor Wand(3),Rand(100,255),Rand(100,255),Rand(100,255)
		EntityColor Wand(4),11,11,11
		;EntityTexture Wand(3),Holz
		
		
		
		; fuss
		fuss(0)=CreateSphere (8,Kommode)
		ScaleEntity fuss(0),0.1,0.1,0.1
		MoveEntity fuss(0), -1.4,-1.1,-0.4
		EntityColor fuss(0),48,33,24
		Fuss(1)=CopyEntity(Fuss(0),Kommode)
		MoveEntity fuss(1), +2.8,0,0
		Fuss(2)=CopyEntity(Fuss(0),Kommode)
		MoveEntity fuss(2), 0,0,0.8
		Fuss(3)=CopyEntity(Fuss(0),Kommode)
		MoveEntity fuss(3), +2.8,0,0.8
		
		; Schublade
		;holz=LoadTexture(TexName)
		ScaleTexture  holz,1,0.4
		RotateTexture holz, 90
		Schub(0)=CreatePivot(Kommode)
		MoveEntity Schub(0),-0.76,0.625,-0.55
		;
		SchubZier=CreateCube(Schub(0))
		ScaleEntity SchubZier,0.75,0.3,MaterialBreite
		MoveEntity SchubZier, 0,0,0
		EntityTexture SchubZier,holz
		;EntityColor SchubZier,Rand(100,255),Rand(100,255),Rand(100,255)
		;
		SchubKnopf=CreateCylinder(16,True,Schub(0))
		ScaleEntity SchubKnopf, 0.1,0.03,0.02
		MoveEntity SchubKnopf,0,0,-0.1
		TurnEntity SchubKnopf,90,0,0
		EntityColor SchubKnopf,155,155,155
		EntityColor SchubKnopf,48,33,24
		EntityShininess SchubKnopf,1
		;
		SchubWangeL=CreateCube(Schub(0))
		ScaleEntity SchubWangeL,MaterialBreite,0.25,0.5
		MoveEntity SchubWangeL, -0.65,0,0.5
		EntityColor SchubWangeL,211,211,211
		EntityTexture SchubWangeL,holz
		
		;
		;HideEntity SchubWangel
		SchubWangeR=CopyEntity (Schubwangel,Schub(0))
		MoveEntity SchubWangeR, 1.3,0,0
		EntityColor SchubWangeR,169,169,188
		;
		SchubBoden=CreateCube(Schub(0))
		ScaleEntity SchubBoden,0.65,MaterialBreite,0.5
		MoveEntity SchubBoden, 0,-0.25,0.5
		EntityColor SchubBoden,151,151,151
		EntityTexture SchubBoden,holz
		
		;
		SchubRueck=CreateCube(Schub(0))
		ScaleEntity SchubRueck,0.65,0.25,MaterialBreite
		MoveEntity SchubRueck, 0,0,1
		EntityColor SchubRueck,111,111,91
		EntityTexture SchubRueck,holz
		
		
		For I=1 To 6
			;EntityColor SchubZier,Rand(100,255),Rand(100,255),Rand(100,255)
			Schub(i)=CopyEntity (Schub(0),Kommode)
		Next
		MoveEntity Schub(1),1.52,0,0
		MoveEntity Schub(2),0,-0.63,0
		MoveEntity Schub(3),1.52,-0.63,0
		MoveEntity Schub(4),0,-1.26,0
		MoveEntity Schub(5),1.52,-1.26,0
		;Kommode2=CopyEntity(Kommode)
		;MoveEntity kommode2,4,0,-2
		 
	
	; restliches Mobiliar
		Wuerfel=CreateCube()
		ScaleEntity wuerfel,0.5,1,0.5
		MoveEntity wuerfel, 0,-1,-4
		EntityColor wuerfel, 0,0,55
		
		Lampe=CreateSphere(8)
		;ScaleEntity Lampe, 0.5,0.5,0.5
		MoveEntity Lampe, 0,4,-2
		EntityColor lampe,55,213,222
		
		Saeule=CreateCylinder(8,0)
		ScaleEntity Saeule,0.5,5,0.5
		EntityColor Saeule, 111,111,111
		MoveEntity Saeule, -4,2,0
		EntityShininess Saeule,1
		
		
		Teppich=CreateCube()
		ScaleEntity Teppich, 8,0.001,8
		MoveEntity teppich, 3,-1.15,-6
		EntityColor teppich, 55,0,0
		r=1
		X=100
		
		Dim Regal(9)
		Regal(0)=CreateCube()
		ScaleEntity regal(0) ,0.5,0.05,2
		EntityColor Regal(0), 111,211,111
		MoveEntity Regal(0),6.6,0,-4
		EntityShininess Regal(0),1
		For i= 1 To 4
			Regal(i)=CopyEntity(Regal(0))
			MoveEntity regal(i),0,i*0.5,0
		Next


; Spiegel Init !!!!!!!!!!!!!!!!

		InitMirror


; Main Loop

Repeat
		PointEntity camera, wand(2)
		ScaleEntity Kommode, 1,1,1

		RenderMirror Camera, MirrorCamera
		UpdateWorld
		RenderWorld


		Color 202,161,114
	
		Text 700,400,"W A L L   M I R R O R    D E M O "
		
		Text 700,460,"<E> and <R> to rotate Mirror"
		Text 700,490,"<+> and <-> to up/down camera"
		Text 700,520,"<curosr keys>  to move camera"
		Text 700,580,"<ESC>  to Quit"
		Text 100,680,"(C)   M I D I M A S T E R   M U S I C   E D U C A T I O N   S O F T W A R E   www.midimaster.de "
		Flip
	
		; Schublade auf/zu
			If (x>100) And (r=1) Then
				r=-1.0
		
			Else If (x<0) Then
				r=1
			EndIf
			x=x+r
			MoveEntity schub(3),0,0,r*0.007
			;DebugLog x + " " + r


		;Steuerung
		a%=GetKey()
		If a>0 Then
				DebugLog "Key: " + a
		;		EndIf
				If a=31 Then
					MoveEntity camera,0.3,0,0
				EndIf
				If a=30 Then
					MoveEntity camera,-0.3,0,0
				EndIf
				If a=28 Then
					MoveEntity camera,0,0,0.3
				EndIf
				If a=29 Then
					MoveEntity camera,0,0,-0.3
				EndIf
				If a=45 Then
					MoveEntity camera,0,-0.3,0
				EndIf
				If a=43 Then
					MoveEntity camera,0,0.3,0
				EndIf
				If a=114 Then
					TurnEntity camera,0,3,0
				EndIf
				If a=108 Then
					TurnEntity camera,0,-3,0
				EndIf
				If a=101 Then
					TurnEntity mirror,0,-3,0
				EndIf
				If a=114 Then
					TurnEntity mirror,0,3,0
				EndIf
				
				If a=27 Then
					End
				EndIf
		EndIf
Forever







; Spiegel-Funktionen



Function InitMirror()

		mirror = CreatePivot()
		MirrorCamera = CreateCamera()
		;	ScaleEntity MirrorCamera, 0.02,0.02,0.02
		CameraViewport MirrorCamera,700,100,256,256

		PositionEntity mirror, 3,1,-1
		RotateEntity mirror,0,90,0

		; the glas plane:
		MirrorPlan=CreateCube(mirror)
		ScaleEntity mirrorPlan,1,1,0.0003
		MirrorTexture = CreateTexture(256,256,256)
		ScaleTexture MirrorTexture,1,1
		EntityFX mirrorPlan,9
		EntityTexture mirrorPlan,MirrorTexture		
		
		; only for the nice frame:
		SpiegelRahmen=CreateCube(mirror)
		ScaleEntity Spiegelrahmen,1.05,0.05,0.05
		MoveEntity SpiegelRahmen,0,1,0
		EntityColor SpiegelRahmen, 65,25,0
		
		SpiegelRahmen2=CopyEntity(SpiegelRahmen,mirror)
		MoveEntity SpiegelRahmen2,0,-2,0

		SpiegelRahmen3=CreateCube(mirror)
		ScaleEntity Spiegelrahmen3,0.05,2.0,0.05
		MoveEntity SpiegelRahmen3,1,-0.5,0
		EntityColor SpiegelRahmen3, 65,25,0
		
		SpiegelRahmen4=CopyEntity(SpiegelRahmen3,mirror)
		MoveEntity SpiegelRahmen4,-2,0,0

End Function




Function RenderMirror(Camera,MirrorCamera)

        ;switch camera
			CameraProjMode Camera,0
			CameraProjMode MirrorCamera,1
		   
		; mirror camera to the mirror
			PositionEntity MirrorCamera, EntityX(Mirror),EntityY(Mirror),EntityZ(Mirror)
			CameraZoom MirrorCamera,1.5
		    HideEntity Mirror
		
		; find out the angle between Original-camera und mirror
			; save old values
			Winkel_Y=EntityYaw(Camera)
			Winkel_X=EntityPitch(Camera)
			PointEntity Camera,MirrorCamera

		; D I E  F O R M E L :
		RotateEntity MirrorCamera, 360-2*EntityPitch(Mirror)+EntityPitch(Camera),180+2*EntityYaw(Mirror)-EntityYaw(Camera),0
		
		; photo from this to the MirrorPlan
			UpdateWorld
			RenderWorld
			; side inversion
			For i=1 To 256
				CopyRect 700+i,100,1,256,256-i,0,BackBuffer(),TextureBuffer(MirrorTexture)
			Next
		; adjust original camera back
		    ShowEntity Mirror
			RotateEntity Camera,Winkel_X,winkel_Y,0
			CameraProjMode Camera,1
			CameraProjMode MirrorCamera,0
End Function


done:

- free positioning in rooms changes mirror image correct
- turning of the mirror changes mirror image correct
- free camera position and orientation changes mirror image correct
- depending on this 3 factores, the mirror images folows the camera optical correct



to do:

- rolling of the mirror on his z-axis not implemented
- "reverse zoom effect" when approaching mirror not implemented
- no class at the moment


GfK(Posted 2009) [#2]
but I only found terrible pseudo code, which was not working correct
Pseudocode generally doesn't work at all. That's why its called pseudocode.


Midimaster(Posted 2009) [#3]
Yes....

...but i was not marked as pseudo code. The code was offered as a "how to code a wall mirror". This old code was terrible and should be replaced.

But don't let us talk about the old stuff! Did you test the new mirror?

I am not sure, that it is worth for the code archive...


Andy(Posted 2009) [#4]
Are you refering to this?

http://www.blitzbasic.com/codearcs/codearcs.php?code=1524


Midimaster(Posted 2009) [#5]
No, that a nice example...and it works!

But he has the same problems like me. A rotation at the z-axis produces errors. When you rotate the mirror like a steering wheel, the world inside should stand still.

I added this to his code to test it:

...
While Not KeyDown(1) 
     ...
     Text 10,50, mirror_distance#
     ;new added:
     TurnEntity mirror_object,0,0,0.3
     ;
     Flip 
Wend
....



_PJ_(Posted 2009) [#6]
Provided the mirror is flat, however you will still see effects of the CAMERA zoom dependant on where the mirror is located with respect to the camera.


OJay(Posted 2009) [#7]
whats the reason to not using simple cubemapping?


Midimaster(Posted 2009) [#8]
is it possible in cubemapping to render the mirror view correct to position and orientation of the camera with light situation?

i am not sure...
I thought with cubemapping you always render the same direction of the mirror-camera and use it all the time. when moving the original camera beside such a mirror. the image inside the mirror looks like a photo of the room, or?

this is what a algorithm has to do:

With a view in a mirror the direction of the "mirror camera" depents on the master camera angles to the mirror and interacts with the camera movement.

Can you show me a sample of a elemtar cubemapping code to test it?


I would be happy if a solution with cubemapping works better then my code.


OJay(Posted 2009) [#9]
search the code archives...it has been done a dozens times. reflection is the main purpose of cube mapping.

there're also samples in the manuals: http://blitzbasic.com/b3ddocs/command.php?name=SetCubeFace&ref=3d_cat


Midimaster(Posted 2009) [#10]
ok, I saw this sample, but I cannot test it, because in my Blitz3D there aren't these media objects. I remember i have seen them in an older version of Blitz3D....

I will test it, but I cannot believe that these fixed camera angles (90°,... etc) will interact with a moving main camera...

And the algorithm need 6x renderworld, which costs a lot of time.

Can somebody test for me, what happens if the teacup is standing still and the camera moves. Does the mirror image change? move? sizes?


Kryzon(Posted 2009) [#11]
I'm sure at least the demo version lets you play with the samples.


Andy(Posted 2009) [#12]
According to a poster on this entry in the archives, that code is faster than cube mapping.

http://www.blitzbasic.com/codearcs/codearcs.php?code=1524


OJay(Posted 2009) [#13]
I will test it, but I cannot believe that these fixed camera angles (90°,... etc) will interact with a moving main camera...



of course it does. if you look at the following line:
Position camera where the entity is - this is where we will be rendering views from for cubemap
PositionEntity camera,EntityX#(entity),EntityY#(entity),EntityZ#(entity)

u will see, that the render camera which is used to render the cubemap is positioned at the mirror position, which basically means the cubemap will show, what the mirror "sees". the cubemap texture shader will take care of the correct view matrix...

please stop moaning, and start trying. it works and has been done infinite times. this will be my last words on this topic.

thank you and good luck.


Midimaster(Posted 2009) [#14]
to OJay:

I don't want to moan. Sorry, but my english is not very good and sometimes I may use the wrong words, so it seems to sound agressiv. But this is not my intention. I want to discuss about mirror coding.

I try to find these media objects to test the demo, then try to enter this cubemapping mirror into my demo and compare, what happens.

What makes me wonder in your code above, is the aspect, that the mirror cam is positioned at the mirror, ok! But it has to turn depenting on the master cameras view.

Example Picture:
             Object "B"
Object          ooo
"A"
    oooo           
    oooo    
    oooo 
                 mirror
              / 
            /
          /
     []
         
camera


( is there a possibility to upload picture to blitzbasic forum?)

With cubemapping you will see the big object "A" in the mirror

in a real mirror you will see only object "B"


jfk EO-11110(Posted 2009) [#15]
I have to say, I also tried a mirror (on a wall) using cubemapping, and I found it relative fiddleworkish. I remember I had it partially working, but it wasn't exact science and most disturbing was the fact, that the mirror didn't have the same resolution as the rest of the world. It works kind of for water:


Other methods are: a seperate Render from the right angle and position, then texture the mirror with this render somehow - still the resolution problem.

When you watch Blitz's interal CreateMirror then you realize: it looks best when the geometry is simply dublicated and flipped - at the cost of additional geometry. Blitz's CreateMirror only works when there is nothing below it, because it "mirrors in both directions". This makes it hard to use and probably rather useless. Now, what you could do is: clone the parts that may become visible in the mirror an flip them along the mirrors axis. Then do an additional render only with these new parts, then put this render onto the main render, using some kind of mask process, so only the surface of the mirror will be painted by the additional render.
Probably your flipped new parts should contain a big black wall around the mirror, this would allow to DrawImage the mirror Render onto the main render.
This would also mean you have to duplicate the player mesh when he's within the view range of the mirror (or eg. inside a helper box) - not a big deal IMHO. If the flipped geometry is created dynamicly, or if you add it to the map, it doesn't make much diffrence, although the 2nd way may be easier.
But this kind of mirror probably isn't very useful in anything other than typical indoor enviroments, eg. bathroom with mirror...


Ross C(Posted 2009) [#16]
I'd go for the render from bounce angle from the camera. Your resolution will be a tid rubbish, but you can choose a smaller texture size the further away you get from the mirror.


_PJ_(Posted 2009) [#17]
For the resolution, a mirror's CameraZoom (FOV) is (unless the mirror is concave/convex) is only dependant on the distance. However the VIEWER's cameraZoom can affect the the mirror too, especially if the mirror object lies on the edges of the viewerer-camera's render.
The only applicable 'solution' to the effect of the viewer's camerazoom is to Limit the camera-Zoom of the mirror's render AND to ensure the Viewer's camera zoom is a constistent and ~90 degree FOV *

The Mirror-Render-Camera also needs to be rotated an equivalent amount to the angles of incidence (difference between the mirror object angles and the viewer camera's angles) across the dimensions of the Mirror Object, and CameraZoom widened or shortened to match the distance of the viewer from the mirror object.

Although at extreme camera-zoom / FOV angles the render can appear distorted, these distortions should remain at the boundaries of the mirror object and OUTSIDE the viewer camera's render of the mirror object when the viewer-camera is close enough to the mirror so that edges of the mirror object are not seen.

For example, stand close to a mirror from the side, and what you can see is only a very thin slice of reflection, however the reflection would be of the farside of the room away from you. Standing face on, you would see yourself and what's behind you. The previously reflected far sides of the room to the left and right (and of course, whatever is BEHIND the mirror) would now be beyond the mirror's reflection.


BlitzSupport(Posted 2009) [#18]
Here's something I did -- yikes! -- 7 years ago:

http://www.sendspace.com/file/393319

It's far from perfect (problems at extreme angles, such as Malice mentions), but something else to play with.

(Apologies for using SendSpace, as I can't access my FTP at present.)


MikhailV(Posted 2009) [#19]
Hi! You can use FastExt library for mirrors (with single additional RenderWorld for reflection map). The algorithm is completely identical to the water system.