Difference between revisions of "PovRay"

From PyMOLWiki
Jump to navigation Jump to search
(New page: ==Nice PovRay settings== I typically use the make_pov.py script and "run" it from pymol once to load the function, and then I do ''make_pov('povray.inp')'' to create the povray.inp file. T...)
 
(intro)
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 +
PyMOL can export input files for [http://www.povray.org/ POV-Ray] with the ".pov" file extension:
 +
 +
set stick_ball
 +
save input.pov
 +
 +
It can also use POV-Ray directly for rendering with the [[ray#Renderer|ray]] command:
 +
 +
ray renderer=1
 +
 +
Since PyMOL 1.7.4, round stick caps are only exported correctly with [[stick_ball]]=on.
 +
 
==Nice PovRay settings==
 
==Nice PovRay settings==
 
I typically use the make_pov.py script and "run" it from pymol once to load the function, and then I do ''make_pov('povray.inp')'' to create the povray.inp file.
 
I typically use the make_pov.py script and "run" it from pymol once to load the function, and then I do ''make_pov('povray.inp')'' to create the povray.inp file.
Line 38: Line 49:
  
 
==make_pov.py v2==
 
==make_pov.py v2==
This version was recently posted with a few more options to the user along with a little more flexibility in rendering the POV scene.
+
This is a more extended version of an earlier extension of the version by Robert Campbell. The scene is written in two parts, a .pov file containing all meta data, such as the lights, camera and #defaults, and an include file (.inc) which contains the structure. In this way you have maximum control over your scene without having to edit a huge povray file. You may even want to consider splitting your scene up in separate parts (taken from the same perspective), which you combine in a global .pov file using #include statements. This will give even more control with regards to modifications to the scene.
 
+
If 'clip' is set to near|far|both, then the corresponding clipping plane(s) is/are included in a CSG difference object. Note that the result may increase the render time significantly unless the scene is simple.
The temporary povray file is written to the working directory. This will write your scene in two parts, a .pov file containing all meta data, such as the lights, camera and #defaults, and an include file (.inc) which contains the structure. In this way you have maximum control over your scene without having to edit a huge povray file. You may even want to consider splitting your scene up in separate parts (taken from the same perspective), which you combine in a global .pov file using #include statements. This will give even more control with regards to modifications to the scene.
 
  
 
Once you run '''run make_pov.py''', run '''make_pov''' to execute the script.
 
Once you run '''run make_pov.py''', run '''make_pov''' to execute the script.
  
NB. the .pov file contains a commented statement with regards to a povray script, which allows transforming scenes and objects from model space to camera space and vice versa. If you want, you can get a copy of that script.
+
NB. the .pov file contains a commented statement with regards to a povray macro file, which allows transforming scenes and objects from model space to camera space and vice versa. The macro file is given below.
  
 
<source lang="python">
 
<source lang="python">
# make_pov.py                                                                                      
+
# make_pov.py
# Do "run make_pov.py" from within pymol and then execute the script                              
+
# Do "run make_pov.py" from within pymol and then execute the script
# with "make_pov('povray.inp')" to create the povray.inp file.                                    
+
# with "make_pov('povray.inp')" to create the povray.inp file.
 
#                                                                                                   
 
#                                                                                                   
 +
# Original script written by Robert Campbell
 +
# Modified by Tsjerk A. Wassenaar
 +
#
  
 
from pymol import cmd
 
from pymol import cmd
  
def make_pov(file, meta=True):
+
def make_pov(file, name="PymolObject", meta=True, clip=False ):
 
         f1, f2 = file, file[:-4] + '.inc'
 
         f1, f2 = file, file[:-4] + '.inc'
  
Line 61: Line 74:
 
         if meta: povfile.write(header)
 
         if meta: povfile.write(header)
 
         povview = cmd.get_view()
 
         povview = cmd.get_view()
 +
 +
        if clip:
 +
                objtype = "difference"
 +
                objclip = ""
 +
                if clip in ["near","both"]:
 +
                        objclip = objclip + "plane { z, -%f }" % povview[15]
 +
                if clip in ["far","both"]:
 +
                        objclip = objclip + "plane { z, -%f }" % povview[16]
 +
        else:
 +
                objtype = "object"
 +
                objclip = ""
  
 
         povfile.write("""\n
 
         povfile.write("""\n
Line 75: Line 99:
  
 
""" % povview)
 
""" % povview)
         povfile.write('#include "%s"\n\n' % f2)
+
 
 +
         povfile.write("""
 +
#declare %s = union { #include "%s" }
 +
%s { %s %s }
 +
""" % (name, f2, objtype, name, objclip ) )
 +
 
 
         povfile.close()
 
         povfile.close()
 
         povfile = open(f2,'w')
 
         povfile = open(f2,'w')
Line 83: Line 112:
 
cmd.extend('make_pov',make_pov)
 
cmd.extend('make_pov',make_pov)
 
</source>
 
</source>
 +
 +
<source lang="text">
 +
//
 +
//  PYMOLMACRO.INC v0.2
 +
//
 +
//  (c)2005 Tsjerk Wassenaar, University of Groningen
 +
//
 +
//  This include file for Povray contains
 +
//  just a few macros which together allow
 +
//  the conversion between the model space
 +
//  (cartesian coordinates) and the Pymol
 +
//  camera space.
 +
//
 +
//  With these macros one can easily combine
 +
//  a Pymol scene with objects defined in the
 +
//  coordinate space of the original
 +
//  structure file.
 +
//
 +
//  The input consists of the output of the
 +
//  get_view() command in Pymol. This output
 +
//  consists of 18 floating point numbers
 +
//  defining a rotation matrix and shift
 +
//  vectors for the origin of rotation and
 +
//  for the camera position.
 +
//
 +
//  The macro PYMOL_VIEW loads a
 +
//  view obtained from Pymol.
 +
//
 +
//  It #declares two transformation statements:
 +
//
 +
//  FROM_PYMOL_VIEW
 +
//  TO_PYMOL_VIEW
 +
//
 +
//  The first can be used to transform the Pymol
 +
//  scene back to model (normal) space, the latter
 +
//  is used to transform other objects to appear in
 +
//  the scene on the correct position.
 +
//
 +
//  Additionally four macros are defined to transform
 +
//  vectors (points) from one space to another:
 +
//
 +
//  VEC2PYMOLSPACE( <x, y, z> )
 +
//  VEC2CARTSPACE( <x, y, z> )
 +
//  VEC2PYMOLVEC( <x, y, z> )
 +
//  VEC2CARTVEC( <x, y, z> )
 +
//
 +
//  *NEW*
 +
//
 +
//  If the view from pymol is stored as an array:
 +
//
 +
//  #declare M = array[18] {...}
 +
//
 +
//  then the macros
 +
//
 +
//  SET_PYMOL_VIEW
 +
//    and
 +
//  UNSET_PYMOL_VIEW
 +
//
 +
//  can be used directly to transform objects to and from that view:
 +
//  object { ... SET_PYMOL_VIEW( M ) }
 +
//
 +
//  This is especially useful if multiple views are defined
 +
//  and the scene was set in one:
 +
//
 +
//  #declare VIEW1 = M;
 +
//  #declare VIEW2 = N;
 +
//  union { #include "file.inc" UNSET_PYMOL_VIEW( M ) SET_PYMOL_VIEW( N ) }
 +
//
 +
//  NOTE: transform statements are combined by POV-Ray prior to
 +
//  transformations of objects, so there's little need to implement a macro
 +
//  SWITCH_PYMOL_VIEW( M, N )
 +
//  although that would appear simpler in the scenes 
 +
 +
//  Tsjerk A. Wassenaar
 +
//  February 16, 2005
 +
//  April 5, 2005
 +
//  September 2, 2009
 +
//
 +
 +
// Determinant of a matrix
 +
//------------------------
 +
#macro DET( M )
 +
 +
  #local a = M[0] * ( M[4]*M[8] - M[5]*M[7] );
 +
  #local b = M[1] * ( M[3]*M[8] - M[5]*M[6] );
 +
  #local c = M[2] * ( M[3]*M[7] - M[4]*M[6] );
 +
 +
  (a - b + c)
 +
 +
#end // of DET()
 +
 +
 +
// The inverse of a matrix
 +
//------------------------
 +
#macro INV( m11, m12, m13, m21, m22, m23, m31, m32, m33 )
 +
 +
  #local M = array[9] { m11, m12, m13, m21, m22, m23, m31, m32, m33 };
 +
  #local invdet = 1/DET( M );
 +
 +
  #local t11 = invdet * ( m22*m33 - m23*m32 );
 +
  #local t12 = invdet * ( m13*m32 - m12*m33 );
 +
  #local t13 = invdet * ( m12*m23 - m13*m22 );
 +
  #local t21 = invdet * ( m23*m31 - m21*m33 );
 +
  #local t22 = invdet * ( m11*m33 - m13*m31 );
 +
  #local t23 = invdet * ( m13*m21 - m11*m23 );
 +
  #local t31 = invdet * ( m21*m32 - m22*m31 );
 +
  #local t32 = invdet * ( m12*m31 - m11*m32 );
 +
  #local t33 = invdet * ( m11*m22 - m12*m21 );
 +
 +
  t11, t12, t13, t21, t22, t23, t31, t32, t33, 0, 0, 0
 +
 +
#end // of INV()
 +
 +
#macro M_INV( M )
 +
  #local invdet = 1/DET( M );
 +
 +
  #local t11 = invdet * ( M[4]*M[8] - M[5]*M[7] );
 +
  #local t21 = invdet * ( M[2]*M[7] - M[1]*M[8] );
 +
  #local t31 = invdet * ( M[1]*M[5] - M[2]*M[4] );
 +
 +
  #local t12 = invdet * ( M[5]*M[6] - M[3]*M[8] );
 +
  #local t22 = invdet * ( M[0]*M[8] - M[2]*M[6] );
 +
  #local t32 = invdet * ( M[2]*M[3] - M[0]*M[5] );
 +
 +
  #local t13 = invdet * ( M[3]*M[7] - M[4]*M[6] );
 +
  #local t23 = invdet * ( M[1]*M[6] - M[0]*M[7] );
 +
  #local t33 = invdet * ( M[0]*M[4] - M[1]*M[3] );
 +
 +
  array[9] {t11, t12, t13, t21, t22, t23, t31, t32, t33}
 +
#end
 +
 +
#macro MV_MUL( M, V )
 +
    < M[0]*V.x + M[1]*V.y + M[2]*V.z,
 +
      M[3]*V.x + M[4]*V.y + M[5]*V.z,
 +
      M[6]*V.x + M[7]*V.y + M[8]*V.z >
 +
#end
 +
 +
#macro SET_PYMOL_VIEW( M )
 +
  transform {
 +
    translate -< M[12], M[13], M[14] >
 +
    matrix < M[0], M[1],  M[2],
 +
    M[3], M[4],  M[5],
 +
    M[6], M[7],  M[8],
 +
    M[9], M[10], M[11] >
 +
  }
 +
#end // of SET_PYMOL_VIEW
 +
 +
#macro UNSET_PYMOL_VIEW( M )
 +
  transform {
 +
    translate -< M[9], M[10], M[11] >
 +
    matrix < INV( M[0], M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8] ) >
 +
    translate < M[12], M[13], M[14] >
 +
  }
 +
#end // of UNSET_PYMOL_VIEW
 +
 +
#macro C2P_VEC( M, vec)
 +
  #local nvec = vec - <M[12],M[13],M[14]>;
 +
  #local nvec =
 +
    < M[0]*nvec.x + M[1]*nvec.y + M[2]*nvec.z,
 +
      M[3]*nvec.x + M[4]*nvec.y + M[5]*nvec.z,
 +
      M[6]*nvec.x + M[7]*nvec.y + M[8]*nvec.z >;
 +
  nvec + <M[9],M[10],M[11]>
 +
#end
 +
 +
#macro P2C_VEC( M, vec)
 +
  MV_MUL( M_INV(M), vec - <M[9],M[10],M[11]> ) + <M[12],M[13],M[14]>
 +
  //#local nvec = vec - <M[9],M[10],M[11]>;
 +
  //#local N = M_INV( M ) ;
 +
  //#local nvec =
 +
  //  < N[0]*nvec.x + N[1]*nvec.y + N[2]*nvec.z,
 +
  //    N[3]*nvec.x + N[4]*nvec.y + N[5]*nvec.z,
 +
  //    N[6]*nvec.x + N[7]*nvec.y + N[8]*nvec.z >;
 +
  //nvec
 +
#end
 +
 +
 +
#macro PYMOL_VIEW( r11, r12, r13,    // 3x3 Rotation matrix ( Model space to Camera space )
 +
  r21, r22, r23,
 +
  r31, r32, r33,
 +
    c1,  c2,  c3,    // Camera position ( Model space )
 +
    o1,  o2,  o3,    // Origin of rotation ( Model space )
 +
    s1,  s2,  or)    // Slab near and far, orthoscopic flag ( discarded )
 +
 +
  #declare PYMOLVIEW_RMATRIX = array[9] { r11, r12, r13,
 +
  r21, r22, r23,
 +
  r31, r32, r33 }
 +
  #declare PYMOLVIEW_CAMPOS  = < c1, c2, c3 >;
 +
  #declare PYMOLVIEW_ORGPOS  = < o1, o2, o3 >;
 +
 +
  #declare TO_PYMOL_VIEW = transform {
 +
    translate -< o1, o2, o3 >
 +
    matrix < r11, r12, r13,
 +
    r21, r22, r23,
 +
    r31, r32, r33,
 +
      c1,  c2,  c3 >
 +
  }
 +
 +
  #declare FROM_PYMOL_VIEW = transform {
 +
    translate -< c1, c2, c3>
 +
    matrix < INV( r11, r12, r13, r21, r22, r23, r31, r32, r33 ) >
 +
    translate  < o1, o2, o3>
 +
  }
 +
 +
  #macro VEC2PYMOLSPACE(vec)
 +
    #local nvec = vec - PYMOLVIEW_ORGPOS;
 +
    #local nvec =
 +
      < PYMOLVIEW_RMATRIX[0]*nvec.x + PYMOLVIEW_RMATRIX[3]*nvec.y + PYMOLVIEW_RMATRIX[6]*nvec.z,
 +
        PYMOLVIEW_RMATRIX[1]*nvec.x + PYMOLVIEW_RMATRIX[4]*nvec.y + PYMOLVIEW_RMATRIX[7]*nvec.z,
 +
        PYMOLVIEW_RMATRIX[2]*nvec.x + PYMOLVIEW_RMATRIX[5]*nvec.y + PYMOLVIEW_RMATRIX[8]*nvec.z >;
 +
    nvec + PYMOLVIEW_CAMPOS
 +
  #end
 +
 +
  #macro VEC2CARTSPACE(vec)
 +
 +
    #local nvec = vec - PYMOLVIEW_CAMPOS;
 +
 +
    #local R = PYMOLVIEW_RMATRIX;
 +
    #local invdet = 1/DET( R );
 +
 +
    #local T = array[9];
 +
 +
    #local T[0] = invdet * ( R[4]*R[8] - R[5]*R[7] );
 +
    #local T[1] = invdet * ( R[2]*R[7] - R[1]*R[8] );
 +
    #local T[2] = invdet * ( R[1]*R[5] - R[2]*R[4] );
 +
    #local T[3] = invdet * ( R[5]*R[6] - R[3]*R[8] );
 +
    #local T[4] = invdet * ( R[0]*R[8] - R[2]*R[6] );
 +
    #local T[5] = invdet * ( R[2]*R[3] - R[0]*R[5] );
 +
    #local T[6] = invdet * ( R[3]*R[7] - R[4]*R[6] );
 +
    #local T[7] = invdet * ( R[1]*R[6] - R[0]*R[7] );
 +
    #local T[8] = invdet * ( R[0]*R[4] - R[1]*R[3] );
 +
 +
    < T[0]*nvec.x + T[3]*nvec.y + T[6]*nvec.z + PYMOLVIEW_ORGPOS.x,
 +
      T[1]*nvec.x + T[4]*nvec.y + T[7]*nvec.z + PYMOLVIEW_ORGPOS.y,
 +
      T[2]*nvec.x + T[5]*nvec.y + T[8]*nvec.z + PYMOLVIEW_ORGPOS.z >
 +
  #end
 +
 +
  #macro VEC2PYMOLVEC(vec)
 +
    < PYMOLVIEW_RMATRIX[0]*vec.x + PYMOLVIEW_RMATRIX[3]*vec.y + PYMOLVIEW_RMATRIX[6]*vec.z,
 +
      PYMOLVIEW_RMATRIX[1]*vec.x + PYMOLVIEW_RMATRIX[4]*vec.y + PYMOLVIEW_RMATRIX[7]*vec.z,
 +
      PYMOLVIEW_RMATRIX[2]*vec.x + PYMOLVIEW_RMATRIX[5]*vec.y + PYMOLVIEW_RMATRIX[8]*vec.z >
 +
  #end
 +
 +
  #macro VEC2CARTVEC(vec)
 +
    #local nvec = vec - PYMOLVIEW_CAMPOS;
 +
  #end
 +
 +
  #macro CAM2PYMOLCAM()
 +
 +
  #end
 +
 +
  #macro CAM2CARTCAM()
 +
 +
  #end
 +
