Jump to content

[C++] Dynamic Shadows for Trees & Objects + Remove Static shadowmap Logic


Recommended Posts

  • Active+ Member
This is the hidden content, please

Alternative download links →

This is the hidden content, please

 

It's about time we get rid of this pre-historic shadowmap loading logic and get proper shadows for both trees and objects.

Before:

.png

After:

.png

 

My method may not be the most efficient and best way to do it. Feel free to improve it and comment them on this topic.

 

  • Metin2 Dev 127
  • Eyes 4
  • Flame 1
  • Scream 1
  • Good 18
  • muscle 1
  • Love 2
  • Love 72
  • Active+ Member

I committed a minor update to fix the shadows not being displayed. And also it would be cool if someone implements the logic to the WorldEditor source that I shared. Currently, I only removed the static shadowmap logic from WorldEditor, but didn't integrate dynamic shadows.

 

 

  • Metin2 Dev 3
  • Lmao 1
  • Love 3
  • Active+ Member

Absolutely legendary!

There’s just a tiny issue with the frustum culling when handling dynamic objects. 

https://metin2.download/picture/guMqTBH4p6tJ9u857pm74905NOV84iTm/.png


You can fix it by slightly extending the bounding sphere so shadows aren’t accidentally cut off.

 

SphereLib/frustum.cpp

Spoiler
ViewState Frustum::ViewVolumeTest(const Vector3d &c_v3Center,const float c_fRadius) const
{
	const auto dynamicShadowExtend = 2.0f; // idk i think even 1.5 should do it
	
	if (m_bUsingSphere)
	{
		D3DXVECTOR3 v(
				c_v3Center.x-m_v3Center.x,
				c_v3Center.y-m_v3Center.y,
				c_v3Center.z-m_v3Center.z);

		if ((c_fRadius * dynamicShadowExtend + m_fRadius) * (c_fRadius * dynamicShadowExtend + m_fRadius) < D3DXVec3LengthSq(&v))
		{
			return VS_OUTSIDE;
		}
	}

	const int count=6;

	D3DXVECTOR3 center = c_v3Center;

	int i;

	float distance[count];
	for(i=0;i<count;i++)
	{
		distance[i] = D3DXPlaneDotCoord(&m_plane[i],&center);
		if (distance[i] <= -c_fRadius * dynamicShadowExtend)
			return VS_OUTSIDE;
	}

	for(i=0;i<count;i++)
	{
		if (distance[i]<=c_fRadius)
			return VS_PARTIAL;
	}

	return VS_INSIDE;
}

 

 

 

also this topic should help with the distance 

 

 

Edited by Metin2 Dev International
Core X - External 2 Internal
  • Metin2 Dev 1
  • Love 2

I don’t know — I think.

 

Discord

 

If you are a masochist like me, and you stucked using the sh*tty Terenzo client source as me, you need to modify the GameLib/MapOutdoorRenderSTP.cpp file as well!
Search:

		if (isFogEnable)
		{
			STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, TRUE);
			STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, 0xFFFFFFFF);
			STATEMANAGER.SetTexture(0, pTerrain->GetShadowTexture());
			STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
			STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, rkTPRS.m_dwFogColor);
			STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, FALSE);
		}
		else
		{
			STATEMANAGER.SetTexture(0, pTerrain->GetShadowTexture());
			STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
		}

Modify like this (add the STATEMANAGER.SetTexture(0, nullptr); lines to the correct place):

		if (isFogEnable)
		{
			STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, TRUE);
			STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, 0xFFFFFFFF);
			STATEMANAGER.SetTexture(0, nullptr);
			STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
			STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, rkTPRS.m_dwFogColor);
			STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, FALSE);
		}
		else
		{
			STATEMANAGER.SetTexture(0, nullptr);
			STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
		}

Search:

void CMapOutdoor::__SoftwareTransformPatch_ApplyStaticShadowRenderState()
{
	STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
	STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
	
	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_MODULATE);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1);
	STATEMANAGER.SetSamplerState(0, D3DSAMP_ADDRESSU,	D3DTADDRESS_CLAMP);
	STATEMANAGER.SetSamplerState(0, D3DSAMP_ADDRESSV,	D3DTADDRESS_CLAMP);
}

Modify like this:

void CMapOutdoor::__SoftwareTransformPatch_ApplyStaticShadowRenderState()
{
	STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
	STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);

	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_CURRENT);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
}


And now you are good to go!

  • Active+ Member
3 minutes ago, Werwolf94 said:

If you are a masochist like me, and you stucked using the sh*tty Terenzo client source as me, you need to modify the GameLib/MapOutdoorRenderSTP.cpp file as well!
Search:

		if (isFogEnable)
		{
			STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, TRUE);
			STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, 0xFFFFFFFF);
			STATEMANAGER.SetTexture(0, pTerrain->GetShadowTexture());
			STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
			STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, rkTPRS.m_dwFogColor);
			STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, FALSE);
		}
		else
		{
			STATEMANAGER.SetTexture(0, pTerrain->GetShadowTexture());
			STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
		}

Modify like this (add the STATEMANAGER.SetTexture(0, nullptr); lines to the correct place):

		if (isFogEnable)
		{
			STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, TRUE);
			STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, 0xFFFFFFFF);
			STATEMANAGER.SetTexture(0, nullptr);
			STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
			STATEMANAGER.SetRenderState(D3DRS_FOGCOLOR, rkTPRS.m_dwFogColor);
			STATEMANAGER.SetRenderState(D3DRS_FOGENABLE, FALSE);
		}
		else
		{
			STATEMANAGER.SetTexture(0, nullptr);
			STATEMANAGER.DrawIndexedPrimitive(ePrimitiveType, 0, m_iPatchTerrainVertexCount, 0, wPrimitiveCount);
		}

Search:

