diff --git a/src/Graphic3d/Graphic3d_Aspects.hxx b/src/Graphic3d/Graphic3d_Aspects.hxx
index 8675df890d..70aa6a2779 100644
--- a/src/Graphic3d/Graphic3d_Aspects.hxx
+++ b/src/Graphic3d/Graphic3d_Aspects.hxx
@@ -286,6 +286,19 @@ public:
   //! Set marker's image texture.
   void SetMarkerImage (const Handle(Graphic3d_MarkerImage)& theImage) { myMarkerImage = theImage; }
 
+  //! Returns TRUE if marker should be drawn using marker sprite (either user-provided or generated).
+  bool IsMarkerSprite() const
+  {
+    if (myMarkerType == Aspect_TOM_POINT
+     || myMarkerType == Aspect_TOM_EMPTY)
+    {
+      return false;
+    }
+
+    return myMarkerType != Aspect_TOM_USERDEFINED
+       || !myMarkerImage.IsNull();
+  }
+
 //! @name parameters specific to text rendering
 public:
 
diff --git a/src/Graphic3d/Graphic3d_ShaderProgram.cxx b/src/Graphic3d/Graphic3d_ShaderProgram.cxx
index c7638c16f1..5e5d4c7a0a 100755
--- a/src/Graphic3d/Graphic3d_ShaderProgram.cxx
+++ b/src/Graphic3d/Graphic3d_ShaderProgram.cxx
@@ -80,6 +80,7 @@ Graphic3d_ShaderProgram::Graphic3d_ShaderProgram()
 : myNbLightsMax (THE_MAX_LIGHTS_DEFAULT),
   myNbClipPlanesMax (THE_MAX_CLIP_PLANES_DEFAULT),
   myNbFragOutputs (THE_NB_FRAG_OUTPUTS),
+  myHasDefSampler (true),
   myHasAlphaTest (false),
   myHasWeightOitOutput (false)
 {
diff --git a/src/Graphic3d/Graphic3d_ShaderProgram.hxx b/src/Graphic3d/Graphic3d_ShaderProgram.hxx
index 96d13e8830..c44ba1205f 100755
--- a/src/Graphic3d/Graphic3d_ShaderProgram.hxx
+++ b/src/Graphic3d/Graphic3d_ShaderProgram.hxx
@@ -138,6 +138,12 @@ public:
   //! Note that this flag is designed for usage with - custom shader program may discard fragment regardless this flag.
   void SetAlphaTest (Standard_Boolean theAlphaTest) { myHasAlphaTest = theAlphaTest; }
 
+  //! Return TRUE if standard program header should define default texture sampler occSampler0; TRUE by default for compatibility.
+  Standard_Boolean HasDefaultSampler() const { return myHasDefSampler; }
+
+  //! Set if standard program header should define default texture sampler occSampler0.
+  void SetDefaultSampler (Standard_Boolean theHasDefSampler) { myHasDefSampler = theHasDefSampler; }
+
   //! Return true if Fragment Shader color should output the weighted OIT coverage; FALSE by default.
   Standard_Boolean HasWeightOitOutput() const { return myHasWeightOitOutput; }
 
@@ -195,6 +201,7 @@ private:
   Standard_Integer              myNbLightsMax;   //!< length of array of light sources (THE_MAX_LIGHTS)
   Standard_Integer              myNbClipPlanesMax; //!< length of array of clipping planes (THE_MAX_CLIP_PLANES)
   Standard_Integer              myNbFragOutputs; //!< length of array of Fragment Shader outputs (THE_NB_FRAG_OUTPUTS)
+  Standard_Boolean              myHasDefSampler; //!< flag indicating that program defines default texture sampler occSampler0
   Standard_Boolean              myHasAlphaTest;       //!< flag indicating that Fragment Shader performs alpha test
   Standard_Boolean              myHasWeightOitOutput; //!< flag indicating that Fragment Shader includes weighted OIT coverage
 
diff --git a/src/OpenGl/OpenGl_Aspects.cxx b/src/OpenGl/OpenGl_Aspects.cxx
index 080c7edc0c..13cf990279 100644
--- a/src/OpenGl/OpenGl_Aspects.cxx
+++ b/src/OpenGl/OpenGl_Aspects.cxx
@@ -86,9 +86,13 @@ void OpenGl_Aspects::SetAspect (const Handle(Graphic3d_Aspects)& theAspect)
                  : Graphic3d_TOSM_UNLIT;
 
   // invalidate resources
-  myResTextureSet.UpdateRediness (myAspect->TextureSet());
+  myResTextureSet.UpdateRediness (myAspect);
   myResSprite.UpdateRediness (myAspect);
   myResProgram.UpdateRediness (myAspect);
+  if (!myResSprite.IsReady())
+  {
+    myResTextureSet.Invalidate();
+  }
 }
 
 // =======================================================================
diff --git a/src/OpenGl/OpenGl_Aspects.hxx b/src/OpenGl/OpenGl_Aspects.hxx
index a711c78445..9e881dfebc 100644
--- a/src/OpenGl/OpenGl_Aspects.hxx
+++ b/src/OpenGl/OpenGl_Aspects.hxx
@@ -45,9 +45,12 @@ public:
   void SetNoLighting() { myShadingModel = Graphic3d_TOSM_UNLIT; }
 
   //! Returns textures map.
-  const Handle(OpenGl_TextureSet)& TextureSet (const Handle(OpenGl_Context)& theCtx) const
+  const Handle(OpenGl_TextureSet)& TextureSet (const Handle(OpenGl_Context)& theCtx,
+                                               bool theToHighlight = false) const
   {
-    return myResTextureSet.TextureSet (theCtx, myAspect->TextureSet());
+    const Handle(OpenGl_PointSprite)& aSprite  = myResSprite.Sprite (theCtx, myAspect, false);
+    const Handle(OpenGl_PointSprite)& aSpriteA = myResSprite.Sprite (theCtx, myAspect, true);
+    return myResTextureSet.TextureSet (theCtx, myAspect, aSprite, aSpriteA, theToHighlight);
   }
 
   //! Init and return OpenGl shader program resource.
@@ -60,18 +63,24 @@ public:
   //! @return marker size
   Standard_ShortReal MarkerSize() const { return myResSprite.MarkerSize(); }
 
-  //! Init and return OpenGl point sprite resource.
-  //! @return point sprite texture.
-  const Handle(OpenGl_TextureSet)& SpriteRes (const Handle(OpenGl_Context)& theCtx) const
+  //! Return TRUE if OpenGl point sprite resource defines texture.
+  bool HasPointSprite (const Handle(OpenGl_Context)& theCtx) const
   {
-    return myResSprite.Sprite (theCtx, myAspect);
+    return myResSprite.HasPointSprite (theCtx, myAspect);
   }
 
-  //! Init and return OpenGl highlight point sprite resource.
-  //! @return point sprite texture for highlight.
-  const Handle(OpenGl_TextureSet)& SpriteHighlightRes (const Handle(OpenGl_Context)& theCtx) const
+  //! Return TRUE if OpenGl point sprite resource defined by obsolete Display List (bitmap).
+  bool IsDisplayListSprite (const Handle(OpenGl_Context)& theCtx) const
   {
-    return myResSprite.SpriteA (theCtx, myAspect);
+    return myResSprite.IsDisplayListSprite (theCtx, myAspect);
+  }
+
+  //! Init and return OpenGl point sprite resource.
+  //! @return point sprite texture.
+  const Handle(OpenGl_PointSprite)& SpriteRes (const Handle(OpenGl_Context)& theCtx,
+                                               bool theIsAlphaSprite) const
+  {
+    return myResSprite.Sprite (theCtx, myAspect, theIsAlphaSprite);
   }
 
   Standard_EXPORT virtual void Render  (const Handle(OpenGl_Workspace)& theWorkspace) const Standard_OVERRIDE;
