扫描二维码关注官方公众号
返回列表
+ 发新帖
查看: 110|回复: 0

[转载发布] 【MZ插件】CRT显示器扫描线和随机故障等效果

[复制链接]
累计送礼:
0 个
累计收礼:
0 个
  • TA的每日心情
    开心
    3 天前
  • 签到天数: 175 天

    连续签到: 1 天

    [LV.7]常住居民III

    2574

    主题

    705

    回帖

    2万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    VIP
    6
    卡币
    16817
    OK点
    16
    推广点
    0
    同能卷
    0
    积分
    20124

    灌水之王

    发表于 6 天前 | 显示全部楼层 |阅读模式
    指挥AI写的,效果还不赖,分享出来,功能文档里写的很明白了,不过自己感觉故障效果没那么完美,勉强可以用,MV 不知道能不能用可以自行测试



    本来录屏的转gif有点糊,明白我意思就好

    JAVASCRIPT 代码下载
    1. /*:
    2. * @target MZ
    3. * @plugindesc CRT 显示器滤镜,包含扫描线、屏幕曲率、暗角、色差和随机故障效果。
    4. * @author enpitsulin
    5. *
    6. * @param scanlineIntensity
    7. * @text 扫描线强度
    8. * @desc 扫描线效果的强度 (0.0 - 1.0)。
    9. * @type number
    10. * @decimals 2
    11. * @min 0
    12. * @max 1
    13. * @default 0.35
    14. *
    15. * @param curvatureAmount
    16. * @text 屏幕曲率
    17. * @desc 桶形畸变的程度 (0.0 - 1.0)。
    18. * @type number
    19. * @decimals 2
    20. * @min 0
    21. * @max 1
    22. * @default 0.25
    23. *
    24. * @param vignetteIntensity
    25. * @text 暗角强度
    26. * @desc 屏幕边缘暗化的程度 (0.0 - 1.0)。
    27. * @type number
    28. * @decimals 2
    29. * @min 0
    30. * @max 1
    31. * @default 0.30
    32. *
    33. * @param chromaticAberration
    34. * @text 色差强度
    35. * @desc RGB 通道分离的程度 (0.0 - 1.0)。
    36. * @type number
    37. * @decimals 2
    38. * @min 0
    39. * @max 1
    40. * @default 0.15
    41. *
    42. * @param colorBleeding
    43. * @text 色溢强度
    44. * @desc 红色通道水平扩散的程度 (0.0 - 1.0)。
    45. * @type number
    46. * @decimals 2
    47. * @min 0
    48. * @max 1
    49. * @default 0.12
    50. *
    51. * @param glitchFrequency
    52. * @text 故障频率
    53. * @desc 故障效果平均间隔秒数。
    54. * @type number
    55. * @decimals 1
    56. * @min 0
    57. * @default 5.0
    58. *
    59. * @param glitchIntensity
    60. * @text 故障强度
    61. * @desc 故障效果的最大强度 (0.0 - 1.0)。
    62. * @type number
    63. * @decimals 2
    64. * @min 0
    65. * @max 1
    66. * @default 0.60
    67. *
    68. * @param glitchEnabled
    69. * @text 启用故障效果
    70. * @desc 是否启用随机故障效果(手动触发仍然可用)。
    71. * @type boolean
    72. * @default true
    73. *
    74. * @param enabled
    75. * @text 默认启用
    76. * @desc 是否默认启用 CRT 滤镜效果。
    77. * @type boolean
    78. * @default true
    79. *
    80. * @command setEnabled
    81. * @text 设置启用状态
    82. * @desc 启用或禁用 CRT 滤镜效果。
    83. *
    84. * @arg enabled
    85. * @text 启用
    86. * @type boolean
    87. * @default true
    88. *
    89. * @command setGlitchEnabled
    90. * @text 设置故障效果启用状态
    91. * @desc 启用或禁用随机故障效果(手动触发仍然可用)。
    92. *
    93. * @arg enabled
    94. * @text 启用
    95. * @type boolean
    96. * @default true
    97. *
    98. * @command triggerGlitch
    99. * @text 触发故障效果
    100. * @desc 手动触发一次故障效果。
    101. *
    102. * @arg duration
    103. * @text 持续时间(帧)
    104. * @desc 故障效果的持续帧数(默认:随机 10-40)。
    105. * @type number
    106. * @min 1
    107. * @default 0
    108. *
    109. * @command setGlitchFrequency
    110. * @text 设置故障频率
    111. * @desc 更改自动故障效果的平均间隔。
    112. *
    113. * @arg frequency
    114. * @text 频率(秒)
    115. * @type number
    116. * @decimals 1
    117. * @min 0
    118. * @default 5.0
    119. *
    120. * @help
    121. * CRTFilter.js
    122. *
    123. * 为游戏画面应用 CRT(阴极射线管)显示器效果,包括扫描线、桶形畸变、
    124. * 暗角、色差和周期性故障效果。
    125. *
    126. * 此滤镜钩入 Spriteset_Base,因此会同时应用于地图场景和战斗场景。
    127. *
    128. * 插件命令:
    129. *   setEnabled          - 开启/关闭 CRT 效果
    130. *   setGlitchEnabled    - 开启/关闭自动故障效果
    131. *   triggerGlitch       - 手动触发故障效果
    132. *   setGlitchFrequency  - 更改自动故障间隔
    133. */
    134. void(function(){
    135.   "use strict";
    136.   var PLUGIN_NAME = "CRTFilter";
    137.   var params = PluginManager.parameters(PLUGIN_NAME);
    138.   var SETTINGS = {
    139.     scanlineIntensity: Number(params["scanlineIntensity"] || 0.35),
    140.     curvatureAmount: Number(params["curvatureAmount"] || 0.25),
    141.     vignetteIntensity: Number(params["vignetteIntensity"] || 0.30),
    142.     chromaticAberration: Number(params["chromaticAberration"] || 0.15),
    143.     colorBleeding: Number(params["colorBleeding"] || 0.12),
    144.     glitchFrequency: Number(params["glitchFrequency"] || 5.0),
    145.     glitchIntensity: Number(params["glitchIntensity"] || 0.60),
    146.     glitchEnabled: params["glitchEnabled"] !== "false",
    147.     enabled: params["enabled"] !== "false",
    148.   };
    149.   // =========================================================================
    150.   // GlitchStateMachine Class - Manages glitch timing and state
    151.   // =========================================================================
    152.   function GlitchStateMachine(){
    153.     this.initialize.apply(this, arguments);
    154.   }
    155.   GlitchStateMachine.prototype.initialize = function(options){
    156.     this.state = "cooldown"; // cooldown | attack | sustain | release
    157.     this.timer = 0;
    158.     this.phaseTimer = 0;
    159.     this.duration = 0;
    160.     this.maxIntensity = options.maxIntensity || 0.6;
    161.     this.frequency = options.frequency || 5.0;
    162.     this.enabled = options.glitchEnabled !== false;
    163.     this.currentIntensity = 0;
    164.     this.cooldownTarget = this._randomCooldown();
    165.   };
    166.   GlitchStateMachine.prototype._randomCooldown = function(){
    167.     var base = this.frequency * 60;
    168.     return Math.floor(base * 0.5 + Math.random() * base);
    169.   };
    170.   GlitchStateMachine.prototype._randomDuration = function(){
    171.     return Math.floor(10 + Math.random() * 30);
    172.   };
    173.   GlitchStateMachine.prototype.update = function(){
    174.     switch(this.state){
    175.       case"cooldown":
    176.         this.timer++;
    177.         if(this.enabled && this.timer >= this.cooldownTarget){
    178.           this.trigger(0);
    179.         }
    180.         break;
    181.       case"attack": {
    182.         this.phaseTimer++;
    183.         var attackLen = Math.max(1, Math.floor(this.duration * 0.2));
    184.         var t = this.phaseTimer / attackLen;
    185.         this.currentIntensity = t * this.maxIntensity;
    186.         if(this.phaseTimer >= attackLen){
    187.           this.state = "sustain";
    188.           this.phaseTimer = 0;
    189.         }
    190.         break;
    191.       }
    192.       case"sustain": {
    193.         this.phaseTimer++;
    194.         var sustainLen = Math.max(
    195.           1,
    196.           Math.floor(this.duration * 0.5)
    197.         );
    198.         this.currentIntensity = this.maxIntensity;
    199.         if(this.phaseTimer >= sustainLen){
    200.           this.state = "release";
    201.           this.phaseTimer = 0;
    202.         }
    203.         break;
    204.       }
    205.       case"release": {
    206.         this.phaseTimer++;
    207.         var releaseLen = Math.max(
    208.           1,
    209.           Math.floor(this.duration * 0.3)
    210.         );
    211.         var rt = 1 - this.phaseTimer / releaseLen;
    212.         this.currentIntensity = rt * this.maxIntensity;
    213.         if(this.phaseTimer >= releaseLen){
    214.           this._end();
    215.         }
    216.         break;
    217.       }
    218.     }
    219.   };
    220.   GlitchStateMachine.prototype.trigger = function(duration){
    221.     this.state = "attack";
    222.     this.phaseTimer = 0;
    223.     this.duration = duration > 0 ? duration : this._randomDuration();
    224.   };
    225.   GlitchStateMachine.prototype._end = function(){
    226.     this.state = "cooldown";
    227.     this.timer = 0;
    228.     this.phaseTimer = 0;
    229.     this.currentIntensity = 0;
    230.     this.cooldownTarget = this._randomCooldown();
    231.   };
    232.   GlitchStateMachine.prototype.setEnabled = function(value){
    233.     this.enabled = value;
    234.   };
    235.   GlitchStateMachine.prototype.setFrequency = function(seconds){
    236.     this.frequency = seconds;
    237.   };
    238.   GlitchStateMachine.prototype.getIntensity = function(){
    239.     returnthis.currentIntensity;
    240.   };
    241.   // =========================================================================
    242.   // Fragment Shader (GLSL ES 1.0)
    243.   // =========================================================================
    244.   var FRAGMENT_SRC =
    245.     "precision mediump float;" +
    246.     "varying vec2 vTextureCoord;" +
    247.     "uniform sampler2D uSampler;" +
    248.     "uniform float uTime;" +
    249.     "uniform float uScanlineIntensity;" +
    250.     "uniform float uCurvature;" +
    251.     "uniform float uVignette;" +
    252.     "uniform float uChromatic;" +
    253.     "uniform float uBleeding;" +
    254.     "uniform float uGlitchStrength;" +
    255.     "uniform float uGlitchSeed;" +
    256.     "" +
    257.     "float rand(vec2 co) {" +
    258.     "  return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);" +
    259.     "}" +
    260.     "" +
    261.     "vec2 curveUV(vec2 uv, float amount) {" +
    262.     "  vec2 c = uv - 0.5;" +
    263.     "  float r2 = dot(c, c);" +
    264.     "  vec2 curved = uv + c * r2 * amount * 0.5;" +
    265.     "  return curved;" +
    266.     "}" +
    267.     "" +
    268.     "void main() {" +
    269.     "  vec2 uv = vTextureCoord;" +
    270.     "" +
    271.     "  uv = curveUV(uv, uCurvature);" +
    272.     "" +
    273.     "  if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) {" +
    274.     "    gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);" +
    275.     "    return;" +
    276.     "  }" +
    277.     "" +
    278.     "  float bandY = floor(uv.y * 20.0);" +
    279.     "  float bandRand = rand(vec2(bandY, uGlitchSeed));" +
    280.     "  float displacement = 0.0;" +
    281.     "  if (uGlitchStrength > 0.0 && bandRand > 0.7) {" +
    282.     "    displacement = (bandRand - 0.7) / 0.3 * 0.06 * uGlitchStrength;" +
    283.     "    displacement *= sign(rand(vec2(bandY + 1.0, uGlitchSeed)) - 0.5);" +
    284.     "  }" +
    285.     "  vec2 glitchUV = vec2(uv.x + displacement, uv.y);" +
    286.     "" +
    287.     "  float caBase = uChromatic * 0.004;" +
    288.     "  float caGlitch = uGlitchStrength * 0.012;" +
    289.     "  float caAmount = caBase + caGlitch;" +
    290.     "" +
    291.     "  float r = texture2D(uSampler, vec2(glitchUV.x + caAmount, glitchUV.y)).r;" +
    292.     "  float g = texture2D(uSampler, glitchUV).g;" +
    293.     "  float b = texture2D(uSampler, vec2(glitchUV.x - caAmount, glitchUV.y)).b;" +
    294.     "  float a = texture2D(uSampler, glitchUV).a;" +
    295.     "" +
    296.     "  float bleedOffset = uBleeding * 0.003;" +
    297.     "  float rBleed = texture2D(uSampler, vec2(glitchUV.x + bleedOffset, glitchUV.y)).r;" +
    298.     "  r = mix(r, rBleed, 0.5);" +
    299.     "" +
    300.     "  float scanline = 1.0 - uScanlineIntensity * 0.5 * (1.0 - cos(vTextureCoord.y * 1000.0 * 3.14159 * 2.0));" +
    301.     "  r *= scanline;" +
    302.     "  g *= scanline;" +
    303.     "  b *= scanline;" +
    304.     "" +
    305.     "  vec2 vig = uv - 0.5;" +
    306.     "  float vigDist = dot(vig, vig);" +
    307.     "  float vigFactor = 1.0 - vigDist * uVignette * 2.5;" +
    308.     "  vigFactor = clamp(vigFactor, 0.0, 1.0);" +
    309.     "  r *= vigFactor;" +
    310.     "  g *= vigFactor;" +
    311.     "  b *= vigFactor;" +
    312.     "" +
    313.     "  if (uGlitchStrength > 0.0) {" +
    314.     "    float flicker = 1.0 + (rand(vec2(uTime, uGlitchSeed)) - 0.5) * 0.3 * uGlitchStrength;" +
    315.     "    r *= flicker;" +
    316.     "    g *= flicker;" +
    317.     "    b *= flicker;" +
    318.     "  }" +
    319.     "" +
    320.     "  if (uGlitchStrength > 0.0) {" +
    321.     "    float noiseLine = rand(vec2(floor(uv.y * 300.0), uGlitchSeed + 7.0));" +
    322.     "    if (noiseLine > 0.97) {" +
    323.     "      float noise = rand(vec2(uv.x * 100.0, uGlitchSeed + uv.y)) * uGlitchStrength;" +
    324.     "      r = mix(r, noise, 0.4 * uGlitchStrength);" +
    325.     "      g = mix(g, noise, 0.4 * uGlitchStrength);" +
    326.     "      b = mix(b, noise, 0.4 * uGlitchStrength);" +
    327.     "    }" +
    328.     "  }" +
    329.     "" +
    330.     "  gl_FragColor = vec4(clamp(r, 0.0, 1.0), clamp(g, 0.0, 1.0), clamp(b, 0.0, 1.0), a);" +
    331.     "}";
    332.   // =========================================================================
    333.   // CRTFilter Class
    334.   // =========================================================================
    335.   function CRTFilter(){
    336.     this.initialize.apply(this, arguments);
    337.   }
    338.   CRTFilter.prototype = Object.create(PIXI.Filter.prototype);
    339.   CRTFilter.prototype.constructor = CRTFilter;
    340.   CRTFilter.prototype.initialize = function(){
    341.     PIXI.Filter.call(this, null, FRAGMENT_SRC);
    342.     this.uniforms.uTime = 0;
    343.     this.uniforms.uScanlineIntensity = SETTINGS.scanlineIntensity;
    344.     this.uniforms.uCurvature = SETTINGS.curvatureAmount;
    345.     this.uniforms.uVignette = SETTINGS.vignetteIntensity;
    346.     this.uniforms.uChromatic = SETTINGS.chromaticAberration;
    347.     this.uniforms.uBleeding = SETTINGS.colorBleeding;
    348.     this.uniforms.uGlitchStrength = 0;
    349.     this.uniforms.uGlitchSeed = 0;
    350.     this._enabled = SETTINGS.enabled;
    351.     this._time = 0;
    352.     this._glitch = new GlitchStateMachine({
    353.       maxIntensity: SETTINGS.glitchIntensity,
    354.       frequency: SETTINGS.glitchFrequency,
    355.       glitchEnabled: SETTINGS.glitchEnabled,
    356.     });
    357.   };
    358.   CRTFilter.prototype.update = function(){
    359.     if(!this._enabled){
    360.       this.uniforms.uGlitchStrength = 0;
    361.       return;
    362.     }
    363.     this._time++;
    364.     this.uniforms.uTime = this._time * 0.01;
    365.     this._glitch.update();
    366.     this.uniforms.uGlitchStrength = this._glitch.getIntensity();
    367.     if(this.uniforms.uGlitchStrength > 0){
    368.       this.uniforms.uGlitchSeed = Math.random() * 100;
    369.     }
    370.   };
    371.   CRTFilter.prototype.setEnabled = function(value){
    372.     this._enabled = value;
    373.     this.enabled = value;
    374.   };
    375.   CRTFilter.prototype.setGlitchEnabled = function(value){
    376.     this._glitch.setEnabled(value);
    377.   };
    378.   CRTFilter.prototype.triggerGlitch = function(duration){
    379.     if(this._enabled){
    380.       this._glitch.trigger(duration || 0);
    381.     }
    382.   };
    383.   CRTFilter.prototype.setGlitchFrequency = function(seconds){
    384.     this._glitch.setFrequency(seconds);
    385.   };
    386.   // Make available globally for save/load compatibility
    387.   window.CRTFilter = CRTFilter;
    388.   window.GlitchStateMachine = GlitchStateMachine;
    389.   // =========================================================================
    390.   // Engine Hooks
    391.   // =========================================================================
    392.   var _Spriteset_Base_createOverallFilters =
    393.     Spriteset_Base.prototype.createOverallFilters;
    394.   Spriteset_Base.prototype.createOverallFilters = function(){
    395.     _Spriteset_Base_createOverallFilters.call(this);
    396.     this._crtFilter = new CRTFilter();
    397.     if(!this._crtFilter._enabled){
    398.       this._crtFilter.enabled = false;
    399.     }
    400.     this.filters.push(this._crtFilter);
    401.   };
    402.   var _Spriteset_Base_update = Spriteset_Base.prototype.update;
    403.   Spriteset_Base.prototype.update = function(){
    404.     _Spriteset_Base_update.call(this);
    405.     if(this._crtFilter){
    406.       this._crtFilter.update();
    407.     }
    408.   };
    409.   // =========================================================================
    410.   // Plugin Commands
    411.   // =========================================================================
    412.   PluginManager.registerCommand(PLUGIN_NAME, "setEnabled", function(args){
    413.     var scene = SceneManager._scene;
    414.     if(scene && scene._spriteset && scene._spriteset._crtFilter){
    415.       var enabled = args.enabled === "true";
    416.       scene._spriteset._crtFilter.setEnabled(enabled);
    417.     }
    418.   });
    419.   PluginManager.registerCommand(PLUGIN_NAME, "setGlitchEnabled", function(args){
    420.     var scene = SceneManager._scene;
    421.     if(scene && scene._spriteset && scene._spriteset._crtFilter){
    422.       var enabled = args.enabled === "true";
    423.       scene._spriteset._crtFilter.setGlitchEnabled(enabled);
    424.     }
    425.   });
    426.   PluginManager.registerCommand(
    427.     PLUGIN_NAME,
    428.     "triggerGlitch",
    429.     function(args){
    430.       var scene = SceneManager._scene;
    431.       if(scene && scene._spriteset && scene._spriteset._crtFilter){
    432.         var duration = Number(args.duration) || 0;
    433.         scene._spriteset._crtFilter.triggerGlitch(duration);
    434.       }
    435.     }
    436.   );
    437.   PluginManager.registerCommand(
    438.     PLUGIN_NAME,
    439.     "setGlitchFrequency",
    440.     function(args){
    441.       var scene = SceneManager._scene;
    442.       if(scene && scene._spriteset && scene._spriteset._crtFilter){
    443.         var frequency = Number(args.frequency) || 5.0;
    444.         scene._spriteset._crtFilter.setGlitchFrequency(frequency);
    445.       }
    446.     }
    447.   );
    448. })();
    复制代码

                本帖来自P1论坛作者铅笔描绘的思念,因Project1站服务器在国外有时候访问缓慢不方便作者交流学习,经联系P1站长fux2同意署名转载一起分享游戏制作经验,共同为国内独立游戏作者共同创造良好交流环境,原文地址:https://rpg.blue/forum.php?mod=viewthread&tid=498644  若有侵权,发帖作者可联系底部站长QQ在线咨询功能删除,谢谢。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有账号?立即注册

    x
    天天去同能,天天有童年!
    回复 送礼论坛版权

    使用道具 举报

    文明发言,和谐互动
    文明发言,和谐互动
    高级模式
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    关闭

    幸运抽奖

    社区每日抽奖来袭,快来试试你是欧皇还是非酋~

    立即查看

    聊天机器人
    Loading...

    QQ|Archiver|手机版|小黑屋|同能RPG制作大师 ( 沪ICP备12027754号-3 )

    GMT+8, 2026-3-6 05:19 , Processed in 0.135696 second(s), 51 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2020, Tencent Cloud.

    快速回复 返回顶部 返回列表