/// <summary> /// Create the corresponding <see cref="LightsState.Light"/> for this object. /// </summary> /// <returns> /// It returns the <see cref="LightsState.Light"/> equivalent to this SceneObjectLight. /// </returns> public override LightsState.Light ToLight(GraphicsContext ctx, SceneGraphContext sceneCtx) { TransformStateBase transformState = (TransformStateBase)sceneCtx.GraphicsStateStack.Current[TransformStateBase.StateSetIndex]; LightsState.LightSpot light = new LightsState.LightSpot(); SetLightParameters(sceneCtx, light); IModelMatrix worldModel = transformState.LocalModelView; IMatrix3x3 normalMatrix = worldModel.GetComplementMatrix(3, 3).GetInverseMatrix().Transpose(); light.Direction = ((Vertex3f)normalMatrix.Multiply((Vertex3f)Direction)).Normalized; light.Position = (Vertex3f)worldModel.Multiply(Vertex3f.Zero); light.AttenuationFactors = AttenuationFactors; light.FallOff = new Vertex2f((float)Math.Cos(Angle.ToRadians(FalloffAngle)), FalloffExponent); // Shadow mapping if (_ShadowMap != null && _ShadowViewMatrix != null) { // Determined later: light.ShadowMapIndex light.ShadowMapMvp.Set(_ShadowViewMatrix); light.ShadowMap2D = _ShadowMap; } else { light.ShadowMapIndex = -1; light.ShadowMap2D = null; } return(light); }
/// <summary> /// Draw this SceneGraphObject instance. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for drawing. /// </param> /// <param name="ctxScene"> /// The <see cref="SceneGraphContext"/> used for drawing. /// </param> protected override void DrawThis(GraphicsContext ctx, SceneGraphContext ctxScene) { // Apply current state ctxScene.GraphicsStateStack.Current.Apply(ctx, _Program); // Draw arrays _VertexArray.Draw(ctx, _Program); }
/// <summary> /// Create the corresponding <see cref="LightsState.Light"/> for this object. /// </summary> /// <returns> /// It returns the <see cref="LightsState.Light"/> equivalent to this SceneObjectLight. /// </returns> public override LightsState.Light ToLight(GraphicsContext ctx, SceneGraphContext sceneCtx) { TransformState transformState = (TransformState)sceneCtx.GraphicsStateStack.Current[TransformState.StateSetIndex]; LightsState.LightSpot light = new LightsState.LightSpot(); SetLightParameters(sceneCtx, light); Matrix4x4f worldModel = transformState.ModelView; Matrix3x3f normalMatrix = new Matrix3x3f(worldModel, 3, 3).Inverse.Transposed; light.Direction = (normalMatrix * (Vertex3f)Direction).Normalized; light.Position = (Vertex3f)(worldModel * Vertex3f.Zero); light.AttenuationFactors = AttenuationFactors; light.FallOff = new Vertex2f((float)Math.Cos(Angle.ToRadians(FalloffAngle)), FalloffExponent); // Shadow mapping if (_ShadowMap != null) { // Determined later: light.ShadowMapIndex light.ShadowMapMvp = _ShadowViewMatrix; light.ShadowMap2D = _ShadowMap; } else { light.ShadowMapIndex = -1; light.ShadowMap2D = null; } return(light); }
private static bool DrawDelegate(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject, object data) { // Draw this object sceneObject.DrawThis(ctx, ctxScene); return(true); }
/// <summary> /// Traverse the scene graph from the current SceneObject to the leaf SceneObject. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for drawing/updating objects, if any. /// </param> /// <param name="ctxScene"> /// The <see cref="SceneGraphContext"/> used for drawing/updating objects, if any. /// </param> /// <param name="traverseFunc"> /// The <see cref="TraverseDelegate"/> executed for each SceneObject instance visited during traversal. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="traverseFunc"/> is null. /// </exception> protected internal void TraverseDirect(GraphicsContext ctx, SceneGraphContext ctxScene, TraverseContext traverseFunc, object data) { CheckCurrentContext(ctx); if (ctxScene == null) { throw new ArgumentNullException("ctxScene"); } if (traverseFunc == null) { throw new ArgumentNullException("traverseFunc"); } traverseFunc.PreContract?.Invoke(ctx, ctxScene, this, data); try { // Visit this object if (traverseFunc.Visit(ctx, ctxScene, this, data) == false) { return; } // Visit children foreach (SceneObject sceneObject in _Children) { sceneObject.TraverseDirect(ctx, ctxScene, traverseFunc, data); } } finally { traverseFunc.PostContract?.Invoke(ctx, ctxScene, this, data); } }
private static bool GraphDrawPreDelegate(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject, object data) { // Push and merge the graphics state ctxScene.GraphicsStateStack.Push(sceneObject.ObjectState); return(true); }
private SceneGraphFlags _Flags = SceneGraphFlags.None; // SceneGraphFlags.CullingViewFrustum | SceneGraphFlags.StateSorting; // | SceneGraphFlags.BoundingVolumes; /// <summary> /// Draw this SceneGraph. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for drawing. /// </param> public void Draw(GraphicsContext ctx) { CheckCurrentContext(ctx); using (SceneGraphContext ctxScene = new SceneGraphContext(this, _CurrentView)) { ObjectBatchContext objectBatchContext = new ObjectBatchContext(); // Override model-view-projection matrices if a camera is defined if (_CurrentView != null) { LocalProjection = _CurrentView.ProjectionMatrix; LocalModel = _CurrentView.LocalModel.GetInverseMatrix(); } // View-frustum culling objectBatchContext.ViewFrustumPlanes = Plane.GetFrustumPlanes(LocalProjection); // Collect geometries to be batched TraverseDirect(ctx, ctxScene, _TraverseDrawContext, objectBatchContext); // Sort geometries List <SceneObjectBatch> sceneObjects = objectBatchContext.Objects; if (((SceneFlags & SceneGraphFlags.StateSorting) != 0) && (_SorterRoot != null)) { sceneObjects = _SorterRoot.Sort(objectBatchContext.Objects); } // Draw all batches foreach (SceneObjectBatch objectBatch in sceneObjects) { objectBatch.Draw(ctx); } } }
protected static bool DrawPostDelegate(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject, object data) { // Restore previous state ctxScene.GraphicsStateStack.Pop(); return(true); }
/// <summary> /// The internal light parameters. /// </summary> /// <param name="light"> /// The <see cref="LightsState.Light"/> to be set. /// </param> protected void SetLightParameters(SceneGraphContext sceneCtx, LightsState.Light light) { light.AmbientColor = AmbientColor; light.DiffuseColor = DiffuseColor; light.SpecularColor = SpecularColor; light.ShadowMapIndex = -1; }
protected static bool DrawPreDelegate(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject, object data) { // Update object before applying state sceneObject.UpdateThis(ctx, ctxScene); // Push and merge the graphics state ctxScene.GraphicsStateStack.Push(sceneObject.ObjectState); return(true); }
/// <summary> /// Create the corresponding <see cref="LightsState.Light"/> for this object. /// </summary> /// <returns> /// It returns the <see cref="LightsState.Light"/> equivalent to this SceneObjectLight. /// </returns> public override LightsState.Light ToLight(SceneGraphContext sceneCtx) { LightsState.LightSpot light = new LightsState.LightSpot(); SetLightParameters(sceneCtx, light); light.FallOff = new Vertex2f(FalloffAngle, FalloffExponent); return(light); }
internal void ResetLights(SceneGraphContext ctxScene, List <SceneObjectLight> lights) { State.LightsState lightState = (State.LightsState)ObjectState[State.LightsState.StateSetIndex]; lightState.Lights.Clear(); foreach (SceneObjectLight lightObject in lights) { lightState.Lights.Add(lightObject.ToLight(ctxScene)); } }
/// <summary> /// Update this SceneGraphObject instance. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for drawing. /// </param> /// <param name="ctxScene"> /// The <see cref="SceneGraphContext"/> used for drawing. /// </param> protected internal override void UpdateThis(GraphicsContext ctx, SceneGraphContext ctxScene) { //List<SceneObject> lightObjects = FindChildren(delegate(SceneObject item) { return (item is SceneObjectLight); }); //SceneLightingState lightingState = (SceneLightingState)ObjectState[SceneLightingState.StateSetIndex]; //lightingState.CurrentSceneContext = ctxScene; //lightingState.ResetLights(); //lightingState.AddLights(lightObjects.ConvertAll(delegate(SceneObject item) { return ((SceneObjectLight)item); })); }
private void PostObject(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObjectLightZone sceneObject) { if (sceneObject == null) { throw new ArgumentNullException("sceneObject"); } _LightState.Pop(); ctxScene.GraphicsStateStack.Current.DefineState(CurrentZone); }
/// <summary> /// Create the corresponding <see cref="LightsState.Light"/> for this object. /// </summary> /// <returns> /// It returns the <see cref="LightsState.Light"/> equivalent to this SceneObjectLight. /// </returns> public override LightsState.Light ToLight(GraphicsContext ctx, SceneGraphContext sceneCtx) { LightsState.LightPoint light = new LightsState.LightPoint(); SetLightParameters(sceneCtx, light); light.Position = (Vertex3f)(WorldModel * Vertex3f.Zero); light.AttenuationFactors = AttenuationFactors; return(light); }
/// <summary> /// Draw this SceneGraphObject hierarchy. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for drawing. /// </param> /// <param name="ctxScene"> /// The <see cref="SceneGraphContext"/> used for drawing. /// </param> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="ctx"/> is null. /// </exception> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="ctx"/> is not current on the calling thread. /// </exception> /// <exception cref="ArgumentNullException"> /// Exception thrown if <paramref name="ctxScene"/>. /// </exception> protected internal virtual void Draw(GraphicsContext ctx, SceneGraphContext ctxScene) { CheckCurrentContext(ctx); if (ctxScene == null) { throw new ArgumentNullException("ctxScene"); } TraverseDirect(ctx, ctxScene, _TraverseDrawContext, null); }
public void PostObject(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject) { if (sceneObject == null) { throw new ArgumentNullException("sceneObject"); } if (sceneObject.ObjectType == SceneObjectLightZone.ClassObjectType) { PostObject(ctx, ctxScene, (SceneObjectLightZone)sceneObject); } }
/// <summary> /// Get all geometries compositing this SceneObjectGeometry, filtering them using view-frustum. /// </summary> /// <param name="currentState"> /// A <see cref="State.GraphicsStateSet"/> that specifies the current graphics state to be merged with /// each returned geometry. /// </param> /// <param name="clippingPlanes"> /// /// </param> /// <param name="viewModel"> /// /// </param> /// <returns> /// It returns a <see cref="IEnumerable{SceneObjectBatch}"/>. /// </returns> private IEnumerable <SceneObjectBatch> GetGeometriesViewFrustum(SceneGraphContext ctxScene) { GraphicsStateSet currentState = ctxScene.GraphicsStateStack.Current.Push(); TransformState sceneGeometryModel = (TransformState)currentState[TransformState.StateSetIndex]; Matrix4x4f viewModel = sceneGeometryModel.ModelView; if (_GeometryInstances.Count > 0) { foreach (Geometry sceneObjectBatch in _GeometryInstances) { IBoundingVolume instanceVolume = sceneObjectBatch.BoundingVolume ?? _BoundingVolume; if (instanceVolume != null && instanceVolume.IsClipped(ctxScene.ViewFrustumPlanes, viewModel)) { continue; } GraphicsStateSet geometryState; if (sceneObjectBatch.State != null) { geometryState = currentState.Push(); geometryState.Merge(sceneObjectBatch.State); } else { geometryState = currentState; } yield return(new SceneObjectBatch( sceneObjectBatch.VertexArray ?? VertexArray, geometryState, sceneObjectBatch.Program ?? Program )); } } else { if (_BoundingVolume != null && _BoundingVolume.IsClipped(ctxScene.ViewFrustumPlanes, viewModel)) { yield break; } if (VertexArray == null) { yield break; } yield return(new SceneObjectBatch(VertexArray, currentState, Program)); } }
/// <summary> /// Create the corresponding <see cref="LightsState.Light"/> for this object. /// </summary> /// <returns> /// It returns the <see cref="LightsState.Light"/> equivalent to this SceneObjectLight. /// </returns> public override LightsState.Light ToLight(GraphicsContext ctx, SceneGraphContext sceneCtx) { LightsState.LightDirectional light = new LightsState.LightDirectional(); SetLightParameters(sceneCtx, light); TransformState transformState = (TransformState)sceneCtx.GraphicsStateStack.Current[TransformState.StateSetIndex]; Matrix3x3f normalMatrix = transformState.NormalMatrix; light.Direction = (normalMatrix * (Vertex3f)Direction).Normalized; light.HalfVector = (Vertex3f.UnitZ + light.Direction).Normalized; return(light); }
/// <summary> /// Traverse delegate for creating resources. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for creating resources. /// </param> /// <param name="ctxScene"></param> /// <param name="sceneObject"></param> /// <param name="data"></param> /// <returns></returns> private static bool CreateDelegate(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject, object data) { SceneObjectGeometry sceneGeometry = sceneObject as SceneObjectGeometry; if (sceneGeometry != null) { GraphicsStateSet sceneGeometryState = ctxScene.GraphicsStateStack.Current; sceneGeometry.Create(ctx); sceneGeometryState.Create(ctx, sceneGeometry.Program); } return(true); }
/// <summary> /// Create the corresponding <see cref="LightsState.Light"/> for this object. /// </summary> /// <returns> /// It returns the <see cref="LightsState.Light"/> equivalent to this SceneObjectLight. /// </returns> public override LightsState.Light ToLight(SceneGraphContext sceneCtx) { LightsState.LightDirectional light = new LightsState.LightDirectional(); SetLightParameters(sceneCtx, light); // Note: avoiding to invert the view matrix twice IMatrix3x3 normalMatrix = sceneCtx.CurrentView.LocalModel.GetComplementMatrix(3, 3).Transpose(); light.Direction = ((Vertex3f)normalMatrix.Multiply((Vertex3f)Direction)).Normalized; light.HalfVector = (Vertex3f.UnitZ + light.Direction).Normalized; return(light); }
private void ManageObject(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObjectLightZone sceneObject) { if (sceneObject == null) { throw new ArgumentNullException("sceneObject"); } if (_LightState.Count == 1) { ShadowLights.Clear(); } _LightState.Push(new State.LightsState()); ctxScene.GraphicsStateStack.Current.DefineState(CurrentZone); }
/// <summary> /// Actually create this GraphicsResource resources. /// </summary> /// <param name="ctx"> /// A <see cref="GraphicsContext"/> used for allocating resources. /// </param> /// <remarks> /// All resources linked with <see cref="LinkResource(IGraphicsResource)"/> will be automatically created. /// </remarks> protected override void CreateObject(GraphicsContext ctx) { // Bounding volume program LinkResource(_BoundingVolumeProgram = ctx.CreateProgram("OpenGL.Standard")); // Bounding volume arrays LinkResource(_BoundingBoxArray = CreateBBoxVertexArray()); // Base implementation base.CreateObject(ctx); // Collect geometries to be batched using (SceneGraphContext ctxScene = new SceneGraphContext(this)) { TraverseDirect(ctx, ctxScene, _TraverseCreateContext, null); } }
private static bool GraphDrawPostDelegate(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject, object data) { ObjectBatchContext objectBatchContext = (ObjectBatchContext)data; // Restore previous state ctxScene.GraphicsStateStack.Pop(); // Perform lighting if ((ctxScene.Scene.SceneFlags & SceneGraphFlags.Lighting) != 0) { ctxScene.Scene._LightManager.PostObject(ctx, ctxScene, sceneObject); } return(true); }
/// <summary> /// Traverse delegate for collecting geometries to be drawn. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for drawing. /// </param> /// <param name="ctxScene"></param> /// <param name="sceneObject"></param> /// <param name="data"></param> /// <returns></returns> private static bool GraphDrawDelegate(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject, object data) { ObjectBatchContext objectBatchContext = (ObjectBatchContext)data; if (sceneObject.ObjectType == SceneObjectGeometry.ClassObjectType) { SceneObjectGeometry sceneGeometry = (SceneObjectGeometry)sceneObject; GraphicsStateSet sceneGeometryState = ctxScene.GraphicsStateStack.Current; TransformStateBase sceneGeometryModel = (TransformStateBase)sceneGeometryState[TransformStateBase.StateSetIndex]; IEnumerable <SceneObjectBatch> geometries; if ((ctxScene.Scene.SceneFlags & SceneGraphFlags.CullingViewFrustum) != 0) { // View-frustum culling geometries = sceneGeometry.GetGeometries(sceneGeometryState, objectBatchContext.ViewFrustumPlanes, sceneGeometryModel.ModelView); } else { // All geometries geometries = sceneGeometry.GetGeometries(sceneGeometryState); } objectBatchContext.Objects.AddRange(geometries); // Bounding volumes if ((ctxScene.Scene.SceneFlags & SceneGraphFlags.BoundingVolumes) != 0) { } } else if (sceneObject.ObjectType == SceneObjectLightZone.ClassObjectType) { SceneObjectLightZone sceneObjectLightZone = (SceneObjectLightZone)sceneObject; // TODO: Push instead of Clear to support stacked zones objectBatchContext.Lights.Clear(); objectBatchContext.LightZone = sceneObjectLightZone; } else if (sceneObject.ObjectType == SceneObjectLight.ClassObjectType) { objectBatchContext.Lights.Add((SceneObjectLight)sceneObject); } return(true); }
private static bool GraphDrawPostDelegate(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject, object data) { ObjectBatchContext objectBatchContext = (ObjectBatchContext)data; if (sceneObject.ObjectType == SceneObjectLightZone.ClassObjectType) { SceneObjectLightZone sceneObjectLightZone = (SceneObjectLightZone)sceneObject; sceneObjectLightZone.ResetLights(ctxScene, objectBatchContext.Lights); // TODO: Pop instead of Clear to support stacked zones objectBatchContext.Lights.Clear(); } // Restore previous state ctxScene.GraphicsStateStack.Pop(); return(true); }
internal IEnumerable <SceneObjectBatch> GetBoundingVolumes(SceneGraphContext ctxScene) { GraphicsStateSet currentState = ctxScene.GraphicsStateStack.Current.Push(); TransformState sceneGeometryModel = (TransformState)currentState[TransformState.StateSetIndex]; Matrix4x4f viewModel = sceneGeometryModel.ModelView; if (_GeometryInstances.Count > 0) { foreach (Geometry sceneObjectBatch in _GeometryInstances) { IBoundingVolume instanceVolume = sceneObjectBatch.BoundingVolume ?? _BoundingVolume; if (instanceVolume != null && instanceVolume.IsClipped(ctxScene.ViewFrustumPlanes, viewModel)) { continue; } GraphicsStateSet volumeState = currentState.Push(); SetBoundingVolumeState(instanceVolume, volumeState); yield return(new SceneObjectBatch( _BoundingVolumeArray, volumeState, _BoundingVolumeProgram )); } } else { if (_BoundingVolume == null || _BoundingVolume.IsClipped(ctxScene.ViewFrustumPlanes, viewModel)) { yield break; } GraphicsStateSet volumeState = currentState.Push(); SetBoundingVolumeState(_BoundingVolume, volumeState); yield return(new SceneObjectBatch(_BoundingVolumeArray, volumeState, _BoundingVolumeProgram)); } }
/// <summary> /// Draw this SceneGraph. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for drawing. /// </param> /// <param name="programOverride"> /// A <see cref="ShaderProgram"/> that overrides the default one used for rendering the batch. It can be null. /// </param> public void Draw(GraphicsContext ctx, ShaderProgram programOverride) { CheckCurrentContext(ctx); // View parameters SceneRoot.LocalProjection = ProjectionMatrix; SceneRoot.LocalModel = new ModelMatrix(); SceneRoot.LocalModelView = ViewMatrix; SceneRoot.LocalModelViewProjection = new ModelMatrix((Matrix4x4)ProjectionMatrix.Multiply(ViewMatrix)); using (SceneGraphContext ctxScene = new SceneGraphContext(this)) { ObjectBatchContext objectBatchContext = new ObjectBatchContext(); // Traverse the scene graph SceneRoot.TraverseDirect(ctx, ctxScene, _TraverseDrawContext, objectBatchContext); // Generate shadow maps if ((SceneFlags & SceneGraphFlags.Lighting) != 0 && (SceneFlags & SceneGraphFlags.ShadowMaps) != 0) { _LightManager.GenerateShadowMaps(ctx, this); } // Sort geometries List <SceneObjectBatch> sceneObjects = objectBatchContext.Objects; if (((SceneFlags & SceneGraphFlags.StateSorting) != 0) && (_SorterRoot != null)) { sceneObjects = _SorterRoot.Sort(objectBatchContext.Objects); } // Draw all batches KhronosApi.LogComment("*** Draw Graph"); foreach (SceneObjectBatch objectBatch in sceneObjects) { objectBatch.Draw(ctx, programOverride); } // Debug: shadow maps if ((SceneFlags & SceneGraphFlags.Lighting) != 0 && (SceneFlags & SceneGraphFlags.ShadowMaps) != 0) { DisplayShadowMaps(ctx); } } }
/// <summary> /// Traverse delegate for collecting geometries to be drawn. /// </summary> /// <param name="ctx"> /// The <see cref="GraphicsContext"/> used for drawing. /// </param> /// <param name="ctxScene"></param> /// <param name="sceneObject"></param> /// <param name="data"></param> /// <returns></returns> private static bool GraphDrawDelegate(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObject sceneObject, object data) { ObjectBatchContext objectBatchContext = (ObjectBatchContext)data; // Collect available geometries IEnumerable <SceneObjectBatch> geometries = sceneObject.GetGeometries(ctx, ctxScene); if (geometries != null) { objectBatchContext.Objects.AddRange(geometries); } // Perform lighting if ((ctxScene.Scene.SceneFlags & SceneGraphFlags.Lighting) != 0) { ctxScene.Scene._LightManager.ManageObject(ctx, ctxScene, sceneObject); } return(true); }
private void ManageObject(GraphicsContext ctx, SceneGraphContext ctxScene, SceneObjectLight sceneObject) { if (sceneObject == null) { throw new ArgumentNullException("sceneObject"); } State.LightsState.Light lightObject = sceneObject.ToLight(ctx, ctxScene); CurrentZone.Lights.Add(lightObject); if (sceneObject.HasShadowMap) { lightObject.ShadowMapIndex = ShadowLights.Count; if (ShadowLights.Contains(sceneObject) == false) { ShadowLights.Add(sceneObject); } } }