diff options
| author | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 | 
|---|---|---|
| committer | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 | 
| commit | 15740faf9fe9fe4be08965098bbf2947e096aeeb (patch) | |
| tree | a730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Terrain/DetailRenderer.cpp | |
Diffstat (limited to 'Runtime/Terrain/DetailRenderer.cpp')
| -rw-r--r-- | Runtime/Terrain/DetailRenderer.cpp | 303 | 
1 files changed, 303 insertions, 0 deletions
diff --git a/Runtime/Terrain/DetailRenderer.cpp b/Runtime/Terrain/DetailRenderer.cpp new file mode 100644 index 0000000..b591fdc --- /dev/null +++ b/Runtime/Terrain/DetailRenderer.cpp @@ -0,0 +1,303 @@ +#include "UnityPrefix.h" +#include "DetailRenderer.h" + +#if ENABLE_TERRAIN + +#include "Runtime/Input/TimeManager.h" +#include "Runtime/BaseClasses/IsPlaying.h" +#include "Runtime/Geometry/Plane.h" +#include "Runtime/Camera/CameraUtil.h" +#include "Runtime/Graphics/Transform.h" +#include "Runtime/Geometry/Intersection.h" +#include "Runtime/Shaders/MaterialProperties.h" +#include "Runtime/Shaders/Shader.h" +#include "Runtime/Shaders/ShaderNameRegistry.h" +#include "Runtime/Camera/IntermediateRenderer.h" + +namespace DetailRenderer_Static +{ +static SHADERPROP(Cutoff); +static SHADERPROP(MainTex); +static SHADERPROP(maxDistanceSqr); +static SHADERPROP(CameraPosition); +static SHADERPROP(WaveAndDistance); +static SHADERPROP(WavingTint); +static SHADERPROP(CameraRight); +static SHADERPROP(CameraUp); +} // namespace SplatMaterials_Static + +DetailRenderer::DetailRenderer (PPtr<TerrainData> terrain, Vector3f position, int lightmapIndex) +{ +	using namespace DetailRenderer_Static; + +	m_Database = terrain; +	m_Position = position; +	m_LightmapIndex = lightmapIndex; +		 +	const char* shaders[] = { +		"Hidden/TerrainEngine/Details/BillboardWavingDoublePass", +		"Hidden/TerrainEngine/Details/Vertexlit", +		"Hidden/TerrainEngine/Details/WavingDoublePass" +	}; + +	ScriptMapper& sm = GetScriptMapper (); +	bool shaderNotFound = false; +	for (int i = 0; i < kDetailRenderModeCount; i++) +	{ +		Shader* shader = sm.FindShader(shaders[i]); +		if (shader == NULL) +		{ +			shaderNotFound = true; +			shader = sm.FindShader("Diffuse"); +		} + +		m_Materials[i] = Material::CreateMaterial (*shader, Object::kHideAndDontSave); +		m_Materials[i]->SetFloat (kSLPropCutoff, .5f * .75f); +	} + +	if (shaderNotFound) +	{ +		ErrorString("Unable to find shaders used for the terrain engine. Please include Nature/Terrain/Diffuse shader in Graphics settings."); +	} +	 +	m_RenderCount = 0; +	m_LastTime = 0; +} + +DetailPatchRender& DetailRenderer::GrabCachedPatch (int x, int y, int lightmapIndex, DetailRenderMode mode, float density) +{ +	DetailList &patches = m_Patches[mode]; +	UInt32 index = x + y*m_Database->GetDetailDatabase().GetPatchCount(); + +	DetailPatchRender& render = patches[index]; +	if(!render.inited) +	{ +		render.mesh = m_Database->GetDetailDatabase().BuildMesh(x, y, m_TerrainSize, lightmapIndex, mode, density); +		render.isMeshNull = render.mesh == NULL; +		render.x = x; +		render.y = y; +		render.inited = true; +	} +	render.lastUsed = m_RenderCount; +	return render; +} +	 +void DetailRenderer::Render (Camera* camera, float viewDistance, int layer, float detailDensity) +{ +	using namespace DetailRenderer_Static; + +	detailDensity = clamp01(detailDensity); + +	DetailDatabase& detail = m_Database->GetDetailDatabase(); +	m_LastTime += (IsWorldPlaying() ? GetDeltaTime() * detail.GetWavingGrassStrength() * .05f : 0); +	m_RenderCount++; +	 + +	m_TerrainSize = m_Database->GetHeightmap().GetSize(); +	int patchCount = detail.GetPatchCount(); +	if (patchCount == 0) +		return; +	 +	detail.UpdateDetailPrototypesIfDirty(); +	 +	for (int i=0;i<kDetailRenderModeCount;i++) +	{ +		if (m_Materials[i]->HasProperty(kSLPropMainTex)) +			m_Materials[i]->SetTexture (kSLPropMainTex, detail.GetAtlasTexture()); +	} + +	Transform* camT = camera->QueryComponent (Transform); + +	Vector3f position = camT->GetPosition() - m_Position; +	int centerX = RoundfToInt(position.x * patchCount / m_TerrainSize.x); +	int centerY = RoundfToInt(position.z * patchCount / m_TerrainSize.z); +	 +	int halfWidth = int(Ceilf(patchCount * viewDistance / m_TerrainSize.x) + 1); +	int halfHeight = int(Ceilf(patchCount * viewDistance / m_TerrainSize.z) + 1); +	 +	int minx = centerX - halfWidth; +	if(minx < 0) minx = 0; +	if(minx > patchCount - 1) minx = patchCount - 1; +	 +	int miny = centerY - halfHeight; +	if(miny < 0) miny = 0; +	if(miny > patchCount - 1) miny = patchCount - 1; + +	int maxx = centerX + halfWidth; +	if(maxx < 0) maxx = 0; +	if(maxx > patchCount - 1) maxx = patchCount - 1; + +	int maxy = centerY + halfHeight; +	if(maxy < 0) maxy = 0; +	if(maxy > patchCount - 1) maxy = patchCount - 1; +	 +	float sqrViewDistance = viewDistance * viewDistance; +	 +	Plane planes[6]; +	ExtractProjectionPlanes( camera->GetWorldToClipMatrix(), planes); +	 +//	DetailList *newPatches = new DetailList[3]; +	int totalVisible = 0; +	int total = 0; +	 +	bool supportsBillboards = m_Materials[0]->GetShader()->IsSupported(); +	 +	// Find and cull all visible patches +	for (int y=miny;y<=maxy;y++) +	{ +		for (int x=minx;x<=maxx;x++) +		{ +			if (detail.IsPatchEmpty (x,y)) +				continue; +			 +			for (int i=0;i<kDetailRenderModeCount;i++) +			{ +				// Skip billboard rendering if not supported +				if( i == 0 && !supportsBillboards ) +					continue; +					 +				// Grab the cached patch +				DetailPatchRender &render = GrabCachedPatch (x, y, m_LightmapIndex, (DetailRenderMode)i, detailDensity); + +				if (render.isMeshNull) +				{ +					render.isCulledVisible = false; +				} +				else +				{ +					AABB bounds = render.mesh->GetBounds(); + +					render.isCulledVisible = true; +					if (CalculateSqrDistance(position,bounds) > sqrViewDistance) +					{ +						render.isCulledVisible = false;	 +					} +					else +					{ +						bounds.GetCenter() += m_Position; +						if (!IntersectAABBFrustumFull(bounds, planes)) +							render.isCulledVisible = false;	 +					} +					 +					if(render.isCulledVisible) +						totalVisible ++; +				} +				total++; +			} +		} +	} +	 +	Vector3f up = camT->InverseTransformDirection (Vector3f(0.0f,1.0f,0.0f)); +	up.z = 0; +	up = camT->TransformDirection(up); +	up = NormalizeSafe(up); +	 +	MaterialPropertyBlock props; +		 +	Vector3f right = Cross (camT->TransformDirection(Vector3f(0.0f,0.0f,-1.0f)), up); +	right = NormalizeSafe(right); + +	Matrix4x4f matrix; +	matrix.SetTranslate( m_Position ); + +	for (int r=0;r<kDetailRenderModeCount;r++) +	{ +		Material *material = m_Materials[r]; +			 +		props.Clear(); +		props.AddPropertyFloat(kSLPropmaxDistanceSqr, sqrViewDistance); +		Vector4f prop; +		prop[0] = position.x; +		prop[1] = position.y; +		prop[2] = position.z; +		prop[3] = 1.0f / sqrViewDistance; +		props.AddPropertyVector(kSLPropCameraPosition, prop); +		prop[0] = m_LastTime; +		prop[1] = detail.GetWavingGrassSpeed() * .4f; +		// cancel wind on mesh lit +		prop[2] = r == kDetailMeshLit ? 0 : detail.GetWavingGrassAmount() * 6.0f; +		prop[3] = sqrViewDistance;		 +		props.AddPropertyVector(kSLPropWaveAndDistance, prop); +		ColorRGBAf color = detail.GetWavingGrassTint(); +		props.AddPropertyColor(kSLPropWavingTint, color); +		prop[0] = right.x; +		prop[1] = right.y; +		prop[2] = right.z; +		prop[3] = 0.0f; +		props.AddPropertyVector(kSLPropCameraRight, prop); +		prop[0] = up.x; +		prop[1] = up.y; +		prop[2] = up.z; +		prop[3] = 0.0f;		 +		props.AddPropertyVector(kSLPropCameraUp, prop);			 + + +		DetailList &curPatches = m_Patches[r]; +		for (DetailList::iterator i = curPatches.begin(); i != curPatches.end(); i++) +		{ +			if (i->second.isCulledVisible) +			{				 +				IntermediateRenderer* r = AddMeshIntermediateRenderer( matrix, i->second.mesh, material, layer, false, true, 0, camera );		 +				r->SetPropertyBlock( props ); +				r->SetLightmapIndexIntNoDirty(m_LightmapIndex); +			} +		} +	} + +	for (int r=0;r<kDetailRenderModeCount;r++) +	{ +		DetailList &curPatches = m_Patches[r]; +		DetailList::iterator next; +		for (DetailList::iterator render = curPatches.begin(); render != curPatches.end(); render=next) +		{ +			next = render; +			next++; +			if(render->second.lastUsed < m_RenderCount) +				curPatches.erase(render); +		} +	} +} +		 +/// Cleanup all the cached render patches +void DetailRenderer::Cleanup () +{ +	for(int i=0;i<kDetailRenderModeCount;i++) +	{ +		DestroySingleObject (m_Materials[i]); +		DetailList &curPatches = m_Patches[i]; + +		for (DetailList::iterator render = curPatches.begin(); render != curPatches.end(); ++render) +		{ +			render->second.inited = false; +			DestroySingleObject(render->second.mesh); +			render->second.mesh = NULL; +		} +	} +} +	 +void DetailRenderer::ReloadAllDetails () +{ +	for (int i=0;i<kDetailRenderModeCount;i++) +	{ +		m_Patches[i].clear(); +	} +} +	 +void DetailRenderer::ReloadDirtyDetails () +{ +	DetailDatabase& detail = m_Database->GetDetailDatabase(); +	for (int i=0;i<kDetailRenderModeCount;i++) +	{ +		DetailList &curPatches = m_Patches[i]; +		DetailList::iterator next; +		for (DetailList::iterator render = curPatches.begin(); render != curPatches.end(); render=next) +		{ +			next = render; +			next++; +			if (detail.IsPatchDirty (render->second.x, render->second.y)) +				curPatches.erase(render); +		} +	} +} + +#endif // ENABLE_TERRAIN  | 