#end
 +
 +
</source>
 +
 +
[[Category:Third_Party_Software|PovRay]]
 +
[[Category:ThirdParty_Scripts]]

Latest revision as of 14:27, 29 October 2017

PyMOL can export input files for POV-Ray with the ".pov" file extension:

set stick_ball
save input.pov

It can also use POV-Ray directly for rendering with the ray command:

ray renderer=1

Since PyMOL 1.7.4, round stick caps are only exported correctly with stick_ball=on.

Nice PovRay settings

I typically use the make_pov.py script and "run" it from pymol once to load the function, and then I do make_pov('povray.inp') to create the povray.inp file. Then I edit that file to insert some lines like:

fog {
  distance 10
  fog_type 2
  fog_alt 10.
  fog_offset -160.
  up <0.,1.,.4>
colour rgbt<1.0, 1.0, 1.0, 0.1>
turbulence 0.8
}

In this case I'm not really doing depth-cueing but adding fog at the lower background edge (there were two planes defining the background and a surface below the molecule) rising up towards the front upper edge of the scene.

"fog_type 2" means a "rising fog" along the "up" vector. fog_type 1 is a constant fog. To get pure depth cueing, you would want "up" to be along the <0., 0., 1.> vector (I think!). You'll need to play around with the distance and fog_offset parameters. You wouldn't necessarily want the "turbulence" parameter in there either. Check out "Atmospheric Effects" in the povray documentation for many more details: http://www.povray.org/documentation/view/201/

