void Terrain::UpdatePatchLod(TerrainPatch* patch) { Geometry* geometry = patch->GetGeometry(); // All LOD levels except the coarsest have 16 versions for stitching unsigned lodLevel = patch->GetLodLevel(); unsigned drawRangeIndex = lodLevel << 4; if (lodLevel < numLodLevels_ - 1) { TerrainPatch* north = patch->GetNorthPatch(); TerrainPatch* south = patch->GetSouthPatch(); TerrainPatch* west = patch->GetWestPatch(); TerrainPatch* east = patch->GetEastPatch(); if (north && north->GetLodLevel() > lodLevel) drawRangeIndex |= STITCH_NORTH; if (south && south->GetLodLevel() > lodLevel) drawRangeIndex |= STITCH_SOUTH; if (west && west->GetLodLevel() > lodLevel) drawRangeIndex |= STITCH_WEST; if (east && east->GetLodLevel() > lodLevel) drawRangeIndex |= STITCH_EAST; } if (drawRangeIndex < drawRanges_.Size()) geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[drawRangeIndex].first_, drawRanges_[drawRangeIndex].second_, false); }
void Renderer2D::AddViewBatch(ViewBatchInfo2D& viewBatchInfo, Material* material, unsigned indexStart, unsigned indexCount, unsigned vertexStart, unsigned vertexCount) { if (!material || indexCount == 0 || vertexCount == 0) return; if (viewBatchInfo.materials_.Size() <= viewBatchInfo.batchCount_) viewBatchInfo.materials_.Resize(viewBatchInfo.batchCount_ + 1); viewBatchInfo.materials_[viewBatchInfo.batchCount_] = material; // Allocate new geometry if necessary if (viewBatchInfo.geometries_.Size() <= viewBatchInfo.batchCount_) { SharedPtr<Geometry> geometry(new Geometry(context_)); geometry->SetIndexBuffer(indexBuffer_); geometry->SetVertexBuffer(0, viewBatchInfo.vertexBuffer_, MASK_VERTEX2D); viewBatchInfo.geometries_.Push(geometry); } Geometry* geometry = viewBatchInfo.geometries_[viewBatchInfo.batchCount_]; geometry->SetDrawRange(TRIANGLE_LIST, indexStart, indexCount, vertexStart, vertexCount, false); viewBatchInfo.batchCount_++; }
void Text3D::UpdateGeometry(const FrameInfo& frame) { if (fontDataLost_) { // Re-evaluation of the text triggers the font face to reload itself UpdateTextBatches(); UpdateTextMaterials(); fontDataLost_ = false; } if (geometryDirty_) { for (unsigned i = 0; i < batches_.Size(); ++i) { Geometry* geometry = geometries_[i]; geometry->SetDrawRange(TRIANGLE_LIST, 0, 0, uiBatches_[i].vertexStart_, (uiBatches_[i].vertexEnd_ - uiBatches_[i].vertexStart_) / UI_VERTEX_SIZE); } } if ((geometryDirty_ || vertexBuffer_->IsDataLost()) && uiVertexData_.Size()) { unsigned vertexCount = uiVertexData_.Size() / UI_VERTEX_SIZE; if (vertexBuffer_->GetVertexCount() != vertexCount) vertexBuffer_->SetSize(vertexCount, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1); vertexBuffer_->SetData(&uiVertexData_[0]); } geometryDirty_ = false; }
void Text3D::UpdateGeometry(const FrameInfo& frame) { if (fontDataLost_) { // Re-evaluation of the text triggers the font face to reload itself UpdateTextBatches(); UpdateTextMaterials(); fontDataLost_ = false; } // In case is being rendered from multiple views, recalculate camera facing & fixed size if (faceCameraMode_ != FC_NONE || fixedScreenSize_) CalculateFixedScreenSize(frame); if (geometryDirty_) { for (unsigned i = 0; i < batches_.Size() && i < uiBatches_.Size(); ++i) { Geometry* geometry = geometries_[i]; geometry->SetDrawRange(TRIANGLE_LIST, 0, 0, uiBatches_[i].vertexStart_, (uiBatches_[i].vertexEnd_ - uiBatches_[i].vertexStart_) / UI_VERTEX_SIZE); } } if ((geometryDirty_ || vertexBuffer_->IsDataLost()) && uiVertexData_.Size()) { unsigned vertexCount = uiVertexData_.Size() / UI_VERTEX_SIZE; if (vertexBuffer_->GetVertexCount() != vertexCount) vertexBuffer_->SetSize(vertexCount, MASK_POSITION | MASK_COLOR | MASK_TEXCOORD1); vertexBuffer_->SetData(&uiVertexData_[0]); } geometryDirty_ = false; }
bool Model::EndLoad() { // Upload vertex buffer data for (unsigned i = 0; i < vertexBuffers_.Size(); ++i) { VertexBuffer* buffer = vertexBuffers_[i]; VertexBufferDesc& desc = loadVBData_[i]; if (desc.data_) { buffer->SetShadowed(true); buffer->SetSize(desc.vertexCount_, desc.vertexElements_); buffer->SetData(desc.data_.Get()); } } // Upload index buffer data for (unsigned i = 0; i < indexBuffers_.Size(); ++i) { IndexBuffer* buffer = indexBuffers_[i]; IndexBufferDesc& desc = loadIBData_[i]; if (desc.data_) { buffer->SetShadowed(true); buffer->SetSize(desc.indexCount_, desc.indexSize_ > sizeof(unsigned short)); buffer->SetData(desc.data_.Get()); } } // Set up geometries for (unsigned i = 0; i < geometries_.Size(); ++i) { for (unsigned j = 0; j < geometries_[i].Size(); ++j) { Geometry* geometry = geometries_[i][j]; GeometryDesc& desc = loadGeometries_[i][j]; geometry->SetVertexBuffer(0, vertexBuffers_[desc.vbRef_]); geometry->SetIndexBuffer(indexBuffers_[desc.ibRef_]); geometry->SetDrawRange(desc.type_, desc.indexStart_, desc.indexCount_); } } loadVBData_.Clear(); loadIBData_.Clear(); loadGeometries_.Clear(); return true; }
void Terrain::CreatePatchGeometry(TerrainPatch* patch) { URHO3D_PROFILE(CreatePatchGeometry); unsigned row = (unsigned)(patchSize_ + 1); VertexBuffer* vertexBuffer = patch->GetVertexBuffer(); Geometry* geometry = patch->GetGeometry(); Geometry* maxLodGeometry = patch->GetMaxLodGeometry(); Geometry* occlusionGeometry = patch->GetOcclusionGeometry(); if (vertexBuffer->GetVertexCount() != row * row) vertexBuffer->SetSize(row * row, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT); SharedArrayPtr<unsigned char> cpuVertexData(new unsigned char[row * row * sizeof(Vector3)]); SharedArrayPtr<unsigned char> occlusionCpuVertexData(new unsigned char[row * row * sizeof(Vector3)]); float* vertexData = (float*)vertexBuffer->Lock(0, vertexBuffer->GetVertexCount()); float* positionData = (float*)cpuVertexData.Get(); float* occlusionData = (float*)occlusionCpuVertexData.Get(); BoundingBox box; unsigned occlusionLevel = occlusionLodLevel_; if (occlusionLevel > numLodLevels_ - 1) occlusionLevel = numLodLevels_ - 1; if (vertexData) { const IntVector2& coords = patch->GetCoordinates(); int lodExpand = (1 << (occlusionLevel)) - 1; int halfLodExpand = (1 << (occlusionLevel)) / 2; for (int z = 0; z <= patchSize_; ++z) { for (int x = 0; x <= patchSize_; ++x) { int xPos = coords.x_ * patchSize_ + x; int zPos = coords.y_ * patchSize_ + z; // Position Vector3 position((float)x * spacing_.x_, GetRawHeight(xPos, zPos), (float)z * spacing_.z_); *vertexData++ = position.x_; *vertexData++ = position.y_; *vertexData++ = position.z_; *positionData++ = position.x_; *positionData++ = position.y_; *positionData++ = position.z_; box.Merge(position); // For vertices that are part of the occlusion LOD, calculate the minimum height in the neighborhood // to prevent false positive occlusion due to inaccuracy between occlusion LOD & visible LOD float minHeight = position.y_; if (halfLodExpand > 0 && (x & lodExpand) == 0 && (z & lodExpand) == 0) { int minX = Max(xPos - halfLodExpand, 0); int maxX = Min(xPos + halfLodExpand, numVertices_.x_ - 1); int minZ = Max(zPos - halfLodExpand, 0); int maxZ = Min(zPos + halfLodExpand, numVertices_.y_ - 1); for (int nZ = minZ; nZ <= maxZ; ++nZ) { for (int nX = minX; nX <= maxX; ++nX) minHeight = Min(minHeight, GetRawHeight(nX, nZ)); } } *occlusionData++ = position.x_; *occlusionData++ = minHeight; *occlusionData++ = position.z_; // Normal Vector3 normal = GetRawNormal(xPos, zPos); *vertexData++ = normal.x_; *vertexData++ = normal.y_; *vertexData++ = normal.z_; // Texture coordinate Vector2 texCoord((float)xPos / (float)numVertices_.x_, 1.0f - (float)zPos / (float)numVertices_.y_); *vertexData++ = texCoord.x_; *vertexData++ = texCoord.y_; // Tangent Vector3 xyz = (Vector3::RIGHT - normal * normal.DotProduct(Vector3::RIGHT)).Normalized(); *vertexData++ = xyz.x_; *vertexData++ = xyz.y_; *vertexData++ = xyz.z_; *vertexData++ = 1.0f; } } vertexBuffer->Unlock(); vertexBuffer->ClearDataLost(); } patch->SetBoundingBox(box); if (drawRanges_.Size()) { unsigned occlusionDrawRange = occlusionLevel << 4; geometry->SetIndexBuffer(indexBuffer_); geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false); geometry->SetRawVertexData(cpuVertexData, MASK_POSITION); maxLodGeometry->SetIndexBuffer(indexBuffer_); maxLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false); maxLodGeometry->SetRawVertexData(cpuVertexData, MASK_POSITION); occlusionGeometry->SetIndexBuffer(indexBuffer_); occlusionGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[occlusionDrawRange].first_, drawRanges_[occlusionDrawRange].second_, false); occlusionGeometry->SetRawVertexData(occlusionCpuVertexData, MASK_POSITION); } patch->ResetLod(); }
void Terrain::CreatePatchGeometry(TerrainPatch* patch) { PROFILE(CreatePatchGeometry); unsigned row = patchSize_ + 1; VertexBuffer* vertexBuffer = patch->GetVertexBuffer(); Geometry* geometry = patch->GetGeometry(); Geometry* maxLodGeometry = patch->GetMaxLodGeometry(); Geometry* minLodGeometry = patch->GetMinLodGeometry(); if (vertexBuffer->GetVertexCount() != row * row) vertexBuffer->SetSize(row * row, MASK_POSITION | MASK_NORMAL | MASK_TEXCOORD1 | MASK_TANGENT); SharedArrayPtr<unsigned char> cpuVertexData(new unsigned char[row * row * sizeof(Vector3)]); float* vertexData = (float*)vertexBuffer->Lock(0, vertexBuffer->GetVertexCount()); float* positionData = (float*)cpuVertexData.Get(); BoundingBox box; if (vertexData) { const IntVector2& coords = patch->GetCoordinates(); for (int z1 = 0; z1 <= patchSize_; ++z1) { for (int x1 = 0; x1 <= patchSize_; ++x1) { int xPos = coords.x_ * patchSize_ + x1; int zPos = coords.y_ * patchSize_ + z1; // Position Vector3 position((float)x1 * spacing_.x_, GetRawHeight(xPos, zPos), (float)z1 * spacing_.z_); *vertexData++ = position.x_; *vertexData++ = position.y_; *vertexData++ = position.z_; *positionData++ = position.x_; *positionData++ = position.y_; *positionData++ = position.z_; box.Merge(position); // Normal Vector3 normal = GetRawNormal(xPos, zPos); *vertexData++ = normal.x_; *vertexData++ = normal.y_; *vertexData++ = normal.z_; // Texture coordinate Vector2 texCoord((float)xPos / (float)numVertices_.x_, 1.0f - (float)zPos / (float)numVertices_.y_); *vertexData++ = texCoord.x_; *vertexData++ = texCoord.y_; // Tangent Vector3 xyz = (Vector3::RIGHT - normal * normal.DotProduct(Vector3::RIGHT)).Normalized(); *vertexData++ = xyz.x_; *vertexData++ = xyz.y_; *vertexData++ = xyz.z_; *vertexData++ = 1.0f; } } vertexBuffer->Unlock(); vertexBuffer->ClearDataLost(); } patch->SetBoundingBox(box); if (drawRanges_.Size()) { unsigned lastDrawRange = drawRanges_.Size() - 1; geometry->SetIndexBuffer(indexBuffer_); geometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false); geometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION); maxLodGeometry->SetIndexBuffer(indexBuffer_); maxLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[0].first_, drawRanges_[0].second_, false); maxLodGeometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION); minLodGeometry->SetIndexBuffer(indexBuffer_); minLodGeometry->SetDrawRange(TRIANGLE_LIST, drawRanges_[lastDrawRange].first_, drawRanges_[lastDrawRange].second_, false); minLodGeometry->SetRawVertexData(cpuVertexData, sizeof(Vector3), MASK_POSITION); } // Offset the occlusion geometry by vertex spacing to reduce possibility of over-aggressive occlusion patch->SetOcclusionOffset(-0.5f * (spacing_.x_ + spacing_.z_)); patch->ResetLod(); }