void AttachSkySphere(SkySpherePtr p){
		if (mSkySphere)
			mSkySphere->OnDetachedFromScene(mSelfPtr.lock());
		mSkySphere = p;
		if (mSkySphere){			
			mSkySphere->OnAttachedToScene(mSelfPtr.lock());
		}
	}
	// IRenderable
	void PreRender(const RenderParam& param, RenderParamOut* paramOut){
		if (mSelf->HasObjFlag(SceneObjectFlag::Hide))
			return;

		if (mLastPreRendered == gpTimer->GetFrame())
			return;
		mLastPreRendered = gpTimer->GetFrame();

		if (mBlendingSkySphere && mBlendingSkySphere->GetAlpha() == 1.0f){
			mBlendingSkySphere->PreRender(param, paramOut);
			return;
		}

		if (mInterpolating)
		{
			mCurInterpolationTime += gpTimer->GetDeltaTime();
			float normTime = mCurInterpolationTime / mInterpolationTime;
			if (normTime >= 1.0f)
			{
				normTime = 1.0f;
				mInterpolating = false;
				if (!mUseAlphaBlend)
				{
					SceneObjectFactory::GetInstance().UpdateEnvMapInNextFrame(mSelfPtr.lock());
				}
			}

			for (int i = 0; i < 5; i++)
			{
				mMaterial->SetMaterialParameter(i, Lerp(mMaterialParamCur[i], mMaterialParamDest[i], normTime));
				if (mMaterialOCC)
				{
					mMaterialOCC->SetMaterialParameter(i, Lerp(mMaterialParamCur[i], mMaterialParamDest[i], normTime));
				}
			}
		}

		if (mBlendingSkySphere && mBlendingSkySphere->GetAlpha() != 0.f){
			mBlendingSkySphere->PreRender(param, paramOut);
		}
	}
	void Render(const RenderParam& param, RenderParamOut* paramOut){
		if (mSelf->HasObjFlag(SceneObjectFlag::Hide))
			return;

		if (mBlendingSkySphere && mBlendingSkySphere->GetAlpha() == 1.0f){
			mBlendingSkySphere->Render(param, paramOut);
			return;
		}

		if (!mMaterial)
		{
			assert(0);
			return;
		}

		auto& renderer = Renderer::GetInstance();
		renderer.SetPrimitiveTopology(PRIMITIVE_TOPOLOGY_TRIANGLELIST);
		renderer.UnbindInputLayout();
		renderer.UnbindVertexBuffers();
		if (mMaterialOCC && param.mRenderPass == RENDER_PASS::PASS_GODRAY_OCC_PRE)
		{
			RenderEventMarker mark("SkySphere_OCC");
			mMaterialOCC->Bind(false);
			renderer.Draw(3, 0);
		}
		else if (param.mRenderPass == RENDER_PASS::PASS_NORMAL)
		{
			RenderEventMarker mark("SkySphere");			
			mMaterial->Bind(false);
			if (mUseAlphaBlend)
			{
				renderer.GetResourceProvider()->BindBlendState(ResourceTypes::BlendStates::AlphaBlend);
			}
			renderer.Draw(3, 0);
		}

		if (mBlendingSkySphere && mBlendingSkySphere->GetAlpha() != 0.f){
			mBlendingSkySphere->Render(param, paramOut);
		}
	}
	void PrepareInterpolation(float time, SkySpherePtr startFrom){
		MaterialPtr srcMaterial = mMaterial;
		if (startFrom)
			srcMaterial = startFrom->GetMaterial();
		for (int i = 0; i < 5; i++)
		{
			mMaterialParamCur[i] = srcMaterial->GetMaterialParameter(i);
		}

		mInterpolationTime = time;
		mCurInterpolationTime = 0;
		mInterpolating = true;
	}
	void PreRender(const RenderParam& renderParam, RenderParamOut* renderParamOut){
		mRenderPass = (RENDER_PASS)renderParam.mRenderPass;
		if (!mSkipSpatialObjects)
		{
			auto cam = renderParam.mCamera;
			assert(cam);

			auto it = mLastPreRenderFramePerCam.Find(cam);
			if (it != mLastPreRenderFramePerCam.end() && it->second == gpTimer->GetFrame())
				return;
			mLastPreRenderFramePerCam[cam] = gpTimer->GetFrame();

			MakeVisibleSet(renderParam, renderParamOut);

			auto objIt = mPreRenderList[cam].begin(), objItEnd = mPreRenderList[cam].end();
			for (; objIt != objItEnd; objIt++)
			{
				// Only objects that have a valid renderable is in the render lists.
				(*objIt)->PreRender(renderParam, renderParamOut);				
			}
		}

		if (mSkyRendering)
		{
			if (mSkySphere)
			{
				mSkySphere->PreRender(renderParam, renderParamOut);
			}
		}

		for (auto it = mObjects.begin(); it != mObjects.end(); /**/){
			auto obj = it->lock();
			if (!obj){
				it = mObjects.erase(it);
				continue;
			}
			++it;
			obj->PreRender(renderParam, renderParamOut);			
		}
	}
	void DetachSkySphere(){
		if (mSkySphere){
			mSkySphere->OnDetachedFromScene(mSelfPtr.lock());
			mSkySphere = 0;
		}
	}
	void Render(const RenderParam& param, RenderParamOut* paramOut){
		mRenderPass = (RENDER_PASS)param.mRenderPass;
		auto lightCamera = param.mLightCamera;
		auto cam = param.mCamera;
		if (!mSkipSpatialObjects)
		{
			if (param.mRenderPass == PASS_SHADOW)
			{
				for (auto& obj : mVisibleObjectsLight[lightCamera])
				{
					obj->Render(param, paramOut);
				}
			}
			else
			{
				auto& observers = mSelf->mObservers_[ISceneObserver::Timing];
				for (auto it = observers.begin(); it != observers.end(); /**/){
					auto observer = it->lock();
					if (!observer){
						it = observers.erase(it);
						continue;
					}
					++it;
					observer->OnBeforeRenderingOpaques(mSelf, param, paramOut);
				}

				for (auto& obj : mVisibleObjectsMain[cam])
				{
					obj->Render(param, paramOut);
				}
			}
		}

		if (!(param.mRenderPass == RENDER_PASS::PASS_SHADOW || param.mRenderPass == RENDER_PASS::PASS_DEPTH))
		{
			if (mSkyRendering)
			{
				if (mSkySphere)
				{
					mSkySphere->Render(param, paramOut);
				}

			}

			for (auto it : mSelf->mObservers_[ISceneObserver::Timing]){
				auto observer = it.lock();
				if (observer){
					observer->OnBeforeRenderingTransparents(mSelf, param, paramOut);
				}
			}

			if (!mSkipSpatialObjects)
			{
				auto it = mVisibleTransparentObjects[cam].begin(), itEnd = mVisibleTransparentObjects[cam].end();
				for (; it != itEnd; it++)
				{
					(*it)->Render(param, paramOut);					
				}
			}
			{
				for (auto it : mObjects){
					auto obj = it.lock();
					if (obj){
						obj->Render(param, paramOut);						
					}
				}
			}
		}
	}
	void AttachBlendingSky(SkySpherePtr sky){
		mBlendingSkySphere = sky;
		mBlendingSkySphere->SetUseAlphaBlend(true);
	}