make_pov.py v1

# make_pov.py
# Do "run make_pov.py" from within pymol and then execute the script
# with "make_pov('povray.inp')" to create the povray.inp file.
#
# written by Robert Campbell 2003
#
from pymol import cmd

def make_pov(file):
	(header,data) = cmd.get_povray()
	povfile=open(file,'w')
	povfile.write(header)
	povfile.write(data)
	povfile.close()

make_pov.py v2

This is a more extended version of an earlier extension of the version by Robert Campbell. The scene is written in two parts, a .pov file containing all meta data, such as the lights, camera and #defaults, and an include file (.inc) which contains the structure. In this way you have maximum control over your scene without having to edit a huge povray file. You may even want to consider splitting your scene up in separate parts (taken from the same perspective), which you combine in a global .pov file using #include statements. This will give even more control with regards to modifications to the scene. If 'clip' is set to near|far|both, then the corresponding clipping plane(s) is/are included in a CSG difference object. Note that the result may increase the render time significantly unless the scene is simple.

Once you run run make_pov.py, run make_pov to execute the script.

NB. the .pov file contains a commented statement with regards to a povray macro file, which allows transforming scenes and objects from model space to camera space and vice versa. The macro file is given below.

# make_pov.py
# Do "run make_pov.py" from within pymol and then execute the script
# with "make_pov('povray.inp')" to create the povray.inp file.
#                                                                                                   
# Original script written by Robert Campbell
# Modified by Tsjerk A. Wassenaar
#

