diff --git a/hydra_app/input.cpp b/hydra_app/input.cpp
index a3030ce..650cd15 100644
--- a/hydra_app/input.cpp
+++ b/hydra_app/input.cpp
@@ -13,7 +13,7 @@ Input::Input()
   //noWindow      = false;         ///< run 'console_main', else run 'window_main'
   //inLibraryPath = "tests/test_42"; ///< cornell box with teapot
   //inLibraryPath = "tests/test_223_small"; ///< cornell box with sphere
-  inLibraryPath = "tests/test_224_sphere";
+  //inLibraryPath = "tests/test_224_sphere";
   //inLibraryPath = "tests/test_224_sphere_microfacet";
   //inLibraryPath = "/media/frol/886234F06234E49A/scenes/benchmark4"; ///< cornell box with mirror glossy back wall
   //inLibraryPath = "/media/frol/886234F06234E49A/scenes/phong_test/torspar1";
@@ -31,13 +31,15 @@ Input::Input()
   //inLibraryPath = "D:/[archive]/2017/HydraAPP/hydra_app/tests/hydra_benchmark_07";
   //inLibraryPath = "D:/[archive]/2017/HydraOldRepo/HydraAPP/home/frol/hydra/rendered_images/a_3602.png/hydra_app/tests/hydra_benchmark_07";
   //inLibraryPath = "/home/frol/PROG/HydraAPI/main/tests/test_77";
-  //inLibraryPath = "/home/frol/PROG/HydraAPI/main/tests_f/test_202";
+  inLibraryPath = "/home/frol/PROG/HydraAPI/main/tests_f/test_403";
 
   //inLibraryPath = "C:/[Hydra]/pluginFiles/scenelib";
   //inLibraryPath   = "/media/frol/6E0467C0046789C3/[Hydra]/pluginFiles/scenelib";
   //inLibraryPath = "D:/temp/scenelib/"; 
   //inLibraryPath = "/home/frol/PROG/HydraAPI/main/tests/test_76";
   //inLibraryPath = "/home/frol/temp/scenelib";
+  //inLibraryPath = "/home/frol/temp/scenelib_thinSphere";
+  //inLibraryPath = "/home/frol/PROG/HydraCore/hydra_app/tests/test_pool";
 
   inDevelopment = true;  ///< recompile shaders each time; note that nvidia have their own shader cache!
   inDeviceId    = 0;     ///< opencl device id
diff --git a/hydra_drv/CPUExp_IntegratorSSS.cpp b/hydra_drv/CPUExp_IntegratorSSS.cpp
index 09d4a4d..7528dbf 100644
--- a/hydra_drv/CPUExp_IntegratorSSS.cpp
+++ b/hydra_drv/CPUExp_IntegratorSSS.cpp
@@ -103,7 +103,7 @@ std::tuple<MatSample, int, float3> IntegratorStupidPTSSS::sampleAndEvalBxDF(floa
 		return std::make_tuple(res, 0, float3(1, 1, 1));
 	}
 	else
-		return IntegratorCommon::sampleAndEvalBxDF(ray_dir, surfElem, flags, shadow);
+		return IntegratorCommon::sampleAndEvalBxDF(ray_dir, surfElem, flags, false, shadow);
 }
 
 float3 SampleHenyeyGreenstein(const float g, const float e1, const float e2)
@@ -303,7 +303,7 @@ std::tuple<MatSample, int, float3> IntegratorShadowPTSSS::sampleAndEvalBxDF(floa
 		return std::make_tuple(res, 0, float3(1, 1, 1));
 	}
 	else
-		return IntegratorCommon::sampleAndEvalBxDF(ray_dir, surfElem, flags, shadow);
+		return IntegratorCommon::sampleAndEvalBxDF(ray_dir, surfElem, flags, false, shadow);
 }
 
 
@@ -537,7 +537,7 @@ std::tuple<MatSample, int, float3> IntegratorShadowPTSSS::sampleAndEvalBxDF(floa
 		return std::make_tuple(res, 0, float3(1, 1, 1));
 	}
 	else
-		return IntegratorCommon::sampleAndEvalBxDF(ray_dir, surfElem, flags, shadow);
+		return IntegratorCommon::sampleAndEvalBxDF(ray_dir, surfElem, flags, false, shadow);
 }
 
 float3  IntegratorShadowPTSSS::PathTrace(float3 ray_pos, float3 ray_dir, MisData misPrev, int a_currDepth, uint flags)
