GraphicsProxy RenderState
I've gotten a few questions lately about how to do some alpha effects using models, specifically MeshGraphicsObject. After you create the GraphicsObject, it has a RenderState object available on it. The fields on this object will be familiar to those experienced with DirectX, but here's a rundown of a few especially useful ones:
Allow your model to cast shadows on the ground.
newMesh.RenderState.Lighting.CastShadows = true;
Allow your model to have directional shading (you can adjust the direction of the light using Host.WorldEngine.Environment.SunPosition).
newMesh.RenderState.Lighting.DirectionalLightEnabled = true;
Allow your model to use transparency, whether from vertex colors, textures, or TextureFactor (see below).
newMesh.RenderState.Alpha.Enabled = true;
newMesh.RenderState.Alpha.SourceBlend = Blend.SourceAlpha;
newMesh.RenderState.Alpha.DestinationBlend = Blend.InvSourceAlpha;
Allow use of TextureFactor to control the overall color of the model. For example, you can create a model that has a texture with a white patch, and then create two models, one red and one blue, both using the same texture but differing on the value of TextureFactor.
newMesh.RenderState.Stages[0].Blending.ColorArgument1 = TextureArgument.TextureColor;
newMesh.RenderState.Stages[0].Blending.ColorArgument2 = TextureArgument.TFactor;
newMesh.RenderState.Stages[0].Blending.ColorOperation = TextureOperation.Modulate;
Allow use of TextureFactor to control the overall opacity of the model. This is great for fading effects, as changing the TextureFactor per-frame is cheap.
newMesh.RenderState.Stages[0].Blending.AlphaArgument1 = TextureArgument.TextureColor;
newMesh.RenderState.Stages[0].Blending.AlphaArgument2 = TextureArgument.TFactor;
newMesh.RenderState.Stages[0].Blending.AlphaOperation = TextureOperation.Modulate;
Change the filtering used for textures. For example, in the XFile sample, if you zoom in close to the model the texture gets blocky. Dropping this code in improves the situation.
newMesh.RenderState.Stages[0].Sampler.MagnificationFilter = TextureFilter.Linear;
newMesh.RenderState.Stages[0].Sampler.MinificationFilter = TextureFilter.Linear;
The TextureFactor value mentioned above. This value would make the model ghostly transparent and red-tinged. This (and other values in RenderState) can be cheaply changed every frame.
newMesh.RenderState.TextureFactor.Value = Color.FromArgb(128, Color.Red);
One additional note: to use alpha, you must also call AddAlphaRenderable in your actor's Render function instead of just AddRenderable. The distance is a sorting function that lets the renderer know what order to draw the alpha in (affects blending). A constant value works in some situations, but if you find things look wrong, especially when one of your models occludes another, try using a value based on the distance between the model and the camera.
Here's a few shots to demonstrate the effects of these switches:
Everyone's favorite XFile sample model.
The same model, with shadows and directional lighting (the sun is above and a bit behind, if you move it the shading and shadows move appropriately).
The same again, with an alternate texture that contains transparency and the various alpha switches on. Note one detail: the shadow casting code does not account for transparency.
Same again, with all switches described above turned on. The texture filtering is improved (look for blockiness in the center of the body in the previous shot), the color is shifted red, and the whole model is somewhat transparent, even parts where the texture is opaque.
Comments
Anonymous
November 05, 2009
Dear NikolaiF, This is great! I have few questions. How can I create a GraphicsObject? Is it possible to create 3D ellipse as a GraphicsObject and display it between two points A & B on the map with specific altitudes? Is it possible to dynamically update the ellipse when A and/or B change? Thanks in advance for your help. Regards, Patrick M.Anonymous
November 09, 2009
Pmambo, I think you want the sample (BezierSurface) mentioned here: http://blogs.msdn.com/virtualearth3d/archive/2008/11/11/animation-redux.aspx There's no built-in ellipse object, but it should be easy to create one using a MeshGraphicsObject. It can be dynamically updated.