from pymol import cmd

def make_pov(file, name="PymolObject", meta=True, clip=False ):
        f1, f2 = file, file[:-4] + '.inc'

        (header,data) = cmd.get_povray()
        povfile = open(f1,'w')
        if meta: povfile.write(header)
        povview = cmd.get_view()

        if clip:
                objtype = "difference"
                objclip = ""
                if clip in ["near","both"]:
                        objclip = objclip + "plane { z, -%f }" % povview[15] 
                if clip in ["far","both"]:
                        objclip = objclip + "plane { z, -%f }" % povview[16] 
        else:
                objtype = "object"
                objclip = ""

        povfile.write("""\n
// Uncomment the following lines if you have the pymolmacro.inc include file and want to use it.
/*
#include \"pymolmacro.inc\"
PYMOL_VIEW( %10.5f, %10.5f, %10.5f,
            %10.5f, %10.5f, %10.5f,
            %10.5f, %10.5f, %10.5f,
            %10.5f, %10.5f, %10.5f,
            %10.5f, %10.5f, %10.5f,
            %10.5f, %10.5f, %10.5f )
*/

""" % povview)

        povfile.write("""
#declare %s = union { #include "%s" }
%s { %s %s }
""" % (name, f2, objtype, name, objclip ) )

        povfile.close()
        povfile = open(f2,'w')
        povfile.write(data)
        povfile.close()

