Rotation artifacts

BlitzMax Forums/BlitzMax Programming/Rotation artifacts

Casaber(Posted 2016) [#1]
I was looking around the forum for some graphic example how to rotate a sprite in different ways, and, I got interested in this strange effect.

Look carefully and you see a square pattern appear and disappear over and over again.
What is it? How would you make it go away?

SuperStrict
Type Tentity

	Field x:Float
	Field y:Float
	Field image:TImage
	Field angle:Float
	Field x1:Float 
	Field y1:Float 
	Field x2:Float
	Field y2:Float
	Field x3:Float
	Field y3:Float
	Field x4:Float
	Field y4:Float
	
	Function Create:Tentity(x:Float,y:Float,image:TImage,angle:Float)
		Local e:Tentity = New Tentity
		e.x = x
		e.y = y
		e.image = image
		e.angle = angle
		e.x1:Float = -image.handle_x                               'rectangle top left corner
		e.y1:Float = -image.handle_y
		e.x2:Float =  image.width - image.handle_x      'rectangle top right corner
		e.y2:Float = -image.handle_y
		e.x3:Float =  image.width - image.handle_x      'rectangle bottom right corner 
		e.y3:Float =  image.height - image.handle_y  
		e.x4:Float =  -image.handle_x                              'rectangle bottom left corner
		e.y4:Float =  image.height - image.handle_y   
		Return e
	End Function

	Method collidedpoint:Int(px:Float,py:Float)
		px = px - x
		py = py - y
		Local tx:Float = px*Cos(-angle) - py*Sin(-angle) 
		Local ty:Float = py*Cos(-angle) + px*Sin(-angle)  
		If tx > x1  
			If ty >y1 
				If tx < x3
					If ty < y3
						Return True
					EndIf
				EndIf
			EndIf
		EndIf
		Return False
	End Method
		
	Method display()
		SetRotation angle
		DrawImage image,x,y
		Local c:Float = Cos(angle)
		Local s:Float = Sin(angle)
		Local px1:Float =x + c*x1 - s*y1
		Local py1:Float =y + c*y1 + s*x1
		Local px2:Float =x + c*x2 - s*y2 
		Local py2:Float =y + c*y2 + s*x2
		Local px3:Float =x + c*x3 - s*y3
		Local py3:Float =y + c*y3 + s*x3
		Local px4:Float =x + c*x4 - s*y4
		Local py4:Float =y + c*y4 + s*x4
		SetRotation 0
		DrawOval x-3,y-3,6,6
		DrawLine px1,py1,px2,py2
		DrawLine px2,py2,px3,py3
		DrawLine px3,py3,px4,py4
		DrawLine px4,py4,px1,py1
	End Method

End Type

Local img:TImage = CreateImage(256,256)
Local pixls:Int Ptr = Int Ptr(LockImage(img).pixels)
For Local i:Int = 0 Until img.width*img.height
	pixls[Rand(img.width*img.height-1)] = $ff00ff00
Next

SetImageHandle img,128,0

Graphics 800,600
Local entity:tentity = Tentity.Create(300,300,img,45)

Local angle:Float  = 0

Repeat
	Cls()
	entity.angle = angle
	If entity.collidedpoint(MouseX(),MouseY())
		DrawText "collided",400,300
	EndIf
	entity.display()
	angle :-.5
	Flip()
Until KeyDown(key_escape)



grable(Posted 2016) [#2]
Looks like a moire pattern..
Trying it on other images and it goes away, so its probably a contrast thing. IE the image your generating is evil ;)

The only way i know to lessen this is no filtering or more filtering (like anisotropic).


Casaber(Posted 2016) [#3]
It seems you're right, I need to learn more about this.

One thing that amazes me it seem to exist everyhere not only in graphics.
Like this fabric.. the moire in it is visible to the naked eye not only to the camera.


I hate filters I hope I can solve it without them.


Floyd(Posted 2016) [#4]
the moire in it is visible to the naked eye not only to the camera.

That's because it's a real thing. You are seeing constructive/destructive interference.

You see the same thing with the fabric in the picture, or with screens from your windows. If you ever take those outside to wash them you will see such patterns when you place one on top of the other and look through the two layers. It can also happen with a screen and it's own shadow.

In your program the interference is between your drawn dots and the grid of screen pixels.

Here is an example, a regular pattern of white dots. It is drawn twice with two different orientations. Where the dots land between each other more of the screen is white.

SuperStrict

Graphics 1024, 1024

Local x:Int, y:Int
For x = 0 To 1020 Step 5
	For y = 0 To 1020 Step 5
		DrawOval x,y, 3,3
	Next
Next

Local dots:TImage = CreateImage( 1024, 1024 )
GrabImage dots, 0, 0
SetImageHandle dots, 512,512
DrawImage dots, 512,512
Flip
Delay 1500


Local angle:Float

While Not KeyDown( KEY_ESCAPE )
	Cls
	SetRotation 0
	DrawImage dots, 512, 512
	
	angle :+ 0.125
	If angle > 360.0 Then angle :- 360
	
	SetRotation angle
	DrawImage dots, 512, 512
	Flip
Wend



Casaber(Posted 2016) [#5]
I´m just puzzled.

The original size was 256x256 so I thought what if you double the size before drawing it and before drawing it (but after rotation), you scale it down equally much?
(Here I used a Pixmap at the init to double the size and then for the draw I use a SetScale origsize/biggersize,orgsize/biggersize to restore it).

It came close to perfect, so I thought I'd double it even moe or some other size to make the last bit go away.

It didn't work at all. Resizing *anything else than a perfect doubling* brought back the pattern with full power (even 513 and all the way to 2047) and
it always has equal strength it's not increasing or anything, the effect is either there or it is not.




Casaber(Posted 2016) [#6]
Thanks Floyd for the example, appriciated. Ya I sortof understand the basics behind it, but it's hard to grasp what's actually happening.


dw817(Posted 2016) [#7]
Hi Casaber. This is a known effect. I managed to create it on the Apple ][ years ago.

Here is the equivalent code:
Strict
Local i
Graphics 800,600
For i=0 Until 800 Step 4
  DrawLine i,0,799-i,599
  If i<600 Then DrawLine 0,i,799,599-i
Next
Flip
WaitKey
when you have pixels next to each other but not touching, you get unusual effects when you warp them around on a pivot.