diff --git a/hydra_drv/CPUExp_Integrators.h b/hydra_drv/CPUExp_Integrators.h
index 3f90950..912945d 100644
--- a/hydra_drv/CPUExp_Integrators.h
+++ b/hydra_drv/CPUExp_Integrators.h
@@ -250,7 +250,7 @@ class IntegratorCommon : public Integrator
   virtual std::tuple<float3, float3> makeEyeRay3(float4 lensOffs);
 
   float3 emissionEval(float3 ray_pos, float3 ray_dir, const SurfaceHit& surfElem, uint flags, const MisData misPrev, const int a_instId);
-  virtual std::tuple<MatSample, int, float3> sampleAndEvalBxDF(float3 ray_dir, const SurfaceHit& surfElem, uint flags = 0, float3 shadow = float3(0,0,0), bool mmltMode = false);
+  virtual std::tuple<MatSample, int, float3> sampleAndEvalBxDF(float3 ray_dir, const SurfaceHit& surfElem, uint flags = 0, bool a_fwdDir = false, float3 shadow = float3(0,0,0), bool mmltMode = false);
 
   GBufferAll     gbufferSample(float3 ray_pos, float3 ray_dir);
 
diff --git a/hydra_drv/CPUExp_Integrators_Common.cpp b/hydra_drv/CPUExp_Integrators_Common.cpp
index 143df7f..4217b7b 100644
--- a/hydra_drv/CPUExp_Integrators_Common.cpp
+++ b/hydra_drv/CPUExp_Integrators_Common.cpp
@@ -532,7 +532,7 @@ RandomGen& IntegratorCommon::randomGen()
   return m_perThread[omp_get_thread_num()].gen;
 }
 