cmd.extend('make_pov',make_pov)
//
//  PYMOLMACRO.INC v0.2 
//
//  (c)2005 Tsjerk Wassenaar, University of Groningen
//
//  This include file for Povray contains
//  just a few macros which together allow
//  the conversion between the model space
//  (cartesian coordinates) and the Pymol
//  camera space.
//
//  With these macros one can easily combine
//  a Pymol scene with objects defined in the
//  coordinate space of the original
//  structure file.
//
//  The input consists of the output of the
//  get_view() command in Pymol. This output
//  consists of 18 floating point numbers
//  defining a rotation matrix and shift
//  vectors for the origin of rotation and
//  for the camera position.
//
//  The macro PYMOL_VIEW loads a
//  view obtained from Pymol.
//
//  It #declares two transformation statements:
//
//  FROM_PYMOL_VIEW
//  TO_PYMOL_VIEW
//
//  The first can be used to transform the Pymol
//  scene back to model (normal) space, the latter
//  is used to transform other objects to appear in
//  the scene on the correct position.
//
//  Additionally four macros are defined to transform
//  vectors (points) from one space to another:
//
//  VEC2PYMOLSPACE( <x, y, z> )
//  VEC2CARTSPACE( <x, y, z> )
//  VEC2PYMOLVEC( <x, y, z> )
//  VEC2CARTVEC( <x, y, z> ) 
//
//  *NEW*
//
//  If the view from pymol is stored as an array:
//
//  #declare M = array[18] {...}
//
//  then the macros
//
//  SET_PYMOL_VIEW 
//    and 
//  UNSET_PYMOL_VIEW
//
//  can be used directly to transform objects to and from that view:
//  object { ... SET_PYMOL_VIEW( M ) }
//
//  This is especially useful if multiple views are defined 
//  and the scene was set in one:
//
//  #declare VIEW1 = M;
//  #declare VIEW2 = N;
//  union { #include "file.inc" UNSET_PYMOL_VIEW( M ) SET_PYMOL_VIEW( N ) }
//
//  NOTE: transform statements are combined by POV-Ray prior to 
//  transformations of objects, so there's little need to implement a macro
//  SWITCH_PYMOL_VIEW( M, N )
//  although that would appear simpler in the scenes  