void CMapOutdoor::__SoftwareTransformPatch_ApplyStaticShadowRenderState()
{
	STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
	STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);
	
	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP,   D3DTOP_MODULATE);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1);
	STATEMANAGER.SetSamplerState(0, D3DSAMP_ADDRESSU,	D3DTADDRESS_CLAMP);
	STATEMANAGER.SetSamplerState(0, D3DSAMP_ADDRESSV,	D3DTADDRESS_CLAMP);
}

Modify like this:

void CMapOutdoor::__SoftwareTransformPatch_ApplyStaticShadowRenderState()
{
	STATEMANAGER.SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
	STATEMANAGER.SetRenderState(D3DRS_DESTBLEND, D3DBLEND_SRCCOLOR);

	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_CURRENT);
	STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
}


And now you are good to go!

Right, I completely removed software tiling from my source so i don't have MapOutdoorSTP.cpp. It's useless in 2025 but many people still haven't removed it, thanks.

  • Metin2 Dev 1
On 10/11/2025 at 6:16 PM, Chookez said:

Thank you for your work, it's working.
I just found one small 'issue', when you step on the bridge, it turns darker.

did you manage to fix it?

3 hours ago, muiekanzidor said:

did you manage to fix it?

Personally I partially don't recommend to implement this to your server because the bridge problem.
The other downside is at the distant terrain where there are no mobs/npcs just buildings/trees and the terrain there will be no shadows because the real time rendering is limited to a specific distance.
The other issue is objects which placed partially undergrond like a bridge a tree, the tree models have a circle base and it will be casted to the grass which is above them or a bridge pillar's shadow could be seen casted on the ground texture.
The idea is good but the classic static shadowmapping has much advantages like shadows are rendered allways at the distant terrain.
Not to mention the dinamic shadows are shaking when you ride a horse or run, they are not stable.

Implement that fixes which @ CONTROL mentioned so mob/other dynamic shadows will be casted further, keep the old static lightmapping engine until the issues I mentioned are not fixed.

Edited by Werwolf94
  • Lmao 1
  • Active+ Member
1 hour ago, Werwolf94 said:

Personally I partially don't recommend to implement this to your server because the bridge problem.
The other downside is at the distant terrain where there are no mobs/npcs just buildings/trees and the terrain there will be no shadows because the real time rendering is limited to a specific distance.
The other issue is objects which placed partially undergrond like a bridge a tree, the tree models have a circle base and it will be casted to the grass which is above them or a bridge pillar's shadow could be seen casted on the ground texture.
The idea is good but the classic static shadowmapping has much advantages like shadows are rendered allways at the distant terrain.
Not to mention the dinamic shadows are shaking when you ride a horse or run, they are not stable.

Implement that fixes which @ CONTROL mentioned so mob/other dynamic shadows will be casted further, keep the old static lightmapping engine until the issues I mentioned are not fixed.

As I said, this should help with the distance.

  

 

As for the bridge issue, I was able to fix it with literally one line of code : img

 

And I don't have any of the other problems you mentioned 🫠

 

Edited by Metin2 Dev International
Core X - External 2 Internal

I don’t know — I think.

 

Discord

 

// MapOutdoorRender.cpp 

//Search:
    void operator () (CGraphicObjectInstance * pInstance)
    {

//Add under:
        if (CGraphicThingInstance* ti = dynamic_cast<CGraphicThingInstance*>(pInstance))
        {
            if (ti->IsObjectHeight())
                return;
        }
        

  • Metin2 Dev 1
  • Good 1
  • Love 2
17 hours ago, HAMLET said:

// MapOutdoorRender.cpp 

//Search:
    void operator () (CGraphicObjectInstance * pInstance)
    {

//Add under:
        if (CGraphicThingInstance* ti = dynamic_cast<CGraphicThingInstance*>(pInstance))
        {
            if (ti->IsObjectHeight())
                return;
        }
        

but this hides the shadows entirely for entities ...

  • Metin2 Dev 1
On 10/15/2025 at 5:48 AM, HAMLET said:

// MapOutdoorRender.cpp 

//Search:
    void operator () (CGraphicObjectInstance * pInstance)
    {

//Add under:
        if (CGraphicThingInstance* ti = dynamic_cast<CGraphicThingInstance*>(pInstance))
        {
            if (ti->IsObjectHeight())
                return;
        }
        

Wooow @HAMLET, you are a lifesaver!
I had this stupid bug from the begining, I think fog was the problem when you stepped on the bridge, before the fix:

After the fix working flawlessly:

I don't have problems like @muiekanzidor mentioned, entity shadows casted well on the ground after the fix.
(Note: I don't implemented the dynamic shadows system, just extended the mobs/other dynamic entities shadow range.)

Edited by Werwolf94
  • Good 1
25 minutes ago, Werwolf94 said:

Wooow @HAMLET, you are a lifesaver!
I had this stupid bug from the begining, I think fog was the problem when you stepped on the bridge, before the fix:

After the fix working flawlessly:

I don't have problems like @muiekanzidor mentioned, entity shadows casted well on the ground after the fix.
(Note: I don't implemented the dynamic shadows system, just extended the mobs/other dynamic entities shadow range.)

He was just trying to advertise and redirect members to another forum. 

Edited by HAMLET
1 hour ago, Werwolf94 said:

I don't have problems like @muiekanzidor mentioned, entity shadows casted well on the ground after the fix.

You have that problem as well, look on the character while crossing the bridge. It does not have shadows..

  • Metin2 Dev 1
  • Active+ Member

By any chance, can this system be modified like the shadows being seen on other objects too? Or it would require an entire overhaul of it in regards of that?

  • Active+ Member
4 hours ago, KolenMG said:

By any chance, can this system be modified like the shadows being seen on other objects too? Or it would require an entire overhaul of it in regards of that?

I would say metin2's current fixed directx pipeline is not worth improving. We need to transition into shaders and get rid of the entire fixed pipeline, and then do such things.

  • Active+ Member
On 10/24/2025 at 7:26 AM, Kaptan Yosun said:

I would say metin2's current fixed directx pipeline is not worth improving. We need to transition into shaders and get rid of the entire fixed pipeline, and then do such things.

ouff. okey. I

ll still trying to do that, tho. 

void CSpeedTreeForestDirectX8::Render(unsigned long ulRenderBitVector)
{
	ms_bRenderingToShadow = (ulRenderBitVector & Forest_RenderToShadow);
	if (m_pMainTreeMap.empty())
		return;

	if (!(ulRenderBitVector & Forest_RenderToShadow) && !(ulRenderBitVector & Forest_RenderToMiniMap))
#ifdef DIN_SHADOW
		if (ms_bRenderingToShadow)
			UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
		else
			UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj); // in real this part were UpdateCompundMatrix2 not UpdateCompundMatrix, for this reason i didn t deleted the if/else statement
#else
		UpdateCompundMatrix(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
#endif
	DWORD dwLightState = STATEMANAGER.GetRenderState(D3DRS_LIGHTING);
	DWORD dwColorVertexState = STATEMANAGER.GetRenderState(D3DRS_COLORVERTEX);
	DWORD dwFogVertexMode = STATEMANAGER.GetRenderState(D3DRS_FOGVERTEXMODE);

	STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
	STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, TRUE);

	UINT uiCount;
	TTreeMap::const_iterator itor = m_pMainTreeMap.begin();

	while (itor != m_pMainTreeMap.end())
	{
		SpeedTreeWrapperPtr pMainTree = (itor++)->second;
		std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

		for (auto it : ppInstances)
		{
			if (it.expired())
				continue;

			auto pInstance = it.lock();
			if (!pInstance->isShow())
				continue;


			pInstance->Advance();
		}
	}

	STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Light, m_afLighting, 3);
	STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Fog, m_afFog, 1);

	if (ulRenderBitVector & Forest_RenderToShadow)
	{
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
	}
	else
	{
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ANISOTROPIC);

		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
		STATEMANAGER.SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		STATEMANAGER.SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}

	STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, TRUE);
	STATEMANAGER.SaveRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
	STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_CW);

	// set up fog if it is enabled
	if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE))
	{
#ifdef JTX_GPU_TREE_WIND
		STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_NONE); // GPU needs to work on all cards
