public Drawer(Vector2 direction, ShaderElement drawable, DrawTargetTexture2D source) { drawable.SetTextureSize(source.Width, source.Height); this.drawable = drawable; this.source = source; this.direction = direction; }
/// <summary></summary> public void Dispose() { DisposeMember(ref positionSizeBufferA); DisposeMember(ref velocityRotationBufferA); DisposeMember(ref userBufferA); DisposeMember(ref colourBufferA); DisposeMember(ref positionSizeBufferB); DisposeMember(ref velocityRotationBufferB); DisposeMember(ref userBufferB); DisposeMember(ref colourBufferB); DisposeMember(ref lifeStoreBufferA); DisposeMember(ref lifeStoreBufferB); DisposeMember(ref mrtGroupA); DisposeMember(ref mrtGroupB); lifeStepParticleData = null; allProcessors = null; activeRenderPass = null; verticesRenderIndex = null; scissorTest = null; backgroundFillPass = null; randomTexture = null; shaderRandomValues = null; }
//construct the displayer. //Because this class needs to load content, a ContentRegister is a required //constructor parameter. This makes sure it will always load content public ImageDisplayer(ContentRegister contentRegister) { if (contentRegister == null) { throw new ArgumentNullException(); } //create the element that will display the texture Vector2 sizeInPixels = new Vector2(768, 384); //create an instance of the shader //The texture will be assigned to the shader in LoadContent this.shader = new Shader.Tutorial09Technique(); //create the element which will display the shader this.element = new ShaderElement(shader, sizeInPixels); //place the element in the centre of the screen this.element.HorizontalAlignment = HorizontalAlignment.Centre; this.element.VerticalAlignment = VerticalAlignment.Centre; //add this object to the content register //items added to a content register do not need to be removed, as they //are tracked by a weak reference. //LoadContent() will be called whenever the device is created/reset. contentRegister.Add(this); //At this point, since the device has been created, LoadContent() will have //been called already. If the device hadn't been created yet, then //LoadContent() would be called at a later time. //LoadContent() will always be called before the first time Draw() is called. }
internal SinglePassTextureFilter(DrawTargetTexture2D source, DrawTargetTexture2D target) { if (source == null || target == null) { throw new ArgumentNullException(); } if (source.SurfaceFormat != target.SurfaceFormat) { throw new ArgumentException("source.SurfaceFormat != target.SurfaceFormat"); } #if XBOX360 if (source == target && source.Width * source.Height * DrawTarget.FormatSize(source.SurfaceFormat) > 1000 * 1000 * 10) //approx 10mb { throw new ArgumentException("source == target is invalid for larget render targets on Xbox360"); } #else if (source == target) { throw new ArgumentException("source == target is invalid on windows"); } #endif if (source.Width > target.Width || source.Height > target.Height) { throw new ArgumentException("source is larger than target"); } this.source = source; this.targetClone = target.Clone(false, false, false); this.targetClone.ClearBuffer.Enabled = false; this.element = new ShaderElement(null, source.Width, source.Height, new Vector2(1, 1), true); this.targetClone.Add(element); if (target.Width != source.Width || target.Height != source.Height) { this.targetClone.AddModifier(new Xen.Graphics.Modifier.ScissorModifier(0, 0, Math.Min(1, (source.Width) / target.Width), Math.Min(1, (source.Height) / target.Height))); this.element.TextureCrop = new Rectangle(0, 0, Math.Min(this.source.Width, this.targetClone.Width), Math.Min(this.source.Height, this.targetClone.Height)); } }
/// <summary> /// Construct the texture downsampler /// </summary> /// <param name="source">Source texture to read</param> /// <param name="target">Target texture to write to</param> /// <param name="intermediate">Intermediate texture (if null, will be created as required)</param> /// <param name="intermediate2">Second intermediate texture (if null, will be created as required)</param> /// <param name="targetWidth">target width to downsample to</param> /// <param name="targetHeight">target height to downsample to</param> public TextureDownsample(DrawTargetTexture2D source, DrawTargetTexture2D target, ref DrawTargetTexture2D intermediate, ref DrawTargetTexture2D intermediate2, int targetWidth, int targetHeight) { if (source == null || target == null) { throw new ArgumentNullException(); } if (targetWidth <= 0 || targetHeight <= 0) { throw new ArgumentException("Invalid target size"); } if (DrawTarget.FormatChannels(source.SurfaceFormat) != DrawTarget.FormatChannels(target.SurfaceFormat)) { throw new ArgumentException("source.SurfaceFormat has a different number of channels than target.SurfaceFormat"); } if (targetWidth > target.Width || targetHeight > target.Height) { throw new ArgumentException("Size is larger than target"); } if (targetWidth > source.Width || targetHeight > source.Height) { throw new ArgumentException("Size is larger than source"); } if (intermediate != null) { if (target.SurfaceFormat != intermediate.SurfaceFormat) { throw new ArgumentException("target.SurfaceFormat != intermediate.SurfaceFormat"); } if (intermediate == intermediate2) { throw new ArgumentException("intermediate == intermediate2"); } } if (intermediate2 != null) { if (target.SurfaceFormat != intermediate2.SurfaceFormat) { throw new ArgumentException("target.SurfaceFormat != intermediate2.SurfaceFormat"); } } int w = source.Width; int h = source.Height; int targetMultipleWidth = targetWidth; int targetMultipleHeight = targetHeight; while (targetMultipleWidth * 2 <= w) { targetMultipleWidth *= 2; } while (targetMultipleHeight * 2 <= h) { targetMultipleHeight *= 2; } DrawTargetTexture2D current = null; Rectangle sRegion = new Rectangle(0, 0, 0, 0); //first pass may require that the source is sized down to a multiple of the target size if ((double)targetWidth / (double)w <= 0.5 && (double)targetHeight / (double)h <= 0.5 && (targetMultipleWidth != w || targetMultipleHeight != h)) { DrawTargetTexture2D go = this.PickRT(ref intermediate, ref intermediate2, source, targetMultipleWidth, targetMultipleHeight, target.SurfaceFormat); Vector2 size = new Vector2((float)targetMultipleWidth, (float)targetMultipleHeight); TexturedElement te = new TexturedElement(source, size, false); te.TextureCrop = new Rectangle(0, 0, w, h); go.Add(te); passes.Add(go); current = go; w = targetMultipleWidth; h = targetMultipleHeight; } //downsample on the larger axis, either 2x, 4x or 8x downsampling, until reached the target size while (target.Equals(current) == false) { DrawTargetTexture2D localSource = current ?? source; double difW = (double)targetWidth / (double)w; double difH = (double)targetHeight / (double)h; sRegion.Width = w; sRegion.Height = h; sRegion.Y = localSource.Height - h; //both width/height difference are less than 50% smaller, so a linear interpolation will do fine if (difW > 0.5 && difH > 0.5) { //write directly to the target DrawTargetTexture2D go = target.Clone(false, false, false); Vector2 te_size = new Vector2((float)targetWidth, (float)targetHeight); TexturedElement te = new TexturedElement(localSource, te_size, false); go.AddModifier(new ScissorModifier(0, go.Height - targetHeight, targetWidth, go.Height, go)); te.TextureCrop = sRegion; go.Add(te); passes.Add(go); current = go; continue; } bool horizontal = difW < difH; double dif = Math.Min(difW, difH); int size = horizontal ? w : h; Vector2 dir = new Vector2(0, 0); if (horizontal) { dir.X = 1.0f / localSource.Width; } else { dir.Y = 1.0f / localSource.Height; } if (dif > 0.25) // cutoff for using 2 samples { DrawTargetTexture2D go; int new_width = w; int new_height = h; if (horizontal) { new_width /= 2; } else { new_height /= 2; } if (new_width == targetWidth && new_height == targetHeight) { go = target.Clone(false, false, false); } else { go = PickRT(ref intermediate, ref intermediate2, localSource, new_width, new_height, target.SurfaceFormat); } Vector2 se_size = new Vector2((float)new_width, (float)new_height); ShaderElement se = new ShaderElement(new Downsample2(), se_size, false); go.AddModifier(new ScissorModifier(0, go.Height - new_height, new_width, go.Height, go)); se.TextureCrop = sRegion; go.Add(new Drawer(dir, se, localSource)); passes.Add(go); w = new_width; h = new_height; current = go; continue; } if (dif > 0.125) // cutoff for using 4 samples { DrawTargetTexture2D go; int new_width = w; int new_height = h; if (horizontal) { new_width /= 4; } else { new_height /= 4; } if (new_width == targetWidth && new_height == targetHeight) { go = target.Clone(false, false, false); } else { go = PickRT(ref intermediate, ref intermediate2, localSource, new_width, new_height, target.SurfaceFormat); } Vector2 se_size = new Vector2((float)new_width, (float)new_height); ShaderElement se = new ShaderElement(new Downsample4(), se_size, false); go.AddModifier(new ScissorModifier(0, go.Height - new_height, new_width, go.Height, go)); se.TextureCrop = sRegion; go.Add(new Drawer(dir, se, localSource)); passes.Add(go); w = new_width; h = new_height; current = go; continue; } // cutoff for using 8 samples { DrawTargetTexture2D go; int new_width = w; int new_height = h; if (horizontal) { new_width /= 8; } else { new_height /= 8; } if (new_width == targetWidth && new_height == targetHeight) { go = target.Clone(false, false, false); } else { go = PickRT(ref intermediate, ref intermediate2, localSource, new_width, new_height, target.SurfaceFormat); } Vector2 se_size = new Vector2((float)new_width, (float)new_height); ShaderElement se = new ShaderElement(new Downsample8(), se_size, false); go.AddModifier(new ScissorModifier(0, go.Height - new_height, new_width, go.Height, go)); se.TextureCrop = sRegion; go.Add(new Drawer(dir, se, localSource)); passes.Add(go); w = new_width; h = new_height; current = go; continue; } } }
void IParticleProcessor.Initalise(ParticleSystemTypeData typeData, IParticleProcessor[] allProcessors, bool useColourValues, uint maxLifeTimeSteps, uint timeStepHz, uint maxExpectedCount) { this.processorData = typeData.RuntimeLogicData.GpuParticleProcessorData; //compute resolution to fit the particle count this.resolutionX = 2; this.resolutionY = 2; while (true) { int count = resolutionX * resolutionY; if (count >= maxExpectedCount) { break; } if (resolutionY >= resolutionX) { resolutionX *= 2; } else { resolutionY *= 2; } } resolutionXF = (float)resolutionX; resolutionYF = (float)resolutionY; this.particleTypeData = typeData; this.allProcessors = allProcessors; this.renderPasses = new GpuParticleRenderPass[4]; this.shaderRandomValues = new Random(); this.maxParticleTimeStep = maxLifeTimeSteps; this.systemStepDeltaTime = 1.0f / ((float)timeStepHz); bool usesUserValues = typeData.RuntimeLogicData.SystemUsesUserValues; bool usesLifeOrAge = typeData.RuntimeLogicData.SystemUsesLifeOrAgeValues; this.usesLifeStorage = usesLifeOrAge; SurfaceFormat vec4Format = SurfaceFormat.HalfVector4; if (!ParticleSystem.gpuVTexHalfVec4supported) { vec4Format = SurfaceFormat.Vector4; } this.positionSizeBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); this.velocityRotationBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); if (useColourValues) { this.colourBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); } if (usesUserValues) { this.userBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); } #if XBOX360 //technically doing this can produce bugs when the buffers combine to be greater than 10MiB //(approx ~320,000 particles) //This can happen as the textures are updated in tiles, and it's possible for a particle //to be shifted across a tile and recieve an invalid update. However the majority of the time, //this would only cause a particle to be a frame behind or ahead. Worst case is the particle //either dissapears or is duplicated. //it is considered a worthwhile tradeoff for half the render target memory usage this.positionSizeBufferB = positionSizeBufferA; this.velocityRotationBufferB = velocityRotationBufferA; this.colourBufferB = colourBufferA; this.userBufferB = userBufferA; #else this.positionSizeBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); this.velocityRotationBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); if (useColourValues) { this.colourBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); } if (usesUserValues) { this.userBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, vec4Format); } #endif //setup the render target groups (MRT) DrawTargetTexture2D[] targets = new DrawTargetTexture2D[2 + (useColourValues ? 1 : 0) + (usesUserValues ? 1 : 0)]; targets[0] = positionSizeBufferA; targets[1] = velocityRotationBufferA; if (useColourValues) { targets[2] = colourBufferA; } if (usesUserValues) { targets[targets.Length - 1] = userBufferA; } this.mrtGroupA = new DrawTargetTexture2DGroup(camera, targets); targets[0] = positionSizeBufferB; targets[1] = velocityRotationBufferB; if (useColourValues) { targets[2] = colourBufferB; } if (usesUserValues) { targets[targets.Length - 1] = userBufferB; } this.mrtGroupB = new DrawTargetTexture2DGroup(camera, targets); this.mrtGroupA.ClearBuffer.Enabled = false; this.mrtGroupB.ClearBuffer.Enabled = false; if (usesLifeOrAge) { SurfaceFormat ageFormat = SurfaceFormat.HalfVector2; if (!ParticleSystem.gpuVTexHalfVec2supported) { ageFormat = SurfaceFormat.HalfVector4; if (!ParticleSystem.gpuVTexHalfVec4supported) { ageFormat = SurfaceFormat.Vector4; } } #if XBOX360 lifeStoreBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, ageFormat); lifeStoreBufferB = lifeStoreBufferA; lifeStoreBufferA.ClearBuffer.Enabled = false; lifeStoreBufferA.Add(new TexturedElement(lifeStoreBufferA, Vector2.One, true)); #else lifeStoreBufferA = new DrawTargetTexture2D(camera, resolutionX, resolutionY, ageFormat); lifeStoreBufferB = new DrawTargetTexture2D(camera, resolutionX, resolutionY, ageFormat); lifeStoreBufferA.ClearBuffer.Enabled = false; lifeStoreBufferB.ClearBuffer.Enabled = false; //setup so that when a store buffer is drawn, it copies in the other buffer. lifeStoreBufferA.Add(new TexturedElement(lifeStoreBufferB, Vector2.One, true)); lifeStoreBufferB.Add(new TexturedElement(lifeStoreBufferA, Vector2.One, true)); #endif } this.scissorTest = new Xen.Graphics.Modifier.ScissorModifier(0, 0, 1, 1); //scissor off the MRT, as it uses a fullsize quad to run the particle logic for every particle this.mrtGroupA.AddModifier(scissorTest); this.mrtGroupB.AddModifier(scissorTest); //this is the pass that runs per-frame logic on the particles this.backgroundFillPass = new ShaderElement(this.processorData.FrameShader, new Vector2(1, 1), true); this.mrtGroupA.Add(backgroundFillPass); this.mrtGroupB.Add(backgroundFillPass); this.mrtGroupA.Add(this); this.mrtGroupB.Add(this); if (usesLifeOrAge) { this.lifeStoreBufferA.Add(this); #if !XBOX360 this.lifeStoreBufferB.Add(this); #endif } }
protected override void Initialise() { Resource.EnableResourceTracking(); //setup the view camera first //-------------------------------------- viewCamera = new Xen.Ex.Camera.FirstPersonControlledCamera3D(this.UpdateManager); viewCamera.Projection.FieldOfView *= 0.65f; viewCamera.MovementSensitivity *= 0.05f; viewCamera.LookAt(new Vector3(-3, 4, 2), new Vector3(6, 6, 2), new Vector3(0, 1, 0)); viewCamera.Projection.NearClip = 0.1f; //shadow map setup: //-------------------------------------- const float shadowArea = 4; const int shadowMapResolution = 1024; //setup the shadow map rendering camera shadowCamera = new Camera3D(); //setup the shadow map projection to roughly cover the character shadowCamera.Projection.Orthographic = true; shadowCamera.Projection.NearClip = shadowArea * 2; shadowCamera.Projection.FarClip = -shadowArea * 2; shadowCamera.Projection.Region = new Vector4(1, -1.8f, -1, 0.2f) * shadowArea; //setup the shadow map draw target //find a desirable format for the shadow map, SurfaceFormat format = SurfaceFormat.Color; //ideally use a high precision format, but only if it's supported. Avoid full 32bit float if (DrawTargetTexture2D.SupportsFormat(SurfaceFormat.Rg32)) { format = SurfaceFormat.Rg32; //ushort * 2 } else if (DrawTargetTexture2D.SupportsFormat(SurfaceFormat.HalfVector2)) { format = SurfaceFormat.HalfVector2; //fp16 * 2 } else if (DrawTargetTexture2D.SupportsFormat(SurfaceFormat.HalfVector4)) { format = SurfaceFormat.HalfVector4; //fp16 * 4 } //create the shadow map shadowMap = new DrawTargetTexture2D(shadowCamera, shadowMapResolution, shadowMapResolution, format, DepthFormat.Depth24); shadowMap.ClearBuffer.ClearColour = Color.White; //setup the shadow map drawer.. shadowDrawer = new Tutorial_25.ShadowMapDrawer(null, new Tutorial_25.ShadowOutputShaderProvider()); this.shadowMap.Add(shadowDrawer); //create the main draw targets. //-------------------------------------- drawToScreen = new DrawTargetScreen(this, new Camera2D()); drawToScreen.ClearBuffer.ClearColourEnabled = false; drawToRenderTarget = new DrawTargetTexture2D(viewCamera, this.WindowWidth, this.WindowHeight, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, false, MultiSampleType.FourSamples, RenderTargetUsage.PlatformContents); drawToRenderTarget.ClearBuffer.ClearColourEnabled = false; //setup the bloom draw targets //-------------------------------------- //scale to reduce the size of the bloom target, compared to main render target const int bloomDownsample = 8; //eight times smaller bloomRenderTarget = new DrawTargetTexture2D(new Camera2D(), Math.Max(1, drawToRenderTarget.Width / bloomDownsample), Math.Max(1, drawToRenderTarget.Height / bloomDownsample), SurfaceFormat.Color); bloomRenderTarget.ClearBuffer.ClearColourEnabled = false; bloomIntermediateRenderTarget = null; #if WINDOWS //the bloom intermediate target is not needed on the xbox, as the full bloom target fits in EDRAM bloomIntermediateRenderTarget = new DrawTargetTexture2D(viewCamera, bloomRenderTarget.Width, bloomRenderTarget.Height, SurfaceFormat.Color); bloomIntermediateRenderTarget.ClearBuffer.ClearColourEnabled = false; #endif //setup the blur filter, with a large 31 sample radius. bloomBlurPass = new Xen.Ex.Filters.BlurFilter(Xen.Ex.Filters.BlurFilterFormat.ThirtyOneSampleBlur_FilteredTextureFormat, 1.0f, bloomRenderTarget, bloomIntermediateRenderTarget); //setup the character model this.model = new ModelInstance(); //(the model is setup in LoadContent) this.modelRotation = new DrawRotated(model); this.modelRotation.RotationAngle = 3; //add the model to be drawn drawToRenderTarget.Add(modelRotation); //setup the shaders this.characterRenderShader = new Shaders.Character(); this.characterBlendRenderShader = new Shaders.CharacterBlend(); //setup the output and bloom shaders outputShader = new Shaders.RgbmDecode(); drawToScreen.Add(new ShaderElement(outputShader, new Vector2(1, 1), true)); bloomPassShader = new Shaders.RgbmDecodeBloomPass(); bloomRenderTarget.Add(new ShaderElement(bloomPassShader, new Vector2(1, 1), true)); //add a background to be drawn drawToRenderTarget.Add(new BackgroundDrawer()); //setup the debug image displays //-------------------------------------- this.rgmbTextureAlphaShader = new Shaders.AlphaWrite(); this.bloomTextureDisplay = new TexturedElement(this.bloomRenderTarget, new Vector2(0.2f, 0.2f), true); this.rgbmTextureDisplay = new TexturedElement(this.drawToRenderTarget, new Vector2(0.2f, 0.2f), true); this.rgbmTextureAlphaDisplay = new ShaderElement(this.rgmbTextureAlphaShader, new Vector2(0.2f, 0.2f), true); this.rgbmTextureAlphaDisplay.Position = new Vector2(0.7f, 0.2f); this.rgbmTextureDisplay.Position = new Vector2(0.7f, 0.4f); this.bloomTextureDisplay.Position = new Vector2(0.7f, 0.6f); this.drawToScreen.Add(this.rgbmTextureDisplay); this.drawToScreen.Add(this.rgbmTextureAlphaDisplay); this.drawToScreen.Add(this.bloomTextureDisplay); //setup the render config this.configEditor = new RenderConfigEditor(this.Content); this.drawToScreen.Add(configEditor); this.UpdateManager.Add(configEditor); //add a statistics overlay. drawStats = new Xen.Ex.Graphics2D.Statistics.DrawStatisticsDisplay(this.UpdateManager); drawToScreen.Add(drawStats); }
private Geometry CreateShaderGeometry(ShaderElement shaderElement) { var geometry = CreateSlabGeometry(shaderElement); geometry.InitialMaterial = new Material { Diffuse = Colors.Orange, Shade = MaterialShade.Gouraud }; return geometry; }