diff --git a/src/main/java/bdv/SpimSource.java b/src/main/java/bdv/SpimSource.java
index f5c8e6c89b8c1d1511367f7cdb9428cb0f90d89b..70b34d0655c43308680cca8e9f692e06d4004e18 100644
--- a/src/main/java/bdv/SpimSource.java
+++ b/src/main/java/bdv/SpimSource.java
@@ -29,15 +29,9 @@ public class SpimSource< T extends NumericType< T > > extends AbstractSpimSource
 			zero.setZero();
 			final View view = sequenceViews.getView( timepoint, setup );
 			final AffineTransform3D reg = view.getModel();
-			final AffineTransform3D mipmapTransform = new AffineTransform3D();
 			for ( int level = 0; level < currentSources.length; level++ )
 			{
-				final double[] resolution = imgLoader.getMipmapResolutions( setup )[ level ];
-				for ( int d = 0; d < 3; ++d )
-				{
-					mipmapTransform.set( resolution[ d ], d, d );
-					mipmapTransform.set( 0.5 * ( resolution[ d ] - 1 ), d, 3 );
-				}
+				final AffineTransform3D mipmapTransform = imgLoader.getMipmapTransforms( setup )[ level ];
 				currentSourceTransforms[ level ].set( reg );
 				currentSourceTransforms[ level ].concatenate( mipmapTransform );
 				currentSources[ level ] = imgLoader.getImage( view, level );
diff --git a/src/main/java/bdv/ViewerImgLoader.java b/src/main/java/bdv/ViewerImgLoader.java
index 5d509c63d0d3a0bb1d6793668ee27518c542cf01..c3d24bd667d36e1337a0c81568b50cc1690d5d84 100644
--- a/src/main/java/bdv/ViewerImgLoader.java
+++ b/src/main/java/bdv/ViewerImgLoader.java
@@ -4,6 +4,7 @@ import mpicbg.spim.data.ImgLoader;
 import mpicbg.spim.data.View;
 import net.imglib2.RandomAccessibleInterval;
 import net.imglib2.Volatile;
+import net.imglib2.realtransform.AffineTransform3D;
 import bdv.img.cache.Cache;
 
 public interface ViewerImgLoader< T, V extends Volatile< T > > extends ImgLoader< T >
@@ -18,6 +19,8 @@ public interface ViewerImgLoader< T, V extends Volatile< T > > extends ImgLoader
 
 	public double[][] getMipmapResolutions( final int setup );
 
+	public AffineTransform3D[] getMipmapTransforms( final int setup );
+
 	public int numMipmapLevels( final int setup );
 
 	public Cache getCache();
diff --git a/src/main/java/bdv/VolatileSpimSource.java b/src/main/java/bdv/VolatileSpimSource.java
index 696847f75c71444a76fcc07dfdea0853ed3af877..d2dfb10d279230c222817119966157e6332ee331 100644
--- a/src/main/java/bdv/VolatileSpimSource.java
+++ b/src/main/java/bdv/VolatileSpimSource.java
@@ -34,15 +34,9 @@ public class VolatileSpimSource< T extends NumericType< T >, V extends Volatile<
 			zero.setZero();
 			final View view = sequenceViews.getView( timepoint, setup );
 			final AffineTransform3D reg = view.getModel();
-			final AffineTransform3D mipmapTransform = new AffineTransform3D();
 			for ( int level = 0; level < currentSources.length; level++ )
 			{
-				final double[] resolution = imgLoader.getMipmapResolutions( setup )[ level ];
-				for ( int d = 0; d < 3; ++d )
-				{
-					mipmapTransform.set( resolution[ d ], d, d );
-					mipmapTransform.set( 0.5 * ( resolution[ d ] - 1 ), d, 3 );
-				}
+				final AffineTransform3D mipmapTransform = imgLoader.getMipmapTransforms( setup )[ level ];
 				currentSourceTransforms[ level ].set( reg );
 				currentSourceTransforms[ level ].concatenate( mipmapTransform );
 				currentSources[ level ] = imgLoader.getVolatileImage( view, level );
diff --git a/src/main/java/bdv/img/hdf5/Hdf5ImageLoader.java b/src/main/java/bdv/img/hdf5/Hdf5ImageLoader.java
index d339e6fdcd24e61741cd5651fbd5fc4a18ff9eb1..526891d2fc8af7b4694f6886620071d11d7161f0 100644
--- a/src/main/java/bdv/img/hdf5/Hdf5ImageLoader.java
+++ b/src/main/java/bdv/img/hdf5/Hdf5ImageLoader.java
@@ -15,6 +15,7 @@ import net.imglib2.RandomAccessibleInterval;
 import net.imglib2.img.NativeImg;
 import net.imglib2.img.basictypeaccess.volatiles.array.VolatileShortArray;
 import net.imglib2.img.cell.CellImg;
+import net.imglib2.realtransform.AffineTransform3D;
 import net.imglib2.sampler.special.ConstantRandomAccessible;
 import net.imglib2.type.NativeType;
 import net.imglib2.type.numeric.integer.UnsignedShortType;
@@ -43,6 +44,8 @@ public class Hdf5ImageLoader extends AbstractViewerImgLoader< UnsignedShortType,
 
 	protected final ArrayList< double[][] > perSetupMipmapResolutions;
 
+	protected final ArrayList< AffineTransform3D[] > perSetupMipmapTransforms;
+
 	protected final ArrayList< int[][] > perSetupSubdivisions;
 
 	/**
@@ -88,6 +91,7 @@ public class Hdf5ImageLoader extends AbstractViewerImgLoader< UnsignedShortType,
 		hdf5Reader = null;
 		cache = null;
 		perSetupMipmapResolutions = new ArrayList< double[][] >();
+		perSetupMipmapTransforms = new ArrayList< AffineTransform3D[] >();
 		perSetupSubdivisions = new ArrayList< int[][] >();
 		partitions = new ArrayList< Partition >();
 		if ( hdf5Partitions != null )
@@ -106,6 +110,7 @@ public class Hdf5ImageLoader extends AbstractViewerImgLoader< UnsignedShortType,
 	{
 		super( new UnsignedShortType(), new VolatileUnsignedShortType() );
 		this.hdf5File = hdf5File;
+		perSetupMipmapTransforms = new ArrayList< AffineTransform3D[] >();
 		perSetupMipmapResolutions = new ArrayList< double[][] >();
 		perSetupSubdivisions = new ArrayList< int[][] >();
 		partitions = new ArrayList< Partition >();
@@ -127,13 +132,27 @@ public class Hdf5ImageLoader extends AbstractViewerImgLoader< UnsignedShortType,
 		perSetupSubdivisions.clear();
 		for ( int setup = 0; setup < numSetups; ++setup )
 		{
-			final double [][] mipmapResolutions = hdf5Reader.readDoubleMatrix( getResolutionsPath( setup ) );
+			final double[][] mipmapResolutions = hdf5Reader.readDoubleMatrix( getResolutionsPath( setup ) );
 			perSetupMipmapResolutions.add( mipmapResolutions );
 			if ( mipmapResolutions.length > maxNumLevels )
 				maxNumLevels = mipmapResolutions.length;
 			maxLevels[ setup ] = mipmapResolutions.length - 1;
 
-			final int [][] subdivisions = hdf5Reader.readIntMatrix( getSubdivisionsPath( setup ) );
+			final AffineTransform3D[] mipmapTransforms = new AffineTransform3D[ mipmapResolutions.length ];
+			for ( int level = 0; level < mipmapResolutions.length; level++ )
+			{
+				final AffineTransform3D mipmapTransform = new AffineTransform3D();
+				final double[] resolution = mipmapResolutions[ level ];
+				for ( int d = 0; d < 3; ++d )
+				{
+					mipmapTransform.set( resolution[ d ], d, d );
+					mipmapTransform.set( 0.5 * ( resolution[ d ] - 1 ), d, 3 );
+				}
+				mipmapTransforms[ level ] = mipmapTransform;
+			}
+			perSetupMipmapTransforms.add( mipmapTransforms );
+
+			final int[][] subdivisions = hdf5Reader.readIntMatrix( getSubdivisionsPath( setup ) );
 			perSetupSubdivisions.add( subdivisions );
 		}
 
@@ -260,6 +279,12 @@ public class Hdf5ImageLoader extends AbstractViewerImgLoader< UnsignedShortType,
 		return perSetupMipmapResolutions.get( setup );
 	}
 
+	@Override
+	public AffineTransform3D[] getMipmapTransforms( final int setup )
+	{
+		return perSetupMipmapTransforms.get( setup );
+	}
+
 	public int[][] getSubdivisions( final int setup )
 	{
 		return perSetupSubdivisions.get( setup );
diff --git a/src/main/java/bdv/img/remote/RemoteImageLoader.java b/src/main/java/bdv/img/remote/RemoteImageLoader.java
index a34b4d4240b9825f8ab03a9b54a1168db06e1140..c6d937387e3911be48c38ff2b2fcc87c5f21ed89 100644
--- a/src/main/java/bdv/img/remote/RemoteImageLoader.java
+++ b/src/main/java/bdv/img/remote/RemoteImageLoader.java
@@ -4,6 +4,7 @@ import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.URL;
+import java.util.ArrayList;
 
 import mpicbg.spim.data.View;
 import net.imglib2.FinalInterval;
@@ -11,6 +12,7 @@ import net.imglib2.RandomAccessibleInterval;
 import net.imglib2.img.NativeImg;
 import net.imglib2.img.basictypeaccess.volatiles.array.VolatileShortArray;
 import net.imglib2.img.cell.CellImg;
+import net.imglib2.realtransform.AffineTransform3D;
 import net.imglib2.sampler.special.ConstantRandomAccessible;
 import net.imglib2.type.NativeType;
 import net.imglib2.type.numeric.integer.UnsignedShortType;
@@ -35,6 +37,8 @@ public class RemoteImageLoader extends AbstractViewerImgLoader< UnsignedShortTyp
 
 	protected RemoteImageLoaderMetaData metadata;
 
+	protected final ArrayList< AffineTransform3D[] > perSetupMipmapTransforms;
+
 	protected int[][] cellsDimensions;
 
 	protected VolatileGlobalCellCache< VolatileShortArray > cache;
@@ -42,6 +46,7 @@ public class RemoteImageLoader extends AbstractViewerImgLoader< UnsignedShortTyp
 	public RemoteImageLoader()
 	{
 		super( new UnsignedShortType(), new VolatileUnsignedShortType() );
+		perSetupMipmapTransforms = new ArrayList< AffineTransform3D[] >();
 	}
 
 	private void open() throws IOException
@@ -57,6 +62,23 @@ public class RemoteImageLoader extends AbstractViewerImgLoader< UnsignedShortTyp
 				metadata.maxNumLevels,
 				metadata.maxLevels,
 				10 );
+		for ( int setup = 0; setup < metadata.numSetups; ++setup )
+		{
+			final double[][] mipmapResolutions = metadata.perSetupMipmapResolutions.get( setup );
+			final AffineTransform3D[] mipmapTransforms = new AffineTransform3D[ mipmapResolutions.length ];
+			for ( int level = 0; level < mipmapResolutions.length; level++ )
+			{
+				final AffineTransform3D mipmapTransform = new AffineTransform3D();
+				final double[] resolution = mipmapResolutions[ level ];
+				for ( int d = 0; d < 3; ++d )
+				{
+					mipmapTransform.set( resolution[ d ], d, d );
+					mipmapTransform.set( 0.5 * ( resolution[ d ] - 1 ), d, 3 );
+				}
+				mipmapTransforms[ level ] = mipmapTransform;
+			}
+			perSetupMipmapTransforms.add( mipmapTransforms );
+		}
 		cellsDimensions = metadata.createCellsDimensions();
 	}
 
@@ -114,6 +136,12 @@ public class RemoteImageLoader extends AbstractViewerImgLoader< UnsignedShortTyp
 		return metadata.perSetupMipmapResolutions.get( setup );
 	}
 
+	@Override
+	public AffineTransform3D[] getMipmapTransforms( final int setup )
+	{
+		return perSetupMipmapTransforms.get( setup );
+	}
+
 	public int[][] getSubdivisions( final int setup )
 	{
 		return metadata.perSetupSubdivisions.get( setup );