public void Draw(DrawState state) { //switch rendering mode based on the TutorialRenderMode flag switch (state.GetDrawFlag <TutorialRenderMode>()) { case TutorialRenderMode.DepthOutput: //bind the depth output shader state.GetShader <Xen.Ex.Shaders.NonLinearDepthOutRg>().Bind(state); break; case TutorialRenderMode.DrawShadow: //bind the shadow rendering shader Shader.ShadowShader shader = state.GetShader <Shader.ShadowShader>(); shader.TextureMap = material.TextureMap; shader.TextureSampler = material.TextureMapSampler; shader.Bind(state); break; default: //no flag known specified material.Bind(state); break; } //draw the ground vertices.Draw(state, null, PrimitiveType.TriangleFan); }
/// <summary> /// Draw the model. This class automatically assigns shaders when drawing /// </summary> /// <param name="state"></param> public void Draw(DrawState state) { if (modelData == null) { throw new InvalidOperationException("ModelData is null"); } if (controller != null) { controller.WaitForAsyncAnimation(state, state.FrameIndex, true); if (controller.IsDisposed) { controller = null; } } if (controller != null && hierarchy == null) { hierarchy = new MaterialAnimationTransformHierarchy(modelData.skeleton); } if (hierarchy != null) { hierarchy.UpdateTransformHierarchy(controller.transformedBones); } ModelInstanceShaderProvider shaderProvider = this.shaderProvider; MaterialLightCollection lights = this.lights; ShaderProviderFlag providerFlag; MaterialLightCollection.LightCollectionFlag lightsFlag; state.GetDrawFlag(out providerFlag); if (providerFlag.OverrideShaderProvider) { shaderProvider = providerFlag.ShaderProvider; } state.GetDrawFlag(out lightsFlag); if (lightsFlag.OverrideLightCollection) { lights = lightsFlag.LightCollection; } if (shaderProvider != null) { if (controller != null) { shaderProvider.BeginDraw(state, controller.transformedBones, hierarchy.GetMatrixData()); } else { shaderProvider.BeginDraw(state); } } Vector3 boundsMin, boundsMax; ContainmentType cullModel = ContainmentType.Contains; //if there is just one geometry object, then the ICullable.CullTest() call will have been suficient. bool skipCullTest = this.modelData != null && this.modelData.meshes.Length == 1 && this.modelData.meshes[0].geometry.Length == 1; if (!skipCullTest) { if (controller != null) { cullModel = state.Culler.IntersectBox(ref controller.boundsMin, ref controller.boundsMax); } else { cullModel = state.Culler.IntersectBox(ref modelData.staticBounds.minimum, ref modelData.staticBounds.maximum); } } if (cullModel != ContainmentType.Disjoint) { for (int m = 0; m < modelData.meshes.Length; m++) { MeshData mesh = modelData.meshes[m]; if (shaderProvider != null) { shaderProvider.BeginMesh(state, mesh); } ContainmentType cullMesh = cullModel; if (cullModel == ContainmentType.Intersects && modelData.meshes.Length > 1) { if (controller != null) { controller.ComputeMeshBounds(m, out boundsMin, out boundsMax); cullMesh = state.Culler.IntersectBox(ref boundsMin, ref boundsMax); } else { cullMesh = state.Culler.IntersectBox(ref mesh.staticBounds.minimum, ref mesh.staticBounds.maximum); } } if (cullMesh != ContainmentType.Disjoint) { for (int g = 0; g < mesh.geometry.Length; g++) { GeometryData geom = mesh.geometry[g]; MaterialShader shader = geom.MaterialShader; if (shaderProvider != null && shaderProvider.BeginGeometryShaderOverride(state, geom, lights)) { shader = null; } bool cullTest = true; if (cullMesh == ContainmentType.Intersects && mesh.geometry.Length > 1) { if (controller != null) { controller.ComputeGeometryBounds(m, g, out boundsMin, out boundsMax); cullTest = state.Culler.TestBox(ref boundsMin, ref boundsMax); } else { cullTest = state.Culler.TestBox(ref geom.staticBounds.minimum, ref geom.staticBounds.maximum); } } if (cullTest) { if (shader != null) { shader.AnimationTransforms = hierarchy; shader.Lights = lights; shader.Bind(state); } geom.Vertices.Draw(state, geom.Indices, PrimitiveType.TriangleList); } if (shaderProvider != null) { shaderProvider.EndGeometry(state, geom); } } } if (shaderProvider != null) { shaderProvider.EndMesh(state, mesh); } } } if (shaderProvider != null) { shaderProvider.EndDraw(state); } }
//this is called just before geometry is drawn, //return true to indicate the shader has been set public override bool BeginGeometryShaderOverride(DrawState state, GeometryData geometry, Xen.Ex.Material.MaterialLightCollection lights) { //query the draw flag, switch (state.GetDrawFlag <TutorialRenderMode>()) { case TutorialRenderMode.DrawShadow: { //bind the shadow rendering shader... if (animationBoneData == null) { Shader.ShadowShader shader = state.GetShader <Shader.ShadowShader>(); shader.TextureMap = geometry.MaterialShader.TextureMap; shader.TextureSampler = geometry.MaterialShader.TextureMapSampler; shader.Bind(state); } else { //bind the animating shader, Shader.ShadowShaderBlend shader = state.GetShader <Shader.ShadowShaderBlend>(); //set the blend matrix data if (animationBoneDataDirty) { //use the 'animationBoneDataDirty' bool so animation data is only copied once. //this could happen if a single model has many pieces of geometry. shader.SetBlendMatrices(animationBoneData); animationBoneDataDirty = false; } shader.TextureMap = geometry.MaterialShader.TextureMap; shader.TextureSampler = geometry.MaterialShader.TextureMapSampler; shader.Bind(state); } return(true); //shader was assigned } case TutorialRenderMode.DepthOutput: { //determine if alpha test is being used (in this tutorial it won't be - but do it anyway...) bool alphaTest = state.RenderState.AlphaTest.Enabled; if (alphaTest) { //alpha test is only needed if a texture is set alphaTest &= geometry.MaterialShader.TextureMap != null; } if (alphaTest) { //bind a depth output shader that samples a texture for alpha (for alpha test compatibility) if (this.animationBoneData != null) { //the model is animated //get the shader Xen.Ex.Shaders.NonLinearDepthOutRgTextureAlphaBlend shader = state.GetShader <Xen.Ex.Shaders.NonLinearDepthOutRgTextureAlphaBlend>(); //set animation data (it's possible this is called redundantly, so logic here could be improved) if (animationBoneDataDirty) { shader.SetBlendMatrices(this.animationBoneData); animationBoneDataDirty = false; } //set the texture shader.AlphaTexture = geometry.MaterialShader.TextureMap; shader.AlphaTextureSampler = geometry.MaterialShader.TextureMapSampler; //bind shader.Bind(state); } else { //get the shader Xen.Ex.Shaders.NonLinearDepthOutRgTextureAlpha shader = state.GetShader <Xen.Ex.Shaders.NonLinearDepthOutRgTextureAlpha>(); //set the texture shader.AlphaTexture = geometry.MaterialShader.TextureMap; shader.AlphaTextureSampler = geometry.MaterialShader.TextureMapSampler; shader.Bind(state); // bind the basic depth out shader } } else { //bind a simple depth output shader if (this.animationBoneData != null) { //the model is animated Xen.Ex.Shaders.NonLinearDepthOutRgBlend shader = state.GetShader <Xen.Ex.Shaders.NonLinearDepthOutRgBlend>(); //set animation data (it's possible this is called redundantly, so logic here could be improved) if (animationBoneDataDirty) { shader.SetBlendMatrices(this.animationBoneData); animationBoneDataDirty = false; } //bind shader.Bind(state); } else { state.GetShader <Xen.Ex.Shaders.NonLinearDepthOutRg>().Bind(state); // bind the basic depth out shader } } return(true); //shader was assigned } } //false, because no shader has been bound (will use the model material shader) return(false); }
/// <summary> /// Draw all the model batch instances /// </summary> /// <param name="state"></param> public void Draw(DrawState state) { if (modelData == null) { throw new InvalidOperationException("ModelData is null"); } if (geometry == null) { SetupGeometry(); } int geometryIndex = 0; BatchModelShaderProvider shaderProvider = this.shaderProvider; MaterialLightCollection lights = this.lights; ShaderProviderFlag providerFlag; MaterialLightCollection.LightCollectionFlag lightsFlag; state.GetDrawFlag(out providerFlag); if (providerFlag.OverrideShaderProvider) { shaderProvider = providerFlag.ShaderProvider; } state.GetDrawFlag(out lightsFlag); if (lightsFlag.OverrideLightCollection) { lights = lightsFlag.LightCollection; } if (shaderProvider != null) { shaderProvider.BeginDraw(state); } //loop through the model data for (int m = 0; m < modelData.meshes.Length; m++) { MeshData mesh = modelData.meshes[m]; if (shaderProvider != null) { shaderProvider.BeginMesh(state, mesh); } for (int g = 0; g < mesh.geometry.Length; g++) { GeometryData geom = mesh.geometry[g]; GeometrySet set = this.geometry[geometryIndex]; if (set.count > 0) { bool instancing = state.SupportsHardwareInstancing && set.count > 2; if (shaderProvider == null || !shaderProvider.BeginGeometryShaderOverride(state, geom, lights, instancing)) { MaterialShader shader = geom.MaterialShader; shader.AnimationTransforms = null; shader.UseHardwareInstancing = instancing; shader.Lights = lights; shader.Bind(state); } //draw the geometry if (instancing) { state.DrawBatch(geom.Vertices, geom.Indices, PrimitiveType.TriangleList, null, set.instances, set.count); } else { for (int i = 0; i < set.count; i++) { state.PushWorldMatrixMultiply(ref set.instances[i]); geom.Vertices.Draw(state, geom.Indices, PrimitiveType.TriangleList); state.PopWorldMatrix(); } } if (shaderProvider != null) { shaderProvider.EndGeometry(state, geom); } } set.count = 0; geometryIndex++; } if (shaderProvider != null) { shaderProvider.EndMesh(state, mesh); } } if (shaderProvider != null) { shaderProvider.EndDraw(state); } drawCount = 0; }