//  Tsjerk A. Wassenaar
//  February 16, 2005
//  April 5, 2005
//  September 2, 2009
//

// Determinant of a matrix
//------------------------
#macro DET( M )

  #local a = M[0] * ( M[4]*M[8] - M[5]*M[7] ); 
  #local b = M[1] * ( M[3]*M[8] - M[5]*M[6] ); 
  #local c = M[2] * ( M[3]*M[7] - M[4]*M[6] );

  (a - b + c)

#end // of DET()


// The inverse of a matrix
//------------------------
#macro INV( m11, m12, m13, m21, m22, m23, m31, m32, m33 )

  #local M = array[9] { m11, m12, m13, m21, m22, m23, m31, m32, m33 };
  #local invdet = 1/DET( M );
	
  #local t11 = invdet * ( m22*m33 - m23*m32 ); 
  #local t12 = invdet * ( m13*m32 - m12*m33 ); 
  #local t13 = invdet * ( m12*m23 - m13*m22 ); 
  #local t21 = invdet * ( m23*m31 - m21*m33 ); 
  #local t22 = invdet * ( m11*m33 - m13*m31 ); 
  #local t23 = invdet * ( m13*m21 - m11*m23 );
  #local t31 = invdet * ( m21*m32 - m22*m31 );
  #local t32 = invdet * ( m12*m31 - m11*m32 );
  #local t33 = invdet * ( m11*m22 - m12*m21 );

  t11, t12, t13, t21, t22, t23, t31, t32, t33, 0, 0, 0

