Hi,
I've implemented a quite basic shader that I'm loading as demonstrated in the Custom Effect sample.
The goal is to render a simple Quad with two textures that are unlitted.
I've developped the shader with Nick gravelyn's Shader Toy which uses a simple XNA Game viewport to render the effect and it worked perfectly. Here is the shader:
float4x4 world : WORLD;float4x4 view : VIEW;float4x4 proj : PROJECTION;texture2D CoreTexture;sampler CoreSampler = sampler_state{ Texture = < CoreTexture >;};texture2D StripeTexture;sampler StripeSampler = sampler_state{ Texture = < StripeTexture >;};struct VertexInput{ float4 Position : POSITION; float2 TexCoord : TEXCOORD0;};struct VertexOutput{ float4 Position : POSITION; float2 TexCoord : TEXCOORD0;};struct PixelInput{ float2 TexCoord : TEXCOORD0;};VertexOutput VertexMain(VertexInput input){ VertexOutput output = (VertexOutput)0; float4x4 wvp = mul(mul(world, view), proj); output.Position = mul(input.Position, wvp); output.TexCoord = input.TexCoord; return output; }float4 PixelMain(PixelInput input) : COLOR{ float4 texColor = tex2D(CoreSampler, input.TexCoord); texColor += tex2D(StripeSampler, input.TexCoord); return texColor;}technique DefaultTechnique{ pass P0 { AlphaBlendEnable = True; SrcBlend = SrcAlpha; DestBlend = One; VertexShader = compile vs_2_0 VertexMain(); PixelShader = compile ps_2_0 PixelMain(); }}
But when I use SunBurn, it seems that the Pass instructions aren't set as the textures are applied to the Quad as expected but do not get any alpha.
Any idea what I'm missing or doing wrong?
Here is the Material file I used:
EffectFile: "StarShader.fx"CoreTexture: "..\Textures\Flares\Core.dds"StripeTexture: "..\Textures\Flares\Stripe.dds"Technique: "DefaultTechnique"
Thanks
Philippe
Hi Philippe,
It looks like that should work, the built-in renderer doesn't change the render states after calling Begin on the effect pass.
What are the contents of the sampled textures? The samples are added together (including the alpha), if either contains 1 in the alpha channel the texture will be fully opaque.
Also please note the built-in renderer does not alpha sort rendered objects. Since the object you're rendering is unlit it's probably best to render it separately after calling RenderManager.Render(). This gives you full control over where and when it's render in relationship to the rest of the scene.
Let me know if this helps!
Follow me on Twitter – development and personal tweetsAwesome XNA Videos – Lighting, Rendering, and game videos
The two textures have RGB with a black zone and an Alpha layer (DDS format). So, this should work souldn't it?
I would have liked to avoid rendering outside of the ObjectManager. That's actually what I'm trying to achieve. :)
Now I have some really strange behavior I can't understand.
I managed to add a mesh behind my Quad and here is the result I get:
As you'll notice in the picture, the Debug Bounding box doesn't render behind my quad.
Moreover, some of the meshes of the Ship do not render either when behind the quad. Here is another view as you may not see the difference in a single picture.
Now, just by curiousity, I changed the order of SceneInterface.Submit calls for my 2 sceneobjects.
In the previous pictures, the Star was submitted before the ship.
In the following picture, the Ship is submitted before the star:
See the difference? :)
And here is another point, when I set the DestBlend = One; If the Quad isn't rendered, I get the normal ship:
Otherwise, the meshes that aren't rendered in the AlphaBlend issues above are also getting alpha blend while they aren't supposed to
Ok, just read carefully your previous post John: Alpha Blended objects aren't sorted. Noted. Argghhhh! Would that be part of the 1.4? ;)
Is that a ship model from EVE online? Looks pretty cool :)
Contributor on the SunBurn sgMotion Animation Library open source project.
Yes, it is. I'm using them as they have all the required features I'm looking to implement in my game which of course will contain my own models :p
I'm focusing on code right now and I'll work on assets later ;)
John,
I've looked at the Custom Renderer sample and it seems to be a good direction to look at. However, I'm not 100% sure, I'll get all the great features you provide in the built-in renderers, am I correct?
Otherwise, what should be the sorting operation to do in order to get alpha blending properly working? Thanks.
The custom renderer kit is a great example, which should provide all of the features from the built-in renderer.
To properly blend transparencies they need to be sorted back-to-front, meaning objects furthest from the camera are rendered first. However there are also asset concerns, for instance to easily render transparent meshes they need to be convex, otherwise parts of the mesh will overlap on screen and potentially render in the wrong order.
Also transparent objects should not be able to pass through one another, or else the rendering order cannot be maintained.
All in all it's tricky, and puts a lot of restrictions on the assets. :/ Which is one of the reasons we haven't found a solution we're comfortable with yet.
I'll try to implement such behavior and let you know if it helped ;)
So, it seems that you didn't make it for 1.4 release?
If it's for something as simple as a particle effect, I would render it entirely out of SunBurn. That's what we had to do in Avatar Land - draw all of the alpha'd objects outside of the main sunburn render loop and composite them in on top of it. It gets much trickier if the objects also need to be depth sorted, but in our case it worked well.
There are several threads here detailing our experiences with getting various types of alpha blending working... Unfortunately that's SunBurn's one weak spot. :(
Just a simple question on the custom renderer implementation to sort meshes from back to front. I've been thinking that it could be done at the ObjectManager level, on its Find methods? Therefore the Renderer would be independent and I could potentially just inherit from ObjectManager and override the Find methods.
What is your call on that?
Ok, I've just implemented my own inherited ObjectManager and overrided Find methods: it works solely with a Custom Renderer.
It doesn't work with Forward renderer (didn't test with Deferred but I guess it works the same) probably because once the ObjectManager.Find() method is called, the BeginFrameRendering must operate the sort there.
Unless ObjectManager Finds methods are used for something else that requires a specific ordering, John, maybe it could be great to provide a protected virtual SortRenderableMeshes method that could be overriden so we can implement our own logic there?
To help others, I'm sharing my code here:
public class ObjectManager : SynapseGaming.LightingSystem.Rendering.ObjectManager { private class SceneObjectComparer : IComparer<ISceneObject> {
// You need to provide the camera position for testing purposes. Mine is on a Camera class but you could easily just pass the SceneState instance and use the ViewToWorld.Translation Matrix's vector3. private readonly Camera camera; public SceneObjectComparer(Camera camera) { this.camera = camera; } #region IComparer<ISceneObject> Members public int Compare(ISceneObject x, ISceneObject y) { float distanceToX = Vector3.Distance(camera.Position, x.World.Translation); float distanceToY = Vector3.Distance(camera.Position, y.World.Translation); if (distanceToX < distanceToY) return 1; else if (distanceToX > distanceToY) return -1; else return 0; } #endregion } private class RenderableMeshComparer : IComparer<RenderableMesh> { private readonly Camera camera; public RenderableMeshComparer(Camera camera) { this.camera = camera; } #region IComparer<ISceneObject> Members public int Compare(RenderableMesh x, RenderableMesh y) { float distanceToX = Vector3.Distance(camera.Position, x.World.Translation); float distanceToY = Vector3.Distance(camera.Position, y.World.Translation); if (distanceToX < distanceToY) return 1; else if (distanceToX > distanceToY) return -1; else return 0; } #endregion } public ObjectManager(IGraphicsDeviceService graphicsDeviceService) : base(graphicsDeviceService) { } public override void Find(List<SynapseGaming.LightingSystem.Rendering.ISceneObject> foundobjects, Microsoft.Xna.Framework.BoundingBox worldbounds, SynapseGaming.LightingSystem.Core.ObjectFilter objectfilter) { base.Find(foundobjects, worldbounds, objectfilter); foundobjects.Sort(new SceneObjectComparer(Application.Instance.ActiveGameState.Cameras.ActiveCamera)); } public override void Find(List<ISceneObject> foundobjects, BoundingFrustum worldbounds, SynapseGaming.LightingSystem.Core.ObjectFilter objectfilter) { base.Find(foundobjects, worldbounds, objectfilter); foundobjects.Sort(new SceneObjectComparer(Application.Instance.ActiveGameState.Cameras.ActiveCamera)); } public override void Find(List<ISceneObject> foundobjects, SynapseGaming.LightingSystem.Core.ObjectFilter objectfilter) { base.Find(foundobjects, objectfilter); foundobjects.Sort(new SceneObjectComparer(Application.Instance.ActiveGameState.Cameras.ActiveCamera)); } public override void Find(List<RenderableMesh> foundmeshes, BoundingBox worldbounds, SynapseGaming.LightingSystem.Core.ObjectFilter objectfilter) { base.Find(foundmeshes, worldbounds, objectfilter); foundmeshes.Sort(new RenderableMeshComparer(Application.Instance.ActiveGameState.Cameras.ActiveCamera)); } public override void Find(List<RenderableMesh> foundmeshes, BoundingFrustum worldbounds, SynapseGaming.LightingSystem.Core.ObjectFilter objectfilter) { base.Find(foundmeshes, worldbounds, objectfilter); foundmeshes.Sort(new RenderableMeshComparer(Application.Instance.ActiveGameState.Cameras.ActiveCamera)); } public override void Find(List<RenderableMesh> foundmeshes, SynapseGaming.LightingSystem.Core.ObjectFilter objectfilter) { base.Find(foundmeshes, objectfilter); foundmeshes.Sort(new RenderableMeshComparer(Application.Instance.ActiveGameState.Cameras.ActiveCamera)); } }
Remember you must use the Custom Renderer class ;)
Oups, it seems that with such sorting, I don't get my Emissive Map rendered correctly :(
That's a very cool solution, I wouldn't have thought to try sorting on the scenegraph level.
Unfortunately the renderer's batch sorting will interfere with the scenegraph's sorting, so while objects within the same material batch are correctly sorted, between batches they will not be.
A similar problem exists with a protected sort method, you would be able to sort within the batch or before the batches are created (which is similar to the above scenegraph sorting), but sorting across batches would not be possible (at least without some fairly complex code).
Here's how we implemented the current R&D transparencies, which are compatible with forward and deferred rendering, a large number of lights, and custom renderers:
The objects are rendered outside of the render managers in a separate transparency manager (which can also be customized and / or replaced with your own implementation). The rendering occurs during EndFrameRendering().
The objects do not receive direct multi-pass lighting and are not rendered via the deferred buffers, instead they use SunBurn's composite lighting (currently used for avatars).
This works very well even though composite lighting does not take into account shadows, except when the scene contains a directional light and the transparent object is indoors / out of the directional light's reach (as it still receives full directional lighting).
However this works very well for 90% of scenes and is very easy to implement, so if you're interested in a quick solution this is definitely what I would suggest. And more importantly composite lighting allows you to specify a custom light list, so you can use information about the scene to remove the directional light from that list effectively shadowing the object.
Going forward we're using composite lighting more and more, so we've solved the shadowing problem with directional lights (at least for static lights - more on that another day :). So in theory this could be extended to dynamic lights and used for transparencies, but we'll need to take another pass at the R&D branch to determine if that will work as expected.