diff --git a/toonz/sources/common/tgeometry/tgeometry.cpp b/toonz/sources/common/tgeometry/tgeometry.cpp
index d8bb6b6..5844316 100644
--- a/toonz/sources/common/tgeometry/tgeometry.cpp
+++ b/toonz/sources/common/tgeometry/tgeometry.cpp
@@ -235,6 +235,77 @@ TScale::TScale(const TPointD &center, double s) {
 
 //==================================================================================================
 
+TPoint3D TAffine3::operator*(const TPoint3D &b) const {
+  return TPoint3D(
+    b.x*a11 + b.y*a21 + b.z*a31,
+    b.x*a12 + b.y*a22 + b.z*a32,
+    b.x*a13 + b.y*a23 + b.z*a33 );
+}
+
+TAffine3 TAffine3::operator*(const TAffine3 &b) const {
+  return TAffine3(
+    *this * b.rowX(),
+    *this * b.rowY(),
+    *this * b.rowZ() );
+}
+
+TAffine3 TAffine3::operator*=(const TAffine3 &b)
+  { return *this = *this * b; }
+
+TAffine3 TAffine3::inv() const {
+  TAffine3 r;
+  r.a11 = a22*a33 - a32*a23;
+  r.a12 = a32*a13 - a12*a33;
+  r.a13 = a12*a23 - a22*a13;
+
+  double det = r.a11*a11 + r.a12*a21 + r.a12*a31;
+  det = fabs(det) > TConsts::epsilon ? 1.0/det : 0.0;
+  r.a11 *= det;
+  r.a12 *= det;
+  r.a13 *= det;
+
+  r.a21 = (a31*a23 - a21*a33)*det;
+  r.a22 = (a11*a33 - a31*a13)*det;
+  r.a23 = (a21*a13 - a11*a23)*det;
+  r.a31 = (a21*a32 - a31*a22)*det;
+  r.a32 = (a31*a12 - a11*a32)*det;
+  r.a33 = (a11*a22 - a21*a12)*det;
+  return r;
+}
+
+TAffine TAffine3::get2d() const {
+  return TAffine(
+    a11, a21, a31,
+    a12, a22, a32 );
+}
+
+TAffine3 TAffine3::translation2d(double x, double y) {
+  TAffine3 r;
+  r.rowZ().x = x;
+  r.rowZ().y = y;
+  return r;
+}
+
+TAffine3 TAffine3::scale2d(double x, double y) {
+  TAffine3 r;
+  r.a11 = x;
+  r.a22 = y;
+  return r;
+}
+
+TAffine3 TAffine3::rotation2d(double angle) {
+  TAffine3 r;
+  double s = sin(angle);
+  double c = cos(angle);
+  r.a11 =  c;
+  r.a12 =  s;
+  r.a21 = -s;
+  r.a22 =  c;
+  return r;
+}
+
+//==================================================================================================
+
 TPoint4D TAffine4::operator*(const TPoint4D &b) const {
   return TPoint4D(
     b.x*a11 + b.y*a21 + b.z*a31 + b.w*a41,
@@ -290,6 +361,13 @@ TAffine TAffine4::get2d(double z) const {
     a12, a22, z*a32 + a42 );
 }
 
+TAffine3 TAffine4::get2dPersp(double z) const {
+  return TAffine3(
+    TPoint3D( a11       , a12       , a14       ),
+    TPoint3D( a21       , a22       , a24       ),
+    TPoint3D( a31*z+a41 , a32*z+a42 , a34*z+a44 ) );
+}
+
 TAffine4 TAffine4::translation(double x, double y, double z) {
   TAffine4 r;
   r.rowW().x = x;
diff --git a/toonz/sources/include/tgeometry.h b/toonz/sources/include/tgeometry.h
index 34b9902..67eb0f5 100644
--- a/toonz/sources/include/tgeometry.h
+++ b/toonz/sources/include/tgeometry.h
@@ -26,6 +26,7 @@ inline double logNormalDistribuition(double x, double x0, double w)
 
 //=============================================================================
 
+template <class T> class TPoint3T;
 template <class T> class TPoint4T;
 
 /*
@@ -42,6 +43,7 @@ public:
   inline TPointT() : x(0), y(0){};
   inline TPointT(T _x, T _y) : x(_x), y(_y){};
   inline TPointT(const TPointT &point) : x(point.x), y(point.y){};
+  inline explicit TPointT(const TPoint3T<T> &point);
   inline explicit TPointT(const TPoint4T<T> &point);
 
   inline TPointT &operator=(const TPointT &a) {
@@ -70,6 +72,23 @@ public:
 };
 
 template <class T>
+class TPoint3T {
+public:
+  union {
+    struct { T x, y, z; };
+    T a[3];
+  };
+
+  inline TPoint3T():
+    x(), y(), z() { };
+  inline TPoint3T(T x, T y, T z):
+    x(x), y(y), z(z) { };
+  inline explicit TPoint3T(const TPointT<T> &p, T z = (T)0):
+      x(p.x), y(p.y), z(z) { };
+  inline explicit TPoint3T(const TPoint4T<T> &point);
+};
+
+template <class T>
 class TPoint4T {
 public:
   union {
@@ -81,12 +100,19 @@ public:
     x(), y(), z(), w() { };
   inline TPoint4T(T x, T y, T z, T w):
     x(x), y(y), z(z), w(w) { };
-  inline explicit TPoint4T(const TPointT<T> &p, T w = (T)1):
-      x(p.x), y(p.y), z(), w(w) { };
+  inline explicit TPoint4T(const TPointT<T> &p, T z = (T)0, T w = (T)1):
+      x(p.x), y(p.y), z(z), w(w) { };
+  inline explicit TPoint4T(const TPoint3T<T> &p, T w = (T)1):
+      x(p.x), y(p.y), z(p.z), w(w) { };
 };
 
 template <class T>
+inline TPointT<T>::TPointT(const TPoint3T<T> &point) : x(point.x), y(point.y){};
+template <class T>
 inline TPointT<T>::TPointT(const TPoint4T<T> &point) : x(point.x), y(point.y){};
+template <class T>
+inline TPoint3T<T>::TPoint3T(const TPoint4T<T> &point) : x(point.x), y(point.y), z(point.z){};
+
 
 /*! \relates TPointT
 * Rotate a point 90 degrees (counterclockwise).
@@ -130,6 +156,7 @@ inline std::ostream &operator<<(std::ostream &out, const TPointT<T> &p) {
 
 typedef TPointT<int> TPoint, TPointI;
 typedef TPointT<double> TPointD;
+typedef TPoint3T<double> TPoint3D;
 typedef TPoint4T<double> TPoint4D;
 
 #ifdef _WIN32
@@ -1267,6 +1294,71 @@ inline std::ostream &operator<<(std::ostream &out, const TAffine &a) {
 
 //=============================================================================
 
+//! This class performs basic manipulations of affine transformations in 2D space.
+//! with ability of perspective transform
+//! the matrix is transposed to TAffine and equal to OpenGL cells order
+
+class DVAPI TAffine3 {
+public:
+  union {
+    struct {
+      double a11, a12, a13;
+      double a21, a22, a23;
+      double a31, a32, a33;
+    };
+    double m[3][3];
+    double a[9];
+  };
+
+  inline TAffine3():
+    a11(1.0), a12(0.0), a13(0.0),
+    a21(0.0), a22(1.0), a23(0.0),
+    a31(0.0), a32(0.0), a33(1.0) { }
+
+  inline explicit TAffine3(const TAffine &a):
+    a11(a.a11), a12(a.a21), a13(0.0),
+    a21(a.a12), a22(a.a22), a23(0.0),
+    a31(a.a13), a32(a.a23), a33(1.0) { }
+
+  inline TAffine3(
+    const TPoint3D &rowX,
+    const TPoint3D &rowY,
+    const TPoint3D &rowZ
+  ):
+    a11(rowX.x), a12(rowX.y), a13(rowX.z),
+    a21(rowY.x), a22(rowY.y), a23(rowY.z),
+    a31(rowZ.x), a32(rowZ.y), a33(rowZ.z) { }
+
+  inline TPoint3D& row(int index)
+    { return *(TPoint3D*)(m[index]); }
+  inline const TPoint3D& row(int index) const
+    { return *(const TPoint3D*)(m[index]); }
+
+  inline TPoint3D& rowX() { return row(0); }
+  inline TPoint3D& rowY() { return row(1); }
+  inline TPoint3D& rowZ() { return row(2); }
+
+  inline const TPoint3D& rowX() const { return row(0); }
+  inline const TPoint3D& rowY() const { return row(1); }
+  inline const TPoint3D& rowZ() const { return row(2); }
+
+  TPoint3D operator*(const TPoint3D &b) const;
+  TAffine3 operator*(const TAffine3 &b) const;
+  TAffine3 operator*=(const TAffine3 &b);
+
+  TAffine3 inv() const;
+
+  TAffine get2d() const;
+
+  inline static TAffine3 identity() { return TAffine3(); }
+  static TAffine3 translation2d(double x, double y);
+  static TAffine3 scale2d(double x, double y);
+  static TAffine3 rotation2d(double angle);
+};
+
+
+//=============================================================================
+
 //! This class performs basic manipulations of affine transformations in 3D space.
 //! the matrix is transposed to TAffine and equal to OpenGL
 
@@ -1328,6 +1420,7 @@ public:
   TAffine4 inv() const;
 
   TAffine get2d(double z = 0.0) const;
+  TAffine3 get2dPersp(double z = 0.0) const;
 
   inline static TAffine4 identity() { return TAffine4(); }
   static TAffine4 translation(double x, double y, double z);