#end // of INV()

#macro M_INV( M )
  #local invdet = 1/DET( M );
	
  #local t11 = invdet * ( M[4]*M[8] - M[5]*M[7] ); 
  #local t21 = invdet * ( M[2]*M[7] - M[1]*M[8] ); 
  #local t31 = invdet * ( M[1]*M[5] - M[2]*M[4] ); 

  #local t12 = invdet * ( M[5]*M[6] - M[3]*M[8] ); 
  #local t22 = invdet * ( M[0]*M[8] - M[2]*M[6] ); 
  #local t32 = invdet * ( M[2]*M[3] - M[0]*M[5] );

  #local t13 = invdet * ( M[3]*M[7] - M[4]*M[6] );
  #local t23 = invdet * ( M[1]*M[6] - M[0]*M[7] );
  #local t33 = invdet * ( M[0]*M[4] - M[1]*M[3] );

  array[9] {t11, t12, t13, t21, t22, t23, t31, t32, t33}
#end

#macro MV_MUL( M, V )
    < M[0]*V.x + M[1]*V.y + M[2]*V.z,
      M[3]*V.x + M[4]*V.y + M[5]*V.z,
      M[6]*V.x + M[7]*V.y + M[8]*V.z >
#end

#macro SET_PYMOL_VIEW( M )
  transform {
    translate -< M[12], M[13], M[14] >
    matrix < M[0], M[1],  M[2],
	     M[3], M[4],  M[5], 
	     M[6], M[7],  M[8], 
	     M[9], M[10], M[11] >
  } 
#end // of SET_PYMOL_VIEW

#macro UNSET_PYMOL_VIEW( M )
  transform {
    translate -< M[9], M[10], M[11] >
    matrix < INV( M[0], M[1], M[2], M[3], M[4], M[5], M[6], M[7], M[8] ) > 
    translate < M[12], M[13], M[14] >
  } 
#end // of UNSET_PYMOL_VIEW

#macro C2P_VEC( M, vec)
  #local nvec = vec - <M[12],M[13],M[14]>;
  #local nvec =
    < M[0]*nvec.x + M[1]*nvec.y + M[2]*nvec.z,
      M[3]*nvec.x + M[4]*nvec.y + M[5]*nvec.z,
      M[6]*nvec.x + M[7]*nvec.y + M[8]*nvec.z >; 
  nvec + <M[9],M[10],M[11]>
#end

#macro P2C_VEC( M, vec)
  MV_MUL( M_INV(M), vec - <M[9],M[10],M[11]> ) + <M[12],M[13],M[14]>
  //#local nvec = vec - <M[9],M[10],M[11]>;
  //#local N = M_INV( M ) ;
  //#local nvec =
  //  < N[0]*nvec.x + N[1]*nvec.y + N[2]*nvec.z,
  //    N[3]*nvec.x + N[4]*nvec.y + N[5]*nvec.z,
  //    N[6]*nvec.x + N[7]*nvec.y + N[8]*nvec.z >; 
  //nvec
#end