diff --git a/src/OpenGl/OpenGl_AspectsSprite.cxx b/src/OpenGl/OpenGl_AspectsSprite.cxx
index b779522e16..646f7281cb 100644
--- a/src/OpenGl/OpenGl_AspectsSprite.cxx
+++ b/src/OpenGl/OpenGl_AspectsSprite.cxx
@@ -1450,21 +1450,21 @@ void OpenGl_AspectsSprite::Release (OpenGl_Context* theCtx)
 
   if (theCtx != NULL)
   {
-    if (mySprite->First()->ResourceId().IsEmpty())
+    if (mySprite->ResourceId().IsEmpty())
     {
-      theCtx->DelayedRelease (mySprite->ChangeFirst());
-      theCtx->DelayedRelease (mySpriteA->ChangeFirst());
+      theCtx->DelayedRelease (mySprite);
+      theCtx->DelayedRelease (mySpriteA);
     }
     else
     {
       {
-        const TCollection_AsciiString aSpriteKey = mySprite->First()->ResourceId();
+        const TCollection_AsciiString aSpriteKey = mySprite->ResourceId();
         mySprite.Nullify(); // we need nullify all handles before ReleaseResource() call
         theCtx->ReleaseResource (aSpriteKey,  Standard_True);
       }
       if (!mySpriteA.IsNull())
       {
-        const TCollection_AsciiString aSpriteKeyA = mySpriteA->First()->ResourceId();
+        const TCollection_AsciiString aSpriteKeyA = mySpriteA->ResourceId();
         mySpriteA.Nullify();
         theCtx->ReleaseResource (aSpriteKeyA, Standard_True);
       }
@@ -1474,6 +1474,36 @@ void OpenGl_AspectsSprite::Release (OpenGl_Context* theCtx)
   mySpriteA.Nullify();
 }
 
+// =======================================================================
+// function : HasPointSprite
+// purpose  :
+// =======================================================================
+bool OpenGl_AspectsSprite::HasPointSprite (const Handle(OpenGl_Context)& theCtx,
+                                           const Handle(Graphic3d_Aspects)& theAspects)
+{
+  const Handle(OpenGl_PointSprite)& aSprite = Sprite (theCtx, theAspects, false);
+  return !aSprite.IsNull()
+      && !aSprite->IsDisplayList();
+}
+
+// =======================================================================
+// function : IsDisplayListSprite
+// purpose  :
+// =======================================================================
+bool OpenGl_AspectsSprite::IsDisplayListSprite (const Handle(OpenGl_Context)& theCtx,
+                                                const Handle(Graphic3d_Aspects)& theAspects)
+{
+#if !defined(GL_ES_VERSION_2_0)
+  const Handle(OpenGl_PointSprite)& aSprite = Sprite (theCtx, theAspects, false);
+  return !aSprite.IsNull()
+       && aSprite->IsDisplayList();
+#else
+  (void )theCtx;
+  (void )theAspects;
+  return false;
+#endif
+}
+
 // =======================================================================
 // function : UpdateRediness
 // purpose  :
@@ -1483,8 +1513,8 @@ void OpenGl_AspectsSprite::UpdateRediness (const Handle(Graphic3d_Aspects)& theA
   // update sprite resource bindings
   TCollection_AsciiString aSpriteKeyNew, aSpriteAKeyNew;
   spriteKeys (theAspect->MarkerImage(), theAspect->MarkerType(), theAspect->MarkerScale(), theAspect->ColorRGBA(), aSpriteKeyNew, aSpriteAKeyNew);
-  const TCollection_AsciiString& aSpriteKeyOld  = !mySprite.IsNull()  ? mySprite ->First()->ResourceId() : THE_EMPTY_KEY;
-  const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->First()->ResourceId() : THE_EMPTY_KEY;
+  const TCollection_AsciiString& aSpriteKeyOld  = !mySprite.IsNull()  ? mySprite ->ResourceId() : THE_EMPTY_KEY;
+  const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY;
   if (aSpriteKeyNew.IsEmpty()  || aSpriteKeyOld  != aSpriteKeyNew
    || aSpriteAKeyNew.IsEmpty() || aSpriteAKeyOld != aSpriteAKeyNew)
   {
@@ -1493,6 +1523,24 @@ void OpenGl_AspectsSprite::UpdateRediness (const Handle(Graphic3d_Aspects)& theA
   }
 }
 
+// =======================================================================
+// function : Sprite
+// purpose  :
+// =======================================================================
+const Handle(OpenGl_PointSprite)& OpenGl_AspectsSprite::Sprite (const Handle(OpenGl_Context)& theCtx,
+                                                                const Handle(Graphic3d_Aspects)& theAspects,
+                                                                bool theIsAlphaSprite)
+{
+  if (!myIsSpriteReady)
+  {
+    build (theCtx, theAspects->MarkerImage(), theAspects->MarkerType(), theAspects->MarkerScale(), theAspects->ColorRGBA(), myMarkerSize);
+    myIsSpriteReady = true;
+  }
+  return theIsAlphaSprite && !mySpriteA.IsNull() && mySpriteA->IsValid()
+       ? mySpriteA
+       : mySprite;
+}
+
 // =======================================================================
 // function : build
 // purpose  :
@@ -1508,8 +1556,8 @@ void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
   TCollection_AsciiString aNewKey, aNewKeyA;
   spriteKeys (theMarkerImage, theType, theScale, theColor, aNewKey, aNewKeyA);
 
-  const TCollection_AsciiString& aSpriteKeyOld  = !mySprite.IsNull()  ? mySprite ->First()->ResourceId() : THE_EMPTY_KEY;
-  const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->First()->ResourceId() : THE_EMPTY_KEY;
+  const TCollection_AsciiString& aSpriteKeyOld  = !mySprite.IsNull()  ? mySprite ->ResourceId() : THE_EMPTY_KEY;
+  const TCollection_AsciiString& aSpriteAKeyOld = !mySpriteA.IsNull() ? mySpriteA->ResourceId() : THE_EMPTY_KEY;
 
   // release old shared resources
   const Standard_Boolean aNewResource = aNewKey.IsEmpty()
@@ -1518,14 +1566,14 @@ void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
   {
     if (!mySprite.IsNull())
     {
-      if (mySprite->First()->ResourceId().IsEmpty())
+      if (mySprite->ResourceId().IsEmpty())
       {
-        theCtx->DelayedRelease (mySprite->ChangeFirst());
+        theCtx->DelayedRelease (mySprite);
         mySprite.Nullify();
       }
       else
       {
-        const TCollection_AsciiString anOldKey = mySprite->First()->ResourceId();
+        const TCollection_AsciiString anOldKey = mySprite->ResourceId();
         mySprite.Nullify(); // we need nullify all handles before ReleaseResource() call
         theCtx->ReleaseResource (anOldKey, Standard_True);
       }
@@ -1535,14 +1583,14 @@ void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
   {
     if (!mySpriteA.IsNull())
     {
-      if (mySpriteA->First()->ResourceId().IsEmpty())
+      if (mySpriteA->ResourceId().IsEmpty())
       {
-        theCtx->DelayedRelease (mySpriteA->ChangeFirst());
+        theCtx->DelayedRelease (mySpriteA);
         mySpriteA.Nullify();
       }
       else
       {
-        const TCollection_AsciiString anOldKey = mySpriteA->First()->ResourceId();
+        const TCollection_AsciiString anOldKey = mySpriteA->ResourceId();
         mySpriteA.Nullify(); // we need nullify all handles before ReleaseResource() call
         theCtx->ReleaseResource (anOldKey, Standard_True);
       }
@@ -1551,7 +1599,7 @@ void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
 
   if (!aNewResource)
   {
-    const OpenGl_PointSprite* aSprite = dynamic_cast<OpenGl_PointSprite*> (mySprite->First().get());
+    const OpenGl_PointSprite* aSprite = dynamic_cast<OpenGl_PointSprite*> (mySprite.get());
     if (!aSprite->IsDisplayList())
     {
       theMarkerSize = Standard_ShortReal (Max (aSprite->SizeX(), aSprite->SizeY()));
@@ -1566,13 +1614,8 @@ void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
     return;
   }
 
-  if (mySprite.IsNull())
-  {
-    mySprite  = new OpenGl_TextureSet (1);
-    mySpriteA = new OpenGl_TextureSet (1);
-  }
-
-  Handle(OpenGl_PointSprite) aSprite, aSpriteA;
+  Handle(OpenGl_PointSprite)& aSprite  = mySprite;
+  Handle(OpenGl_PointSprite)& aSpriteA = mySpriteA;
   if (!aNewKey.IsEmpty()
    && theCtx->GetResource<Handle(OpenGl_PointSprite)> (aNewKeyA, aSpriteA) // alpha sprite could be shared
    && theCtx->GetResource<Handle(OpenGl_PointSprite)> (aNewKey,  aSprite))
@@ -1582,8 +1625,6 @@ void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
     {
       theMarkerSize = Standard_ShortReal (Max (aSprite->SizeX(), aSprite->SizeY()));
     }
-    mySprite ->ChangeFirst() = aSprite;
-    mySpriteA->ChangeFirst() = aSpriteA;
     return;
   }
 
@@ -1593,8 +1634,6 @@ void OpenGl_AspectsSprite::build (const Handle(OpenGl_Context)& theCtx,
     aSpriteA = new OpenGl_PointSprite (aNewKeyA);
   }
   aSprite = new OpenGl_PointSprite (aNewKey);
-  mySprite ->ChangeFirst() = aSprite;
-  mySpriteA->ChangeFirst() = aSpriteA;
   if (!aNewKey.IsEmpty())
   {
     theCtx->ShareResource (aNewKey, aSprite);
diff --git a/src/OpenGl/OpenGl_AspectsSprite.hxx b/src/OpenGl/OpenGl_AspectsSprite.hxx
index 36b5125411..e7f1a0002e 100644
--- a/src/OpenGl/OpenGl_AspectsSprite.hxx
+++ b/src/OpenGl/OpenGl_AspectsSprite.hxx
@@ -18,7 +18,7 @@
 #include <Graphic3d_TextureMap.hxx>
 
 class OpenGl_Context;
-class OpenGl_TextureSet;
+class OpenGl_PointSprite;
 
 //! OpenGl resources for custom point sprites.
 class OpenGl_AspectsSprite
@@ -31,30 +31,25 @@ public:
 
   Standard_ShortReal MarkerSize() const { return myMarkerSize; }
 
-  //! Return RGB sprite.
-  const Handle(OpenGl_TextureSet)& Sprite (const Handle(OpenGl_Context)& theCtx,
-                                           const Handle(Graphic3d_Aspects)& theAspecta)
-  {
-    if (!myIsSpriteReady)
-    {
-      build (theCtx, theAspecta->MarkerImage(), theAspecta->MarkerType(), theAspecta->MarkerScale(), theAspecta->ColorRGBA(), myMarkerSize);
-      myIsSpriteReady = true;
-    }
-    return mySprite;
-  }
-  
-  //! Return Alpha sprite.
-  const Handle(OpenGl_TextureSet)& SpriteA (const Handle(OpenGl_Context)& theCtx,
-                                            const Handle(Graphic3d_Aspects)& theAspecta)
-  {
-    if (!myIsSpriteReady)
-    {
-      build (theCtx, theAspecta->MarkerImage(), theAspecta->MarkerType(), theAspecta->MarkerScale(), theAspecta->ColorRGBA(), myMarkerSize);
-      myIsSpriteReady = true;
-    }
-    return mySpriteA;
-  }
-  
+  //! Return TRUE if resource is up-to-date.
+  bool IsReady() const { return myIsSpriteReady; }
+
+  //! Invalidate resource state.
+  void Invalidate() { myIsSpriteReady = false; }
+
+  //! Return TRUE if OpenGl point sprite resource defines texture.
+  Standard_EXPORT bool HasPointSprite (const Handle(OpenGl_Context)& theCtx,
+                                       const Handle(Graphic3d_Aspects)& theAspects);
+
+  //! Return TRUE if OpenGl point sprite resource defined by obsolete Display List (bitmap).
+  Standard_EXPORT bool IsDisplayListSprite (const Handle(OpenGl_Context)& theCtx,
+                                            const Handle(Graphic3d_Aspects)& theAspects);
+
+  //! Return sprite.
+  Standard_EXPORT const Handle(OpenGl_PointSprite)& Sprite (const Handle(OpenGl_Context)& theCtx,
+                                                            const Handle(Graphic3d_Aspects)& theAspects,
+                                                            bool theIsAlphaSprite);
+
   //! Update texture resource up-to-date state.
   Standard_EXPORT void UpdateRediness (const Handle(Graphic3d_Aspects)& theAspect);
 
@@ -81,8 +76,8 @@ private:
 
 private:
 
-  Handle(OpenGl_TextureSet) mySprite;
-  Handle(OpenGl_TextureSet) mySpriteA;
+  Handle(OpenGl_PointSprite) mySprite;
+  Handle(OpenGl_PointSprite) mySpriteA;
   Standard_ShortReal myMarkerSize;
   Standard_Boolean myIsSpriteReady;
 
diff --git a/src/OpenGl/OpenGl_AspectsTextureSet.cxx b/src/OpenGl/OpenGl_AspectsTextureSet.cxx
index 1d705854bd..ac3906f738 100644
--- a/src/OpenGl/OpenGl_AspectsTextureSet.cxx
+++ b/src/OpenGl/OpenGl_AspectsTextureSet.cxx
@@ -15,7 +15,7 @@
 
 #include <OpenGl_Context.hxx>
 #include <OpenGl_Sampler.hxx>
-#include <OpenGl_Texture.hxx>
+#include <OpenGl_PointSprite.hxx>
 #include <OpenGl_TextureSet.hxx>
 
 #include <Graphic3d_TextureParams.hxx>
@@ -33,12 +33,18 @@ namespace
 // =======================================================================
 void OpenGl_AspectsTextureSet::Release (OpenGl_Context* theCtx)
 {
-  if (myTextures.IsNull())
+  if (myTextures[0].IsNull())
   {
     return;
   }
 
-  for (OpenGl_TextureSet::Iterator aTextureIter (myTextures); aTextureIter.More(); aTextureIter.Next())
+  if (!myTextures[1].IsNull())
+  {
+    // ReleaseResource() will have no effect until nullifying all copies
+    myTextures[1]->InitZero();
+  }
+
+  for (OpenGl_TextureSet::Iterator aTextureIter (myTextures[0]); aTextureIter.More(); aTextureIter.Next())
   {
     Handle(OpenGl_Texture)& aTextureRes = aTextureIter.ChangeValue();
     if (aTextureRes.IsNull())
@@ -54,6 +60,8 @@ void OpenGl_AspectsTextureSet::Release (OpenGl_Context* theCtx)
       }
       else
       {
+        // OpenGl_PointSprite will be actually released later by OpenGl_AspectsSprite,
+        // see order OpenGl_Aspects::Release()
         const TCollection_AsciiString aName = aTextureRes->ResourceId();
         aTextureRes.Nullify(); // we need nullify all handles before ReleaseResource() call
         theCtx->ReleaseResource (aName, Standard_True);
@@ -68,23 +76,33 @@ void OpenGl_AspectsTextureSet::Release (OpenGl_Context* theCtx)
 // function : UpdateRediness
 // purpose  :
 // =======================================================================
-void OpenGl_AspectsTextureSet::UpdateRediness (const Handle(Graphic3d_TextureSet)& theTextures)
+void OpenGl_AspectsTextureSet::UpdateRediness (const Handle(Graphic3d_Aspects)& theAspect)
 {
-  const Standard_Integer aNbTexturesOld = !myTextures.IsNull()  ? myTextures->Size()  : 0;
-  const Standard_Integer aNbTexturesNew = !theTextures.IsNull() ? theTextures->Size() : 0;
+  const Handle(Graphic3d_TextureSet)& aNewTextureSet = theAspect->TextureSet();
+
+  const Standard_Integer aNbTexturesOld = !myTextures[0].IsNull() ? myTextures[0]->Size() : 0;
+  Standard_Integer aNbTexturesNew = !aNewTextureSet.IsNull() && theAspect->ToMapTexture()
+                                   ? aNewTextureSet->Size()
+                                   : 0;
+  if (theAspect->IsMarkerSprite())
+  {
+    ++aNbTexturesNew;
+  }
+
   if (aNbTexturesOld != aNbTexturesNew)
   {
     myIsTextureReady = Standard_False;
     return;
   }
-  if (aNbTexturesOld == 0)
+  if (aNbTexturesOld == 0
+  || !theAspect->ToMapTexture())
   {
     return;
   }
 
-  Graphic3d_TextureSet::Iterator aTextureIter (theTextures);
-  OpenGl_TextureSet::Iterator aResIter (myTextures);
-  for (; aResIter.More(); aResIter.Next(), aTextureIter.Next())
+  Graphic3d_TextureSet::Iterator aTextureIter (aNewTextureSet);
+  OpenGl_TextureSet::Iterator aResIter (myTextures[0]);
+  for (; aTextureIter.More(); aResIter.Next(), aTextureIter.Next())
   {
     const Handle(OpenGl_Texture)&       aResource = aResIter.Value();
     const Handle(Graphic3d_TextureMap)& aTexture  = aTextureIter.Value();
@@ -122,91 +140,150 @@ void OpenGl_AspectsTextureSet::UpdateRediness (const Handle(Graphic3d_TextureSet
 // purpose  :
 // =======================================================================
 void OpenGl_AspectsTextureSet::build (const Handle(OpenGl_Context)& theCtx,
-                                      const Handle(Graphic3d_TextureSet)& theTextures)
+                                      const Handle(Graphic3d_Aspects)& theAspect,
+                                      const Handle(OpenGl_PointSprite)& theSprite,
+                                      const Handle(OpenGl_PointSprite)& theSpriteA)
 {
+  const Handle(Graphic3d_TextureSet)& aNewTextureSet = theAspect->TextureSet();
+
+  const bool hasSprite = theAspect->IsMarkerSprite();
+  const Standard_Integer aNbTexturesOld = !myTextures[0].IsNull() ? myTextures[0]->Size() : 0;
+  Standard_Integer aNbTexturesNew = !aNewTextureSet.IsNull() && theAspect->ToMapTexture()
+                                  ? aNewTextureSet->Size()
+                                  : 0;
+  if (hasSprite)
+  {
+    ++aNbTexturesNew;
+  }
+
   // release old texture resources
-  const Standard_Integer aNbTexturesOld = !myTextures.IsNull()  ? myTextures->Size()  : 0;
-  const Standard_Integer aNbTexturesNew = !theTextures.IsNull() ? theTextures->Size() : 0;
   if (aNbTexturesOld != aNbTexturesNew)
   {
     Release (theCtx.get());
     if (aNbTexturesNew > 0)
     {
-      myTextures = new OpenGl_TextureSet (theTextures->Size());
+      myTextures[0] = new OpenGl_TextureSet (aNbTexturesNew);
     }
     else
     {
-      myTextures.Nullify();
+      myTextures[0].Nullify();
+      myTextures[1].Nullify();
     }
   }
-  if (myTextures.IsNull())
+  if (myTextures[0].IsNull())
   {
     return;
   }
 
-  Graphic3d_TextureSet::Iterator aTextureIter (theTextures);
-  OpenGl_TextureSet::Iterator aResIter (myTextures);
-  for (; aResIter.More(); aResIter.Next(), aTextureIter.Next())
+  if (theSprite == theSpriteA)
   {
-    Handle(OpenGl_Texture)& aResource = aResIter.ChangeValue();
-    const Handle(Graphic3d_TextureMap)& aTexture = aTextureIter.Value();
-    if (!aResource.IsNull())
+    myTextures[1].Nullify();
+  }
+  else
+  {
+    if (myTextures[1].IsNull()
+     || myTextures[1]->Size() != myTextures[0]->Size())
     {
-      if (!aTexture.IsNull()
-       &&  aTexture->GetId()    == aResource->ResourceId()
-       &&  aTexture->Revision() != aResource->Revision())
-      {
-        if (Handle(Image_PixMap) anImage = aTexture->GetImage())
-        {
-          aResource->Sampler()->SetParameters (aTexture->GetParams());
-          aResource->Init (theCtx, *anImage.operator->(), aTexture->Type());
-          aResource->SetRevision (aTexture->Revision());
-          continue;
-        }
-      }
-
-      if (aResource->ResourceId().IsEmpty())
-      {
-        theCtx->DelayedRelease (aResource);
-        aResource.Nullify();
-      }
-      else
-      {
-        const TCollection_AsciiString aTextureKey = aResource->ResourceId();
-        aResource.Nullify(); // we need nullify all handles before ReleaseResource() call
-        theCtx->ReleaseResource (aTextureKey, Standard_True);
-      }
+      myTextures[1] = new OpenGl_TextureSet (aNbTexturesNew);
     }
-
-    if (!aTexture.IsNull())
+    else
     {
-      const TCollection_AsciiString& aTextureKeyNew = aTexture->GetId();
-      if (aTextureKeyNew.IsEmpty()
-      || !theCtx->GetResource<Handle(OpenGl_Texture)> (aTextureKeyNew, aResource))
+      myTextures[1]->InitZero();
+    }
+  }
+
+  if (theAspect->ToMapTexture())
+  {
+    Graphic3d_TextureSet::Iterator aTextureIter (aNewTextureSet);
+    OpenGl_TextureSet::Iterator aResIter0 (myTextures[0]);
+    for (; aTextureIter.More(); aResIter0.Next(), aTextureIter.Next())
+    {
+      Handle(OpenGl_Texture)& aResource = aResIter0.ChangeValue();
+      const Handle(Graphic3d_TextureMap)& aTexture = aTextureIter.Value();
+      if (!aResource.IsNull())
       {
-        aResource = new OpenGl_Texture (aTextureKeyNew, aTexture->GetParams());
-        if (Handle(Image_PixMap) anImage = aTexture->GetImage())
+        if (!aTexture.IsNull()
+         &&  aTexture->GetId()    == aResource->ResourceId()
+         &&  aTexture->Revision() != aResource->Revision())
         {
-          aResource->Init (theCtx, *anImage.operator->(), aTexture->Type());
-          aResource->SetRevision (aTexture->Revision());
+          if (Handle(Image_PixMap) anImage = aTexture->GetImage())
+          {
+            aResource->Sampler()->SetParameters (aTexture->GetParams());
+            aResource->Init (theCtx, *anImage.operator->(), aTexture->Type());
+            aResource->SetRevision (aTexture->Revision());
+            continue;
+          }
         }
-        if (!aTextureKeyNew.IsEmpty())
+
+        if (aResource->ResourceId().IsEmpty())
         {
-          theCtx->ShareResource (aTextureKeyNew, aResource);
+          theCtx->DelayedRelease (aResource);
+          aResource.Nullify();
+        }
+        else
+        {
+          const TCollection_AsciiString aTextureKey = aResource->ResourceId();
+          aResource.Nullify(); // we need nullify all handles before ReleaseResource() call
+          theCtx->ReleaseResource (aTextureKey, Standard_True);
         }
       }
-      else
+
+      if (!aTexture.IsNull())
       {
-        if (aTexture->Revision() != aResource->Revision())
+        const TCollection_AsciiString& aTextureKeyNew = aTexture->GetId();
+        if (aTextureKeyNew.IsEmpty()
+        || !theCtx->GetResource<Handle(OpenGl_Texture)> (aTextureKeyNew, aResource))
         {
+          aResource = new OpenGl_Texture (aTextureKeyNew, aTexture->GetParams());
           if (Handle(Image_PixMap) anImage = aTexture->GetImage())
           {
             aResource->Init (theCtx, *anImage.operator->(), aTexture->Type());
             aResource->SetRevision (aTexture->Revision());
           }
+          if (!aTextureKeyNew.IsEmpty())
+          {
+            theCtx->ShareResource (aTextureKeyNew, aResource);
+          }
+        }
+        else
+        {
+          if (aTexture->Revision() != aResource->Revision())
+          {
+            if (Handle(Image_PixMap) anImage = aTexture->GetImage())
+            {
+              aResource->Init (theCtx, *anImage.operator->(), aTexture->Type());
+              aResource->SetRevision (aTexture->Revision());
+            }
+          }
+          aResource->Sampler()->SetParameters (aTexture->GetParams());
         }
-        aResource->Sampler()->SetParameters (aTexture->GetParams());
       }
     }
   }
+
+  if (hasSprite)
+  {
+    myTextures[0]->ChangeLast() = theSprite;
+    if (!theSprite.IsNull())
+    {
+      theSprite ->Sampler()->Parameters()->SetTextureUnit (theCtx->SpriteTextureUnit());
+    }
+    if (!theSpriteA.IsNull())
+    {
+      theSpriteA->Sampler()->Parameters()->SetTextureUnit (theCtx->SpriteTextureUnit());
+    }
+  }
+  if (myTextures[1].IsNull())
+  {
+    return;
+  }
+
+  for (OpenGl_TextureSet::Iterator aResIter0 (myTextures[0]), aResIter1 (myTextures[1]); aResIter0.More(); aResIter0.Next(), aResIter1.Next())
+  {
+    aResIter1.ChangeValue() = aResIter0.Value();
+  }
+  if (hasSprite)
+  {
+    myTextures[1]->ChangeLast() = theSpriteA;
+  }
 }
diff --git a/src/OpenGl/OpenGl_AspectsTextureSet.hxx b/src/OpenGl/OpenGl_AspectsTextureSet.hxx
index 9fbf3ce61f..0aa2c29c1a 100644
--- a/src/OpenGl/OpenGl_AspectsTextureSet.hxx
+++ b/src/OpenGl/OpenGl_AspectsTextureSet.hxx
@@ -14,11 +14,13 @@
 #ifndef _OpenGl_AspectsTextureSet_Header
 #define _OpenGl_AspectsTextureSet_Header
 
+#include <Graphic3d_Aspects.hxx>
 #include <Graphic3d_TextureMap.hxx>
 #include <Graphic3d_TextureSet.hxx>
 
 class OpenGl_Context;
 class OpenGl_TextureSet;
+class OpenGl_PointSprite;
 
 //! OpenGl resources for custom textures.
 class OpenGl_AspectsTextureSet
@@ -29,20 +31,31 @@ public:
   //! Empty constructor.
   OpenGl_AspectsTextureSet() : myIsTextureReady (Standard_False) {}
 
+  //! Return TRUE if resource is up-to-date.
+  bool IsReady() const { return myIsTextureReady; }
+
+  //! Invalidate resource state.
+  void Invalidate() { myIsTextureReady = false; }
+
   //! Return textures array.
   const Handle(OpenGl_TextureSet)& TextureSet (const Handle(OpenGl_Context)& theCtx,
-                                               const Handle(Graphic3d_TextureSet)& theTextures)
+                                               const Handle(Graphic3d_Aspects)& theAspect,
+                                               const Handle(OpenGl_PointSprite)& theSprite,
+                                               const Handle(OpenGl_PointSprite)& theSpriteA,
+                                               bool theToHighlight)
   {
     if (!myIsTextureReady)
     {
-      build (theCtx, theTextures);
+      build (theCtx, theAspect, theSprite, theSpriteA);
       myIsTextureReady = true;
     }
-    return myTextures;
+    return theToHighlight && !myTextures[1].IsNull()
+         ? myTextures[1]
+         : myTextures[0];
   }
 
   //! Update texture resource up-to-date state.
-  Standard_EXPORT void UpdateRediness (const Handle(Graphic3d_TextureSet)& theTextures);
+  Standard_EXPORT void UpdateRediness (const Handle(Graphic3d_Aspects)& theAspect);
 
   //! Release texture resource.
   Standard_EXPORT void Release (OpenGl_Context* theCtx);
@@ -51,11 +64,13 @@ private:
 
   //! Build texture resource.
   Standard_EXPORT void build (const Handle(OpenGl_Context)& theCtx,
-                              const Handle(Graphic3d_TextureSet)& theTextures);
+                              const Handle(Graphic3d_Aspects)& theAspect,
+                              const Handle(OpenGl_PointSprite)& theSprite,
+                              const Handle(OpenGl_PointSprite)& theSpriteA);
 
 private:
 
-  Handle(OpenGl_TextureSet) myTextures;
+  Handle(OpenGl_TextureSet) myTextures[2];
   Standard_Boolean          myIsTextureReady;
 
 };
diff --git a/src/OpenGl/OpenGl_Context.cxx b/src/OpenGl/OpenGl_Context.cxx
index f16fb4a8e2..48bd620f7d 100644
--- a/src/OpenGl/OpenGl_Context.cxx
+++ b/src/OpenGl/OpenGl_Context.cxx
@@ -170,6 +170,7 @@ OpenGl_Context::OpenGl_Context (const Handle(OpenGl_Caps)& theCaps)
   myIsInitialized (Standard_False),
   myIsStereoBuffers (Standard_False),
   myIsGlNormalizeEnabled (Standard_False),
+  mySpriteTexUnit (Graphic3d_TextureUnit_0),
   myHasRayTracing (Standard_False),
   myHasRayTracingTextures (Standard_False),
   myHasRayTracingAdaptiveSampling (Standard_False),
@@ -1481,10 +1482,21 @@ void OpenGl_Context::init (const Standard_Boolean theIsCoreProfile)
   }
 
   glGetIntegerv (GL_MAX_TEXTURE_SIZE, &myMaxTexDim);
-  if (IsGlGreaterEqual (1, 5))
+  if (IsGlGreaterEqual (2, 0))
   {
     glGetIntegerv (GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &myMaxTexCombined);
   }
+#if !defined(GL_ES_VERSION_2_0)
+  else if (IsGlGreaterEqual (1, 3))
+  {
+    // this is a maximum of texture units for FFP functionality,
+    // dramatically smaller than combined texture units available for GLSL
+    glGetIntegerv (GL_MAX_TEXTURE_UNITS, &myMaxTexCombined);
+  }
+#endif
+  mySpriteTexUnit = myMaxTexCombined >= 2
+                  ? Graphic3d_TextureUnit_1
+                  : Graphic3d_TextureUnit_0;
 
   GLint aMaxVPortSize[2] = {0, 0};
   glGetIntegerv (GL_MAX_VIEWPORT_DIMS, aMaxVPortSize);
diff --git a/src/OpenGl/OpenGl_Context.hxx b/src/OpenGl/OpenGl_Context.hxx
index 5733865e09..f58cb999b3 100644
--- a/src/OpenGl/OpenGl_Context.hxx
+++ b/src/OpenGl/OpenGl_Context.hxx
@@ -473,6 +473,9 @@ public:
   //! @return value for GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
   Standard_Integer MaxCombinedTextureUnits() const { return myMaxTexCombined; }
 
+  //! @return texture unit to be used for sprites
+  Graphic3d_TextureUnit SpriteTextureUnit() const { return mySpriteTexUnit; }
+
   //! @return value for GL_MAX_SAMPLES
   Standard_Integer MaxMsaaSamples() const { return myMaxMsaaSamples; }
 
@@ -946,6 +949,7 @@ private: // context info
   Standard_Boolean myIsStereoBuffers;      //!< context supports stereo buffering
   Standard_Boolean myIsGlNormalizeEnabled; //!< GL_NORMALIZE flag
                                            //!< Used to tell OpenGl that normals should be normalized
+  Graphic3d_TextureUnit mySpriteTexUnit;   //!< texture unit for point sprite texture
 
   Standard_Boolean myHasRayTracing;                 //! indicates whether ray tracing mode is supported
   Standard_Boolean myHasRayTracingTextures;         //! indicates whether textures in ray tracing mode are supported
diff --git a/src/OpenGl/OpenGl_PointSprite.hxx b/src/OpenGl/OpenGl_PointSprite.hxx
index bb8f458ccc..8573f7689a 100755
--- a/src/OpenGl/OpenGl_PointSprite.hxx
+++ b/src/OpenGl/OpenGl_PointSprite.hxx
@@ -24,7 +24,7 @@ DEFINE_STANDARD_HANDLE(OpenGl_PointSprite, OpenGl_Texture)
 //! On ancient hardware sprites will be drawn using bitmaps.
 class OpenGl_PointSprite : public OpenGl_Texture
 {
-
+  DEFINE_STANDARD_RTTIEXT(OpenGl_PointSprite, OpenGl_Texture)
 public:
 
   //! Create uninitialized resource.
@@ -36,6 +36,9 @@ public:
   //! Destroy object - will release GPU memory if any.
   Standard_EXPORT virtual void Release (OpenGl_Context* theCtx) Standard_OVERRIDE;
 
+  //! Returns TRUE for point sprite texture.
+  virtual bool IsPointSprite() const Standard_OVERRIDE { return true; }
+
   //! @return true if this is display list bitmap
   inline Standard_Boolean IsDisplayList() const
   {
@@ -54,10 +57,6 @@ protected:
 
   GLuint myBitmapList; //!< if of display list to draw sprite using glBitmap (for backward compatibility)
 
-public:
-
-  DEFINE_STANDARD_RTTIEXT(OpenGl_PointSprite,OpenGl_Texture) // Type definition
-
 };
 
 #endif // _OpenGl_PointSprite_H__
diff --git a/src/OpenGl/OpenGl_PrimitiveArray.cxx b/src/OpenGl/OpenGl_PrimitiveArray.cxx
index 95a76a160e..30f7cd2a67 100644
--- a/src/OpenGl/OpenGl_PrimitiveArray.cxx
+++ b/src/OpenGl/OpenGl_PrimitiveArray.cxx
@@ -592,16 +592,12 @@ void OpenGl_PrimitiveArray::drawEdges (const Handle(OpenGl_Workspace)& theWorksp
 void OpenGl_PrimitiveArray::drawMarkers (const Handle(OpenGl_Workspace)& theWorkspace) const
 {
   const OpenGl_Aspects* anAspectMarker = theWorkspace->Aspects();
-  const Handle(OpenGl_Context)&     aCtx    = theWorkspace->GetGlContext();
+  const Handle(OpenGl_Context)&   aCtx = theWorkspace->GetGlContext();
   const GLenum aDrawMode = !aCtx->ActiveProgram().IsNull()
                          && aCtx->ActiveProgram()->HasTessellationStage()
                          ? GL_PATCHES
                          : myDrawMode;
-
-  const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectMarker->SpriteRes (aCtx);
-  const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
-  if (aSpriteNorm != NULL
-  && !aSpriteNorm->IsDisplayList())
+  if (anAspectMarker->HasPointSprite (aCtx))
   {
     // Textured markers will be drawn with the point sprites
     aCtx->SetPointSize (anAspectMarker->MarkerSize());
@@ -644,9 +640,14 @@ void OpenGl_PrimitiveArray::drawMarkers (const Handle(OpenGl_Workspace)& theWork
   }
 #if !defined(GL_ES_VERSION_2_0)
   // Textured markers will be drawn with the glBitmap
-  else if (anAspectMarker->Aspect()->MarkerType() != Aspect_TOM_POINT
-        && aSpriteNorm != NULL)
+  else if (anAspectMarker->Aspect()->MarkerType() != Aspect_TOM_POINT)
   {
+    const Handle(OpenGl_PointSprite)& aSpriteNorm = anAspectMarker->SpriteRes (aCtx, false);
+    if (aSpriteNorm.IsNull())
+    {
+      return;
+    }
+
     /**if (!isHilight && (myPArray->vcolours != NULL))
     {
       for (Standard_Integer anIter = 0; anIter < myAttribs->NbElements; anIter++)
@@ -771,7 +772,8 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
   const OpenGl_Aspects* anAspectFace = theWorkspace->ApplyAspects();
   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
 
-  Handle(OpenGl_TextureSet) aTextureBack;
+  const bool toEnableEnvMap = !aCtx->ActiveTextures().IsNull()
+                            && aCtx->ActiveTextures() == theWorkspace->EnvironmentTexture();
   bool toDrawArray = true;
   int toDrawInteriorEdges = 0; // 0 - no edges, 1 - glsl edges, 2 - polygonMode
   if (myIsFillType)
@@ -818,23 +820,14 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
         return;
       }
     }
-
-    // Temporarily disable environment mapping
-    aTextureBack = aCtx->BindTextures (Handle(OpenGl_TextureSet)());
   }
 
   // create VBOs on first render call
   if (!myIsVboInit)
   {
     // compatibility - keep data to draw markers using display lists
-    Standard_Boolean toKeepData = Standard_False;
-    if (myDrawMode == GL_POINTS)
-    {
-      const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectFace->SpriteRes (aCtx);
-      const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
-      toKeepData = aSpriteNorm != NULL
-               &&  aSpriteNorm->IsDisplayList();
-    }
+    Standard_Boolean toKeepData = myDrawMode == GL_POINTS
+                               && anAspectFace->IsDisplayListSprite (aCtx);
   #if defined (GL_ES_VERSION_2_0)
     processIndices (aCtx);
   #endif
@@ -862,28 +855,16 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
       case GL_POINTS:
       {
         aShadingModel = aCtx->ShaderManager()->ChooseMarkerShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
-        const Handle(OpenGl_TextureSet)& aSpriteNormRes = anAspectFace->SpriteRes (aCtx);
-        const OpenGl_PointSprite* aSpriteNorm = !aSpriteNormRes.IsNull() ? dynamic_cast<const OpenGl_PointSprite*> (aSpriteNormRes->First().get()) : NULL;
-        if (aSpriteNorm != NULL
-        && !aSpriteNorm->IsDisplayList())
-        {
-          const Handle(OpenGl_TextureSet)& aSprite = toHilight && anAspectFace->SpriteHighlightRes (aCtx)->First()->IsValid()
-                                                   ? anAspectFace->SpriteHighlightRes (aCtx)
-                                                   : aSpriteNormRes;
-          aCtx->BindTextures (aSprite);
-          aCtx->ShaderManager()->BindMarkerProgram (aSprite, aShadingModel, Graphic3d_AlphaMode_Opaque, hasVertColor, anAspectFace->ShaderProgramRes (aCtx));
-        }
-        else
-        {
-          aCtx->ShaderManager()->BindMarkerProgram (Handle(OpenGl_TextureSet)(), aShadingModel, Graphic3d_AlphaMode_Opaque, hasVertColor, anAspectFace->ShaderProgramRes (aCtx));
-        }
+        aCtx->ShaderManager()->BindMarkerProgram (aCtx->ActiveTextures(),
+                                                  aShadingModel, Graphic3d_AlphaMode_Opaque,
+                                                  hasVertColor, anAspectFace->ShaderProgramRes (aCtx));
         break;
       }
       case GL_LINES:
       case GL_LINE_STRIP:
       {
         aShadingModel = aCtx->ShaderManager()->ChooseLineShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
-        aCtx->ShaderManager()->BindLineProgram (NULL,
+        aCtx->ShaderManager()->BindLineProgram (Handle(OpenGl_TextureSet)(),
                                                 anAspectFace->Aspect()->LineType(),
                                                 aShadingModel,
                                                 Graphic3d_AlphaMode_Opaque,
@@ -894,9 +875,7 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
       default:
       {
         aShadingModel = aCtx->ShaderManager()->ChooseFaceShadingModel (anAspectFace->ShadingModel(), hasVertNorm);
-        const Handle(OpenGl_TextureSet)& aTextures = aCtx->ActiveTextures();
-        const Standard_Boolean toEnableEnvMap = (!aTextures.IsNull() && (aTextures == theWorkspace->EnvironmentTexture()));
-        aCtx->ShaderManager()->BindFaceProgram (aTextures,
+        aCtx->ShaderManager()->BindFaceProgram (aCtx->ActiveTextures(),
                                                 aShadingModel,
                                                 aCtx->ShaderManager()->MaterialState().HasAlphaCutoff() ? Graphic3d_AlphaMode_Mask : Graphic3d_AlphaMode_Opaque,
                                                 toDrawInteriorEdges == 1 ? anAspectFace->Aspect()->InteriorStyle() : Aspect_IS_SOLID,
@@ -952,7 +931,6 @@ void OpenGl_PrimitiveArray::Render (const Handle(OpenGl_Workspace)& theWorkspace
       }
 
       drawArray (theWorkspace, aFaceColors, hasColorAttrib);
-      aCtx->BindTextures (aTextureBack);
       return;
     }
 
diff --git a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx
index e82b7858cc..8c0434b0c4 100644
--- a/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx
+++ b/src/OpenGl/OpenGl_SetOfShaderPrograms.hxx
@@ -23,10 +23,11 @@
 //! Standard GLSL program combination bits.
 enum OpenGl_ProgramOptions
 {
-  OpenGl_PO_Point           = 0x0001, //!< point marker
-  OpenGl_PO_VertColor       = 0x0002, //!< per-vertex color
-  OpenGl_PO_TextureRGB      = 0x0004, //!< handle RGB   texturing
-  OpenGl_PO_TextureA        = 0x0008, //!< handle Alpha texturing (point sprites only)
+  OpenGl_PO_VertColor       = 0x0001, //!< per-vertex color
+  OpenGl_PO_TextureRGB      = 0x0002, //!< handle RGB   texturing
+  OpenGl_PO_PointSimple     = 0x0004, //!< point marker without sprite
+  OpenGl_PO_PointSprite     = 0x0008, //!< point sprite with RGB image
+  OpenGl_PO_PointSpriteA    = OpenGl_PO_PointSimple|OpenGl_PO_PointSprite, //!< point sprite with Alpha image
   OpenGl_PO_TextureEnv      = 0x0010, //!< handle environment map
   OpenGl_PO_StippleLine     = 0x0020, //!< stipple line
   OpenGl_PO_ClipPlanes1     = 0x0040, //!< handle 1 clipping plane
@@ -38,7 +39,8 @@ enum OpenGl_ProgramOptions
   OpenGl_PO_WriteOit        = 0x0800, //!< write coverage buffer for Blended Order-Independent Transparency
   //
   OpenGl_PO_NB              = 0x1000, //!< overall number of combinations
-  OpenGl_PO_HasTextures     = OpenGl_PO_TextureRGB|OpenGl_PO_TextureA,
+  OpenGl_PO_IsPoint         = OpenGl_PO_PointSimple|OpenGl_PO_PointSprite|OpenGl_PO_PointSpriteA,
+  OpenGl_PO_HasTextures     = OpenGl_PO_TextureRGB,
   OpenGl_PO_NeedsGeomShader = OpenGl_PO_MeshEdges,
 };
 
diff --git a/src/OpenGl/OpenGl_ShaderManager.cxx b/src/OpenGl/OpenGl_ShaderManager.cxx
index 3e8be7ffe4..5544e67f9e 100644
--- a/src/OpenGl/OpenGl_ShaderManager.cxx
+++ b/src/OpenGl/OpenGl_ShaderManager.cxx
@@ -22,6 +22,7 @@
 #include <OpenGl_ShaderManager.hxx>
 #include <OpenGl_ShaderProgram.hxx>
 #include <OpenGl_VertexBufferCompat.hxx>
+#include <OpenGl_PointSprite.hxx>
 #include <OpenGl_Workspace.hxx>
 
 #include <TCollection_ExtendedString.hxx>
@@ -1297,6 +1298,7 @@ void OpenGl_ShaderManager::PushState (const Handle(OpenGl_ShaderProgram)& thePro
 Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
 {
   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
+  aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec2 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
 
   TCollection_AsciiString aSrcVert = TCollection_AsciiString()
@@ -1327,6 +1329,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFont()
 
   Handle(Graphic3d_ShaderProgram) aProgramSrc = new Graphic3d_ShaderProgram();
   defaultGlslVersion (aProgramSrc, "font", 0);
+  aProgramSrc->SetDefaultSampler (false);
   aProgramSrc->SetNbLightsMax (0);
   aProgramSrc->SetNbClipPlanesMax (0);
   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
@@ -1392,6 +1395,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramFboBlit()
   }
 #endif
   aProgramSrc->SetId ("occt_blit");
+  aProgramSrc->SetDefaultSampler (false);
   aProgramSrc->SetNbLightsMax (0);
   aProgramSrc->SetNbClipPlanesMax (0);
   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
@@ -1483,6 +1487,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const St
   }
 
   aProgramSrc->SetId (theMsaa ? "occt_weight-oit-msaa" : "occt_weight-oit");
+  aProgramSrc->SetDefaultSampler (false);
   aProgramSrc->SetNbLightsMax (0);
   aProgramSrc->SetNbClipPlanesMax (0);
   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
@@ -1505,14 +1510,14 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramOitCompositing (const St
 // function : pointSpriteAlphaSrc
 // purpose  :
 // =======================================================================
-TCollection_AsciiString OpenGl_ShaderManager::pointSpriteAlphaSrc (const Standard_Integer theBits)
+TCollection_AsciiString OpenGl_ShaderManager::pointSpriteAlphaSrc (Standard_Integer theBits)
 {
-  TCollection_AsciiString aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ").a; }";
+  TCollection_AsciiString aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord ").a; }";
 #if !defined(GL_ES_VERSION_2_0)
   if (myContext->core11 == NULL
-   && (theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureA)
+   && (theBits & OpenGl_PO_PointSpriteA) == OpenGl_PO_PointSpriteA)
   {
-    aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ").r; }";
+    aSrcGetAlpha = EOL"float getAlpha(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord ").r; }";
   }
 #else
   (void )theBits;
@@ -1699,18 +1704,29 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
   TCollection_AsciiString aSrcFragMainGetColor = EOL"  occSetFragColor (getFinalColor());";
   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
 
-  if ((theBits & OpenGl_PO_Point) != 0)
+  if ((theBits & OpenGl_PO_IsPoint) != 0)
   {
   #if defined(GL_ES_VERSION_2_0)
     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
   #endif
 
-    if ((theBits & OpenGl_PO_HasTextures) != 0)
+    if ((theBits & OpenGl_PO_PointSprite) != 0)
     {
-      if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
+      aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
+      if ((theBits & OpenGl_PO_PointSpriteA) != OpenGl_PO_PointSpriteA)
       {
         aSrcFragGetColor =
-          EOL"vec4 getColor(void) { return occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord "); }";
+          EOL"vec4 getColor(void) { return occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord "); }";
+      }
+      else if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
+            && (theBits & OpenGl_PO_VertColor) == 0)
+      {
+        aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
+        aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
+        aSrcVertExtraMain +=
+          EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
+        aSrcFragGetColor =
+          EOL"vec4 getColor(void) { return VertColor; }";
       }
 
       aSrcGetAlpha = pointSpriteAlphaSrc (theBits);
@@ -1731,6 +1747,17 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
     }
     else
     {
+      if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
+       && (theBits & OpenGl_PO_VertColor) == 0)
+      {
+        aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
+        aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
+        aSrcVertExtraMain +=
+          EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
+        aSrcFragGetColor =
+          EOL"vec4 getColor(void) { return VertColor; }";
+      }
+
       aSrcFragMainGetColor =
         EOL"  vec4 aColor = getColor();"
         EOL"  if (aColor.a <= 0.1) discard;"
@@ -1741,6 +1768,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
   {
     if ((theBits & OpenGl_PO_TextureRGB) != 0 || (theBits & OpenGl_PO_TextureEnv) != 0)
     {
+      aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
     }
 
@@ -1863,6 +1891,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
     + EOL"}";
 
   defaultGlslVersion (aProgramSrc, theIsOutline ? "outline" : "unlit", theBits);
+  aProgramSrc->SetDefaultSampler (false);
   aProgramSrc->SetNbLightsMax (0);
   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
@@ -1883,11 +1912,11 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramUnlit (Handle(OpenGl_Sha
 // function : pointSpriteShadingSrc
 // purpose  :
 // =======================================================================
-TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TCollection_AsciiString theBaseColorSrc,
-                                                                     const Standard_Integer theBits)
+TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TCollection_AsciiString& theBaseColorSrc,
+                                                                     Standard_Integer theBits)
 {
   TCollection_AsciiString aSrcFragGetColor;
-  if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureA)
+  if ((theBits & OpenGl_PO_PointSpriteA) == OpenGl_PO_PointSpriteA)
   {
     aSrcFragGetColor = pointSpriteAlphaSrc (theBits) +
       EOL"vec4 getColor(void)"
@@ -1898,13 +1927,13 @@ TCollection_AsciiString OpenGl_ShaderManager::pointSpriteShadingSrc (const TColl
       EOL"  return aColor;"
       EOL"}";
   }
-  else if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
+  else if ((theBits & OpenGl_PO_PointSprite) == OpenGl_PO_PointSprite)
   {
     aSrcFragGetColor = TCollection_AsciiString() +
       EOL"vec4 getColor(void)"
       EOL"{"
       EOL"  vec4 aColor = " + theBaseColorSrc + ";"
-      EOL"  aColor = occTexture2D(occSamplerBaseColor, " THE_VEC2_glPointCoord ") * aColor;"
+      EOL"  aColor = occTexture2D(occSamplerPointSprite, " THE_VEC2_glPointCoord ") * aColor;"
       EOL"  if (aColor.a <= 0.1) discard;"
       EOL"  return aColor;"
       EOL"}";
@@ -2062,29 +2091,38 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return gl_FrontFacing ? FrontColor : BackColor; }";
   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
 
-  if ((theBits & OpenGl_PO_Point) != 0)
+  if ((theBits & OpenGl_PO_IsPoint) != 0)
   {
   #if defined(GL_ES_VERSION_2_0)
     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
   #endif
 
-    if ((theBits & OpenGl_PO_HasTextures) != 0)
+    if ((theBits & OpenGl_PO_PointSprite) != 0)
     {
-      #if !defined(GL_ES_VERSION_2_0)
-        if (myContext->core11 != NULL
-         && myContext->IsGlGreaterEqual (2, 1))
-        {
-          aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
-        }
-      #endif
+    #if !defined(GL_ES_VERSION_2_0)
+      if (myContext->core11 != NULL
+        && myContext->IsGlGreaterEqual (2, 1))
+      {
+        aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
+      }
+    #endif
 
+      aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
       aSrcFragGetColor = pointSpriteShadingSrc ("gl_FrontFacing ? FrontColor : BackColor", theBits);
     }
+
+    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
+     && (theBits & OpenGl_PO_VertColor) == 0)
+    {
+      aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
+      aSrcVertColor = EOL"vec4 getVertColor(void) { return occTexture2D (occSamplerBaseColor, occTexCoord.xy); }";
+    }
   }
   else
   {
     if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
     {
+      aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
 
@@ -2141,7 +2179,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
   aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 BackColor",  Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
 
   Standard_Integer aNbLights = 0;
-  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, (theBits & OpenGl_PO_VertColor) != 0);
+  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcVertColor.IsEmpty());
   aSrcVert = TCollection_AsciiString()
     + THE_FUNC_transformNormal
     + EOL
@@ -2174,6 +2212,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramGouraud (Handle(OpenGl_S
 
   const TCollection_AsciiString aProgId = TCollection_AsciiString ("gouraud-") + genLightKey (myLightSourceState.LightSources()) + "-";
   defaultGlslVersion (aProgramSrc, aProgId, theBits);
+  aProgramSrc->SetDefaultSampler (false);
   aProgramSrc->SetNbLightsMax (aNbLights);
   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
@@ -2223,29 +2262,41 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
   TCollection_AsciiString aSrcFrag, aSrcFragExtraOut, aSrcFragGetVertColor, aSrcFragExtraMain;
   TCollection_AsciiString aSrcFragGetColor = EOL"vec4 getColor(void) { return " thePhongCompLight "; }";
   OpenGl_ShaderObject::ShaderVariableList aUniforms, aStageInOuts;
-  if ((theBits & OpenGl_PO_Point) != 0)
+  if ((theBits & OpenGl_PO_IsPoint) != 0)
   {
   #if defined(GL_ES_VERSION_2_0)
     aSrcVertExtraMain += EOL"  gl_PointSize = occPointSize;";
   #endif
 
-    if ((theBits & OpenGl_PO_HasTextures) != 0)
+    if ((theBits & OpenGl_PO_PointSprite) != 0)
     {
-      #if !defined(GL_ES_VERSION_2_0)
-        if (myContext->core11 != NULL
-         && myContext->IsGlGreaterEqual (2, 1))
-        {
-          aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
-        }
-      #endif
+    #if !defined(GL_ES_VERSION_2_0)
+      if (myContext->core11 != NULL
+        && myContext->IsGlGreaterEqual (2, 1))
+      {
+        aProgramSrc->SetHeader ("#version 120"); // gl_PointCoord has been added since GLSL 1.2
+      }
+    #endif
 
+      aUniforms.Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerPointSprite", Graphic3d_TOS_FRAGMENT));
       aSrcFragGetColor = pointSpriteShadingSrc (thePhongCompLight, theBits);
     }
+
+    if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB
+     && (theBits & OpenGl_PO_VertColor) == 0)
+    {
+      aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_VERTEX));
+      aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 VertColor", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
+
+      aSrcVertExtraMain   += EOL"  VertColor = occTexture2D (occSamplerBaseColor, occTexCoord.xy);";
+      aSrcFragGetVertColor = EOL"vec4 getVertColor(void) { return VertColor; }";
+    }
   }
   else
   {
     if ((theBits & OpenGl_PO_HasTextures) == OpenGl_PO_TextureRGB)
     {
+      aUniforms   .Append (OpenGl_ShaderObject::ShaderVariable ("sampler2D occSamplerBaseColor", Graphic3d_TOS_FRAGMENT));
       aStageInOuts.Append (OpenGl_ShaderObject::ShaderVariable ("vec4 TexCoord", Graphic3d_TOS_VERTEX | Graphic3d_TOS_FRAGMENT));
       aSrcVertExtraMain += THE_VARY_TexCoord_Trsf;
 
@@ -2329,7 +2380,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
     : EOL"#define getFinalColor getColor";
 
   Standard_Integer aNbLights = 0;
-  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, (theBits & OpenGl_PO_VertColor) != 0);
+  const TCollection_AsciiString aLights = stdComputeLighting (aNbLights, !aSrcFragGetVertColor.IsEmpty());
   aSrcFrag = TCollection_AsciiString()
     + EOL
     + aSrcFragExtraOut
@@ -2345,6 +2396,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramPhong (Handle(OpenGl_Sha
 
   const TCollection_AsciiString aProgId = TCollection_AsciiString (theIsFlatNormal ? "flat-" : "phong-") + genLightKey (myLightSourceState.LightSources()) + "-";
   defaultGlslVersion (aProgramSrc, aProgId, theBits, isFlatNormal);
+  aProgramSrc->SetDefaultSampler (false);
   aProgramSrc->SetNbLightsMax (aNbLights);
   aProgramSrc->SetNbClipPlanesMax (aNbClipPlanes);
   aProgramSrc->SetAlphaTest ((theBits & OpenGl_PO_AlphaTest) != 0);
@@ -2536,6 +2588,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramStereo (Handle(OpenGl_Sh
   }
 
   defaultGlslVersion (aProgramSrc, aName, 0);
+  aProgramSrc->SetDefaultSampler (false);
   aProgramSrc->SetNbLightsMax (0);
   aProgramSrc->SetNbClipPlanesMax (0);
   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
@@ -2581,6 +2634,7 @@ Standard_Boolean OpenGl_ShaderManager::prepareStdProgramBoundBox()
     EOL"}";
 
   defaultGlslVersion (aProgramSrc, "bndbox", 0);
+  aProgramSrc->SetDefaultSampler (false);
   aProgramSrc->SetNbLightsMax (0);
   aProgramSrc->SetNbClipPlanesMax (0);
   aProgramSrc->AttachShader (OpenGl_ShaderObject::CreateFromSource (aSrcVert, Graphic3d_TOS_VERTEX,   aUniforms, aStageInOuts));
@@ -2647,3 +2701,33 @@ Standard_Boolean OpenGl_ShaderManager::bindProgramWithState (const Handle(OpenGl
   PushState (theProgram);
   return isBound;
 }
+
+// =======================================================================
+// function : BindMarkerProgram
+// purpose  :
+// =======================================================================
+Standard_Boolean OpenGl_ShaderManager::BindMarkerProgram (const Handle(OpenGl_TextureSet)& theTextures,
+                                                          Graphic3d_TypeOfShadingModel theShadingModel,
+                                                          Graphic3d_AlphaMode theAlphaMode,
+                                                          Standard_Boolean theHasVertColor,
+                                                          const Handle(OpenGl_ShaderProgram)& theCustomProgram)
+{
+  if (!theCustomProgram.IsNull()
+    || myContext->caps->ffpEnable)
+  {
+    return bindProgramWithState (theCustomProgram);
+  }
+
+  Standard_Integer aBits = getProgramBits (theTextures, theAlphaMode, Aspect_IS_SOLID, theHasVertColor, false, false);
+  if (!theTextures.IsNull()
+    && theTextures->HasPointSprite())
+  {
+    aBits |= theTextures->Last()->IsAlpha() ? OpenGl_PO_PointSpriteA : OpenGl_PO_PointSprite;
+  }
+  else
+  {
+    aBits |= OpenGl_PO_PointSimple;
+  }
+  Handle(OpenGl_ShaderProgram)& aProgram = getStdProgram (theShadingModel, aBits);
+  return bindProgramWithState (aProgram);
+}
diff --git a/src/OpenGl/OpenGl_ShaderManager.hxx b/src/OpenGl/OpenGl_ShaderManager.hxx
index 3fdacc2976..5599136161 100644
--- a/src/OpenGl/OpenGl_ShaderManager.hxx
+++ b/src/OpenGl/OpenGl_ShaderManager.hxx
@@ -141,22 +141,11 @@ public:
   }
 
   //! Bind program for point rendering
-  Standard_Boolean BindMarkerProgram (const Handle(OpenGl_TextureSet)&    theTextures,
-                                      const Graphic3d_TypeOfShadingModel  theShadingModel,
-                                      const Graphic3d_AlphaMode           theAlphaMode,
-                                      const Standard_Boolean              theHasVertColor,
-                                      const Handle(OpenGl_ShaderProgram)& theCustomProgram)
-  {
-    if (!theCustomProgram.IsNull()
-     || myContext->caps->ffpEnable)
-    {
-      return bindProgramWithState (theCustomProgram);
-    }
-
-    const Standard_Integer        aBits    = getProgramBits (theTextures, theAlphaMode, Aspect_IS_SOLID, theHasVertColor, false, false) | OpenGl_PO_Point;
-    Handle(OpenGl_ShaderProgram)& aProgram = getStdProgram (theShadingModel, aBits);
-    return bindProgramWithState (aProgram);
-  }
+  Standard_EXPORT Standard_Boolean BindMarkerProgram (const Handle(OpenGl_TextureSet)& theTextures,
+                                                      Graphic3d_TypeOfShadingModel theShadingModel,
+                                                      Graphic3d_AlphaMode theAlphaMode,
+                                                      Standard_Boolean theHasVertColor,
+                                                      const Handle(OpenGl_ShaderProgram)& theCustomProgram);
 
   //! Bind program for rendering alpha-textured font.
   Standard_Boolean BindFontProgram (const Handle(OpenGl_ShaderProgram)& theCustomProgram)
@@ -510,10 +499,9 @@ protected:
       aBits |= OpenGl_PO_TextureEnv;
     }
     else if (!theTextures.IsNull()
-          && !theTextures->IsEmpty()
-          && !theTextures->First().IsNull())
+           && theTextures->HasNonPointSprite())
     {
-      aBits |= theTextures->First()->IsAlpha() ? OpenGl_PO_TextureA : OpenGl_PO_TextureRGB;
+      aBits |= OpenGl_PO_TextureRGB;
     }
     if (theHasVertColor
      && theInteriorStyle != Aspect_IS_HIDDENLINE)
@@ -554,10 +542,11 @@ protected:
   }
 
   //! Prepare standard GLSL program for accessing point sprite alpha.
-  Standard_EXPORT TCollection_AsciiString pointSpriteAlphaSrc (const Standard_Integer theBits);
+  Standard_EXPORT TCollection_AsciiString pointSpriteAlphaSrc (Standard_Integer theBits);
 
   //! Prepare standard GLSL program for computing point sprite shading.
-  Standard_EXPORT TCollection_AsciiString pointSpriteShadingSrc (const TCollection_AsciiString theBaseColorSrc, const Standard_Integer theBits);
+  Standard_EXPORT TCollection_AsciiString pointSpriteShadingSrc (const TCollection_AsciiString& theBaseColorSrc,
+                                                                 Standard_Integer theBits);
 
   //! Prepare standard GLSL program for textured font.
   Standard_EXPORT Standard_Boolean prepareStdProgramFont();
diff --git a/src/OpenGl/OpenGl_ShaderObject.cxx b/src/OpenGl/OpenGl_ShaderObject.cxx
index 783a032afd..90803f1639 100755
--- a/src/OpenGl/OpenGl_ShaderObject.cxx
+++ b/src/OpenGl/OpenGl_ShaderObject.cxx
@@ -49,6 +49,21 @@ static TCollection_AsciiString putLineNumbers (const TCollection_AsciiString& th
   return aResultSource;
 }
 
+//! Return GLSL shader stage title.
+static TCollection_AsciiString getShaderTypeString (GLenum theType)
+{
+  switch (theType)
+  {
+    case GL_VERTEX_SHADER:          return "Vertex Shader";
+    case GL_FRAGMENT_SHADER:        return "Fragment Shader";
+    case GL_GEOMETRY_SHADER:        return "Geometry Shader";
+    case GL_TESS_CONTROL_SHADER:    return "Tessellation Control Shader";
+    case GL_TESS_EVALUATION_SHADER: return "Tessellation Evaluation Shader";
+    case GL_COMPUTE_SHADER:         return "Compute Shader";
+  }
+  return "Shader";
+}
+
 // =======================================================================
 // function : CreateFromSource
 // purpose  :
@@ -211,6 +226,7 @@ OpenGl_ShaderObject::~OpenGl_ShaderObject()
 // purpose  :
 // =======================================================================
 Standard_Boolean OpenGl_ShaderObject::LoadAndCompile (const Handle(OpenGl_Context)& theCtx,
+                                                      const TCollection_AsciiString& theId,
                                                       const TCollection_AsciiString& theSource,
                                                       bool theIsVerbose,
                                                       bool theToPrintSource)
@@ -227,7 +243,8 @@ Standard_Boolean OpenGl_ShaderObject::LoadAndCompile (const Handle(OpenGl_Contex
     {
       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, theSource);
     }
-    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Error! Failed to set shader source");
+    theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
+                         TCollection_AsciiString ("Error! Failed to set ") + getShaderTypeString (myType) + " [" + theId + "] source");
     return false;
   }
 
@@ -244,7 +261,7 @@ Standard_Boolean OpenGl_ShaderObject::LoadAndCompile (const Handle(OpenGl_Contex
       aLog = "Compilation log is empty.";
     }
     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
-                         TCollection_AsciiString ("Failed to compile shader object. Compilation log:\n") + aLog);
+                         TCollection_AsciiString ("Failed to compile ") + getShaderTypeString (myType) + " [" + theId + "]. Compilation log:\n" + aLog);
     return false;
   }
   else if (theCtx->caps->glslWarnings)
@@ -255,12 +272,24 @@ Standard_Boolean OpenGl_ShaderObject::LoadAndCompile (const Handle(OpenGl_Contex
      && !aLog.IsEqual ("No errors.\n"))
     {
       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
-                           TCollection_AsciiString ("Shader compilation log:\n") + aLog);
+                           getShaderTypeString (myType) + " [" + theId + "] compilation log:\n" + aLog);
     }
   }
   return true;
 }
 
+// =======================================================================
+// function : DumpSourceCode
+// purpose  :
+// =======================================================================
+void OpenGl_ShaderObject::DumpSourceCode (const Handle(OpenGl_Context)& theCtx,
+                                          const TCollection_AsciiString& theId,
+                                          const TCollection_AsciiString& theSource) const
+{
+  theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 0, GL_DEBUG_SEVERITY_MEDIUM,
+                       getShaderTypeString (myType) + " [" + theId + "] source code:\n"  + theSource);
+}
+
 // =======================================================================
 // function : LoadSource
 // purpose  : Loads shader source code
@@ -467,7 +496,7 @@ Standard_Boolean OpenGl_ShaderObject::updateDebugDump (const Handle(OpenGl_Conte
         TCollection_AsciiString aNewSource;
         if (restoreShaderSource (aNewSource, aFileName))
         {
-          LoadAndCompile (theCtx, aNewSource);
+          LoadAndCompile (theCtx, theProgramId, aNewSource);
           return Standard_True;
         }
       }
diff --git a/src/OpenGl/OpenGl_ShaderObject.hxx b/src/OpenGl/OpenGl_ShaderObject.hxx
index 5a2650a6cc..0d90082fb9 100755
--- a/src/OpenGl/OpenGl_ShaderObject.hxx
+++ b/src/OpenGl/OpenGl_ShaderObject.hxx
@@ -88,14 +88,21 @@ public:
 
   //! Wrapper for compiling shader object with verbose printing on error.
   //! @param theCtx bound OpenGL context
+  //! @param theId  GLSL program id to define file name
   //! @param theSource source code to load
   //! @param theIsVerbose flag to print log on error
   //! @param theToPrintSource flag to print source code on error
   Standard_EXPORT Standard_Boolean LoadAndCompile (const Handle(OpenGl_Context)& theCtx,
+                                                   const TCollection_AsciiString& theId,
                                                    const TCollection_AsciiString& theSource,
                                                    bool theIsVerbose = true,
                                                    bool theToPrintSource = true);
 
+  //! Print source code of this shader object to messenger.
+  Standard_EXPORT void DumpSourceCode (const Handle(OpenGl_Context)& theCtx,
+                                       const TCollection_AsciiString& theId,
+                                       const TCollection_AsciiString& theSource) const;
+
   //! Fetches information log of the last compile operation.
   Standard_EXPORT Standard_Boolean FetchInfoLog (const Handle(OpenGl_Context)& theCtx,
                                                  TCollection_AsciiString&      theLog);
diff --git a/src/OpenGl/OpenGl_ShaderProgram.cxx b/src/OpenGl/OpenGl_ShaderProgram.cxx
index b9eff19c9b..9b10c93b86 100755
--- a/src/OpenGl/OpenGl_ShaderProgram.cxx
+++ b/src/OpenGl/OpenGl_ShaderProgram.cxx
@@ -402,6 +402,11 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
     aHeaderConstants += TCollection_AsciiString("#define THE_MAX_LIGHTS ") + myNbLightsMax + "\n";
     aHeaderConstants += TCollection_AsciiString("#define THE_MAX_CLIP_PLANES ") + myNbClipPlanesMax + "\n";
     aHeaderConstants += TCollection_AsciiString("#define THE_NB_FRAG_OUTPUTS ") + myNbFragOutputs + "\n";
+    if (!myProxy.IsNull()
+      && myProxy->HasDefaultSampler())
+    {
+      aHeaderConstants += "#define THE_HAS_DEFAULT_SAMPLER\n";
+    }
 
     const TCollection_AsciiString aSource = aHeaderVer                     // #version   - header defining GLSL version, should be first
                                           + (!aHeaderVer.IsEmpty() ? "\n" : "")
@@ -412,7 +417,7 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
                                           + Shaders_Declarations_glsl      // common declarations (global constants and Vertex Shader inputs)
                                           + Shaders_DeclarationsImpl_glsl
                                           + anIter.Value()->Source();      // the source code itself (defining main() function)
-    if (!aShader->LoadAndCompile (theCtx, aSource))
+    if (!aShader->LoadAndCompile (theCtx, myResourceId, aSource))
     {
       aShader->Release (theCtx.operator->());
       return Standard_False;
@@ -420,16 +425,6 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
 
     if (theCtx->caps->glslDumpLevel)
     {
-      TCollection_AsciiString aShaderTypeMsg;
-      switch (anIter.Value()->Type())
-      {
-        case Graphic3d_TOS_COMPUTE:         { aShaderTypeMsg = "Compute shader source code:\n";                break; }
-        case Graphic3d_TOS_VERTEX:          { aShaderTypeMsg = "Vertex shader source code:\n";                 break; }
-        case Graphic3d_TOS_TESS_CONTROL:    { aShaderTypeMsg = "Tesselation control shader source code:\n";    break; }
-        case Graphic3d_TOS_TESS_EVALUATION: { aShaderTypeMsg = "Tesselation evaluation shader source code:\n"; break; }
-        case Graphic3d_TOS_GEOMETRY:        { aShaderTypeMsg = "Geometry shader source code:\n";               break; }
-        case Graphic3d_TOS_FRAGMENT:        { aShaderTypeMsg = "Fragment shader source code:\n";               break; }
-      }
       TCollection_AsciiString anOutputSource = aSource;
       if (theCtx->caps->glslDumpLevel == OpenGl_ShaderProgramDumpLevel_Short)
       {
@@ -441,8 +436,7 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
                        + aHeaderConstants
                        + anIter.Value()->Source();
       }
-      theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_OTHER, 0, GL_DEBUG_SEVERITY_MEDIUM,
-                           TCollection_ExtendedString (aShaderTypeMsg + anOutputSource));
+      aShader->DumpSourceCode (theCtx, myResourceId, anOutputSource);
     }
 
     if (!AttachShader (theCtx, aShader))
@@ -484,6 +478,14 @@ Standard_Boolean OpenGl_ShaderProgram::Initialize (const Handle(OpenGl_Context)&
   {
     SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_0));
   }
+  if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerBaseColor"))
+  {
+    SetUniform (theCtx, aLocSampler, GLint(Graphic3d_TextureUnit_BaseColor));
+  }
+  if (const OpenGl_ShaderUniformLocation aLocSampler = GetUniformLocation (theCtx, "occSamplerPointSprite"))
+  {
+    SetUniform (theCtx, aLocSampler, GLint(theCtx->SpriteTextureUnit()));
+  }
 
   const TCollection_AsciiString aSamplerNamePrefix ("occSampler");
   const Standard_Integer aNbUnitsMax = Max (theCtx->MaxCombinedTextureUnits(), Graphic3d_TextureUnit_NB);
@@ -616,7 +618,7 @@ Standard_Boolean OpenGl_ShaderProgram::Link (const Handle(OpenGl_Context)& theCt
       aLog = "Linker log is empty.";
     }
     theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
-                         TCollection_AsciiString ("Failed to link program object! Linker log:\n") + aLog);
+                         TCollection_AsciiString ("Failed to link program object [") + myResourceId + "]! Linker log:\n" + aLog);
     return false;
   }
   else if (theCtx->caps->glslWarnings)
@@ -627,7 +629,7 @@ Standard_Boolean OpenGl_ShaderProgram::Link (const Handle(OpenGl_Context)& theCt
      && !aLog.IsEqual ("No errors.\n"))
     {
       theCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_PORTABILITY, 0, GL_DEBUG_SEVERITY_LOW,
-                           TCollection_AsciiString ("GLSL linker log:\n") + aLog);
+                           TCollection_AsciiString ("GLSL linker log [") + myResourceId +"]:\n" + aLog);
     }
   }
   return true;
diff --git a/src/OpenGl/OpenGl_Texture.hxx b/src/OpenGl/OpenGl_Texture.hxx
index da9ec7bb78..c077d15edd 100644
--- a/src/OpenGl/OpenGl_Texture.hxx
+++ b/src/OpenGl/OpenGl_Texture.hxx
@@ -453,6 +453,9 @@ public:
   //! Returns estimated GPU memory usage for holding data without considering overheads and allocation alignment rules.
   Standard_EXPORT virtual Standard_Size EstimatedDataSize() const Standard_OVERRIDE;
 
+  //! Returns TRUE for point sprite texture.
+  virtual bool IsPointSprite() const { return false; }
+
 protected:
 
   //! Apply default sampler parameters after texture creation.
diff --git a/src/OpenGl/OpenGl_TextureSet.cxx b/src/OpenGl/OpenGl_TextureSet.cxx
index 51c3c75300..bc42d126ab 100644
--- a/src/OpenGl/OpenGl_TextureSet.cxx
+++ b/src/OpenGl/OpenGl_TextureSet.cxx
@@ -28,3 +28,32 @@ bool OpenGl_TextureSet::IsModulate() const
       || myTextures.First().IsNull()
       || myTextures.First()->Sampler()->Parameters()->IsModulate();
 }
+
+// =======================================================================
+// function : HasNonPointSprite
+// purpose  :
+// =======================================================================
+bool OpenGl_TextureSet::HasNonPointSprite() const
+{
+  if (myTextures.IsEmpty())
+  {
+    return false;
+  }
+  else if (myTextures.Size() == 1)
+  {
+    return !myTextures.First().IsNull()
+        && !myTextures.First()->IsPointSprite();
+  }
+  return !myTextures.First().IsNull();
+}
+
+// =======================================================================
+// function : HasPointSprite
+// purpose  :
+// =======================================================================
+bool OpenGl_TextureSet::HasPointSprite() const
+{
+  return !myTextures.IsEmpty()
+      && !myTextures.Last().IsNull()
+      &&  myTextures.Last()->IsPointSprite();
+}
diff --git a/src/OpenGl/OpenGl_TextureSet.hxx b/src/OpenGl/OpenGl_TextureSet.hxx
index d7c4c5aedb..748ba7da96 100644
--- a/src/OpenGl/OpenGl_TextureSet.hxx
+++ b/src/OpenGl/OpenGl_TextureSet.hxx
@@ -75,6 +75,12 @@ public:
   //! Return the first texture.
   Handle(OpenGl_Texture)& ChangeFirst() { return myTextures.ChangeFirst(); }
 
+  //! Return the last texture.
+  const Handle(OpenGl_Texture)& Last() const { return myTextures.Last(); }
+
+  //! Return the last texture.
+  Handle(OpenGl_Texture)& ChangeLast() { return myTextures.ChangeLast(); }
+
   //! Return the texture at specified position within [0, Size()) range.
   const Handle(OpenGl_Texture)& Value (Standard_Integer theIndex) const { return myTextures.Value (theIndex); }
 
@@ -85,6 +91,18 @@ public:
   //! or if texture is not set at all.
   Standard_EXPORT bool IsModulate() const;
 
+  //! Return TRUE if other than point sprite textures are defined within point set.
+  Standard_EXPORT bool HasNonPointSprite() const;
+
+  //! Return TRUE if last texture is a point sprite.
+  Standard_EXPORT bool HasPointSprite() const;
+
+  //! Nullify all handles.
+  void InitZero()
+  {
+    myTextures.Init (Handle(OpenGl_Texture)());
+  }
+
 protected:
 
   NCollection_Array1<Handle(OpenGl_Texture)> myTextures;
diff --git a/src/OpenGl/OpenGl_View_Raytrace.cxx b/src/OpenGl/OpenGl_View_Raytrace.cxx
index 3185033a1c..7245548bea 100644
--- a/src/OpenGl/OpenGl_View_Raytrace.cxx
+++ b/src/OpenGl/OpenGl_View_Raytrace.cxx
@@ -1450,9 +1450,9 @@ Standard_Boolean OpenGl_View::initRaytraceResources (const Standard_Integer theS
       myPostFSAAShaderSource.SetPrefix (aPrefixString);
       myOutImageShaderSource.SetPrefix (aPrefixString);
 
-      if (!myRaytraceShader->LoadAndCompile (theGlContext, myRaytraceShaderSource.Source())
-       || !myPostFSAAShader->LoadAndCompile (theGlContext, myPostFSAAShaderSource.Source())
-       || !myOutImageShader->LoadAndCompile (theGlContext, myOutImageShaderSource.Source()))
+      if (!myRaytraceShader->LoadAndCompile (theGlContext, myRaytraceProgram->ResourceId(), myRaytraceShaderSource.Source())
+       || !myPostFSAAShader->LoadAndCompile (theGlContext, myPostFSAAProgram->ResourceId(), myPostFSAAShaderSource.Source())
+       || !myOutImageShader->LoadAndCompile (theGlContext, myOutImageProgram->ResourceId(), myOutImageShaderSource.Source()))
       {
         return safeFailBack ("Failed to compile ray-tracing fragment shaders", theGlContext);
       }
diff --git a/src/OpenGl/OpenGl_Workspace.cxx b/src/OpenGl/OpenGl_Workspace.cxx
index 2e82f08374..44451b4937 100644
--- a/src/OpenGl/OpenGl_Workspace.cxx
+++ b/src/OpenGl/OpenGl_Workspace.cxx
@@ -305,9 +305,11 @@ const OpenGl_Aspects* OpenGl_Workspace::ApplyAspects()
     myGlContext->SetShadingMaterial (myAspectsSet, myHighlightStyle);
   }
 
-  if (myAspectsSet->Aspect()->ToMapTexture())
+  const Handle(OpenGl_TextureSet)& aTextureSet = myAspectsSet->TextureSet (myGlContext, ToHighlight());
+  if (!aTextureSet.IsNull()
+   || myAspectsSet->Aspect()->ToMapTexture())
   {
-    myGlContext->BindTextures (myAspectsSet->TextureSet (myGlContext));
+    myGlContext->BindTextures (aTextureSet);
   }
   else
   {
diff --git a/src/Shaders/Declarations.glsl b/src/Shaders/Declarations.glsl
index d214e4a403..05eafa88b0 100644
--- a/src/Shaders/Declarations.glsl
+++ b/src/Shaders/Declarations.glsl
@@ -139,9 +139,11 @@ vec4  occBackMaterial_Specular(void);      //!< Specular reflection
 float occBackMaterial_Shininess(void);     //!< Specular exponent
 float occBackMaterial_Transparency(void);  //!< Transparency coefficient
 
+#ifdef THE_HAS_DEFAULT_SAMPLER
 #define occActiveSampler    occSampler0                //!< alias for backward compatibility
 #define occSamplerBaseColor occSampler0                //!< alias to a base color texture
 uniform               sampler2D occSampler0;           //!< current active sampler;
+#endif
                                                        //!  occSampler1, occSampler2,... should be defined in GLSL program body for multitexturing
 uniform               vec4      occColor;              //!< color value (in case of disabled lighting)
 uniform THE_PREC_ENUM int       occDistinguishingMode; //!< Are front and back faces distinguished?
diff --git a/src/Shaders/Shaders_Declarations_glsl.pxx b/src/Shaders/Shaders_Declarations_glsl.pxx
index f8de26c38b..39929a58fc 100644
--- a/src/Shaders/Shaders_Declarations_glsl.pxx
+++ b/src/Shaders/Shaders_Declarations_glsl.pxx
@@ -142,9 +142,11 @@ static const char Shaders_Declarations_glsl[] =
   "float occBackMaterial_Shininess(void);     //!< Specular exponent\n"
   "float occBackMaterial_Transparency(void);  //!< Transparency coefficient\n"
   "\n"
+  "#ifdef THE_HAS_DEFAULT_SAMPLER\n"
   "#define occActiveSampler    occSampler0                //!< alias for backward compatibility\n"
   "#define occSamplerBaseColor occSampler0                //!< alias to a base color texture\n"
   "uniform               sampler2D occSampler0;           //!< current active sampler;\n"
+  "#endif\n"
   "                                                       //!  occSampler1, occSampler2,... should be defined in GLSL program body for multitexturing\n"
   "uniform               vec4      occColor;              //!< color value (in case of disabled lighting)\n"
   "uniform THE_PREC_ENUM int       occDistinguishingMode; //!< Are front and back faces distinguished?\n"
diff --git a/src/ViewerTest/ViewerTest_ObjectCommands.cxx b/src/ViewerTest/ViewerTest_ObjectCommands.cxx
index 0c16c2293c..aec48cdc60 100644
--- a/src/ViewerTest/ViewerTest_ObjectCommands.cxx
+++ b/src/ViewerTest/ViewerTest_ObjectCommands.cxx
@@ -5600,6 +5600,7 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
   Standard_Boolean toRandColors = Standard_False;
   Standard_Boolean hasNormals   = Standard_True;
   Standard_Boolean isSetArgNorm = Standard_False;
+  Standard_Boolean hasUV        = Standard_False;
   for (Standard_Integer anArgIter = 1; anArgIter < theArgNum; ++anArgIter)
   {
     Standard_CString anArg = theArgs[anArgIter];
@@ -5633,9 +5634,27 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
       isSetArgNorm = Standard_True;
       hasNormals   = Standard_False;
     }
+    else if (aFlag == "-uv"
+          || aFlag == "-texels")
+    {
+      hasUV = Standard_True;
+    }
   }
 
   Standard_CString aName = theArgs[1];
+  Graphic3d_ArrayFlags aFlags = Graphic3d_ArrayFlags_None;
+  if (hasNormals)
+  {
+    aFlags |= Graphic3d_ArrayFlags_VertexNormal;
+  }
+  if (toRandColors)
+  {
+    aFlags |= Graphic3d_ArrayFlags_VertexColor;
+  }
+  if (hasUV)
+  {
+    aFlags |= Graphic3d_ArrayFlags_VertexTexel;
+  }
 
   // generate arbitrary set of points
   Handle(Graphic3d_ArrayOfPoints) anArrayPoints;
@@ -5668,7 +5687,7 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
       return 1;
     }
 
-    anArrayPoints = new Graphic3d_ArrayOfPoints (aNbPoints, toRandColors, hasNormals);
+    anArrayPoints = new Graphic3d_ArrayOfPoints (aNbPoints, aFlags);
     for (TopExp_Explorer aFaceIt (aShape, TopAbs_FACE); aFaceIt.More(); aFaceIt.Next())
     {
       const TopoDS_Face& aFace = TopoDS::Face (aFaceIt.Current());
@@ -5714,6 +5733,11 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
         {
           anArrayPoints->SetVertexNormal (anIndexOfPoint, aNormals (aNodeIter));
         }
+        if (hasUV
+         && aTriangulation->HasUVNodes())
+        {
+          anArrayPoints->SetVertexTexel (anIndexOfPoint, aTriangulation->UVNode (aNodeIter));
+        }
       }
     }
   }
@@ -5737,7 +5761,7 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
 
     gp_Pnt aCenter(aCenterX, aCenterY, aCenterZ);
 
-    anArrayPoints = new Graphic3d_ArrayOfPoints (aNbPoints, toRandColors, hasNormals);
+    anArrayPoints = new Graphic3d_ArrayOfPoints (aNbPoints, aFlags);
     for (Standard_Integer aPntIt = 0; aPntIt < aNbPoints; ++aPntIt)
     {
       Standard_Real anAlpha   = (Standard_Real (rand() % 2000) / 1000.0) * M_PI;
@@ -5762,6 +5786,11 @@ static Standard_Integer VPointCloud (Draw_Interpretor& theDI,
       {
         anArrayPoints->SetVertexNormal (anIndexOfPoint, aDir);
       }
+      if (hasUV)
+      {
+        anArrayPoints->SetVertexTexel (anIndexOfPoint, gp_Pnt2d (anAlpha / 2.0 * M_PI,
+                                                                 aBeta   / 2.0 * M_PI));
+      }
     }
   }
 
@@ -6367,12 +6396,12 @@ void ViewerTest::ObjectCommands(Draw_Interpretor& theCommands)
                    __FILE__, VVertexMode, group);
 
   theCommands.Add ("vpointcloud",
-                   "vpointcloud name shape [-randColor] [-normals] [-noNormals]"
+                   "vpointcloud name shape [-randColor] [-normals] [-noNormals] [-uv]"
                    "\n\t\t: Create an interactive object for arbitary set of points"
                    "\n\t\t: from triangulated shape."
                    "\n"
                    "vpointcloud name x y z r npts {surface|volume}\n"
-                   "            ... [-randColor] [-normals] [-noNormals]"
+                   "            ... [-randColor] [-normals] [-noNormals] [-uv]"
                    "\n\t\t: Create arbitrary set of points (npts) randomly distributed"
                    "\n\t\t: on spheric surface or within spheric volume (x y z r)."
                    "\n\t\t:"
diff --git a/tests/v3d/point_cloud/sphere b/tests/v3d/point_cloud/sphere
index 70dd27a1e3..bcd3d98ded 100644
--- a/tests/v3d/point_cloud/sphere
+++ b/tests/v3d/point_cloud/sphere
@@ -22,6 +22,16 @@ vdump $::imagedir/${::casename}_green.png
 vpointcloud p s -randcolors
 vdump $::imagedir/${::casename}_rand.png
 
+# texture mapping
+vpointcloud p s -normals -uv
+vtexture p 0
+vaspects p -shadingModel GOURAUD
+vdump $::imagedir/${::casename}_tex3.png
+vaspects p -shadingModel PHONG
+vdump $::imagedir/${::casename}_tex2.png
+vaspects p -shadingModel UNLIT
+vdump $::imagedir/${::casename}_tex1.png
+
 # mode with normals
 vpointcloud p s -normals
 vsetmaterial p COPPER