internal void Draw() { EntityShadow mode = game.Players.ShadowMode; Vector3 Position = entity.Position; float posX = Position.X, posZ = Position.Z; int posY = Math.Min( (int)Position.Y, game.World.Height - 1 ); int index = 0, vb = 0; VertexP3fT2fC4b[] verts = null; int posCount = 0, dataCount = 0; Vector3I* coords = stackalloc Vector3I[4]; ShadowData* data = stackalloc ShadowData[4]; for( int i = 0; i < 4; i++ ) { coords[i] = new Vector3I( int.MinValue ); data[i] = new ShadowData(); } if( mode == EntityShadow.SnapToBlock ) { vb = game.Graphics.texVb; verts = game.Graphics.texVerts; if( !GetBlocks( coords, ref posCount, posX, posZ, posY, data, ref dataCount ) ) return; float x1 = Utils.Floor( posX ), z1 = Utils.Floor( posZ ); DraqSquareShadow( verts, ref index, data[0].Y, 220, x1, z1 ); } else { vb = game.ModelCache.vb; verts = game.ModelCache.vertices; float x = posX - 7/16f, z = posZ - 7/16f; if( GetBlocks( coords, ref posCount, x, z, posY, data, ref dataCount ) && data[0].A > 0 ) DrawCircle( verts, ref index, data, dataCount, x, z ); x = Math.Max( posX - 7/16f, Utils.Floor( posX + 7/16f ) ); if( GetBlocks( coords, ref posCount, x, z, posY, data, ref dataCount ) && data[0].A > 0 ) DrawCircle( verts, ref index, data, dataCount, x, z ); z = Math.Max( posZ - 7/16f, Utils.Floor( posZ + 7/16f ) ); if( GetBlocks( coords, ref posCount, x, z, posY, data, ref dataCount ) && data[0].A > 0 ) DrawCircle( verts, ref index, data, dataCount, x, z ); x = posX - 7/16f; if( GetBlocks( coords, ref posCount, x, z, posY, data, ref dataCount ) && data[0].A > 0 ) DrawCircle( verts, ref index, data, dataCount, x, z ); } if( index == 0 ) return; CheckShadowTexture( game.Graphics ); if( !boundShadowTex ) { game.Graphics.BindTexture( shadowTex ); boundShadowTex = true; } game.Graphics.UpdateDynamicIndexedVb( DrawMode.Triangles, vb, verts, index, index * 6 / 4 ); }
static void CalcAlpha( float playerY, ref ShadowData data ) { float y = data.Y; if( (playerY - y) <= 6 ) { data.A = (byte)(160 - 160 * (playerY - y) / 6); data.Y += 1/64f; return; } data.A = 0; if( (playerY - y) <= 16 ) data.Y += 1/64f; else if( (playerY - y) <= 32 ) data.Y += 1/16f; else if( (playerY - y) <= 96 ) data.Y += 1/8f; else data.Y += 1/4f; }
void DrawCoords( VertexP3fT2fC4b[] verts, ref int index, ShadowData data, float x1, float z1, float x2, float z2) { Vector3 centre = entity.Position; BlockInfo info = game.BlockInfo; if( lequal( x2, x1 ) || lequal( z2, z1 ) ) return; float u1 = (x1 - centre.X) * 16/14f + 0.5f; float v1 = (z1 - centre.Z) * 16/14f + 0.5f; float u2 = (x2 - centre.X) * 16/14f + 0.5f; float v2 = (z2 - centre.Z) * 16/14f + 0.5f; if( u2 <= 0 || v2 <= 0 || u1 >= 1 || v1 >= 1 ) return; x1 = Math.Max( x1, centre.X - 7/16f ); u1 = Math.Max( u1, 0 ); z1 = Math.Max( z1, centre.Z - 7/16f ); v1 = Math.Max( v1, 0 ); x2 = Math.Min( x2, centre.X + 7/16f ); u2 = Math.Min( u2, 1 ); z2 = Math.Min( z2, centre.Z + 7/16f ); v2 = Math.Min( v2, 1 ); FastColour col = FastColour.White; col.A = data.A; verts[index++] = new VertexP3fT2fC4b( x1, data.Y, z1, u1, v1, col ); verts[index++] = new VertexP3fT2fC4b( x2, data.Y, z1, u2, v1, col ); verts[index++] = new VertexP3fT2fC4b( x2, data.Y, z2, u2, v2, col ); verts[index++] = new VertexP3fT2fC4b( x1, data.Y, z2, u1, v2, col ); }
bool GetBlocks( Vector3I* coords, ref int posCount, float x, float z, int posY, ShadowData* data, ref int index) { int blockX = Utils.Floor( x ), blockZ = Utils.Floor( z ); Vector3I p = new Vector3I( blockX, 0, blockZ ); BlockInfo info = game.BlockInfo; Vector3 Position = entity.Position; index = 0; // Check we have not processed this particular block already. if( Position.Y < 0 ) return false; for( int i = 0; i < 4; i++ ) { if( coords[i] == p ) return false; data[i] = new ShadowData(); } coords[posCount] = p; posCount++; while( posY >= 0 && index < 4 ) { byte block = GetShadowBlock( blockX, posY, blockZ ); posY--; if( info.IsAir[block] || info.IsSprite[block] || info.IsLiquid[block] ) continue; float blockY = posY + 1 + info.MaxBB[block].Y; if( blockY >= Position.Y + 0.01f ) continue; data[index].Block = block; data[index].Y = blockY; CalcAlpha( Position.Y, ref data[index] ); index++; // Check if the casted shadow will continue on further down. if( info.MinBB[block].X == 0 && info.MaxBB[block].X == 1 && info.MinBB[block].Z == 0 && info.MaxBB[block].Z == 1 ) return true; } if( index < 4 ) { data[index].Block = (byte)game.World.Env.EdgeBlock; data[index].Y = 0; CalcAlpha( Position.Y, ref data[index] ); index++; } return true; }
void RenderAdditionalShadowmapAtlas(ref ScriptableRenderContext context, ref CullingResults cullResults, ref LightData lightData, ref ShadowData shadowData) { NativeArray <VisibleLight> visibleLights = lightData.visibleLights; bool additionalLightHasSoftShadows = false; CommandBuffer cmd = CommandBufferPool.Get(m_ProfilerTag); using (new ProfilingScope(cmd, m_ProfilingSampler)) { bool anyShadowSliceRenderer = false; int shadowSlicesCount = m_AdditionalShadowCastingLightIndices.Count; for (int i = 0; i < shadowSlicesCount; ++i) { // we do the shadow strength check here again here because when using // the uniform array path we might have zero strength shadow lights. // In that case we need the shadow data buffer but we can skip // rendering them to shadowmap. if (!m_UseStructuredBuffer && Mathf.Approximately(m_AdditionalLightsShadowParams[i].x, 0.0f)) { continue; } // Index of the VisibleLight int shadowLightIndex = m_AdditionalShadowCastingLightIndices[i]; VisibleLight shadowLight = visibleLights[shadowLightIndex]; ShadowSliceData shadowSliceData = m_AdditionalLightSlices[i]; var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex); Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, shadowSliceData.projectionMatrix, shadowSliceData.resolution); ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias); ShadowUtils.RenderShadowSlice(cmd, ref context, ref shadowSliceData, ref settings, shadowBias, shadowLight, i); additionalLightHasSoftShadows |= shadowLight.light.shadows == LightShadows.Soft; anyShadowSliceRenderer = true; } // We share soft shadow settings for main light and additional lights to save keywords. // So we check here if pipeline supports soft shadows and either main light or any additional light has soft shadows // to enable the keyword. // TODO: In PC and Consoles we can upload shadow data per light and branch on shader. That will be more likely way faster. bool mainLightHasSoftShadows = shadowData.supportsMainLightShadows && lightData.mainLightIndex != -1 && visibleLights[lightData.mainLightIndex].light.shadows == LightShadows.Soft; bool softShadows = shadowData.supportsSoftShadows && (mainLightHasSoftShadows || additionalLightHasSoftShadows); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.AdditionalLightShadows, anyShadowSliceRenderer); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, softShadows); if (anyShadowSliceRenderer) { SetupAdditionalLightsShadowReceiverConstants(cmd, ref shadowData, softShadows); } } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); }
void DrawCircle( VertexP3fT2fC4b[] verts, ref int index, ShadowData* data, int dataCount, float x, float z) { x = Utils.Floor( x ); z = Utils.Floor( z ); BlockInfo info = game.BlockInfo; Vector3 min = info.MinBB[data[0].Block], max = info.MaxBB[data[0].Block]; DrawCoords( verts, ref index, data[0], x + min.X, z + min.Z, x + max.X, z + max.Z ); for( int i = 1; i < dataCount; i++ ) { Vector3 nMin = info.MinBB[data[i].Block], nMax = info.MaxBB[data[i].Block]; DrawCoords( verts, ref index, data[i], x + min.X, z + nMin.Z, x + max.X, z + min.Z ); DrawCoords( verts, ref index, data[i], x + min.X, z + max.Z, x + max.X, z + nMax.Z ); DrawCoords( verts, ref index, data[i], x + nMin.X, z + nMin.Z, x + min.X, z + nMax.Z ); DrawCoords( verts, ref index, data[i], x + max.X, z + nMin.Z, x + nMax.X, z + nMax.Z ); min = nMin; max = nMax; } }
void RenderMainLightCascadeShadowmap(ref ScriptableRenderContext context, ref CullingResults cullResults, ref LightData lightData, ref ShadowData shadowData) { int shadowLightIndex = lightData.mainLightIndex; if (shadowLightIndex == -1) { return; } VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex]; // NOTE: Do NOT mix ProfilingScope with named CommandBuffers i.e. CommandBufferPool.Get("name"). // Currently there's an issue which results in mismatched markers. CommandBuffer cmd = CommandBufferPool.Get(); using (new ProfilingScope(cmd, m_ProfilingSampler)) { var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex); for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex) { var splitData = settings.splitData; splitData.cullingSphere = m_CascadeSplitDistances[cascadeIndex]; settings.splitData = splitData; Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].resolution); ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias); ShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex], ref settings, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].viewMatrix); } bool softShadows = shadowLight.light.shadows == LightShadows.Soft && shadowData.supportsSoftShadows; CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, true); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, shadowData.mainLightShadowCascadesCount > 1); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, softShadows); SetupMainLightShadowReceiverConstants(cmd, shadowLight, shadowData.supportsSoftShadows); } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); }
internal void Draw() { EntityShadow mode = game.Entities.ShadowMode; Vector3 Position = entity.Position; float posX = Position.X, posZ = Position.Z; int posY = Math.Min((int)Position.Y, game.World.Height - 1); int index = 0, vb = 0; radius = 7f * Math.Min(entity.ModelScale, 1) * entity.Model.ShadowScale; VertexP3fT2fC4b[] verts = null; int posCount = 0, dataCount = 0; Vector3I * coords = stackalloc Vector3I[4]; ShadowData *data = stackalloc ShadowData[4]; for (int i = 0; i < 4; i++) { coords[i] = new Vector3I(int.MinValue); data[i] = new ShadowData(); } if (mode == EntityShadow.SnapToBlock) { vb = game.Graphics.texVb; verts = game.Graphics.texVerts; if (!GetBlocks(coords, ref posCount, posX, posZ, posY, data, ref dataCount)) { return; } float x1 = Utils.Floor(posX), z1 = Utils.Floor(posZ); DraqSquareShadow(verts, ref index, data[0].Y, 220, x1, z1); } else { vb = game.ModelCache.vb; verts = game.ModelCache.vertices; float x = posX - radius / 16f, z = posZ - radius / 16f; if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0) { DrawCircle(verts, ref index, data, dataCount, x, z); } x = Math.Max(posX - radius / 16f, Utils.Floor(posX + radius / 16f)); if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0) { DrawCircle(verts, ref index, data, dataCount, x, z); } z = Math.Max(posZ - radius / 16f, Utils.Floor(posZ + radius / 16f)); if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0) { DrawCircle(verts, ref index, data, dataCount, x, z); } x = posX - radius / 16f; if (GetBlocks(coords, ref posCount, x, z, posY, data, ref dataCount) && data[0].A > 0) { DrawCircle(verts, ref index, data, dataCount, x, z); } } if (index == 0) { return; } CheckShadowTexture(game.Graphics); if (!boundShadowTex) { game.Graphics.BindTexture(shadowTex); boundShadowTex = true; } game.Graphics.UpdateDynamicIndexedVb(DrawMode.Triangles, vb, verts, index); }
void RenderDirectionalCascadeShadowmap(ref ScriptableRenderContext context, ref RenderingData renderingData) { LightData lightData = renderingData.lightData; ShadowData shadowData = renderingData.shadowData; CullResults cullResults = renderingData.cullResults; float shadowFarPlane = renderingData.cameraData.maxShadowDistance; int shadowLightIndex = lightData.mainLightIndex; if (shadowLightIndex == -1) { return; } VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex]; Light light = shadowLight.light; if (light.shadows == LightShadows.None) { return; } Bounds bounds; if (!cullResults.GetShadowCasterBounds(shadowLightIndex, out bounds)) { return; } CommandBuffer cmd = commandBufferPool.Get(k_RenderDirectionalShadowmapTag); { m_ShadowCasterCascadesCount = shadowData.directionalLightCascadeCount; int shadowResolution = (m_ShadowCasterCascadesCount > 1) ? (int)(shadowData.directionalShadowAltasRes / 2f) : shadowData.directionalShadowAltasRes; float shadowNearPlane = light.shadowNearPlane; Matrix4x4 view, proj; DrawShadowsSettings settings = new DrawShadowsSettings(cullResults, shadowLightIndex); m_DirectionalShadowmapTexture = RenderTexture.GetTemporary(shadowData.directionalShadowAltasRes, shadowData.directionalShadowAltasRes, k_ShadowmapBufferBits, m_ShadowmapFormat); m_DirectionalShadowmapTexture.filterMode = FilterMode.Bilinear; m_DirectionalShadowmapTexture.wrapMode = TextureWrapMode.Clamp; cmd.GetTemporaryRT(destination.id, m_DirectionalShadowmapTexture.descriptor); SetRenderTarget(cmd, destination.Identifier(), RenderBufferLoadAction.DontCare, RenderBufferStoreAction.Store, ClearFlag.Depth, Color.black, TextureDimension.Tex2D); bool success = false; for (int i = 0; i < m_ShadowCasterCascadesCount; i++) { success = CoreShadowUtils.ExtractDirectionalLightMatrix(ref cullResults, ref shadowData, shadowLightIndex, i, shadowResolution, shadowNearPlane, shadowFarPlane, out m_CascadeSplitDistances[i], out m_CascadeSlices[i], out view, out proj); if (success) { //Debug.Log("Cascade " + i.ToString() + " " + m_ShadowCasterCascadesCount.ToString() + " " + view * proj); settings.splitData.cullingSphere = m_CascadeSplitDistances[i]; CoreShadowUtils.SetupShadowCasterConstants(cmd, ref shadowLight, proj, shadowResolution); CoreShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[i], ref settings, proj, view); } } if (success) { SetupDirectionalShadowReceiverConstants(cmd, ref shadowData, shadowLight); } } context.ExecuteCommandBuffer(cmd); commandBufferPool.Release(cmd); }
abstract public bool Reserve(FrameId frameId, ref ShadowData shadowData, ShadowRequest sr, uint[] widths, uint[] heights, ref VectorArray <ShadowData> entries, ref VectorArray <ShadowPayload> payloads, VisibleLight[] lights);
void RenderMainLightCascadeShadowmap(ref ScriptableRenderContext context, ref CullingResults cullResults, ref LightData lightData, ref ShadowData shadowData) { int shadowLightIndex = lightData.mainLightIndex; if (shadowLightIndex == -1) { return; } VisibleLight shadowLight = lightData.visibleLights[shadowLightIndex]; // NOTE: Do NOT mix ProfilingScope with named CommandBuffers i.e. CommandBufferPool.Get("name"). // Currently there's an issue which results in mismatched markers. CommandBuffer cmd = CommandBufferPool.Get(); using (new ProfilingScope(cmd, ProfilingSampler.Get(URPProfileId.MainLightShadow))) { var settings = new ShadowDrawingSettings(cullResults, shadowLightIndex); for (int cascadeIndex = 0; cascadeIndex < m_ShadowCasterCascadesCount; ++cascadeIndex) { //settings.splitData = m_CascadeSlices[cascadeIndex].splitData; // NOTE: currently DrawShadows culls more casters if no ShadowSplitData.cullingPlanes are set (version cds 8652678b), so it is currently better to not pass the m_CascadeSlices[cascadeIndex].splitData object returned by CullingResults.ComputeDirectionalShadowMatricesAndCullingPrimitives (change introduced in 8bf71cf). Culling is only based on the ShadowSplitData.cullingSphere distances. var splitData = settings.splitData; splitData.cullingSphere = m_CascadeSplitDistances[cascadeIndex]; settings.splitData = splitData; Vector4 shadowBias = ShadowUtils.GetShadowBias(ref shadowLight, shadowLightIndex, ref shadowData, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].resolution); ShadowUtils.SetupShadowCasterConstantBuffer(cmd, ref shadowLight, shadowBias); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.CastingPunctualLightShadow, false); ShadowUtils.RenderShadowSlice(cmd, ref context, ref m_CascadeSlices[cascadeIndex], ref settings, m_CascadeSlices[cascadeIndex].projectionMatrix, m_CascadeSlices[cascadeIndex].viewMatrix); } bool softShadows = shadowLight.light.shadows == LightShadows.Soft && shadowData.supportsSoftShadows; CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadows, true); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.MainLightShadowCascades, shadowData.mainLightShadowCascadesCount > 1); CoreUtils.SetKeyword(cmd, ShaderKeywordStrings.SoftShadows, softShadows); SetupMainLightShadowReceiverConstants(cmd, shadowLight, shadowData.supportsSoftShadows); } context.ExecuteCommandBuffer(cmd); CommandBufferPool.Release(cmd); }