private void RenderTexturedBackground(IDrawDevice device) { if (!cachedTexturedBackground.IsAvailable) { return; } float timeMult = Time.TimeMult; backgroundX += timeMult * 1.2f; backgroundY += timeMult * -0.2f + timeMult * MathF.Sin(backgroundPhase) * 0.6f; backgroundPhase += timeMult * 0.001f; Vector3 renderPos = new Vector3(0, 0, 600); // Fit the target rect to actual pixel coordinates to avoid unnecessary filtering offsets renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { // AMD Bugfix? renderPos.Y -= 0.004f; } // Reserve the required space for vertex data in our locally cached buffer int neededVertices = 4; if (cachedVertices == null || cachedVertices.Length < neededVertices) { cachedVertices = new VertexC1P3T2[neededVertices]; } // Render it as world-space fullscreen quad cachedVertices[0].Pos = new Vector3(renderPos.X, renderPos.Y, renderPos.Z); cachedVertices[1].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y, renderPos.Z); cachedVertices[2].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); cachedVertices[3].Pos = new Vector3(renderPos.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); cachedVertices[0].TexCoord = new Vector2(0.0f, 0.0f); cachedVertices[1].TexCoord = new Vector2(1f, 0.0f); cachedVertices[2].TexCoord = new Vector2(1f, 1f); cachedVertices[3].TexCoord = new Vector2(0.0f, 1f); cachedVertices[0].Color = cachedVertices[1].Color = cachedVertices[2].Color = cachedVertices[3].Color = ColorRgba.White; // Setup custom pixel shader BatchInfo material = device.RentMaterial(); material.Technique = texturedBackgroundShader; material.MainTexture = cachedTexturedBackground; material.SetValue("horizonColor", horizonColor); material.SetValue("shift", new Vector2(backgroundX, backgroundY)); material.SetValue("parallaxStarsEnabled", 0f); device.AddVertices(material, VertexMode.Quads, cachedVertices, 0, 4); }
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); } }
public void RenderTexturedBackground(IDrawDevice device, ref TileMapLayer layer, int cacheIndex, float x, float y) { if (!cachedTexturedBackground.IsAvailable || cachedTexturedBackgroundAnimated) { RecreateTexturedBackground(ref layer); } // Fit the input material rect to the output size according to rendering step config Vector3 renderPos = new Vector3(device.ViewerPos.X - device.TargetSize.X / 2, device.ViewerPos.Y - device.TargetSize.Y / 2, layer.Depth); // Fit the target rect to actual pixel coordinates to avoid unnecessary filtering offsets renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { // AMD Bugfix? renderPos.Y -= 0.004f; } // Reserve the required space for vertex data in our locally cached buffer int neededVertices = 4; if (cachedVertices == null || cachedVertices.Length < neededVertices) { cachedVertices = new VertexC1P3T2[neededVertices]; } // Render it as world-space fullscreen quad cachedVertices[0].Pos = new Vector3(renderPos.X, renderPos.Y, renderPos.Z); cachedVertices[1].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y, renderPos.Z); cachedVertices[2].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); cachedVertices[3].Pos = new Vector3(renderPos.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); cachedVertices[0].TexCoord = new Vector2(0f, 0f); cachedVertices[1].TexCoord = new Vector2(1f, 0f); cachedVertices[2].TexCoord = new Vector2(1f, 1f); cachedVertices[3].TexCoord = new Vector2(0f, 1f); cachedVertices[0].Color = cachedVertices[1].Color = cachedVertices[2].Color = cachedVertices[3].Color = ColorRgba.White; // Setup custom pixel shader BatchInfo material = device.RentMaterial(); material.Technique = texturedBackgroundShader; material.MainTexture = cachedTexturedBackground; material.SetValue("horizonColor", layer.BackgroundColor); material.SetValue("shift", new Vector2(x, y)); material.SetValue("parallaxStarsEnabled", layer.ParallaxStarsEnabled ? 1f : 0f); device.AddVertices(material, VertexMode.Quads, cachedVertices, 0, 4); }
public override void Draw(IDrawDevice device) { if (animHidden) { return; } Texture mainTex = RetrieveMainTex(); DrawTechnique tech = RetrieveDrawTechnique(); Rect uvRect, uvRectNext; bool smoothShaderInput = (tech != null && tech.PreferredVertexFormat == VertexC1P3T4A1.Declaration); GetAnimData(mainTex, smoothShaderInput, out uvRect, out uvRectNext); if (!smoothShaderInput) { PrepareVertices(ref vertices, device, this.colorTint, uvRect); if (customMat != null) { device.AddVertices(customMat, VertexMode.Quads, vertices, 0, 4); } else { if (flipMode == 0) { device.AddVertices(sharedMat, VertexMode.Quads, vertices, 0, 4); } else { BatchInfo material = device.RentMaterial(sharedMat.Res.Info); material.SetValue("normalMultiplier", new Vector2((flipMode & FlipMode.Horizontal) == 0 ? 1 : -1f, (flipMode & FlipMode.Vertical) == 0 ? 1 : -1f)); device.AddVertices(material, VertexMode.Quads, vertices, 0, 4); } } } else { PrepareVerticesSmooth(ref verticesSmooth, device, curAnimFrameFade, this.colorTint, uvRect, uvRectNext); if (customMat != null) { device.AddVertices(customMat, VertexMode.Quads, verticesSmooth, 0, 4); } else { if (flipMode == 0) { device.AddVertices(sharedMat, VertexMode.Quads, verticesSmooth, 0, 4); } else { BatchInfo material = device.RentMaterial(sharedMat.Res.Info); material.SetValue("normalMultiplier", new Vector2((flipMode & FlipMode.Horizontal) == 0 ? 1 : -1f, (flipMode & FlipMode.Vertical) == 0 ? 1 : -1f)); device.AddVertices(material, VertexMode.Quads, verticesSmooth, 0, 4); } } } }
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); }
void ICmpUpdatable.OnUpdate() { var renderer = GameObj.GetComponent <SpriteRenderer>(); _batch = _batch ?? new BatchInfo(renderer.SharedMaterial.Res); renderer.CustomMaterial = _batch; var offset = Speed * (float)Time.GameTimer.TotalSeconds; offset.X %= 1; offset.Y %= 1; _batch.SetValue("texOffset", offset); }
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); } }
public void RenderTexturedBackground(IDrawDevice device, ref TileMapLayer layer, int cacheIndex, float x, float y) { if (cachedTexturedBackground == null || cachedTexturedBackgroundAnimated) { RecreateTexturedBackground(ref layer); } // Fit the input material rect to the output size according to rendering step config Vector3 renderPos = new Vector3(device.RefCoord.X - device.TargetSize.X / 2, device.RefCoord.Y - device.TargetSize.Y / 2, layer.Depth); float scale = 1.0f; device.PreprocessCoords(ref renderPos, ref scale); // Fit the target rect to actual pixel coordinates to avoid unnecessary filtering offsets renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { //renderPos.Y += 0.5f; // AMD Bugfix? renderPos.Y -= 0.001f; } // Reserve the required space for vertex data in our locally cached buffer VertexC1P3T2[] vertexData; int neededVertices = 4; if (cachedVertices[cacheIndex] == null || cachedVertices[cacheIndex].Length < neededVertices) { cachedVertices[cacheIndex] = vertexData = new VertexC1P3T2[neededVertices]; } else { vertexData = cachedVertices[cacheIndex]; } // Render it as world-space fullscreen quad vertexData[0].Pos = new Vector3(renderPos.X, renderPos.Y, renderPos.Z); vertexData[1].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y, renderPos.Z); vertexData[2].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); vertexData[3].Pos = new Vector3(renderPos.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); vertexData[0].TexCoord = new Vector2(0.0f, 0.0f); vertexData[1].TexCoord = new Vector2(1f, 0.0f); vertexData[2].TexCoord = new Vector2(1f, 1f); vertexData[3].TexCoord = new Vector2(0.0f, 1f); vertexData[0].Color = vertexData[1].Color = vertexData[2].Color = vertexData[3].Color = ColorRgba.White; // Setup custom pixel shader BatchInfo material = new BatchInfo(texturedBackgroundShader, cachedTexturedBackground); material.SetValue("horizonColor", layer.BackgroundColor); material.SetValue("shift", new Vector2(x, y)); device.AddVertices(material, VertexMode.Quads, vertexData); }
private void RenderTexturedBackground(IDrawDevice device) { if (cachedTexturedBackground == null) { return; } float timeMult = Time.TimeMult; backgroundX += timeMult * 1.2f; backgroundY += timeMult * -0.2f + timeMult * MathF.Sin(backgroundPhase) * 0.6f; backgroundPhase += timeMult * 0.001f; Vector3 renderPos = new Vector3(0, 0, (device.NearZ + device.FarZ) * 0.5f); // Fit the target rect to actual pixel coordinates to avoid unnecessary filtering offsets renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { //renderPos.Y += 0.5f; // AMD Bugfix? renderPos.Y -= 0.001f; } // Reserve the required space for vertex data in our locally cached buffer VertexC1P3T2[] vertexData; int neededVertices = 4; if (cachedVertices == null || cachedVertices.Length < neededVertices) { cachedVertices = vertexData = new VertexC1P3T2[neededVertices]; } else { vertexData = cachedVertices; } // Render it as world-space fullscreen quad vertexData[0].Pos = new Vector3(renderPos.X, renderPos.Y, renderPos.Z); vertexData[1].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y, renderPos.Z); vertexData[2].Pos = new Vector3(renderPos.X + device.TargetSize.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); vertexData[3].Pos = new Vector3(renderPos.X, renderPos.Y + device.TargetSize.Y, renderPos.Z); vertexData[0].TexCoord = new Vector2(0.0f, 0.0f); vertexData[1].TexCoord = new Vector2(1f, 0.0f); vertexData[2].TexCoord = new Vector2(1f, 1f); vertexData[3].TexCoord = new Vector2(0.0f, 1f); vertexData[0].Color = vertexData[1].Color = vertexData[2].Color = vertexData[3].Color = ColorRgba.White; // Setup custom pixel shader BatchInfo material = new BatchInfo(texturedBackgroundShader, cachedTexturedBackground); material.SetValue("horizonColor", horizonColor); material.SetValue("shift", new Vector2(backgroundX, backgroundY)); device.AddVertices(material, VertexMode.Quads, vertexData); }