Introduction
The non affine transform is available now in WPF with the tilt shader effect.
If you are interested in writing pixel shader effects in WPF or DirectX, you will be very interested in this article.
Background
First I imagined that the effect was easy and small operations can be made but technically while working with the shader kernel, I found some limits of pixel shade 2
when running on WPF 3.5 sp1 and that was a very bad thing.
After a few months I started again to search for
a solution and I found the trick.
The Effect
The Effect is based on transforming a rectangle (the Visual layout rectangle) by its 4 corners.
Because of PixelShader2 limits, the Effect is divided into two parts:
Part 1: Running on CPU (normal VB.NET code). This part involves converting input points and
transforming it to be usable by the shader effect.
The
TiltEffect
class has nine dependency properties
- 1 for the InputProperty
- 4 for the Pixel Shader Handlers of the transformed points
- 4 for the public layout of the points used by the user
Part 2 is running on GPU (shader effect). This part involves calculating the transformation of the tilt effect.
The trick of this effect is to calculate the result point in two steps. First calculate the "Y" value of the point and then calculate the "X" value of the result point.
The transformation of the points on the CPU first will decrease heavy load from the GPU and thus the Effect will work.
Description
The four points pt1, pt2, pt3, pt4 can be changed by the user and the
TiltEffect
class has to compute the p1, p2, p3, p4 points. The x and y values of
the p1, p2, p3, p4 points have no relation because they are computed this way (p1 as example):
slope of (a - pt1) = slope of (pt1 - pt2)
(a.y- pt1.y) / (a.x-pt1.x) = ( (pt1.y -pt2.y)/(pt1.x- pt2.x) )
(a.y- pt1.y) = ( (pt1.y -pt2.y)/(pt1.x- pt2.x) )/(a.x-pt1.x)
a.y =[ ( (pt1.y -pt2.y)/(pt1.x- pt2.x) )/(a.x-pt1.x) ] +pt1.y
the value of a.x = 0
a.y =[ ( (pt1.y -pt2.y)/(pt1.x- pt2.x) )/(0-pt1.x) ] +pt1.y
p1.y = a.y
slope of (b - pt1 ) = slope of ( pt1 - pt3 )
(b.y - pt1.y )/(b.x - pt1.x ) = (pt1.y - pt3.y)/(pt1.x - pt3.x )
(b.x - pt1.x ) /(b.y - pt1.y ) = (pt1.x - pt3.x ) / (pt1.y - pt3.y)
(b.x - pt1.x ) =( (pt1.x - pt3.x ) / (pt1.y - pt3.y) ) /(b.y - pt1.y )
b.x =[( (pt1.x - pt3.x ) / (pt1.y - pt3.y) ) /(b.y - pt1.y ) ] + pt1.x
the value of b.y = 0
b.x =[( (pt1.x - pt3.x ) / (pt1.y - pt3.y) ) /(0 - pt1.y ) ] + pt1.x
p1.x = b.x
And then calculate p2, p3, p4 points the same way.
On the GPU
The 4 registers pt1, pt2, pt3, pt4 resemble the p1
,
p2
, p3
, p4
properties in the TiltEffect
class.
w1 = pt1.y + (pt2.y-pt1.y) * uv.x;
w2 = pt3.y+ (pt4.y- pt3.y) * uv.x;
maxy = w2 - w1;
cury = (uv.y - w1)/maxy;
This algorithm retrieves the Y value of the result point to be rendered in uv position and
also curx is calculated by this algorithm separately.
Finally,
trimming the results and returning the result color from the input texture.
But
why this hard way?
The pixel shader limited arithmetic operations count.
Using the code
WPF 3.5 sp1 provides a very nice property named "Effect" for visual objects.
This property can be used for making special effects on pixels of a specified visual.
Points of Interest
While playing with GPU you can make
awesome Effects. Use your mind and release your imagination to get the most of your mind and to learn faster.