From 15740faf9fe9fe4be08965098bbf2947e096aeeb Mon Sep 17 00:00:00 2001 From: chai Date: Wed, 14 Aug 2019 22:50:43 +0800 Subject: +Unity Runtime code --- Runtime/Terrain/DetailRenderer.cpp | 303 +++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 Runtime/Terrain/DetailRenderer.cpp (limited to 'Runtime/Terrain/DetailRenderer.cpp') 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 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;iHasProperty(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;iGetBounds(); + + 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;rsecond.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;rsecond.lastUsed < m_RenderCount) + curPatches.erase(render); + } + } +} + +/// Cleanup all the cached render patches +void DetailRenderer::Cleanup () +{ + for(int i=0;isecond.inited = false; + DestroySingleObject(render->second.mesh); + render->second.mesh = NULL; + } + } +} + +void DetailRenderer::ReloadAllDetails () +{ + for (int i=0;iGetDetailDatabase(); + for (int i=0;isecond.x, render->second.y)) + curPatches.erase(render); + } + } +} + +#endif // ENABLE_TERRAIN -- cgit v1.1-26-g67d0