#endif
	}

	STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);


	if (ulRenderBitVector & Forest_RenderLeaves)
	{
		STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_LEAF_VERTEX);
		STATEMANAGER.SetVertexShader(m_dwLeafVertexShader);

		if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE)) {}
		if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
		{
			STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_NOTEQUAL);
			STATEMANAGER.SaveRenderState(D3DRS_ALPHAREF, 0x00000000);
		}

		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupLeafForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;


				pInstance->RenderLeaves();
			}
		}

		if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
		{
			STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
			STATEMANAGER.RestoreRenderState(D3DRS_ALPHAREF);
		}
	}

	if (ulRenderBitVector & Forest_RenderFronds)
	{
		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupFrondForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;


				pInstance->RenderFronds();
			}
		}
	}

	STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_BRANCH_VERTEX);
	STATEMANAGER.SetVertexShader(m_dwBranchVertexShader);


	if (ulRenderBitVector & Forest_RenderBranches)
	{
		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupBranchForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;


				pInstance->RenderBranches();
			}
		}
	}

	if (ulRenderBitVector & Forest_RenderBillboards)
	{
		STATEMANAGER.SetVertexShader(NULL);
		STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_BILLBOARD_VERTEX);
		STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
		STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, FALSE);

		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupBranchForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;


				pInstance->RenderBillboards();
			}
		}
	}

	STATEMANAGER.SetRenderState(D3DRS_LIGHTING, dwLightState);
	STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, dwColorVertexState);
	STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, dwFogVertexMode);

	if (!(ulRenderBitVector & Forest_RenderToShadow))
	{
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);

	}

	STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
	STATEMANAGER.RestoreRenderState(D3DRS_ALPHAFUNC);
	STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
	m_bIsRenderingToShadow = false;
}


void CSpeedTreeForestDirectX8::UpdateCompundMatrix2(const D3DXVECTOR3& c_rEyeVec, const D3DXMATRIX& c_rmatView, const D3DXMATRIX& c_rmatProj)
{
	// setup composite matrix for shader
	D3DXMATRIX matBlend;
	D3DXMatrixIdentity(&matBlend);

	D3DXMATRIX matBlendShader;
	D3DXMatrixMultiply(&matBlendShader, &c_rmatView, &c_rmatProj);

	float afDirection[3];
	//afDirection[0] = matBlendShader.m[0][2];
	//afDirection[1] = matBlendShader.m[1][2];
	//afDirection[2] = matBlendShader.m[2][2];
	//CSpeedTreeRT::SetCamera(c_rEyeVec, afDirection);

	D3DXMatrixTranspose(&matBlendShader, &matBlendShader);
	STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_CompoundMatrix, &matBlendShader, 4);
}

in class CSpeedTreeForestDirectX8 : public CSpeedTreeForest, public CGraphicBase    (speedtreeforestdirectx8.h)

public:
#ifdef DIN_SHADOW
	static bool ms_bRenderingToShadow;
	static bool IsRenderingToShadowMap() { return ms_bRenderingToShadow; }
#endif

private:
#ifdef DIN_SHADOW
	bool m_bIsRenderingToShadow;
#endif

speedtreewrapper.cpp
 

