| 554 | } |
| 555 | |
| 556 | bool Terrain::DrawSetup(RenderContext& renderContext) |
| 557 | { |
| 558 | // Special drawing modes |
| 559 | const DrawPass drawModes = DrawModes & renderContext.View.Pass; |
| 560 | if (drawModes == DrawPass::GlobalSDF) |
| 561 | { |
| 562 | const float chunkScale = 0.25f / (TERRAIN_UNITS_PER_VERTEX * (float)_chunkSize); // Patch heightfield is divided into 4x4 chunks |
| 563 | for (const TerrainPatch* patch : _patches) |
| 564 | { |
| 565 | if (!patch->Heightmap) |
| 566 | continue; |
| 567 | GPUTexture* heightfield = patch->Heightmap->GetTexture(); |
| 568 | float size = (float)heightfield->Width(); |
| 569 | Float4 localToUV; |
| 570 | localToUV.X = localToUV.Y = chunkScale * (size - 1) / size; // Skip the last edge texel |
| 571 | localToUV.Z = localToUV.W = 0.5f / size; // Include half-texel offset |
| 572 | Transform patchTransform; |
| 573 | patchTransform.Translation = patch->_offset + Vector3(0, patch->_yOffset, 0); |
| 574 | patchTransform.Orientation = Quaternion::Identity; |
| 575 | patchTransform.Scale = Float3(1.0f, patch->_yHeight, 1.0f); |
| 576 | patchTransform = _transform.LocalToWorld(patchTransform); |
| 577 | GlobalSignDistanceFieldPass::Instance()->RasterizeHeightfield(this, heightfield, patchTransform, patch->_bounds, localToUV); |
| 578 | } |
| 579 | return true; |
| 580 | } |
| 581 | if (drawModes == DrawPass::GlobalSurfaceAtlas) |
| 582 | { |
| 583 | for (TerrainPatch* patch : _patches) |
| 584 | { |
| 585 | if (!patch->Heightmap) |
| 586 | continue; |
| 587 | Matrix localToWorld, worldToLocal; |
| 588 | BoundingSphere chunkSphere; |
| 589 | BoundingBox localBounds; |
| 590 | for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) |
| 591 | { |
| 592 | TerrainChunk* chunk = &patch->Chunks[chunkIndex]; |
| 593 | chunk->GetTransform().GetWorld(localToWorld); // TODO: large-worlds |
| 594 | Matrix::Invert(localToWorld, worldToLocal); |
| 595 | BoundingBox::Transform(chunk->GetBounds(), worldToLocal, localBounds); |
| 596 | BoundingSphere::FromBox(chunk->GetBounds(), chunkSphere); |
| 597 | GlobalSurfaceAtlasPass::Instance()->RasterizeActor(this, chunk, chunkSphere, chunk->GetTransform(), localBounds, 1 << 2, false); |
| 598 | } |
| 599 | } |
| 600 | return true; |
| 601 | } |
| 602 | |
| 603 | // Reset cached LOD for chunks (prevent LOD transition from invisible chunks) |
| 604 | for (int32 patchIndex = 0; patchIndex < _patches.Count(); patchIndex++) |
| 605 | { |
| 606 | const auto patch = _patches[patchIndex]; |
| 607 | for (int32 chunkIndex = 0; chunkIndex < Terrain::ChunksCount; chunkIndex++) |
| 608 | { |
| 609 | auto chunk = &patch->Chunks[chunkIndex]; |
| 610 | chunk->_cachedDrawLOD = 0; |
| 611 | } |
| 612 | } |
| 613 |
nothing calls this directly
no test coverage detected