-std::tuple<MatSample, int, float3> IntegratorCommon::sampleAndEvalBxDF(float3 ray_dir, const SurfaceHit& surfElem, uint flags, float3 shadow, bool a_mmltMode)
+std::tuple<MatSample, int, float3> IntegratorCommon::sampleAndEvalBxDF(float3 ray_dir, const SurfaceHit& surfElem, uint flags, bool a_fwdDir, float3 shadow, bool a_mmltMode)
 {
   const PlainMaterial* pHitMaterial = materialAt(m_pGlobals, m_matStorage, surfElem.matId);
   auto& gen = randomGen();
@@ -552,7 +552,7 @@ std::tuple<MatSample, int, float3> IntegratorCommon::sampleAndEvalBxDF(float3 ra
             allRands);
 
   MatSample brdfSample; int matOffset;
-  MaterialSampleAndEvalBxDF(pHitMaterial, allRands, &surfElem, ray_dir, shadow, flags,
+  MaterialSampleAndEvalBxDF(pHitMaterial, allRands, &surfElem, ray_dir, shadow, flags, a_fwdDir,
                             m_pGlobals, m_texStorage, m_texStorageAux, &m_ptlDummy, 
                             &brdfSample, &matOffset);
 
diff --git a/hydra_drv/CPUExp_Integrators_MMLT.cpp b/hydra_drv/CPUExp_Integrators_MMLT.cpp
index 64fcd0a..bfa7bf6 100644
--- a/hydra_drv/CPUExp_Integrators_MMLT.cpp
+++ b/hydra_drv/CPUExp_Integrators_MMLT.cpp
@@ -703,7 +703,7 @@ void IntegratorMMLT::TraceLightPath(float3 ray_pos, float3 ray_dir, int a_currDe
     a_perThread->pdfArray[a_currDepth].pdfFwd = -1.0f*GTermPrev;
 
   const PlainMaterial* pHitMaterial = materialAt(m_pGlobals, m_matStorage, surfElem.matId);
-  const MatSample      matSam       = std::get<0>(sampleAndEvalBxDF(ray_dir, surfElem, packBounceNum(0, a_currDepth - 1), float3(0, 0, 0), true));
+  const MatSample      matSam       = std::get<0>(sampleAndEvalBxDF(ray_dir, surfElem, packBounceNum(0, a_currDepth - 1), true, float3(0, 0, 0), true));
 
   // calc new ray
   //
@@ -869,7 +869,7 @@ PathVertex IntegratorMMLT::CameraPath(float3 ray_pos, float3 ray_dir, MisData a_
   // (3) eval reverse and forward pdfs
   //
   const PlainMaterial* pHitMaterial = materialAt(m_pGlobals, m_matStorage, surfElem.matId);
-  const MatSample matSam = std::get<0>(sampleAndEvalBxDF(ray_dir, surfElem, packBounceNum(0, a_currDepth - 1), float3(0, 0, 0), true));
+  const MatSample matSam = std::get<0>(sampleAndEvalBxDF(ray_dir, surfElem, packBounceNum(0, a_currDepth - 1), false, float3(0, 0, 0), true));
   const float3 bxdfVal   = matSam.color; // *(1.0f / fmaxf(matSam.pdf, 1e-20f));
   const float cosNext    = fabs(dot(matSam.direction, surfElem.normal));
 
diff --git a/hydra_drv/CPUExp_bxdf.h b/hydra_drv/CPUExp_bxdf.h
index cad823f..ea3ef11 100644
--- a/hydra_drv/CPUExp_bxdf.h
+++ b/hydra_drv/CPUExp_bxdf.h
@@ -323,7 +323,7 @@ std::tuple<MatSample, int, float3> IntegratorShadowPTSSS::sampleAndEvalGGXBxDF(f
 		return std::make_tuple(res, 0, float3(1, 1, 1));
 	}
 	else
-		return IntegratorCommon::sampleAndEvalBxDF(ray_dir, surfElem, flags, shadow);
+		return IntegratorCommon::sampleAndEvalBxDF(ray_dir, surfElem, flags, false, shadow);
 }
 
 
diff --git a/hydra_drv/cmaterial.h b/hydra_drv/cmaterial.h
index 66ea96c..30e1943 100644
--- a/hydra_drv/cmaterial.h
+++ b/hydra_drv/cmaterial.h
@@ -490,6 +490,7 @@ typedef struct RefractResultT
 
   float3 ray_dir;
   bool   success;
+  float  eta;
 
 }RefractResult;
 
@@ -522,11 +523,15 @@ static inline RefractResult myrefract(float3 ray_dir, float3 a_normal, float a_m
   RefractResult res;
   res.ray_dir = ray_dir;
   res.success = refrSuccess;
+  if (refrSuccess)
+    res.eta = eta;
+  else
+    res.eta = 1.0f;
   return res;
 }
 
-static inline void GlassSampleAndEvalBRDF(__global const PlainMaterial* a_pMat, const float3 rands, const float3 ray_dir, float3 a_normal, const float2 a_texCoord, const bool a_hitFromInside,
-                                          __global const EngineGlobals* a_globals, texture2d_t a_tex, __private const ProcTextureList* a_ptList,
+static inline void GlassSampleAndEvalBRDF(__global const PlainMaterial* a_pMat, const float3 rands, const float3 ray_dir, float3 a_normal, const float2 a_texCoord, const bool a_hitFromInside, 
+                                          __global const EngineGlobals* a_globals, texture2d_t a_tex, __private const ProcTextureList* a_ptList, const bool a_isFwdDir,
                                           __private MatSample* a_out)
 {
   const float3 normal2 = a_hitFromInside ? (-1.0f)*a_normal : a_normal;
@@ -555,10 +560,13 @@ static inline void GlassSampleAndEvalBRDF(__global const PlainMaterial* a_pMat,
 
   const float cosThetaOut = dot(refractData.ray_dir, a_normal);
   const float cosMult     = 1.0f / fmax(fabs(cosThetaOut), 1e-6f);
+                                                                                     // only camera paths are multiplied by this factor, and etas
+                                                                                     // are swapped because radiance flows in the opposite direction
+  const float adjointBsdfMult = a_isFwdDir ? 1.0f : refractData.eta*refractData.eta; // see SmallVCM and or Veach adjoint bsdf
 
   a_out->direction    = refractData.ray_dir;
   a_out->pdf          = pdf;
-  a_out->color        = refractData.success ? fVal*clamp(glassGetColor(a_pMat)*texColor, 0.0f, 1.0f)*cosMult : make_float3(1.0f, 1.0f, 1.0f)*cosMult;
+  a_out->color        = refractData.success ? fVal*clamp(glassGetColor(a_pMat)*texColor, 0.0f, 1.0f)*cosMult*adjointBsdfMult : make_float3(1.0f, 1.0f, 1.0f)*cosMult;
 
   if(spec)
     a_out->flags = (RAY_EVENT_S | RAY_EVENT_T);
@@ -1304,7 +1312,7 @@ static inline float3 BumpMapping(const float3 tangent, const float3 bitangent, c
   return  normalize(mul3x3x3(inverse(tangentTransform), normalTS));
 }
 
-static inline void MaterialLeafSampleAndEvalBRDF(__global const PlainMaterial* pMat, __private const SurfaceHit* pSurfHit, const float3 ray_dir, const float3 rands, const float3 a_shadow, 
+static inline void MaterialLeafSampleAndEvalBRDF(__global const PlainMaterial* pMat, __private const SurfaceHit* pSurfHit, const float3 ray_dir, const float3 rands, const float3 a_shadow, const bool a_isFwdDir, 
                                                  __global const EngineGlobals* a_globals, texture2d_t a_tex, texture2d_t a_texNormal, __private const ProcTextureList* a_ptList,
                                                  __private MatSample* a_out)
 {
@@ -1348,7 +1356,7 @@ static inline void MaterialLeafSampleAndEvalBRDF(__global const PlainMaterial* p
                                a_out);
     break;
   case PLAIN_MAT_CLASS_GLASS: 
-    GlassSampleAndEvalBRDF(pMat, rands, ray_dir, hitNorm, pSurfHit->texCoord, pSurfHit->hfi, a_globals, a_tex, a_ptList,
+    GlassSampleAndEvalBRDF(pMat, rands, ray_dir, hitNorm, pSurfHit->texCoord, pSurfHit->hfi, a_globals, a_tex, a_ptList, a_isFwdDir,
                            a_out);
     break;
 
@@ -1399,7 +1407,7 @@ Sample and eval layered material (with blends). Store result in a_out.
 
 */
 static inline void MaterialSampleAndEvalBxDF(__global const PlainMaterial* pMat, __private float a_rands[MMLT_FLOATS_PER_BOUNCE], 
-                                             __private const SurfaceHit* pSurfHit, const float3 a_rayDir, const float3 a_shadow, const uint rayFlags,
+                                             __private const SurfaceHit* pSurfHit, const float3 a_rayDir, const float3 a_shadow, const uint rayFlags, const bool a_isFwdDir,
                                              __global const EngineGlobals* a_globals, texture2d_t a_tex, texture2d_t a_texNormal, __private const ProcTextureList* a_ptList,
                                              __private MatSample* a_out, __private int* pLocalOffset)
 {
@@ -1413,7 +1421,7 @@ static inline void MaterialSampleAndEvalBxDF(__global const PlainMaterial* pMat,
   __global const PlainMaterial* pMatLeaf = pMat + mixSelector.localOffs;
   (*pLocalOffset)                        = mixSelector.localOffs;
   
-  MaterialLeafSampleAndEvalBRDF(pMatLeaf, pSurfHit, a_rayDir, make_float3(a_rands[0], a_rands[1], a_rands[2]), a_shadow, 
+  MaterialLeafSampleAndEvalBRDF(pMatLeaf, pSurfHit, a_rayDir, make_float3(a_rands[0], a_rands[1], a_rands[2]), a_shadow, a_isFwdDir,
                                 a_globals, a_tex, a_texNormal, a_ptList,
                                 a_out);
 
diff --git a/hydra_drv/shaders/material.cl b/hydra_drv/shaders/material.cl
index 2049482..c4ac32a 100644
--- a/hydra_drv/shaders/material.cl
+++ b/hydra_drv/shaders/material.cl
@@ -831,7 +831,7 @@ __kernel void NextBounce(__global   float4*        restrict a_rpos,
   const float3 shadowVal = decompressShadow(in_shadow[tid]);
 
   MatSample brdfSample; int localOffset = 0; 
-  MaterialSampleAndEvalBxDF(pHitMaterial, allRands, &surfHit, ray_dir, shadowVal, flags,
+  MaterialSampleAndEvalBxDF(pHitMaterial, allRands, &surfHit, ray_dir, shadowVal, flags, ((a_globals->g_flags & HRT_FORWARD_TRACING) != 0),
                             a_globals, in_texStorage1, in_texStorage2, &ptl, 
                             &brdfSample, &localOffset);
                             
diff --git a/hydra_drv/shaders/mlt.cl b/hydra_drv/shaders/mlt.cl
index 31d64a5..24a1a21 100644
--- a/hydra_drv/shaders/mlt.cl
+++ b/hydra_drv/shaders/mlt.cl
@@ -819,7 +819,7 @@ __kernel void MMLTCameraPathBounce(__global   float4*        restrict a_rpos,
   int matOffset = materialOffset(a_globals, surfElem.matId);
 
   MatSample matSam; int localOffset = 0; 
-  MaterialSampleAndEvalBxDF(pHitMaterial, allRands, &surfElem, ray_dir, make_float3(1,1,1), flags,
+  MaterialSampleAndEvalBxDF(pHitMaterial, allRands, &surfElem, ray_dir, make_float3(1,1,1), flags, false,
                             a_globals, in_texStorage1, in_texStorage2, &ptl, 
                             &matSam, &localOffset);
   
@@ -1101,7 +1101,7 @@ __kernel void MMLTLightPathBounce (__global   float4*        restrict a_rpos,
   int matOffset = materialOffset(a_globals, surfElem.matId);
   
   MatSample matSam; int localOffset = 0; 
-  MaterialSampleAndEvalBxDF(pHitMaterial, allRands, &surfElem, ray_dir, make_float3(1,1,1), flags,
+  MaterialSampleAndEvalBxDF(pHitMaterial, allRands, &surfElem, ray_dir, make_float3(1,1,1), flags, true,
                             a_globals, in_texStorage1, in_texStorage2, &ptl, 
                             &matSam, &localOffset);