void CSpeedTreeWrapper::RenderLeaves(void) const
{
	STATEMANAGER.SetRenderState(D3DRS_ALPHATESTENABLE, TRUE);
	m_pSpeedTree->GetGeometry(*m_pGeometryCache, SpeedTree_LeafGeometry);

	PositionTree();

	const CSpeedTreeRT::SGeometry::SLeaf* pLeaf = &m_pGeometryCache->m_sLeaves0;
	int unLod = pLeaf->m_nDiscreteLodLevel;

	if (unLod > -1 && pLeaf->m_bIsActive && pLeaf->m_usLeafCount > 0)
	{
		STATEMANAGER.SetStreamSource(0, m_pLeafVertexBuffer[unLod], sizeof(SFVFLeafVertex));
		UINT leafPrimitiveCount = pLeaf->m_usLeafCount * 2;
		ms_faceCount += leafPrimitiveCount * 2;

		DWORD oldCullMode;
		STATEMANAGER.GetRenderState(D3DRS_CULLMODE, &oldCullMode);
		STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
		float rotationParams[4] = { 1.0f, 0.0f, 0.0f, 0.0f };
		STATEMANAGER.SetVertexShaderConstant(91, rotationParams, 1);
		STATEMANAGER.DrawPrimitive(D3DPT_TRIANGLELIST, 0, leafPrimitiveCount);

		if (!CSpeedTreeForestDirectX8::IsRenderingToShadowMap())
		{
			//Draw the second quad (the one roated by 90°)
			rotationParams[0] = 0.0f;
			rotationParams[1] = 1.0f;
			STATEMANAGER.SetVertexShaderConstant(91, rotationParams, 1);
			STATEMANAGER.DrawPrimitive(D3DPT_TRIANGLELIST, 0, leafPrimitiveCount);
		}

		STATEMANAGER.SetRenderState(D3DRS_CULLMODE, oldCullMode);
	}
}

vertexshader.h
 

///////////////////////////////////////////////////////////////////////
//    SpeedTreeRT4.1 DirectX9 Example
//
//    (c) 2006 IDV, Inc.
//
//    This example demonstrates how to render trees using SpeedTreeRT
//    and DirectX.  Techniques illustrated include ".spt" file parsing,
//    static lighting, dynamic lighting, LOD implementation, cloning,
//    instancing, and dynamic wind effects.
//
//
//    *** INTERACTIVE DATA VISUALIZATION (IDV) PROPRIETARY INFORMATION ***
//
//    This software is supplied under the terms of a license agreement or
//    nondisclosure agreement with Interactive Data Visualization and may
//    not be copied or disclosed except in accordance with the terms of
//    that agreement.
//
//      Copyright (c) 2001-2006 IDV, Inc.
//      All Rights Reserved.
//
//          IDV, Inc.
//          1233 Washington St. Suite 610
//          Columbia, SC 29201
//          Voice: (803) 799-1699
//          Fax:   (803) 931-0320
//          Web:   http://www.idvinc.com


///////////////////////////////////////////////////////////////////////
//    Includes

#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include "SpeedTreeConfig.h"
#include <map>
#include <string>


static DWORD D3DFVF_SPEEDTREE_BRANCH_VERTEX =
D3DFVF_XYZ |
#ifdef JTX_TREE_DYNAMIC_LIGHT
D3DFVF_NORMAL |
#else
D3DFVF_DIFFUSE |
#endif
D3DFVF_TEXCOORDSIZE2(0) |
D3DFVF_TEXCOORDSIZE2(1) |
D3DFVF_TEXCOORDSIZE2(2)
#ifdef JTX_GPU_TREE_WIND
#ifdef WRAPPER_RENDER_SELF_SHADOWS
| D3DFVF_TEX3;
#else
| D3DFVF_TEX2;
#endif
#else
#ifdef WRAPPER_RENDER_SELF_SHADOWS
| D3DFVF_TEX2;
#else
| D3DFVF_TEX1;
#endif
#endif


///////////////////////////////////////////////////////////////////////
// FVF Branch Vertex Structure

struct SFVFBranchVertex
{
    D3DXVECTOR3     m_vPosition;        // Always Used
#ifdef JTX_TREE_DYNAMIC_LIGHT
    D3DXVECTOR3     m_vNormal;          // Dynamic Lighting Only
#else
    DWORD           m_dwDiffuseColor;   // Static Lighting Only
#endif
    FLOAT           m_fTexCoords[2];    // Always Used
#ifdef JTX_GPU_TREE_WIND
    FLOAT           m_fWindIndex;       // GPU Only
    FLOAT           m_fWindWeight;
#endif
#ifdef WRAPPER_RENDER_SELF_SHADOWS
    FLOAT           m_fShadowCoords[2]; // Texture coordinates for the shadows
#endif
};


///////////////////////////////////////////////////////////////////////
//    Branch/Frond Vertex Program

static const char g_achSimpleVertexProgram[] =
{
        "vs.1.1\n"                      // identity shader version

        "dcl_position     v0\n"          // declare the data coming in
    #ifdef JTX_TREE_DYNAMIC_LIGHT
        "dcl_normal        v3\n"
    #else
        "dcl_color         v5\n"
    #endif
        "dcl_texcoord0     v7\n"
        "dcl_texcoord1     v8\n"
    #ifdef WRAPPER_RENDER_SELF_SHADOWS
        "dcl_texcoord2     v9\n"
    #endif

        "mov    oT0.xy,   v7\n"          // always pass texcoord0 through

    #ifdef WRAPPER_RENDER_SELF_SHADOWS
        "mov    oT1.xy, v9\n"           // pass shadow texcoords through
    #endif

        // retrieve and convert wind matrix index
        "mov    a0.x,   v8.x\n"

    // perform wind interpolation
    "m4x4   r1,       v0,         c[54+a0.x]\n"    // compute full wind effect
    "sub    r2,       r1,         v0\n"          // compute difference between full wind and none
    "mov    r3.x,   v8.y\n"                      // mad can't access two v's at once, use r3.x as tmp
    "mad    r1,       r2,         r3.x,       v0\n" // perform interpolation

    "add    r2,       c[52],      r1\n"          // translate to tree's position
    "m4x4   r4,       r2,         c[0]\n"        // project to screen
    "mov    oPos,   r4\n"              //// use of temp register
    "mov    oT1,    r4\n"              //// pass Z value as additional output

#ifdef WRAPPER_USE_FOG
    "dp4    r1,         r2,         c[2]\n"        // compute distance
    "sub    r2.x,     c[85].y,    r1.z\n"        // linear fog
    "mul    oFog,     r2.x,       c[85].z\n"     // write outputs
#endif

#ifdef WRAPPER_USE_STATIC_LIGHTING
    "mov    oD0,    v5\n"              // pass color through
#else
    "mov    r1,       c[74]\n"                     // can only use one const register per instruction
    "mul    r5,       c[73],      r1\n"          // diffuse values

    "mov    r1,       c[75]\n"                     // can only use one const register per instruction
    "mul    r4,       c[72],      r1\n"          // ambient values

    "dp3    r2,       v3,         -c[71]\n"        // dot light direction with normal
    "max    r2.x,     r2.x,       c[38].x\n"     // limit it
    "mad    oD0,    r2.x,       r5,         r4\n"  // compute the final color
#endif
};


