private void ProcessBloomStep(RenderStep step, DrawDevice drawDevice) { ContentRef <RenderTarget> outputTarget = drawDevice.Target; Vector2 imageSize = drawDevice.TargetSize; Rect viewportRect = drawDevice.ViewportRect; this.SetupTargets((Point2)drawDevice.TargetSize); // Extract bright spots from the rendered image { BatchInfo material = drawDevice.RentMaterial(); material.Technique = this.techFilterBrightness; material.MainTexture = step.Input.MainTexture; material.SetValue("minBrightness", this.minBrightness); material.SetValue("bloomStrength", this.bloomStrength); this.Blit(drawDevice, material, this.targetPingPongA[0]); } // Downsample to lowest target for (int i = 1; i < this.targetPingPongA.Length; i++) { BatchInfo material = drawDevice.RentMaterial(); material.Technique = this.techDownsample; material.MainTexture = this.targetPingPongA[i - 1].Targets[0]; this.Blit(drawDevice, material, this.targetPingPongA[i]); } // Blur all targets, separating horizontal and vertical blur for (int i = 0; i < this.targetPingPongA.Length; i++) { BatchInfo material; material = drawDevice.RentMaterial(); material.Technique = this.techBlur; material.MainTexture = this.targetPingPongA[i].Targets[0]; material.SetValue("blurDirection", new Vector2(1.0f, 0.0f)); this.Blit(drawDevice, material, this.targetPingPongB[i]); material = drawDevice.RentMaterial(); material.Technique = this.techBlur; material.MainTexture = this.targetPingPongB[i].Targets[0]; material.SetValue("blurDirection", new Vector2(0.0f, 1.0f)); this.Blit(drawDevice, material, this.targetPingPongA[i]); } // Combine all targets into the final image using the draw device's original target { BatchInfo material = drawDevice.RentMaterial(); material.Technique = this.techCombineFinal; material.MainTexture = step.Input.MainTexture; material.SetTexture("blurFullTex", this.targetPingPongA[0].Targets[0]); material.SetTexture("blurHalfTex", this.targetPingPongA[1].Targets[0]); material.SetTexture("blurQuarterTex", this.targetPingPongA[2].Targets[0]); material.SetTexture("blurEighthTex", this.targetPingPongA[3].Targets[0]); this.Blit(drawDevice, material, outputTarget.Res, imageSize, viewportRect); } }
private void ProcessResizeStep(DrawDevice drawDevice) { BatchInfo material = drawDevice.RentMaterial(); material.Technique = resizeShader; material.MainTexture = finalTexture; material.SetValue("mainTexSize", new Vector2(finalTexture.ContentWidth, finalTexture.ContentHeight)); this.Blit(drawDevice, material, drawDevice.ViewportRect); }
public Texture RequestBlurredInGame() { #if PLATFORM_ANDROID || PLATFORM_WASM // Blur is disabled in Android and WebAssembly version return(finalTexture); #else DrawDevice device = new DrawDevice(); device.Projection = ProjectionMode.Screen; // One temporary material is used for all operations BatchInfo tempMaterial = device.RentMaterial(); // Downsample to half size tempMaterial.Technique = downsampleShader; tempMaterial.MainTexture = finalTexture; tempMaterial.SetValue("pixelOffset", new Vector2(1f / finalTexture.ContentWidth, 1f / finalTexture.ContentHeight)); this.Blit(device, tempMaterial, targetPingPongA[0]); // Downsample to quarter size tempMaterial.MainTexture = targetPingPongA[0].Targets[0]; tempMaterial.SetValue("pixelOffset", new Vector2(1f / tempMaterial.MainTexture.Res.ContentWidth, 1f / tempMaterial.MainTexture.Res.ContentHeight)); this.Blit(device, tempMaterial, targetPingPongA[1]); // Blur last target, separating horizontal and vertical blur tempMaterial.Technique = blurShader; tempMaterial.MainTexture = targetPingPongA[1].Targets[0]; tempMaterial.SetValue("blurDirection", new Vector2(1f, 0f)); tempMaterial.SetValue("pixelOffset", new Vector2(1f / tempMaterial.MainTexture.Res.ContentWidth, 1f / tempMaterial.MainTexture.Res.ContentHeight)); this.Blit(device, tempMaterial, targetPingPongB[1]); tempMaterial.MainTexture = targetPingPongB[1].Targets[0]; tempMaterial.SetValue("blurDirection", new Vector2(0f, 1f)); tempMaterial.SetValue("pixelOffset", new Vector2(1f / tempMaterial.MainTexture.Res.ContentWidth, 1f / tempMaterial.MainTexture.Res.ContentHeight)); this.Blit(device, tempMaterial, targetPingPongA[1]); return(targetPingPongA[1].Targets[0].Res); #endif }
private void ProcessCombineSceneStep(DrawDevice drawDevice) { // ToDo: Split lighting to RGB channels // ToDo: Implement dynamic lighting/shadows (https://github.com/mattdesl/lwjgl-basics/wiki/2D-Pixel-Perfect-Shadows) Vector2 viewSize = drawDevice.TargetSize; Vector2 viewOffset = new Vector2( drawDevice.RefCoord.X - viewSize.X / 2, drawDevice.RefCoord.Y - viewSize.Y / 2 ); float ambientLight = levelHandler.AmbientLightCurrent; float viewWaterLevel = (levelHandler.WaterLevel - viewOffset.Y); // Blit ambient light color { BatchInfo material = drawDevice.RentMaterial(); material.Technique = DrawTechnique.Solid; material.MainColor = new ColorRgba(ambientLight, 0, 0); this.Blit(drawDevice, material, lightingTarget); } // Render lights (target was set in previous step) drawDevice.PrepareForDrawcalls(); foreach (GameObject actor in levelHandler.ActiveObjects) { LightEmitter light = actor.GetComponent <LightEmitter>(); if (light != null) { // World-space to screen-space position transformation Vector3 pos = actor.Transform.Pos; pos.X -= viewOffset.X; pos.Y -= viewOffset.Y; float left = pos.X - light.RadiusFar; float top = pos.Y - light.RadiusFar; float right = pos.X + light.RadiusFar; float bottom = pos.Y + light.RadiusFar; if (left < viewSize.X && top < viewSize.Y && right > 0 && bottom > 0) { lightBuffer[0].Pos.X = left; lightBuffer[0].Pos.Y = top; lightBuffer[1].Pos.X = left; lightBuffer[1].Pos.Y = bottom; lightBuffer[2].Pos.X = right; lightBuffer[2].Pos.Y = bottom; lightBuffer[3].Pos.X = right; lightBuffer[3].Pos.Y = top; // Use TexCoord X & Y for screen-space Light position lightBuffer[0].TexCoord.X = lightBuffer[1].TexCoord.X = lightBuffer[2].TexCoord.X = lightBuffer[3].TexCoord.X = pos.X; lightBuffer[0].TexCoord.Y = lightBuffer[1].TexCoord.Y = lightBuffer[2].TexCoord.Y = lightBuffer[3].TexCoord.Y = pos.Y; // Use TexCoord Z & W for Light radius lightBuffer[0].TexCoord.Z = lightBuffer[1].TexCoord.Z = lightBuffer[2].TexCoord.Z = lightBuffer[3].TexCoord.Z = light.RadiusNear; lightBuffer[0].TexCoord.W = lightBuffer[1].TexCoord.W = lightBuffer[2].TexCoord.W = lightBuffer[3].TexCoord.W = light.RadiusFar; // Use Red channel for Light intensity lightBuffer[0].Color.R = lightBuffer[1].Color.R = lightBuffer[2].Color.R = lightBuffer[3].Color.R = (byte)(light.Intensity * 255); // Use Green channel for Light brightness lightBuffer[0].Color.G = lightBuffer[1].Color.G = lightBuffer[2].Color.G = lightBuffer[3].Color.G = (byte)(light.Brightness * 255); switch (light.Type) { default: case LightType.Solid: drawDevice.AddVertices(lightingMaterial, VertexMode.Quads, lightBuffer); break; case LightType.WithNoise: drawDevice.AddVertices(lightingNoiseMaterial, VertexMode.Quads, lightBuffer); break; } } } } drawDevice.Render(); // Resize Blur targets SetupTargets((Point2)drawDevice.TargetSize); // Blit it into screen { BatchInfo material = drawDevice.RentMaterial(); material.Technique = DrawTechnique.Solid; material.MainTexture = mainTexture; this.Blit(drawDevice, material, targetPingPongA[0]); } // Downsample to lowest target for (int i = 1; i < targetPingPongA.Length; i++) { BatchInfo material = drawDevice.RentMaterial(); material.Technique = downsampleShader; material.MainTexture = targetPingPongA[i - 1].Targets[0]; material.SetValue("pixelOffset", new Vector2(1f / material.MainTexture.Res.ContentWidth, 1f / material.MainTexture.Res.ContentHeight)); this.Blit(drawDevice, material, targetPingPongA[i]); } // Blur all targets, separating horizontal and vertical blur for (int i = 0; i < targetPingPongA.Length; i++) { BatchInfo material = drawDevice.RentMaterial(); material.Technique = blurShader; material.MainTexture = targetPingPongA[i].Targets[0]; material.SetValue("blurDirection", new Vector2(1f, 0f)); material.SetValue("pixelOffset", new Vector2(1f / material.MainTexture.Res.ContentWidth, 1f / material.MainTexture.Res.ContentHeight)); this.Blit(drawDevice, material, targetPingPongB[i]); material.MainTexture = targetPingPongB[i].Targets[0]; material.SetValue("blurDirection", new Vector2(0f, 1f)); material.SetValue("pixelOffset", new Vector2(1f / material.MainTexture.Res.ContentWidth, 1f / material.MainTexture.Res.ContentHeight)); this.Blit(drawDevice, material, targetPingPongA[i]); } // Blit it into screen if (viewWaterLevel < viewSize.Y) { // Render lighting with water BatchInfo material = drawDevice.RentMaterial(); material.Technique = combineSceneWaterShader; material.SetTexture("mainTex", mainTexture); material.SetTexture("lightTex", lightingTexture); material.SetTexture("displacementTex", noiseTexture); // Underwater displacement material.SetTexture("blurHalfTex", targetPingPongA[1].Targets[0]); material.SetTexture("blurQuarterTex", targetPingPongA[2].Targets[0]); material.SetValue("ambientLight", ambientLight); material.SetValue("darknessColor", levelHandler.DarknessColor); material.SetValue("waterLevel", viewWaterLevel / viewSize.Y); this.Blit(drawDevice, material, finalTarget); } else { // Render lighting without water BatchInfo material = drawDevice.RentMaterial(); material.Technique = combineSceneShader; material.SetTexture("mainTex", mainTexture); material.SetTexture("lightTex", lightingTexture); material.SetTexture("blurHalfTex", targetPingPongA[1].Targets[0]); material.SetTexture("blurQuarterTex", targetPingPongA[2].Targets[0]); material.SetValue("ambientLight", ambientLight); material.SetValue("darknessColor", levelHandler.DarknessColor); this.Blit(drawDevice, material, finalTarget); } }