public override void ApplyViewParameters(RenderDrawContext context, int viewIndex, ParameterCollection parameters) { CurrentLights.Clear(); var lightRange = LightRanges[viewIndex]; for (int i = lightRange.Start; i < lightRange.End; ++i) { CurrentLights.Add(Lights[i]); } base.ApplyViewParameters(context, viewIndex, parameters); foreach (var lightEntry in CurrentLights) { var light = lightEntry.Light; lightsData.Add(new DirectionalLightData { DirectionWS = light.Direction, Color = light.Color, }); } parameters.Set(countKey, lightsData.Count); parameters.Set(lightsKey, lightsData.Count, ref lightsData.Items[0]); lightsData.Clear(); }
public int ApplyViewParameters_PopulateParameterLightsOrig() { int sum = 0; for (int ii = 0; ii < N; ii++) { for (int viewIndex = 0; viewIndex < lightRanges.Length; viewIndex++) { var lightRange = lightRanges[viewIndex]; PopulateLightsInRange(ref lights, lightRange, ref currentLights); lightsData.Clear(); // ----- Test foreach (var lightEntry in currentLights) { var light = lightEntry.Light; lightsData.Add(new DirectionalLightData { DirectionWS = light.Direction, Color = light.Color, }); } // ----- End Test sum += lightsData.Count; } } return(sum); }
public override void ApplyViewParameters(FastListStruct <LightDynamicEntry>?lightList, RenderDrawContext context, int viewIndex, ParameterCollection parameters) { FastListStruct <DirectionalLightData> lightsData = new FastListStruct <DirectionalLightData>(8); if (lightList == null) { lightList = new FastListStruct <LightDynamicEntry>(8); } FastListStruct <LightDynamicEntry> currentLights = lightList.Value; var lightRange = lightRanges[viewIndex]; for (int i = lightRange.Start; i < lightRange.End; ++i) { currentLights.Add(lights[i]); } base.ApplyViewParameters(currentLights, context, viewIndex, parameters); foreach (var lightEntry in currentLights) { var light = lightEntry.Light; lightsData.Add(new DirectionalLightData { DirectionWS = light.Direction, Color = light.Color, }); } parameters.Set(countKey, lightsData.Count); parameters.Set(lightsKey, lightsData.Count, ref lightsData.Items[0]); }
public void Initialize() { EffectValues = new FastListStruct <EffectParameterEntry>(4); // Add a dummy value so that an effect without parameter fails validation first time EffectValues.Add(new EffectParameterEntry()); }
public override void FillParameterCollections(ref FastListStruct <ParameterCollection> parameterCollections) { var material = Material; if (material != null && material.Parameters != null) { parameterCollections.Add(material.Parameters); } if (RenderModel.ModelComponent.Parameters != null) { parameterCollections.Add(RenderModel.ModelComponent.Parameters); } // TODO: Should we add RenderMesh.Parameters before ModelComponent.Parameters to allow user overiddes at component level? parameterCollections.Add(parameters); }
public override void ApplyDrawParameters(RenderDrawContext context, int viewIndex, ParameterCollection parameters, ref BoundingBoxExt boundingBox) { if (currentLights.Items == null) { currentLights = new FastListStruct <LightDynamicEntry>(8); } else { currentLights.Clear(); } if (lightsData.Items == null) { lightsData = new FastListStruct <SpotLightData>(8); } var lightRange = lightRanges[viewIndex]; for (int i = lightRange.Start; i < lightRange.End; ++i) { currentLights.Add(lights[i]); } base.ApplyDrawParameters(context, viewIndex, parameters, ref boundingBox); // TODO: Octree structure to select best lights quicker var boundingBox2 = (BoundingBox)boundingBox; for (int i = 0; i < currentLights.Count; i++) { var light = currentLights[i].Light; if (light.BoundingBox.Intersects(ref boundingBox2)) { var spotLight = (LightSpot)light.Type; lightsData.Add(new SpotLightData { PositionWS = light.Position, DirectionWS = light.Direction, AngleOffsetAndInvSquareRadius = new Vector3(spotLight.LightAngleScale, spotLight.LightAngleOffset, spotLight.InvSquareRange), Color = light.Color, }); // Did we reach max number of simultaneous lights? // TODO: Still collect everything but sort by importance and remove the rest? if (lightsData.Count >= LightCurrentCount) { break; } } } parameters.Set(countKey, lightsData.Count); parameters.Set(lightsKey, lightsData.Count, ref lightsData.Items[0]); TextureProjectionShaderGroupData?.ApplyDrawParameters(context, parameters, currentLights, ref boundingBox); lightsData.Clear(); }
public override void ApplyDrawParameters(RenderDrawContext context, int viewIndex, ParameterCollection parameters, ref BoundingBoxExt boundingBox) { if (currentLights.Items == null) { currentLights = new FastListStruct <LightDynamicEntry>(8); } else { currentLights.Clear(); } if (lightsData.Items == null) { lightsData = new FastListStruct <PointLightData>(8); } var lightRange = lightRanges[viewIndex]; for (int i = lightRange.Start; i < lightRange.End; ++i) { currentLights.Add(lights[i]); } base.ApplyDrawParameters(context, viewIndex, parameters, ref boundingBox); // TODO: Since we cull per object, we could maintain a higher number of allowed light than the shader support (i.e. 4 lights active per object even though the scene has many more of them) // TODO: Octree structure to select best lights quicker var boundingBox2 = (BoundingBox)boundingBox; foreach (var lightEntry in currentLights) { var light = lightEntry.Light; if (light.BoundingBox.Intersects(ref boundingBox2)) { var pointLight = (LightPoint)light.Type; lightsData.Add(new PointLightData { PositionWS = light.Position, InvSquareRadius = pointLight.InvSquareRadius, Color = light.Color, }); // Did we reach max number of simultaneous lights? // TODO: Still collect everything but sort by importance and remove the rest? if (lightsData.Count >= LightCurrentCount) { break; } } } parameters.Set(countKey, lightsData.Count); parameters.Set(lightsKey, lightsData.Count, ref lightsData.Items[0]); lightsData.Clear(); }
private void PrepareRenderMeshes(RenderModel renderModel, List <Mesh> meshes, ref FastListStruct <RenderMesh> renderMeshes, RenderItemCollection opaqueList, RenderItemCollection transparentList) { // Add new render meshes for (int i = renderMeshes.Count; i < meshes.Count; i++) { var renderMesh = new RenderMesh(renderModel, meshes[i]); renderMeshes.Add(renderMesh); } // Create the bounding frustum locally on the stack, so that frustum.Contains is performed with boundingBox that is also on the stack var frustum = new BoundingFrustum(ref ViewProjectionMatrix); var sceneCameraRenderer = Context.Tags.Get(SceneCameraRenderer.Current); var cullingMode = CullingModeOverride ?? (sceneCameraRenderer?.CullingMode ?? CameraCullingMode.None); for (int i = 0; i < renderMeshes.Count; i++) { var renderMesh = renderMeshes[i]; // Update the model hierarchy var modelViewHierarchy = renderModel.ModelComponent.Skeleton; modelViewHierarchy.UpdateRenderMesh(renderMesh); if (!renderMesh.Enabled || !renderMesh.UpdateMaterial()) { continue; } // Upload skinning blend matrices BoundingBoxExt boundingBox; skinningUpdater.Update(modelViewHierarchy, renderMesh, out boundingBox); // Fast AABB transform: http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ // Compute transformed AABB (by world) // TODO: CameraCullingMode should be pluggable // TODO: This should not be necessary. Add proper bounding boxes to gizmos etc. if (cullingMode == CameraCullingMode.Frustum && boundingBox.Extent != Vector3.Zero && !frustum.Contains(ref boundingBox)) { continue; } // Project the position // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object var worldPosition = new Vector4(renderMesh.WorldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref ViewProjectionMatrix, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; renderMesh.RasterizerState = renderMesh.IsGeometryInverted ? RasterizerStateForInvertedGeometry : RasterizerState; renderMesh.ForceRasterizer = ForceRasterizer; var list = renderMesh.HasTransparency ? transparentList : opaqueList; list.Add(new RenderItem(this, renderMesh, projectedZ)); } }
public override void FillParameterCollections(ref FastListStruct <ParameterCollection> parameterCollections) { // Test common types to avoid struct enumerator boxing var localParameterCollectionsList = localParameterCollections as List <ParameterCollection>; if (localParameterCollectionsList != null) { foreach (var parameter in localParameterCollectionsList) { if (parameter != null) { parameterCollections.Add(parameter); } } } else { var localParameterCollectionsArray = localParameterCollections as ParameterCollection[]; if (localParameterCollectionsArray != null) { foreach (var parameter in localParameterCollectionsArray) { if (parameter != null) { parameterCollections.Add(parameter); } } } else { // Slow: enumerator will be boxed foreach (var parameter in localParameterCollections) { if (parameter != null) { parameterCollections.Add(parameter); } } } } }
public void GlobalSetup() { for (int i = 0; i < TotalLights; i++) { lights.Add(new LightDynamicEntry(new RenderLight(), shadowMapTexture: null)); } lightRanges = new[] { new LightShaderGroupDynamic.LightRange(0, 4), new LightShaderGroupDynamic.LightRange(4, 8), }; }
public override void FillParameterCollections(ref FastListStruct<ParameterCollection> parameterCollections) { // Test common types to avoid struct enumerator boxing var localParameterCollectionsList = localParameterCollections as List<ParameterCollection>; if (localParameterCollectionsList != null) { foreach (var parameter in localParameterCollectionsList) { if (parameter != null) { parameterCollections.Add(parameter); } } } else { var localParameterCollectionsArray = localParameterCollections as ParameterCollection[]; if (localParameterCollectionsArray != null) { foreach (var parameter in localParameterCollectionsArray) { if (parameter != null) { parameterCollections.Add(parameter); } } } else { // Slow: enumerator will be boxed foreach (var parameter in localParameterCollections) { if (parameter != null) { parameterCollections.Add(parameter); } } } } }
private void AssignRectangle(LightShadowMapTexture lightShadowMapTexture) { var size = lightShadowMapTexture.Size; // Try to fit the shadow map into an existing atlas ShadowMapAtlasTexture currentAtlas = null; foreach (var atlas in atlases) { if (atlas.TryInsert(size, size, lightShadowMapTexture.CascadeCount, (int index, ref Rectangle rectangle) => lightShadowMapTexture.SetRectangle(index, rectangle))) { currentAtlas = atlas; break; } } // Allocate a new atlas texture if (currentAtlas == null) { // For now, our policy is to allow only one shadow map, esp. because we can have only one shadow texture per lighting group // TODO: Group by DirectLightGroups, so that we can have different atlas per lighting group // TODO: Allow multiple textures per LightingGroup (using array of Texture?) if (atlases.Count == 0) { // TODO: handle FilterType texture creation here // TODO: This does not work for Omni lights // TODO: Allow format selection externally var texture = Texture.New2D(RenderSystem.GraphicsDevice, maximumTextureSize, maximumTextureSize, 1, PixelFormat.D32_Float, TextureFlags.DepthStencil | TextureFlags.ShaderResource); currentAtlas = new ShadowMapAtlasTexture(texture, atlases.Count) { FilterType = lightShadowMapTexture.FilterType }; atlases.Add(currentAtlas); for (int i = 0; i < lightShadowMapTexture.CascadeCount; i++) { var rect = Rectangle.Empty; currentAtlas.Insert(size, size, ref rect); lightShadowMapTexture.SetRectangle(i, rect); } } } // Make sure the atlas cleared (will be clear just once) lightShadowMapTexture.Atlas = currentAtlas; lightShadowMapTexture.TextureId = (byte)(currentAtlas?.Id ?? 0); }
public override void ApplyDrawParameters(RenderDrawContext context, int viewIndex, ParameterCollection parameters, ref BoundingBoxExt boundingBox) { // TODO THREADING: Make CurrentLights and lightData (thread-) local lock (applyLock) { CurrentLights.Clear(); var lightRange = LightRanges[viewIndex]; for (int i = lightRange.Start; i < lightRange.End; ++i) { CurrentLights.Add(Lights[i]); } base.ApplyDrawParameters(context, viewIndex, parameters, ref boundingBox); // TODO: Octree structure to select best lights quicker var boundingBox2 = (BoundingBox)boundingBox; for (int i = 0; i < CurrentLights.Count; i++) { var light = CurrentLights[i].Light; if (light.BoundingBox.Intersects(ref boundingBox2)) { var spotLight = (LightSpot)light.Type; lightsData.Add(new SpotLightData { PositionWS = light.Position, DirectionWS = light.Direction, AngleOffsetAndInvSquareRadius = new Vector3(spotLight.LightAngleScale, spotLight.LightAngleOffset, spotLight.InvSquareRange), Color = light.Color, }); // Did we reach max number of simultaneous lights? // TODO: Still collect everything but sort by importance and remove the rest? if (lightsData.Count >= LightCurrentCount) { break; } } } parameters.Set(countKey, lightsData.Count); parameters.Set(lightsKey, lightsData.Count, ref lightsData.Items[0]); lightsData.Clear(); } }
protected override void DrawCore(RenderContext context, RenderItemCollection renderItemList, int fromIndex, int toIndex) { if (dynamicEffectCompiler == null) { throw new InvalidOperationException("This instance is not correctly initialized (no EffectName)"); } // Get all meshes from render models meshesToRender.Clear(); for (int i = fromIndex; i <= toIndex; i++) { meshesToRender.Add((RenderMesh)renderItemList[i].DrawContext); } // Slow path there is a callback if (Callbacks.UpdateMeshes != null) { Callbacks.UpdateMeshes(context, ref meshesToRender); } // Fetch callback on PreRenderGroup var preRenderMesh = Callbacks.PreRenderMesh; for (int i = 0; i < meshesToRender.Count; i++) { var renderMesh = meshesToRender[i]; // If the EntityGroup is changing, call the callback to allow to plug specific parameters for this group if (preRenderMesh != null) { preRenderMesh(context, renderMesh); } // Update Effect and mesh UpdateEffect(context, renderMesh, context.Parameters); // Draw the mesh renderMesh.Draw(context); } }
/// <summary> /// Draw this effect mesh. /// </summary> public void Draw(RenderContext context) { // Retrieve effect parameters var graphicsDevice = context.GraphicsDevice; var mesh = Mesh; var currentRenderData = mesh.Draw; var material = Material; var vao = vertexArrayObject; var drawCount = currentRenderData.DrawCount; var primitiveType = currentRenderData.PrimitiveType; parameters.Set(TransformationKeys.World, WorldMatrix); // TODO: We should clarify exactly how to override rasterizer states. Currently setup here on Context.Parameters to allow Material/ModelComponent overrides, but this is ugly // Apply rasterizer var rasterizer = RasterizerState; if (!ForceRasterizer && Material.CullMode.HasValue && Material.CullMode.Value != RasterizerState.Description.CullMode) { switch (Material.CullMode.Value) { case CullMode.Back: rasterizer = graphicsDevice.RasterizerStates.CullBack; break; case CullMode.Front: rasterizer = graphicsDevice.RasterizerStates.CullFront; break; case CullMode.None: rasterizer = graphicsDevice.RasterizerStates.CullNone; break; } } context.Parameters.Set(Effect.RasterizerStateKey, rasterizer); // Handle picking if (context.IsPicking()) // TODO move this code corresponding to picking outside of the runtime code! { parameters.Set(ModelComponentPickingShaderKeys.ModelComponentId, new Color4(RuntimeIdHelper.ToRuntimeId(RenderModel.ModelComponent))); parameters.Set(ModelComponentPickingShaderKeys.MeshId, new Color4(RenderModel.ModelComponent.Model.Meshes.IndexOf(Mesh))); parameters.Set(ModelComponentPickingShaderKeys.MaterialId, new Color4(Mesh.MaterialIndex)); // Don't use the materials blend state on picking targets parameters.Set(Effect.BlendStateKey, null); } if (material != null && material.TessellationMethod != XenkoTessellationMethod.None) { var tessellationMethod = material.TessellationMethod; // adapt the primitive type and index buffer to the tessellation used if (tessellationMethod.PerformsAdjacentEdgeAverage()) { vao = GetOrCreateVertexArrayObjectAEN(context); drawCount = 12 / 3 * drawCount; } primitiveType = tessellationMethod.GetPrimitiveType(); } //using (Profiler.Begin(ProfilingKeys.PrepareMesh)) { // Order of application of parameters: // - RenderPass.Parameters // - ModelComponent.Parameters // - RenderMesh.Parameters (originally copied from mesh parameters) // The order is based on the granularity level of each element and how shared it can be. Material is heavily shared, a model contains many meshes. An renderMesh is unique. // TODO: really copy mesh parameters into renderMesh instead of just referencing the meshDraw parameters. //var modelComponent = RenderModel.ModelComponent; //var hasModelComponentParams = modelComponent != null && modelComponent.Parameters != null; //var materialParameters = material != null && material.Parameters != null ? material.Parameters : null; parameterCollections.Clear(); parameterCollections.Add(context.Parameters); FillParameterCollections(ref parameterCollections); // Check if we need to recreate the EffectParameterCollectionGroup // TODO: We can improve performance by redesigning FillParameterCollections to avoid ArrayExtensions.ArraysReferenceEqual (or directly check the appropriate parameter collections) // This also happens in another place: DynamicEffectCompiler (we probably want to factorize it when doing additional optimizations) if (parameterCollectionGroup == null || parameterCollectionGroup.Effect != Effect || !ArrayExtensions.ArraysReferenceEqual(ref previousParameterCollections, ref parameterCollections)) { previousParameterCollections.Clear(); previousParameterCollections.AddRange(parameterCollections); parameterCollectionGroup = new EffectParameterCollectionGroup(context.GraphicsDevice, Effect, previousParameterCollections.Count, previousParameterCollections.Items); } Effect.Apply(context.GraphicsDevice, parameterCollectionGroup, true); } //using (Profiler.Begin(ProfilingKeys.RenderMesh)) { if (currentRenderData != null) { graphicsDevice.SetVertexArrayObject(vao); if (currentRenderData.IndexBuffer == null) { graphicsDevice.Draw(primitiveType, drawCount, currentRenderData.StartLocation); } else { graphicsDevice.DrawIndexed(primitiveType, drawCount, currentRenderData.StartLocation); } } } }
public override void FillParameterCollections(ref FastListStruct<ParameterCollection> parameterCollections) { var material = Material; if (material != null && material.Parameters != null) { parameterCollections.Add(material.Parameters); } if (RenderModel.ModelComponent.Parameters != null) { parameterCollections.Add(RenderModel.ModelComponent.Parameters); } // TODO: Should we add RenderMesh.Parameters before ModelComponent.Parameters to allow user overiddes at component level? parameterCollections.Add(parameters); }
private void PrepareRenderMeshes(RenderModel renderModel, List<Mesh> meshes, ref FastListStruct<RenderMesh> renderMeshes, RenderItemCollection opaqueList, RenderItemCollection transparentList) { // Add new render meshes for (int i = renderMeshes.Count; i < meshes.Count; i++) { var renderMesh = new RenderMesh(renderModel, meshes[i]); renderMeshes.Add(renderMesh); } // Create the bounding frustum locally on the stack, so that frustum.Contains is performed with boundingBox that is also on the stack var frustum = new BoundingFrustum(ref ViewProjectionMatrix); for (int i = 0; i < renderMeshes.Count; i++) { var renderMesh = renderMeshes[i]; // Update the model hierarchy var modelViewHierarchy = renderModel.ModelComponent.ModelViewHierarchy; modelViewHierarchy.UpdateRenderMesh(renderMesh); if (!renderMesh.Enabled) { continue; } // Upload skinning blend matrices BoundingBoxExt boundingBox; skinningUpdater.Update(modelViewHierarchy, renderMesh, out boundingBox); // Fast AABB transform: http://zeuxcg.org/2010/10/17/aabb-from-obb-with-component-wise-abs/ // Compute transformed AABB (by world) // TODO: CullingMode should be pluggable // TODO: This should not be necessary. Add proper bounding boxes to gizmos etc. if (CullingMode == CullingMode.Frustum && boundingBox.Extent != Vector3.Zero && !frustum.Contains(ref boundingBox)) { continue; } // Project the position // TODO: This could be done in a SIMD batch, but we need to figure-out how to plugin in with RenderMesh object var worldPosition = new Vector4(renderMesh.WorldMatrix.TranslationVector, 1.0f); Vector4 projectedPosition; Vector4.Transform(ref worldPosition, ref ViewProjectionMatrix, out projectedPosition); var projectedZ = projectedPosition.Z / projectedPosition.W; renderMesh.RasterizerState = renderMesh.IsGeometryInverted ? RasterizerStateForInvertedGeometry : RasterizerState; renderMesh.UpdateMaterial(); var list = renderMesh.HasTransparency ? transparentList : opaqueList; list.Add(new RenderItem(this, renderMesh, projectedZ)); } }