///////////////////////////////////////////////////////////////////////
//    LoadBranchShader

inline LPDIRECT3DVERTEXSHADER9 LoadBranchShader(LPDIRECT3DDEVICE9 pDx)
{
#ifndef JTX_GPU_TREE_WIND
    //lint -e522
    UNREFERENCED_PARAMETER(pDx);
    return NULL;
#else
    // assemble shader
    LPDIRECT3DVERTEXSHADER9 dwShader;
    LPD3DXBUFFER pCode, pError;
    if (D3DXAssembleShader(g_achSimpleVertexProgram, sizeof(g_achSimpleVertexProgram) - 1, 0, NULL, 0, &pCode, &pError) == D3D_OK)
    {
        if (pDx->CreateVertexShader((DWORD*)pCode->GetBufferPointer(), &dwShader) != D3D_OK)
        {
            char szError[1024];
            sprintf(szError, "Failed to create branch vertex shader.");
            MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
        }
    }
    else
    {
        char szError[1024];
        sprintf(szError, "Failed to assemble branch vertex shader.\nThe error reported is [ %s ].\n", pError->GetBufferPointer());
        MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
    }

    if (pCode)
        pCode->Release();

    return dwShader;
#endif
}


///////////////////////////////////////////////////////////////////////
//    Leaf Vertex Formats

static DWORD D3DFVF_SPEEDTREE_LEAF_VERTEX =
D3DFVF_XYZ |                  // always have the position
#ifdef JTX_TREE_DYNAMIC_LIGHT // precomputed colors or geometric normals
D3DFVF_NORMAL |
#else
D3DFVF_DIFFUSE |
#endif
D3DFVF_TEXCOORDSIZE2(0) |
D3DFVF_TEXCOORDSIZE2(1) |
D3DFVF_TEXCOORDSIZE2(2) |
#if defined JTX_GPU_TREE_WIND || defined JTX_GPU_LEAF_PLACEMENT
D3DFVF_TEX3;
#else
D3DFVF_TEX1;
#endif


///////////////////////////////////////////////////////////////////////
// FVF Leaf Vertex Structure

struct SFVFLeafVertex
{
    D3DXVECTOR3     m_vPosition;        // Always Used
#ifdef JTX_TREE_DYNAMIC_LIGHT
    D3DXVECTOR3     m_vNormal;          // Dynamic Lighting Only
#else
    DWORD           m_dwDiffuseColor;   // Static Lighting Only
#endif
    FLOAT           m_fTexCoords[2];    // Always Used
#if defined JTX_GPU_TREE_WIND || defined JTX_GPU_LEAF_PLACEMENT
    FLOAT           m_fWindIndex;       // Only used when GPU is involved
    FLOAT           m_fWindWeight;
    FLOAT           m_fLeafPlacementIndex;
    FLOAT           m_fLeafScalarValue;
#endif
};


///////////////////////////////////////////////////////////////////////
//    Leaf Vertex Program
//
//    *** TRICK FOR DO NOT USE ROTATIVE BILLBOARDING, WE WILL USE THE CROSS BLEEDS RENDERING ***

//
static const char g_achLeafVertexProgram[] =
{
        "vs.1.1\n"

        "dcl_position      v0\n"        // Vertex centered
    #ifdef JTX_TREE_DYNAMIC_LIGHT
        "dcl_normal        v3\n"
    #else
        "dcl_color         v5\n"
    #endif
        "dcl_texcoord0     v7\n"        // UV coords
        "dcl_texcoord1     v8\n"        // Wind (x, y)
        "dcl_texcoord2     v9\n"        // Leaf Placement (x, y)

        "mov   oT0.xy,     v7\n"

    #ifdef JTX_GPU_TREE_WIND
        "mov   a0.x,       v8.x\n"
        "m4x4  r1,         v0,         c[54+a0.x]\n"
        "sub   r2,         r1,         v0\n"
        "mov   r3,         v8.y\n"
        "mad   r0,         r2,         r3,     v0\n"
    #else
        "mov   r0,         v0\n"
    #endif

    #ifdef JTX_GPU_LEAF_PLACEMENT
        "mov   a0.x,       v9.x\n"
        "mul   r1,         c[a0.x],   v9.y\n"  // r1 = Original offset vector

        "mov   r4.xy,      r1.xy\n"

        // Calc  r_new.x
        "mul   r6.x,       r4.x,       c[91].x\n"
        "mad   r6.x,      -r4.y,       c[91].y,  r6.x\n"

        // Calc r_new.y
        "mul   r6.y,       r4.x,       c[91].y\n"
        "mad   r6.y,       r4.y,       c[91].x,  r6.y\n"

        "mov   r6.z,       r1.z\n"

        "mov   r6.w,       c[38].x\n"

        "add   r0,         r6,         r0\n"
    #endif

    "add    r0,       c[52],      r0\n"
    "m4x4   r4,       r0,         c[0]\n"
    "mov    oPos,   r4\n"
    "mov    oT1,    r4\n"

#ifdef WRAPPER_USE_FOG
    "dp4    r1,         r0,         c[2]\n"
    "sub    r2.x,     c[85].y,    r1.z\n"
    "mul    oFog,     r2.x,       c[85].z\n"
#endif

#ifdef WRAPPER_USE_STATIC_LIGHTING
    "mov    oD0,    v5\n"
#else
    "mov    r1,       c[74]\n"
    "mul    r5,       c[73],      r1\n"
    "mov    r1,       c[75]\n"
    "mul    r4,       c[72],      r1\n"
    "dp3    r2.x,   v3,         -c[71]\n"
    "max    r2.x,     r2.x,       c[38].x\n"
    "mad    oD0,    r2.x,       r5,         r4\n"
#endif
};
//
///////////////////////////////////////////////////////////////////////