#macro PYMOL_VIEW( r11, r12, r13,     // 3x3 Rotation matrix ( Model space to Camera space )
		   r21, r22, r23, 
		   r31, r32, r33,
		    c1,  c2,  c3,     // Camera position ( Model space )
		    o1,  o2,  o3,     // Origin of rotation ( Model space )
		    s1,  s2,  or)     // Slab near and far, orthoscopic flag ( discarded )

  #declare PYMOLVIEW_RMATRIX = array[9] { r11, r12, r13, 
					  r21, r22, r23, 
					  r31, r32, r33 }
  #declare PYMOLVIEW_CAMPOS  = < c1, c2, c3 >;
  #declare PYMOLVIEW_ORGPOS  = < o1, o2, o3 >;

  #declare TO_PYMOL_VIEW = transform {
    translate -< o1, o2, o3 >
    matrix < r11, r12, r13,
	     r21, r22, r23, 
	     r31, r32, r33, 
	      c1,  c2,  c3 >
  }

  #declare FROM_PYMOL_VIEW = transform {
    translate -< c1, c2, c3>
    matrix < INV( r11, r12, r13, r21, r22, r23, r31, r32, r33 ) >
    translate  < o1, o2, o3>
  }

  #macro VEC2PYMOLSPACE(vec)
    #local nvec = vec - PYMOLVIEW_ORGPOS;
    #local nvec =
      < PYMOLVIEW_RMATRIX[0]*nvec.x + PYMOLVIEW_RMATRIX[3]*nvec.y + PYMOLVIEW_RMATRIX[6]*nvec.z,
        PYMOLVIEW_RMATRIX[1]*nvec.x + PYMOLVIEW_RMATRIX[4]*nvec.y + PYMOLVIEW_RMATRIX[7]*nvec.z,
        PYMOLVIEW_RMATRIX[2]*nvec.x + PYMOLVIEW_RMATRIX[5]*nvec.y + PYMOLVIEW_RMATRIX[8]*nvec.z >; 
    nvec + PYMOLVIEW_CAMPOS
  #end

  #macro VEC2CARTSPACE(vec)

    #local nvec = vec - PYMOLVIEW_CAMPOS;

    #local R = PYMOLVIEW_RMATRIX;
    #local invdet = 1/DET( R );

    #local T = array[9];

    #local T[0] = invdet * ( R[4]*R[8] - R[5]*R[7] ); 
    #local T[1] = invdet * ( R[2]*R[7] - R[1]*R[8] ); 
    #local T[2] = invdet * ( R[1]*R[5] - R[2]*R[4] ); 
    #local T[3] = invdet * ( R[5]*R[6] - R[3]*R[8] ); 
    #local T[4] = invdet * ( R[0]*R[8] - R[2]*R[6] ); 
    #local T[5] = invdet * ( R[2]*R[3] - R[0]*R[5] );
    #local T[6] = invdet * ( R[3]*R[7] - R[4]*R[6] );
    #local T[7] = invdet * ( R[1]*R[6] - R[0]*R[7] );
    #local T[8] = invdet * ( R[0]*R[4] - R[1]*R[3] );

    < T[0]*nvec.x + T[3]*nvec.y + T[6]*nvec.z + PYMOLVIEW_ORGPOS.x,
      T[1]*nvec.x + T[4]*nvec.y + T[7]*nvec.z + PYMOLVIEW_ORGPOS.y,
      T[2]*nvec.x + T[5]*nvec.y + T[8]*nvec.z + PYMOLVIEW_ORGPOS.z >
  #end

  #macro VEC2PYMOLVEC(vec)
    < PYMOLVIEW_RMATRIX[0]*vec.x + PYMOLVIEW_RMATRIX[3]*vec.y + PYMOLVIEW_RMATRIX[6]*vec.z,
      PYMOLVIEW_RMATRIX[1]*vec.x + PYMOLVIEW_RMATRIX[4]*vec.y + PYMOLVIEW_RMATRIX[7]*vec.z,
      PYMOLVIEW_RMATRIX[2]*vec.x + PYMOLVIEW_RMATRIX[5]*vec.y + PYMOLVIEW_RMATRIX[8]*vec.z >
  #end

  #macro VEC2CARTVEC(vec)
    #local nvec = vec - PYMOLVIEW_CAMPOS;
  #end

  #macro CAM2PYMOLCAM()

  #end

  #macro CAM2CARTCAM()

  #end
#end