#include <OpenGl_View.hxx>
+#include <Aspect_NeutralWindow.hxx>
#include <Aspect_RenderingContext.hxx>
-#include <Aspect_Window.hxx>
#include <Aspect_XRSession.hxx>
#include <Graphic3d_AspectFillArea3d.hxx>
#include <Graphic3d_Texture2Dmanual.hxx>
#include <Graphic3d_TextureEnv.hxx>
-#include <Graphic3d_Mat4d.hxx>
#include <Image_AlienPixMap.hxx>
#include <OpenGl_ArbFBO.hxx>
#include <OpenGl_BackgroundArray.hxx>
#include <OpenGl_GlCore11.hxx>
#include <OpenGl_GraduatedTrihedron.hxx>
#include <OpenGl_GraphicDriver.hxx>
+#include <OpenGl_RenderFilter.hxx>
#include <OpenGl_ShaderManager.hxx>
#include <OpenGl_ShadowMap.hxx>
#include <OpenGl_Texture.hxx>
myNoShadingLight = new Graphic3d_LightSet();
myNoShadingLight->Add (aLight);
- myMainSceneFbos[0] = new OpenGl_FrameBuffer();
- myMainSceneFbos[1] = new OpenGl_FrameBuffer();
- myMainSceneFbosOit[0] = new OpenGl_FrameBuffer();
- myMainSceneFbosOit[1] = new OpenGl_FrameBuffer();
- myImmediateSceneFbos[0] = new OpenGl_FrameBuffer();
- myImmediateSceneFbos[1] = new OpenGl_FrameBuffer();
- myImmediateSceneFbosOit[0] = new OpenGl_FrameBuffer();
- myImmediateSceneFbosOit[1] = new OpenGl_FrameBuffer();
- myXrSceneFbo = new OpenGl_FrameBuffer();
- myOpenGlFBO = new OpenGl_FrameBuffer();
- myOpenGlFBO2 = new OpenGl_FrameBuffer();
- myRaytraceFBO1[0] = new OpenGl_FrameBuffer();
- myRaytraceFBO1[1] = new OpenGl_FrameBuffer();
- myRaytraceFBO2[0] = new OpenGl_FrameBuffer();
- myRaytraceFBO2[1] = new OpenGl_FrameBuffer();
+ myMainSceneFbos[0] = new OpenGl_FrameBuffer ("fbo0_main");
+ myMainSceneFbos[1] = new OpenGl_FrameBuffer ("fbo1_main");
+ myMainSceneFbosOit[0] = new OpenGl_FrameBuffer ("fbo0_main_oit");
+ myMainSceneFbosOit[1] = new OpenGl_FrameBuffer ("fbo1_main_oit");
+ myImmediateSceneFbos[0] = new OpenGl_FrameBuffer ("fbo0_imm");
+ myImmediateSceneFbos[1] = new OpenGl_FrameBuffer ("fbo1_imm");
+ myImmediateSceneFbosOit[0] = new OpenGl_FrameBuffer ("fbo0_imm_oit");
+ myImmediateSceneFbosOit[1] = new OpenGl_FrameBuffer ("fbo1_imm_oit");
+ myXrSceneFbo = new OpenGl_FrameBuffer ("fbo_xr");
+ myOpenGlFBO = new OpenGl_FrameBuffer ("fbo_gl");
+ myOpenGlFBO2 = new OpenGl_FrameBuffer ("fbo_gl2");
+ myRaytraceFBO1[0] = new OpenGl_FrameBuffer ("fbo0_raytrace1");
+ myRaytraceFBO1[1] = new OpenGl_FrameBuffer ("fbo1_raytrace1");
+ myRaytraceFBO2[0] = new OpenGl_FrameBuffer ("fbo0_raytrace2");
+ myRaytraceFBO2[1] = new OpenGl_FrameBuffer ("fbo1_raytrace2");
myDepthPeelingFbos = new OpenGl_DepthPeeling();
myShadowMaps = new OpenGl_ShadowMapArray();
+
+ myXrSceneFbo->ColorTexture()->Sampler()->Parameters()->SetFilter (Graphic3d_TOTF_BILINEAR);
}
// =======================================================================
}
Handle(OpenGl_Texture) aTextureEnv = new OpenGl_Texture (myTextureEnvData->GetId(), myTextureEnvData->GetParams());
- if (Handle(Image_PixMap) anImage = myTextureEnvData->GetImage (theContext->SupportedTextureFormats()))
- {
- aTextureEnv->Init (theContext, *anImage, myTextureEnvData->Type(), true);
- }
+ aTextureEnv->Init (theContext, myTextureEnvData);
+
myTextureEnv = new OpenGl_TextureSet (aTextureEnv);
myTextureEnv->ChangeTextureSetBits() = Graphic3d_TextureSetBits_BaseColor;
}
// =======================================================================
Handle(Aspect_Window) OpenGl_View::Window() const
{
- return myWindow->PlatformWindow();
+ return myWindow->SizeWindow();
}
// =======================================================================
// function : SetWindow
// purpose :
// =======================================================================
-void OpenGl_View::SetWindow (const Handle(Aspect_Window)& theWindow,
+void OpenGl_View::SetWindow (const Handle(Graphic3d_CView)& theParentVIew,
+ const Handle(Aspect_Window)& theWindow,
const Aspect_RenderingContext theContext)
{
- myWindow = myDriver->CreateRenderWindow (theWindow, theContext);
- Standard_ASSERT_RAISE (!myWindow.IsNull(),
- "OpenGl_View::SetWindow, "
- "Failed to create OpenGl window.");
+ if (theContext != nullptr
+ && !theParentVIew.IsNull())
+ {
+ throw Standard_ProgramError ("OpenGl_View::SetWindow(), internal error");
+ }
+
+ if (myParentView != nullptr)
+ {
+ myParentView->RemoveSubview (this);
+ myParentView = nullptr;
+ }
+
+ OpenGl_View* aParentView = dynamic_cast<OpenGl_View*> (theParentVIew.get());
+ if (!theParentVIew.IsNull())
+ {
+ if (aParentView == nullptr
+ || aParentView->GlWindow().IsNull()
+ || aParentView->GlWindow()->GetGlContext().IsNull())
+ {
+ throw Standard_ProgramError ("OpenGl_View::SetWindow(), internal error");
+ }
+
+ myParentView = aParentView;
+ myParentView->AddSubview (this);
+
+ Handle(Aspect_NeutralWindow) aSubWindow = Handle(Aspect_NeutralWindow)::DownCast(theWindow);
+ SubviewResized (aSubWindow);
+
+ const Handle(OpenGl_Window)& aParentGlWindow = aParentView->GlWindow();
+ Aspect_RenderingContext aRendCtx = aParentGlWindow->GetGlContext()->RenderingContext();
+ myWindow = myDriver->CreateRenderWindow (aParentGlWindow->PlatformWindow(), theWindow, aRendCtx);
+ }
+ else
+ {
+ myWindow = myDriver->CreateRenderWindow (theWindow, theWindow, theContext);
+ }
+ if (myWindow.IsNull())
+ {
+ throw Standard_ProgramError ("OpenGl_View::SetWindow, Failed to create OpenGl window");
+ }
myWorkspace = new OpenGl_Workspace (this, myWindow);
myWorldViewProjState.Reset();
myHasFboBlit = Standard_True;
Invalidate();
+ // choose preferred FBO format
+ const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
+ if (aCtx->IsWindowDeepColor()
+ && aCtx->IsGlGreaterEqual (3, 0))
+ {
+ myFboColorFormat = GL_RGB10_A2;
+ }
+ else if (aCtx->HasSRGB())
+ {
+ // note that GL_SRGB8 is not required to be renderable, unlike GL_RGB8, GL_RGBA8, GL_SRGB8_ALPHA8
+ myFboColorFormat = GL_SRGB8_ALPHA8;
+ }
+ else
+ {
+ myFboColorFormat = GL_RGBA8;
+ }
+
// Environment texture resource does not support lazy initialization.
- initTextureEnv (myWorkspace->GetGlContext());
+ initTextureEnv (aCtx);
}
// =======================================================================
// =======================================================================
void OpenGl_View::Resized()
{
- if (myWindow.IsNull())
- return;
-
- myWindow->Resize();
+ base_type::Resized();
+ if (!myWindow.IsNull())
+ {
+ myWindow->Resize();
+ }
}
// =======================================================================
Bnd_Box aBox = base_type::MinMaxValues (theToIncludeAuxiliary);
+ // make sure that stats overlay isn't clamped on hardware with unavailable depth clamping
+ if (theToIncludeAuxiliary
+ && myRenderParams.ToShowStats
+ && !myWorkspace->GetGlContext()->arbDepthClamp)
+ {
+ Bnd_Box aStatsBox (gp_Pnt (float(myWindow->Width() / 2.0), float(myWindow->Height() / 2.0), 0.0),
+ gp_Pnt (float(myWindow->Width() / 2.0), float(myWindow->Height() / 2.0), 0.0));
+ myRenderParams.StatsPosition->Apply (myCamera, myCamera->ProjectionMatrix(), myCamera->OrientationMatrix(),
+ myWindow->Width(), myWindow->Height(), aStatsBox);
+ aBox.Add (aStatsBox);
+ }
return aBox;
}
{
TCollection_AsciiString aResRatio (myRenderParams.ResolutionRatio());
theDict.ChangeFromIndex (theDict.Add ("ResolutionRatio", aResRatio)) = aResRatio;
+ if (myMainSceneFbos[0]->IsValid())
+ {
+ TCollection_AsciiString anFboInfo;
+ if (const Handle(OpenGl_Texture)& aColorTex = myMainSceneFbos[0]->ColorTexture())
+ {
+ anFboInfo += OpenGl_TextureFormat::FormatFormat (aColorTex->SizedFormat());
+ }
+ if (const Handle(OpenGl_Texture)& aDepthTex = myMainSceneFbos[0]->DepthStencilTexture())
+ {
+ anFboInfo = anFboInfo + " " + OpenGl_TextureFormat::FormatFormat (aDepthTex->SizedFormat());
+ }
+ theDict.ChangeFromIndex (theDict.Add ("FBO buffer", anFboInfo)) = anFboInfo;
+ }
}
}
const bool hasTextureMsaa = aCtx->HasTextureMultisampling();
bool toUseOit = myRenderParams.TransparencyMethod != Graphic3d_RTM_BLEND_UNORDERED
+ && !myIsSubviewComposer
&& checkOitCompatibility (aCtx, aNbSamples > 0);
- const bool toInitImmediateFbo = myTransientDrawToFront
+ const bool toInitImmediateFbo = myTransientDrawToFront && !myIsSubviewComposer
&& (!aCtx->caps->useSystemBuffer || (toUseOit && HasImmediateStructures()));
if ( aFrameBuffer == NULL
aParams->SetTextureUnit (aCtx->PBREnvLUTTexUnit());
anEnvLUT = new OpenGl_Texture(THE_SHARED_ENV_LUT_KEY, aParams);
if (!aTexFormat.IsValid()
- || !anEnvLUT->Init (aCtx, aTexFormat, Graphic3d_Vec2i((Standard_Integer)Textures_EnvLUTSize), Graphic3d_TOT_2D, aPixMap.get()))
+ || !anEnvLUT->Init (aCtx, aTexFormat, Graphic3d_Vec2i((Standard_Integer)Textures_EnvLUTSize), Graphic3d_TypeOfTexture_2D, aPixMap.get()))
{
aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Failed allocation of LUT for PBR");
anEnvLUT.Nullify();
OpenGl_FrameBuffer* aFrameBuffer = myFBO.get();
bool toSwap = aCtx->IsRender()
&& !aCtx->caps->buffersNoSwap
- && aFrameBuffer == NULL
+ && aFrameBuffer == nullptr
&& (!IsActiveXR() || myRenderParams.ToMirrorComposer);
if ( aFrameBuffer == NULL
&& !aCtx->DefaultFrameBuffer().IsNull()
{
toSwap = false;
}
- else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip && toSwap)
+ else if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
+ && toSwap
+ && myParentView == nullptr)
{
aCtx->SwapBuffers();
}
}
// Swap the buffers
- if (toSwap)
+ if (toSwap
+ && myParentView == nullptr)
{
aCtx->SwapBuffers();
if (!myMainSceneFbos[0]->IsValid())
Standard_True) || toSwap;
if (aStereoMode == Graphic3d_StereoMode_SoftPageFlip
&& toSwap
- && myFBO.get() == NULL
- && !aCtx->caps->buffersNoSwap)
+ && myFBO.get() == nullptr
+ && !aCtx->caps->buffersNoSwap
+ && myParentView == nullptr)
{
aCtx->SwapBuffers();
}
if (toSwap
&& myFBO.get() == NULL
- && !aCtx->caps->buffersNoSwap)
+ && !aCtx->caps->buffersNoSwap
+ && myParentView == nullptr)
{
aCtx->SwapBuffers();
}
render (theProjection, theDrawFbo, theOitAccumFbo, Standard_True);
+ blitSubviews (theProjection, theDrawFbo);
+
return !toCopyBackToFront;
}
+// =======================================================================
+// function : blitSubviews
+// purpose :
+// =======================================================================
+bool OpenGl_View::blitSubviews (const Graphic3d_Camera::Projection ,
+ OpenGl_FrameBuffer* theDrawFbo)
+{
+ const Handle(OpenGl_Context)& aCtx = myWorkspace->GetGlContext();
+ if (aCtx->arbFBOBlit == nullptr)
+ {
+ return false;
+ }
+
+ bool isChanged = false;
+ for (const Handle(Graphic3d_CView)& aChildIter : mySubviews)
+ {
+ OpenGl_View* aSubView = dynamic_cast<OpenGl_View*> (aChildIter.get());
+ if (!aSubView->IsActive())
+ {
+ continue;
+ }
+
+ const Handle(OpenGl_FrameBuffer)& aChildFbo = !aSubView->myImmediateSceneFbos[0].IsNull()
+ ? aSubView->myImmediateSceneFbos[0]
+ : aSubView->myMainSceneFbos[0];
+ if (aChildFbo.IsNull() || !aChildFbo->IsValid())
+ {
+ continue;
+ }
+
+ aChildFbo->BindReadBuffer (aCtx);
+ if (theDrawFbo != NULL
+ && theDrawFbo->IsValid())
+ {
+ theDrawFbo->BindDrawBuffer (aCtx);
+ }
+ else
+ {
+ aCtx->arbFBO->glBindFramebuffer (GL_DRAW_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
+ aCtx->SetFrameBufferSRGB (false);
+ }
+
+ Graphic3d_Vec2i aWinSize (aCtx->Viewport()[2], aCtx->Viewport()[3]); //aSubView->GlWindow()->PlatformWindow()->Dimensions();
+ Graphic3d_Vec2i aSubViewSize = aChildFbo->GetVPSize();
+ Graphic3d_Vec2i aSubViewPos = aSubView->SubviewTopLeft();
+ Graphic3d_Vec2i aDestSize = aSubViewSize;
+ if (aSubView->RenderingParams().RenderResolutionScale != 1.0f)
+ {
+ aDestSize = Graphic3d_Vec2i (Graphic3d_Vec2d(aDestSize) / Graphic3d_Vec2d(aSubView->RenderingParams().RenderResolutionScale));
+ }
+ aSubViewPos.y() = aWinSize.y() - aDestSize.y() - aSubViewPos.y();
+
+ const GLint aFilterGl = aDestSize == aSubViewSize ? GL_NEAREST : GL_LINEAR;
+ aCtx->arbFBOBlit->glBlitFramebuffer (0, 0, aSubViewSize.x(), aSubViewSize.y(),
+ aSubViewPos.x(), aSubViewPos.y(), aSubViewPos.x() + aDestSize.x(), aSubViewPos.y() + aDestSize.y(),
+ GL_COLOR_BUFFER_BIT, aFilterGl);
+ const int anErr = aCtx->core11fwd->glGetError();
+ if (anErr != GL_NO_ERROR)
+ {
+ TCollection_ExtendedString aMsg = TCollection_ExtendedString() + "FBO blitting has failed [Error " + OpenGl_Context::FormatGlError (anErr) + "]\n"
+ + " Please check your graphics driver settings or try updating driver.";
+ if (aChildFbo->NbSamples() != 0)
+ {
+ myToDisableMSAA = true;
+ aMsg += "\n MSAA settings should not be overridden by driver!";
+ }
+ aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, aMsg);
+ }
+
+ if (theDrawFbo != NULL
+ && theDrawFbo->IsValid())
+ {
+ theDrawFbo->BindBuffer (aCtx);
+ }
+ else
+ {
+ aCtx->arbFBO->glBindFramebuffer (GL_FRAMEBUFFER, OpenGl_FrameBuffer::NO_FRAMEBUFFER);
+ aCtx->SetFrameBufferSRGB (false);
+ }
+ isChanged = true;
+ }
+
+ return isChanged;
+}
+
//=======================================================================
//function : renderShadowMap
//purpose :
aCtx->core11fwd->glClearDepth (1.0);
aCtx->core11fwd->glClear (GL_DEPTH_BUFFER_BIT);
+ Graphic3d_Camera::Projection aProjection = theShadowMap->LightSource()->Type() == Graphic3d_TypeOfLightSource_Directional
+ ? Graphic3d_Camera::Projection_Orthographic
+ : Graphic3d_Camera::Projection_Perspective;
myWorkspace->SetRenderFilter (myWorkspace->RenderFilter() | OpenGl_RenderFilter_SkipTrsfPersistence);
- renderScene (Graphic3d_Camera::Projection_Orthographic, aShadowBuffer.get(), NULL, false);
- myWorkspace->SetRenderFilter (myWorkspace->RenderFilter() & ~(Standard_Integer )OpenGl_RenderFilter_SkipTrsfPersistence);
+ renderScene (aProjection, aShadowBuffer.get(), NULL, false);
+ myWorkspace->SetRenderFilter (myWorkspace->RenderFilter() & ~(Standard_Integer)OpenGl_RenderFilter_SkipTrsfPersistence);
aCtx->SetColorMask (true);
myWorkspace->ResetAppliedAspect();
OpenGl_FrameBuffer* theOitAccumFbo,
const Standard_Boolean theToDrawImmediate)
{
+ if (myIsSubviewComposer)
+ {
+ return;
+ }
+
myZLayers.UpdateCulling (myWorkspace, theToDrawImmediate);
- if ( myZLayers.NbStructures() <= 0 )
+ if (myZLayers.NbStructures() <= 0)
+ {
return;
+ }
Handle(OpenGl_Context) aCtx = myWorkspace->GetGlContext();
Standard_Boolean toRenderGL = theToDrawImmediate ||
if (!myOpenGlFBO ->InitLazy (aCtx, aPair[0]->GetVPSize(), myFboColorFormat, myFboDepthFormat, 0)
|| !myOpenGlFBO2->InitLazy (aCtx, aPair[0]->GetVPSize(), myFboColorFormat, 0, 0))
{
- aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_ERROR,
- 0,
- GL_DEBUG_SEVERITY_HIGH,
+ aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH,
"Error! Unable to allocate FBO for blitting stereo pair");
bindDefaultFbo (theDrawFbo);
return;
OpenGl_VertexBuffer* aVerts = initBlitQuad (myToFlipOutput);
const Handle(OpenGl_ShaderManager)& aManager = aCtx->ShaderManager();
- if (aVerts->IsValid()
- && aManager->BindStereoProgram (myRenderParams.StereoMode))
+ if (!aVerts->IsValid()
+ || !aManager->BindStereoProgram (myRenderParams.StereoMode))
+ {
+ aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION, GL_DEBUG_TYPE_ERROR, 0, GL_DEBUG_SEVERITY_HIGH, "Error! Anaglyph has failed");
+ return;
+ }
+
+ switch (myRenderParams.StereoMode)
{
- if (myRenderParams.StereoMode == Graphic3d_StereoMode_Anaglyph)
+ case Graphic3d_StereoMode_Anaglyph:
{
OpenGl_Mat4 aFilterL, aFilterR;
aFilterL.SetDiagonal (Graphic3d_Vec4 (0.0f, 0.0f, 0.0f, 0.0f));
}
aCtx->ActiveProgram()->SetUniform (aCtx, "uMultL", aFilterL);
aCtx->ActiveProgram()->SetUniform (aCtx, "uMultR", aFilterR);
+ break;
}
-
- aPair[0]->ColorTexture()->Bind (aCtx, Graphic3d_TextureUnit_0);
- aPair[1]->ColorTexture()->Bind (aCtx, Graphic3d_TextureUnit_1);
- aVerts->BindVertexAttrib (aCtx, 0);
-
- aCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
-
- aVerts->UnbindVertexAttrib (aCtx, 0);
- aPair[1]->ColorTexture()->Unbind (aCtx, Graphic3d_TextureUnit_1);
- aPair[0]->ColorTexture()->Unbind (aCtx, Graphic3d_TextureUnit_0);
+ case Graphic3d_StereoMode_RowInterlaced:
+ {
+ Graphic3d_Vec2 aTexOffset = myRenderParams.ToSmoothInterlacing
+ ? Graphic3d_Vec2 (0.0f, -0.5f / float(aPair[0]->GetSizeY()))
+ : Graphic3d_Vec2();
+ aCtx->ActiveProgram()->SetUniform (aCtx, "uTexOffset", aTexOffset);
+ break;
+ }
+ case Graphic3d_StereoMode_ColumnInterlaced:
+ {
+ Graphic3d_Vec2 aTexOffset = myRenderParams.ToSmoothInterlacing
+ ? Graphic3d_Vec2 (0.5f / float(aPair[0]->GetSizeX()), 0.0f)
+ : Graphic3d_Vec2();
+ aCtx->ActiveProgram()->SetUniform (aCtx, "uTexOffset", aTexOffset);
+ break;
+ }
+ case Graphic3d_StereoMode_ChessBoard:
+ {
+ Graphic3d_Vec2 aTexOffset = myRenderParams.ToSmoothInterlacing
+ ? Graphic3d_Vec2 (0.5f / float(aPair[0]->GetSizeX()),
+ -0.5f / float(aPair[0]->GetSizeY()))
+ : Graphic3d_Vec2();
+ aCtx->ActiveProgram()->SetUniform (aCtx, "uTexOffset", aTexOffset);
+ break;
+ }
+ default: break;
}
- else
+
+ for (int anEyeIter = 0; anEyeIter < 2; ++anEyeIter)
{
- TCollection_ExtendedString aMsg = TCollection_ExtendedString()
- + "Error! Anaglyph has failed";
- aCtx->PushMessage (GL_DEBUG_SOURCE_APPLICATION,
- GL_DEBUG_TYPE_ERROR,
- 0,
- GL_DEBUG_SEVERITY_HIGH,
- aMsg);
+ OpenGl_FrameBuffer* anEyeFbo = aPair[anEyeIter];
+ anEyeFbo->ColorTexture()->Bind (aCtx, (Graphic3d_TextureUnit )(Graphic3d_TextureUnit_0 + anEyeIter));
+ if (anEyeFbo->ColorTexture()->Sampler()->Parameters()->Filter() != Graphic3d_TOTF_BILINEAR)
+ {
+ // force filtering
+ anEyeFbo->ColorTexture()->Sampler()->Parameters()->SetFilter (Graphic3d_TOTF_BILINEAR);
+ aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ aCtx->core20fwd->glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ }
}
+ aVerts->BindVertexAttrib (aCtx, 0);
+
+ aCtx->core20fwd->glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
+
+ aVerts->UnbindVertexAttrib (aCtx, 0);
+ aPair[1]->ColorTexture()->Unbind (aCtx, Graphic3d_TextureUnit_1);
+ aPair[0]->ColorTexture()->Unbind (aCtx, Graphic3d_TextureUnit_0);
}
// =======================================================================