///////////////////////////////////////////////////////////////////////
//    LoadLeafShader

inline LPDIRECT3DVERTEXSHADER9 LoadLeafShader(LPDIRECT3DDEVICE9 pDx)
{
    LPDIRECT3DVERTEXSHADER9 dwShader = NULL;

    // La define JTX_GPU_LEAF_PLACEMENT è necessaria per caricare lo shader
#if defined JTX_GPU_LEAF_PLACEMENT || defined JTX_GPU_TREE_WIND

    // assemble shader
    LPD3DXBUFFER pCode, pError;

    if (D3DXAssembleShader(g_achLeafVertexProgram, sizeof(g_achLeafVertexProgram) - 1, 0, NULL, 0, &pCode, &pError) == D3D_OK)
    {
        if (pDx->CreateVertexShader((DWORD*)pCode->GetBufferPointer(), &dwShader) != D3D_OK)
        {
            char szError[1024];
            sprintf(szError, "Failed to create leaf vertex shader.");
            (void)MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
        }
    }
    else
    {
        char szError[1024];
        sprintf(szError, "Failed to assemble leaf vertex shader. The error reported is [ %s ].\n", (char*)pError->GetBufferPointer());
        (void)MessageBox(NULL, szError, "Vertex Shader Error", MB_ICONSTOP);
    }

    if (pCode)
        pCode->Release();

#endif

    return dwShader;
}

static DWORD D3DFVF_SPEEDTREE_BILLBOARD_VERTEX = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;


///////////////////////////////////////////////////////////////////////
//    Branch & Frond Vertex Formats

probably i m forgetting something, or it will not work in every source because mines is dx9 and i m actually rendering the shadows in a different way, so i adapted the code, but probably it could help, i think this system is interesting @ KolenMG

im proposing this code for fix the problems in these videos:


 now the bleeds doesn t need to rotate for be visible from every angulation you watch it, i also added a fix for draw only the shadow of the non rotate bleeds (every bleed set is formed by 2 quads, one normally in front of the light spot, and another intersected at the center of the first one using a 90° angulation), the result is this:

 

I discovered another bug about the shadows, i don t know if it is a bug i made handling the code, or if it were already existent from the beginnings, but it is what happen when you place two or more trees in same place:

the problem is about the alphachannel overwriting in the same shadow texture, it is the new render function:
 

void CSpeedTreeForestDirectX8::Render(unsigned long ulRenderBitVector)
{
	ms_bRenderingToShadow = (ulRenderBitVector & Forest_RenderToShadow);
	if (m_pMainTreeMap.empty())
		return;

	if (!(ulRenderBitVector & Forest_RenderToShadow) && !(ulRenderBitVector & Forest_RenderToMiniMap))
#ifdef DIN_SHADOW
		if (ms_bRenderingToShadow)
			UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
		else
			UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
#else
		UpdateCompundMatrix(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
#endif
	DWORD dwLightState = STATEMANAGER.GetRenderState(D3DRS_LIGHTING);
	DWORD dwColorVertexState = STATEMANAGER.GetRenderState(D3DRS_COLORVERTEX);
	DWORD dwFogVertexMode = STATEMANAGER.GetRenderState(D3DRS_FOGVERTEXMODE);

	STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
	STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, TRUE);

	UINT uiCount;
	TTreeMap::const_iterator itor = m_pMainTreeMap.begin();

	while (itor != m_pMainTreeMap.end())
	{
		SpeedTreeWrapperPtr pMainTree = (itor++)->second;
		std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

		for (auto it : ppInstances)
		{
			if (it.expired())
				continue;

			auto pInstance = it.lock();
			if (!pInstance->isShow())
				continue;

			pInstance->Advance();
		}
	}

	STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Light, m_afLighting, 3);
	STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Fog, m_afFog, 1);

	if (ulRenderBitVector & Forest_RenderToShadow)
	{
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
	}
	else
	{
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ANISOTROPIC);

		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
		STATEMANAGER.SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		STATEMANAGER.SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}

	STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, TRUE);
	STATEMANAGER.SaveRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
	STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_CW);

	if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE))
	{
#ifdef JTX_GPU_TREE_WIND
		STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_NONE);
#endif
	}

	STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

	if (ulRenderBitVector & Forest_RenderLeaves)
	{
		STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_LEAF_VERTEX);
		STATEMANAGER.SetVertexShader(m_dwLeafVertexShader);

		if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE)) {}
		if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
		{
			STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
			STATEMANAGER.SaveRenderState(D3DRS_ALPHAREF, 0x00000080);
		}

		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupLeafForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderLeaves();
			}
		}

		if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
		{
			STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
			STATEMANAGER.RestoreRenderState(D3DRS_ALPHAREF);
		}
	}

	if (ulRenderBitVector & Forest_RenderFronds)
	{
		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupFrondForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderFronds();
			}
		}
	}

	STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_BRANCH_VERTEX);
	STATEMANAGER.SetVertexShader(m_dwBranchVertexShader);

	if (ulRenderBitVector & Forest_RenderBranches)
	{
		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupBranchForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderBranches();
			}
		}
	}

	if (ulRenderBitVector & Forest_RenderBillboards)
	{
		STATEMANAGER.SetVertexShader(NULL);
		STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_BILLBOARD_VERTEX);
		STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
		STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, FALSE);

		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupBranchForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderBillboards();
			}
		}
	}

	STATEMANAGER.SetRenderState(D3DRS_LIGHTING, dwLightState);
	STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, dwColorVertexState);
	STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, dwFogVertexMode);

	if (!(ulRenderBitVector & Forest_RenderToShadow))
	{
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
	}

	STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
	STATEMANAGER.RestoreRenderState(D3DRS_ALPHAFUNC);
	STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
	m_bIsRenderingToShadow = false;
}

