From eb27c679c3de4b0f3326438c2a4b0ff23d7e871b Mon Sep 17 00:00:00 2001 From: shr Date: Thu, 14 Sep 2023 06:28:59 +0900 Subject: [PATCH] update shader --- .../shaders/RuntimePostEffectShader.hx | 92 +++++++++++++++---- .../graphics/shaders/RuntimeRainShader.hx | 36 ++++++-- 2 files changed, 100 insertions(+), 28 deletions(-) diff --git a/source/funkin/graphics/shaders/RuntimePostEffectShader.hx b/source/funkin/graphics/shaders/RuntimePostEffectShader.hx index b9ec73c76..7488d086f 100644 --- a/source/funkin/graphics/shaders/RuntimePostEffectShader.hx +++ b/source/funkin/graphics/shaders/RuntimePostEffectShader.hx @@ -1,38 +1,92 @@ package funkin.shaderslmfao; +import flixel.FlxCamera; import flixel.FlxG; import flixel.addons.display.FlxRuntimeShader; -import flixel.system.FlxAssets.FlxShader; -import haxe.CallStack; import lime.graphics.opengl.GLProgram; import lime.utils.Log; class RuntimePostEffectShader extends FlxRuntimeShader { - @:glVertexHeader(" - varying vec2 fragCoord; // normalized texture coord - varying vec2 screenPos; // y: always between 0 and 1, x: between 0 and (width/height) - uniform vec2 screenResolution; - ", true) - @:glVertexBody(" - fragCoord = vec2( + @:glVertexHeader(' + // normalized screen coord + // (0, 0) is the top left of the window + // (1, 1) is the bottom right of the window + varying vec2 screenCoord; + ', true) + @:glVertexBody(' + screenCoord = vec2( openfl_TextureCoord.x > 0.0 ? 1.0 : 0.0, openfl_TextureCoord.y > 0.0 ? 1.0 : 0.0 ); - screenPos = fragCoord * vec2(screenResolution.x / screenResolution.y, 1.0); - ") - @:glFragmentHeader(" - varying vec2 fragCoord; - varying vec2 screenPos; + ') + @:glFragmentHeader(' + // normalized screen coord + // (0, 0) is the top left of the window + // (1, 1) is the bottom right of the window + varying vec2 screenCoord; - vec2 texCoordSize() { // hack - return openfl_TextureCoordv / fragCoord; + // equals (FlxG.width, FlxG.height) + uniform vec2 uScreenResolution; + + // equals (camera.viewLeft, camera.viewTop, camera.viewRight, camera.viewBottom) + uniform vec4 uCameraBounds; + + // screen coord -> world coord conversion + // returns world coord in px + vec2 screenToWorld(vec2 screenCoord) { + float left = uCameraBounds.x; + float top = uCameraBounds.y; + float right = uCameraBounds.z; + float bottom = uCameraBounds.w; + vec2 scale = vec2(right - left, bottom - top); + vec2 offset = vec2(left, top); + return screenCoord * scale + offset; } - ", true) + + // world coord -> screen coord conversion + // returns normalized screen coord + vec2 worldToScreen(vec2 worldCoord) { + float left = uCameraBounds.x; + float top = uCameraBounds.y; + float right = uCameraBounds.z; + float bottom = uCameraBounds.w; + vec2 scale = vec2(right - left, bottom - top); + vec2 offset = vec2(left, top); + return (worldCoord - offset) / scale; + } + + // internally used to get the maximum `openfl_TextureCoordv` + vec2 bitmapCoordScale() { + return openfl_TextureCoordv / screenCoord; + } + + // internally used to compute bitmap coord + vec2 screenToBitmap(vec2 screenCoord) { + return screenCoord * bitmapCoordScale(); + } + + // samples the frame buffer using a screen coord + vec4 sampleBitmapScreen(vec2 screenCoord) { + return texture2D(bitmap, screenToBitmap(screenCoord)); + } + + // samples the frame buffer using a world coord + vec4 sampleBitmapWorld(vec2 worldCoord) { + return sampleBitmapScreen(worldToScreen(worldCoord)); + } + ', true) public function new(fragmentSource:String = null, glVersion:String = null) { super(fragmentSource, null, glVersion); - screenResolution.value = [FlxG.width, FlxG.height]; + uScreenResolution.value = [FlxG.width, FlxG.height]; + } + + // basically `updateViewInfo(FlxG.width, FlxG.height, FlxG.camera)` is good + public function updateViewInfo(screenWidth:Float, screenHeight:Float, camera:FlxCamera):Void + { + uScreenResolution.value = [screenWidth, screenHeight]; + uCameraBounds.value = [camera.viewLeft, camera.viewTop, camera.viewRight, camera.viewBottom]; } override function __createGLProgram(vertexSource:String, fragmentSource:String):GLProgram @@ -44,7 +98,7 @@ class RuntimePostEffectShader extends FlxRuntimeShader } catch (error) { - Log.warn(error); + Log.warn(error); // prevent the app from dying immediately return null; } } diff --git a/source/funkin/graphics/shaders/RuntimeRainShader.hx b/source/funkin/graphics/shaders/RuntimeRainShader.hx index cab0a8964..1150e4002 100644 --- a/source/funkin/graphics/shaders/RuntimeRainShader.hx +++ b/source/funkin/graphics/shaders/RuntimeRainShader.hx @@ -24,8 +24,6 @@ class RuntimeRainShader extends RuntimePostEffectShader radius:ShaderParameter, }>; - // This is a property, whenever the value is set it calls the set_time function. - // This makes the code cleaner elsewhere. public var time(default, set):Float = 1; function set_time(value:Float):Float @@ -34,13 +32,33 @@ class RuntimeRainShader extends RuntimePostEffectShader return time = value; } + // The scale of the rain depends on the world coordinate system, so higher resolution makes + // the raindrops smaller. This parameter can be used to adjust the total scale of the scene. + // The size of the raindrops is proportional to the value of this parameter. + public var scale(default, set):Float = 1; + + function set_scale(value:Float):Float + { + this.setFloat('uScale', value); + return scale = value; + } + + // The intensity of the rain. Zero means no rain and one means the maximum amount of rain. + public var intensity(default, set):Float = 1; + + function set_intensity(value:Float):Float + { + this.setFloat('uIntensity', value); + return intensity = value; + } + public var puddleMap(default, set):BitmapData; public var groundMap(default, set):BitmapData; function set_groundMap(value:BitmapData):BitmapData { - trace("groundmap set"); + trace('groundmap set'); this.setBitmapData('uGroundMap', value); // this.setFloat2('uPuddleTextureSize', value.width, value.height); return groundMap = value; @@ -56,7 +74,7 @@ class RuntimeRainShader extends RuntimePostEffectShader function set_lightMap(value:BitmapData):BitmapData { - trace("lightmap set"); + trace('lightmap set'); this.setBitmapData('uLightMap', value); return lightMap = value; } @@ -71,7 +89,7 @@ class RuntimeRainShader extends RuntimePostEffectShader public function new() { - super(Assets.getText(Paths.frag("rain"))); + super(Assets.getText(Paths.frag('rain'))); } public function update(elapsed:Float):Void @@ -82,14 +100,14 @@ class RuntimeRainShader extends RuntimePostEffectShader override function __processGLData(source:String, storageType:String):Void { super.__processGLData(source, storageType); - if (storageType == "uniform") + if (storageType == 'uniform') { lights = [ for (i in 0...MAX_LIGHTS) { - position: addFloatUniform("lights[" + i + "].position", 2), - color: addFloatUniform("lights[" + i + "].color", 3), - radius: addFloatUniform("lights[" + i + "].radius", 1), + position: addFloatUniform('lights[$i].position', 2), + color: addFloatUniform('lights[$i].color', 3), + radius: addFloatUniform('lights[$i].radius', 1), } ]; }