and it is the result:

 

  • Active+ Member
4 minutes ago, StormyFF said:

I discovered another bug about the shadows, i don t know if it is a bug i made handling the code, or if it were already existent from the beginnings, but it is what happen when you place two or more trees in same place:

the problem is about the alphachannel overwriting in the same shadow texture, it is the new render function:
 

void CSpeedTreeForestDirectX8::Render(unsigned long ulRenderBitVector)
{
	ms_bRenderingToShadow = (ulRenderBitVector & Forest_RenderToShadow);
	if (m_pMainTreeMap.empty())
		return;

	if (!(ulRenderBitVector & Forest_RenderToShadow) && !(ulRenderBitVector & Forest_RenderToMiniMap))
#ifdef DIN_SHADOW
		if (ms_bRenderingToShadow)
			UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
		else
			UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
#else
		UpdateCompundMatrix(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
#endif
	DWORD dwLightState = STATEMANAGER.GetRenderState(D3DRS_LIGHTING);
	DWORD dwColorVertexState = STATEMANAGER.GetRenderState(D3DRS_COLORVERTEX);
	DWORD dwFogVertexMode = STATEMANAGER.GetRenderState(D3DRS_FOGVERTEXMODE);

	STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
	STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, TRUE);

	UINT uiCount;
	TTreeMap::const_iterator itor = m_pMainTreeMap.begin();

	while (itor != m_pMainTreeMap.end())
	{
		SpeedTreeWrapperPtr pMainTree = (itor++)->second;
		std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

		for (auto it : ppInstances)
		{
			if (it.expired())
				continue;

			auto pInstance = it.lock();
			if (!pInstance->isShow())
				continue;

			pInstance->Advance();
		}
	}

	STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Light, m_afLighting, 3);
	STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Fog, m_afFog, 1);

	if (ulRenderBitVector & Forest_RenderToShadow)
	{
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
	}
	else
	{
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ANISOTROPIC);

		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
		STATEMANAGER.SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		STATEMANAGER.SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}

	STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, TRUE);
	STATEMANAGER.SaveRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
	STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_CW);

	if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE))
	{
#ifdef JTX_GPU_TREE_WIND
		STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_NONE);
#endif
	}

	STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

	if (ulRenderBitVector & Forest_RenderLeaves)
	{
		STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_LEAF_VERTEX);
		STATEMANAGER.SetVertexShader(m_dwLeafVertexShader);

		if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE)) {}
		if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
		{
			STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
			STATEMANAGER.SaveRenderState(D3DRS_ALPHAREF, 0x00000080);
		}

		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupLeafForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderLeaves();
			}
		}

		if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
		{
			STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
			STATEMANAGER.RestoreRenderState(D3DRS_ALPHAREF);
		}
	}

	if (ulRenderBitVector & Forest_RenderFronds)
	{
		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupFrondForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderFronds();
			}
		}
	}

	STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_BRANCH_VERTEX);
	STATEMANAGER.SetVertexShader(m_dwBranchVertexShader);

	if (ulRenderBitVector & Forest_RenderBranches)
	{
		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupBranchForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderBranches();
			}
		}
	}

	if (ulRenderBitVector & Forest_RenderBillboards)
	{
		STATEMANAGER.SetVertexShader(NULL);
		STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_BILLBOARD_VERTEX);
		STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
		STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, FALSE);

		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupBranchForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderBillboards();
			}
		}
	}

	STATEMANAGER.SetRenderState(D3DRS_LIGHTING, dwLightState);
	STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, dwColorVertexState);
	STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, dwFogVertexMode);

	if (!(ulRenderBitVector & Forest_RenderToShadow))
	{
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
	}

	STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
	STATEMANAGER.RestoreRenderState(D3DRS_ALPHAFUNC);
	STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
	m_bIsRenderingToShadow = false;
}

and it is the result:

 

why do you have this if? basically you told it to do the same either way

 if (ms_bRenderingToShadow) UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj); else UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);

9 minutes ago, KolenMG said:

why do you have this if? basically you told it to do the same either way

 if (ms_bRenderingToShadow) UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj); else UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);

Because i want to preserve the possibility to change function called, that s all xD, i added in the comment the first time i shared the function (scroll up), at the beginnings i wasusing two different cumputematrix

Edited by StormyFF
  • Good 1
void CSpeedTreeForestDirectX8::Render(unsigned long ulRenderBitVector)
{
	ms_bRenderingToShadow = (ulRenderBitVector & Forest_RenderToShadow);
	if (m_pMainTreeMap.empty())
		return;

	if (!(ulRenderBitVector & Forest_RenderToShadow) && !(ulRenderBitVector & Forest_RenderToMiniMap))
#ifdef DIN_SHADOW
		if (ms_bRenderingToShadow)
			UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
		else
			UpdateCompundMatrix2(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
#else
		UpdateCompundMatrix(CCameraManager::Instance().GetCurrentCamera()->GetEye(), ms_matView, ms_matProj);
#endif
	DWORD dwLightState = STATEMANAGER.GetRenderState(D3DRS_LIGHTING);
	DWORD dwColorVertexState = STATEMANAGER.GetRenderState(D3DRS_COLORVERTEX);
	DWORD dwFogVertexMode = STATEMANAGER.GetRenderState(D3DRS_FOGVERTEXMODE);

	STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
	STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, TRUE);

	UINT uiCount;
	TTreeMap::const_iterator itor = m_pMainTreeMap.begin();

	while (itor != m_pMainTreeMap.end())
	{
		SpeedTreeWrapperPtr pMainTree = (itor++)->second;
		std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

		for (auto it : ppInstances)
		{
			if (it.expired())
				continue;

			auto pInstance = it.lock();
			if (!pInstance->isShow())
				continue;

			pInstance->Advance();
		}
	}

	STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Light, m_afLighting, 3);
	STATEMANAGER.SetVertexShaderConstant(c_nVertexShader_Fog, m_afFog, 1);

	if (ulRenderBitVector & Forest_RenderToShadow)
	{
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
	}
	else
	{
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
		STATEMANAGER.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_ANISOTROPIC);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_ANISOTROPIC);
		STATEMANAGER.SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_ANISOTROPIC);

		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_TEXTURE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_CURRENT);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
		STATEMANAGER.SetSamplerState(1, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP);
		STATEMANAGER.SetSamplerState(1, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP);
	}

	STATEMANAGER.SaveRenderState(D3DRS_ALPHATESTENABLE, TRUE);
	STATEMANAGER.SaveRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
	STATEMANAGER.SaveRenderState(D3DRS_CULLMODE, D3DCULL_CW);

	if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE))
	{
		STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_NONE);
	}

	STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);

	if (ulRenderBitVector & Forest_RenderLeaves)
	{
		STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_LEAF_VERTEX);
		STATEMANAGER.SetVertexShader(m_dwLeafVertexShader);

		if (STATEMANAGER.GetRenderState(D3DRS_FOGENABLE)) {}
		if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
		{
			STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
			STATEMANAGER.SaveRenderState(D3DRS_ALPHAREF, 0x00000080);
		}

		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupLeafForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderLeaves();
			}
		}

		if (ulRenderBitVector & Forest_RenderToShadow || ulRenderBitVector & Forest_RenderToMiniMap)
		{
			STATEMANAGER.SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATER);
			STATEMANAGER.RestoreRenderState(D3DRS_ALPHAREF);
		}
		// --- FIX 07/11/2025 (i displayed a bug on the leaves and grass, some parts of the environment were draw on the leaves/grass)
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
		STATEMANAGER.SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
		STATEMANAGER.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
		STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
		// --- END FIX ---

	}

	if (ulRenderBitVector & Forest_RenderFronds)
	{
		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupFrondForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderFronds();
			}
		}
	}
	// --- FIX 07/11/2025 (i displayed a bug on the leaves and grass, some parts of the environment were draw on the leaves/grass)
	STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
	STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
	STATEMANAGER.SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
	STATEMANAGER.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
	// --- END FIX ---

	STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_BRANCH_VERTEX);
	STATEMANAGER.SetVertexShader(m_dwBranchVertexShader);

	if (ulRenderBitVector & Forest_RenderBranches)
	{
		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupBranchForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderBranches();
			}
		}
	}
	// --- FIX 07/11/2025 (i displayed a bug on the leaves and grass, some parts of the environment were draw on the leaves/grass)
	STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
	STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
	STATEMANAGER.SetRenderState(D3DRS_ALPHATESTENABLE, FALSE);
	STATEMANAGER.SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
	STATEMANAGER.SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
	// --- END FIX ---

	if (ulRenderBitVector & Forest_RenderBillboards)
	{
		STATEMANAGER.SetVertexShader(NULL);
		STATEMANAGER.SetFVF(D3DFVF_SPEEDTREE_BILLBOARD_VERTEX);
		STATEMANAGER.SetRenderState(D3DRS_LIGHTING, FALSE);
		STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, FALSE);

		itor = m_pMainTreeMap.begin();

		while (itor != m_pMainTreeMap.end())
		{
			SpeedTreeWrapperPtr pMainTree = (itor++)->second;
			std::list<CSpeedTreeForest::SpeedTreeWrapperWeakPtr> ppInstances = pMainTree->GetInstances(uiCount);

			pMainTree->SetupBranchForTreeType();

			for (auto it : ppInstances)
			{
				if (it.expired())
					continue;

				auto pInstance = it.lock();
				if (!pInstance->isShow())
					continue;

				pInstance->RenderBillboards();
			}
		}
	}

	STATEMANAGER.SetRenderState(D3DRS_LIGHTING, dwLightState);
	STATEMANAGER.SetRenderState(D3DRS_COLORVERTEX, dwColorVertexState);
	STATEMANAGER.SetRenderState(D3DRS_FOGVERTEXMODE, dwFogVertexMode);

	if (!(ulRenderBitVector & Forest_RenderToShadow))
	{
		STATEMANAGER.SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE);
		STATEMANAGER.SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
	}

	STATEMANAGER.RestoreRenderState(D3DRS_ALPHATESTENABLE);
	STATEMANAGER.RestoreRenderState(D3DRS_ALPHAFUNC);
	STATEMANAGER.RestoreRenderState(D3DRS_CULLMODE);
	m_bIsRenderingToShadow = false;
}

Update, fixed a bug about the drawing of environment parts on the leaves in the moment that the camera were too much closer to these ones and so the alpha value were decreased

  • Love 1
  • Active+ Member

With this system at the base + AI and basic coding knowledge + shader + 2 weeks of frustration and work, you can achieve this 

https://metin2.download/video/vvu116UMwGpoTFvY6dCNiE8ftJbR2A6B/.mp4

Edited by Metin2 Dev International
Core X - External 2 Internal
  • Metin2 Dev 1
  • Flame 2
  • muscle 2
  • Love 1

Wow that's just fantastic, it really change the game, any suggestion on how to achieve this? I was also playing with AI coding but for now I've just spent a lot of time without any useful step forward.

Don't use any images from : imgur, turkmmop, freakgamers, inforge, hizliresim... Or your content will be deleted without notice...
Use : https://metin2.download/media/add/

Please use https://metin2.download/ when uploading files smaller than 100MB, otherwise the approval will take longer due to manual upload.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
×
×
  • Create New...

Important Information

Terms of Use / Privacy Policy / Guidelines / We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.