前言

“滤色”混合模式是视频剪辑中非常实用的工具,它的核心原理是去黑留白——让画面中纯黑色的部分变得完全透明,只保留亮色部分。这一特性让它可以完美叠加雨雪、光效等素材。

今天我们就用两种方案,制作一个“暴雨倾盆的江南水乡风景”短视频,并深入解析为什么AI生成的黑色背景素材有时无法完美使用滤色模式。

先来看一下最终效果:

用剪映专业版滤色混合模式制作下雨时的江南风景《江南水乡》

方案一:使用剪映官方素材库(快速但存在版权隐患)

第一步:添加江南水乡风景素材

  1. 打开剪映专业版,进入编辑界面。

  2. 点击左上角素材面板的 “素材库”

  3. 在搜索框输入“江南水乡”,筛选出风景素材。

  4. 选择一两段喜欢的素材,点击右下角的 “+”号 添加到时间线。

  5. 调整素材顺序,让它们拼接成你想要的时长。

注:剪映素材库中有部分素材标注“可商用”,使用时请注意筛选。如用于商业用途,建议优先选择带“可商用”标识的素材,或使用自己的原创素材。

第二步:添加下雨效果

  1. 再次点击素材面板的 “素材库”

  2. 搜索关键词 “下雨”

  3. 浏览搜索结果,选择一个你喜欢的下雨效果视频。

  4. 点击右下角的 “+”号 添加到时间线。

  5. 关键操作:将下雨视频所在的轨道拖拽到时间线的最上层(即所有轨道的顶部)。

第三步:应用滤色混合模式

  1. 选中下雨视频轨道。

  2. 点击右上角功能面板的 “画面” 选项卡。

  3. 找到 “混合” 选项

  4. 点击混合模式下拉菜单,选择 “滤色”

  5. 此时你会发现:下雨视频的黑色背景消失了,只剩下白色的雨丝叠加在江南水乡的画面上,暴雨倾盆的效果瞬间呈现。

⚠️ 方案一的版权提醒

剪映素材库中没有“可商用”的下雨视频素材。如果你用于商业发布,存在侵权风险。

因此,方案一只适合个人练习。对于需要正式发布的内容,请看方案二。

方案二:使用代码生成素材(完全原创,可商用)

这个方案的核心思路是:用AI生成江南水乡视频,用代码生成纯黑背景的下雨视频和雨声,确保所有素材可商用、无版权风险

第一步:生成江南水乡风景视频

  1. 打开百度AI(或其他AI视频生成工具,如可灵AI、Runway等)。

  2. 输入提示词,例如:

    江南水乡,古镇,小桥流水,白墙黛瓦,烟雨朦胧,4K,电影质感

  3. 生成一两段满意的视频,下载到本地。

  4. 将视频导入剪映,拖拽到时间线。

第二步:用代码生成下雨视频

这里我们使用HTML/JavaScript代码生成纯黑背景的下雨动画。原理是用Canvas绘制雨滴,确保背景是严格的纯黑(RGB 0,0,0)。

<!DOCTYPE html>
<html>
<head>
    <style>
        body { margin: 0; overflow: hidden; background: black; }
        canvas { display: block; }
    </style>
</head>
<body>
    <canvas id="rainCanvas"></canvas>
    <script>
        const canvas = document.getElementById('rainCanvas');
        const ctx = canvas.getContext('2d');
        canvas.width = 1920;
        canvas.height = 1080;

        const drops = [];
        const dropCount = 800;

        for (let i = 0; i < dropCount; i++) {
            drops.push({
                x: Math.random() * canvas.width,
                y: Math.random() * canvas.height - canvas.height,
                length: Math.random() * 20 + 10,
                speed: Math.random() * 8 + 3,
                opacity: Math.random() * 0.5 + 0.3
            });
        }

        function draw() {
            // 纯黑色背景,保证滤色可用
            ctx.fillStyle = 'black';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            ctx.strokeStyle = 'white';
            ctx.lineWidth = 1.5;

            for (let drop of drops) {
                ctx.beginPath();
                ctx.moveTo(drop.x, drop.y);
                ctx.lineTo(drop.x + 2, drop.y + drop.length);
                ctx.strokeStyle = `rgba(255, 255, 255, ${drop.opacity})`;
                ctx.stroke();

                drop.y += drop.speed;

                if (drop.y > canvas.height + drop.length) {
                    drop.y = -drop.length;
                    drop.x = Math.random() * canvas.width;
                }
            }

            requestAnimationFrame(draw);
        }

        draw();
    </script>
</body>
</html>

使用方法

  1. 将以上代码保存为 rain.html

  2. 用浏览器打开,全屏(F11)

  3. 使用录屏软件(如Pixpin、OBS)录制10-20秒,保存为 rain_heavy.mp4

第三步:用代码生成下雨声

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>真正的雨声合成器</title>
    <style>
        body { background: #1a1a1a; color: white; font-family: system-ui; padding: 30px; }
        .container { max-width: 600px; margin: 0 auto; }
        button { background: #3b82f6; color: white; border: none; padding: 12px 24px; border-radius: 8px; font-size: 16px; cursor: pointer; margin-right: 10px; }
        button:hover { background: #2563eb; }
        .control { margin: 20px 0; }
        input[type=range] { width: 300px; }
        .note { color: #94a3b8; font-size: 14px; margin-top: 30px; border-top: 1px solid #334155; padding-top: 20px; }
    </style>
</head>
<body>
    <div class="container">
        <h1>🌧️ 真正的雨声合成器</h1>
        <p>专业级Web Audio雨声生成,无杂音,可商用</p>
        
        <div class="control">
            <button onclick="startRain()">开始下雨</button>
            <button onclick="stopRain()">停止</button>
            <button onclick="setRainType('light')">小雨</button>
            <button onclick="setRainType('medium')">中雨</button>
            <button onclick="setRainType('heavy')">大雨</button>
        </div>
        
        <div class="control">
            <label>雨量强度 <span id="intensityValue">50%</span></label><br>
            <input type="range" id="intensity" min="0" max="100" value="50" step="1" oninput="updateIntensity(this.value)">
        </div>
        
        <div class="note">
            <p><strong>原理说明</strong>:真正的雨声由三部分组成</p>
            <p>1️⃣ <strong>雨声基底</strong>:粉红噪声 + 带通滤波 (800-4000Hz) - 模拟雨落在地面的沙沙声</p>
            <p>2️⃣ <strong>雨滴颗粒</strong>:多组不同频率的短时脉冲 (800-5000Hz随机) - 模拟单个雨滴的噼啪声</p>
            <p>3️⃣ <strong>空间感</strong>:卷积混响 + 立体声扩散 - 模拟雨的空间包围感</p>
            <p>✅ 背景无电流杂音,声音自然,可无限循环</p>
        </div>
    </div>

    <script>
        let audioContext;
        let isPlaying = false;
        
        // 音频节点
        let noiseNode;
        let filterNodes = [];
        let gainNodes = [];
        let convolver;
        let pannerNodes = [];
        
        // 当前强度
        let currentIntensity = 50;
        
        // 初始化音频上下文(需要用户手势触发)
        function initAudio() {
            if (audioContext) return;
            
            audioContext = new (window.AudioContext || window.webkitAudioContext)();
            
            // 创建卷积混响(模拟空间感)
            createReverb();
        }
        
        // 创建卷积混响(真实的空间感)
        async function createReverb() {
            const sampleRate = audioContext.sampleRate;
            const length = sampleRate * 2; // 2秒混响
            const impulseResponse = audioContext.createBuffer(2, length, sampleRate);
            
            for (let channel = 0; channel < 2; channel++) {
                const channelData = impulseResponse.getChannelData(channel);
                for (let i = 0; i < length; i++) {
                    // 指数衰减的噪声,模拟房间混响
                    const decay = Math.exp(-i / (sampleRate * 0.3));
                    channelData[i] = (Math.random() * 2 - 1) * decay;
                }
            }
            
            convolver = audioContext.createConvolver();
            convolver.buffer = impulseResponse;
        }
        
        // 生成粉红噪声(比白噪声更自然)
        function createPinkNoise() {
            const bufferSize = 4096;
            const noise = audioContext.createScriptProcessor(bufferSize, 1, 1);
            
            let b0, b1, b2, b3, b4, b5, b6;
            b0 = b1 = b2 = b3 = b4 = b5 = b6 = 0.0;
            
            noise.onaudioprocess = function(e) {
                const output = e.outputBuffer.getChannelData(0);
                for (let i = 0; i < bufferSize; i++) {
                    const white = Math.random() * 2 - 1;
                    
                    // 粉红噪声滤波算法
                    b0 = 0.99886 * b0 + white * 0.0555179;
                    b1 = 0.99332 * b1 + white * 0.0750759;
                    b2 = 0.96900 * b2 + white * 0.1538520;
                    b3 = 0.86650 * b3 + white * 0.3104856;
                    b4 = 0.55000 * b4 + white * 0.5329522;
                    b5 = -0.7616 * b5 - white * 0.0168980;
                    
                    output[i] = b0 + b1 + b2 + b3 + b4 + b5 + b6 + white * 0.5362;
                    b6 = white * 0.115926;
                }
            };
            
            return noise;
        }
        
        // 创建雨声基底
        function createRainBase() {
            // 粉红噪声作为基础(比白噪声更自然)
            const pinkNoise = createPinkNoise();
            
            // 多个带通滤波器,模拟不同距离的雨声
            const filters = [];
            const gains = [];
            
            // 近处雨声 (高频成分)
            const filter1 = audioContext.createBiquadFilter();
            filter1.type = 'bandpass';
            filter1.frequency.value = 2000;
            filter1.Q.value = 1.5;
            filters.push(filter1);
            
            // 中距离雨声 (中频成分)
            const filter2 = audioContext.createBiquadFilter();
            filter2.type = 'bandpass';
            filter2.frequency.value = 1200;
            filter2.Q.value = 1.2;
            filters.push(filter2);
            
            // 远处雨声 (低频成分)
            const filter3 = audioContext.createBiquadFilter();
            filter3.type = 'bandpass';
            filter3.frequency.value = 600;
            filter3.Q.value = 1.0;
            filters.push(filter3);
            
            // 每个频段单独增益控制
            for (let i = 0; i < filters.length; i++) {
                const gain = audioContext.createGain();
                gain.gain.value = 0.15; // 基础增益
                gains.push(gain);
                
                pinkNoise.connect(filters[i]);
                filters[i].connect(gain);
            }
            
            return { source: pinkNoise, filters, gains };
        }
        
        // 创建雨滴颗粒(真正的噼啪声)
        function createRainDrops(count = 20) {
            const drops = [];
            const dropGains = [];
            
            for (let i = 0; i < count; i++) {
                // 为每个雨滴创建一个噪声发生器(不是共享的,这样才能产生独立的噼啪声)
                const dropNode = audioContext.createScriptProcessor(256, 1, 1);
                const gainNode = audioContext.createGain();
                
                // 随机参数
                const freq = 800 + Math.random() * 4200; // 800-5000Hz
                const duration = 0.02 + Math.random() * 0.06; // 20-80ms
                const pan = Math.random() * 2 - 1; // -1到1的立体声位置
                
                // 立体声定位
                const panner = audioContext.createStereoPanner();
                panner.pan.value = pan;
                
                let phase = 0;
                let envelope = 0;
                
                dropNode.onaudioprocess = function(e) {
                    const output = e.outputBuffer.getChannelData(0);
                    const input = e.inputBuffer.getChannelData(0);
                    
                    for (let j = 0; j < output.length; j++) {
                        if (phase < duration * audioContext.sampleRate) {
                            // 衰减振荡器模拟雨滴音色(不是简单的噪声)
                            const t = phase / audioContext.sampleRate;
                            const decay = Math.exp(-t * 20); // 快速衰减
                            
                            // 混合噪声和正弦波,让雨滴有音高感
                            const noise = (Math.random() * 2 - 1) * 0.7;
                            const tone = Math.sin(2 * Math.PI * freq * t) * 0.3;
                            
                            output[j] = (noise + tone) * decay;
                        } else {
                            output[j] = 0;
                        }
                        phase++;
                    }
                    
                    // 重置相位
                    if (phase >= duration * audioContext.sampleRate * 1.5) {
                        phase = 0;
                    }
                };
                
                dropNode.connect(gainNode);
                gainNode.connect(panner);
                
                dropGains.push(gainNode);
                drops.push({ node: dropNode, gain: gainNode, panner, baseGain: 0.05 + Math.random() * 0.1 });
            }
            
            return { drops, gains: dropGains };
        }
        
        // 开始下雨
        function startRain() {
            initAudio();
            
            if (isPlaying) return;
            
            // 恢复音频上下文(浏览器策略)
            if (audioContext.state === 'suspended') {
                audioContext.resume();
            }
            
            // 1. 创建雨声基底
            const base = createRainBase();
            noiseNode = base.source;
            filterNodes = base.filters;
            gainNodes = base.gains;
            
            // 2. 连接基底到输出
            const baseMixGain = audioContext.createGain();
            baseMixGain.gain.value = 0.4; // 基底音量
            
            gainNodes.forEach(gain => {
                gain.connect(baseMixGain);
            });
            
            // 3. 创建雨滴颗粒(20个独立雨滴发生器)
            const drops = createRainDrops(25);
            const dropGains = drops.gains;
            
            // 4. 连接雨滴到立体声扩散
            const dropsMixGain = audioContext.createGain();
            dropsMixGain.gain.value = 0.3;
            
            dropGains.forEach(gain => {
                // 通过立体声定位器
                if (gain.nextSterePanner) {
                    gain.nextSterePanner.connect(dropsMixGain);
                } else {
                    gain.connect(dropsMixGain);
                }
            });
            
            // 5. 混合基底和雨滴
            const masterGain = audioContext.createGain();
            masterGain.gain.value = 0.7; // 总音量
            
            baseMixGain.connect(masterGain);
            dropsMixGain.connect(masterGain);
            
            // 6. 添加混响效果(空间感)
            if (convolver) {
                masterGain.connect(convolver);
                convolver.connect(audioContext.destination);
            } else {
                masterGain.connect(audioContext.destination);
            }
            
            // 保存节点以便停止时清理
            window.activeNodes = {
                base, drops, masterGain, baseMixGain, dropsMixGain
            };
            
            isPlaying = true;
            
            // 根据当前强度设置音量
            updateIntensity(currentIntensity);
        }
        
        // 停止下雨
        function stopRain() {
            if (!isPlaying) return;
            
            if (window.activeNodes) {
                try {
                    // 断开所有连接
                    if (noiseNode && noiseNode.disconnect) {
                        noiseNode.disconnect();
                    }
                    
                    filterNodes.forEach(f => f.disconnect());
                    gainNodes.forEach(g => g.disconnect());
                    
                    if (window.activeNodes.drops) {
                        window.activeNodes.drops.drops.forEach(d => {
                            if (d.node && d.node.disconnect) d.node.disconnect();
                            if (d.gain && d.gain.disconnect) d.gain.disconnect();
                        });
                    }
                    
                    window.activeNodes.masterGain.disconnect();
                    window.activeNodes.baseMixGain.disconnect();
                    window.activeNodes.dropsMixGain.disconnect();
                } catch (e) {
                    console.log('停止时出错:', e);
                }
            }
            
            isPlaying = false;
        }
        
        // 更新强度
        function updateIntensity(val) {
            currentIntensity = val;
            document.getElementById('intensityValue').innerText = val + '%';
            
            if (!isPlaying || !window.activeNodes) return;
            
            // 强度映射
            const intensityFactor = val / 50; // 0-2之间
            
            // 调整基底音量(0.2-0.6)
            if (window.activeNodes.baseMixGain) {
                window.activeNodes.baseMixGain.gain.value = 0.2 + intensityFactor * 0.2;
            }
            
            // 调整雨滴音量(0.1-0.5)
            if (window.activeNodes.dropsMixGain) {
                window.activeNodes.dropsMixGain.gain.value = 0.1 + intensityFactor * 0.2;
            }
            
            // 调整滤波器频率(强度越大,高频越多)
            if (filterNodes.length >= 3) {
                filterNodes[0].frequency.value = 1500 + intensityFactor * 500; // 近处雨声
                filterNodes[1].frequency.value = 800 + intensityFactor * 400;  // 中距离
                filterNodes[2].frequency.value = 400 + intensityFactor * 200;  // 远处
            }
        }
        
        // 预设雨型
        function setRainType(type) {
            let val;
            switch(type) {
                case 'light': val = 30; break;
                case 'medium': val = 50; break;
                case 'heavy': val = 80; break;
            }
            document.getElementById('intensity').value = val;
            updateIntensity(val);
            
            if (!isPlaying) {
                startRain();
            }
        }
    </script>
</body>
</html>

使用方法

  1. 保存为 rain_sound.html

  2. 浏览器打开,点击“开始下雨”

  3. 用录屏软件录制音频(或使用系统录音工具)

  4. 保存为 rain_sound.mp3 或 .wav

  5. 我是用Pixpi录屏,然后导入剪映中分离出音频。

第四步:在剪映中合成

  1. 将第一步生成的江南水乡视频拖入时间线。

  2. 将第二步生成的 下雨视频 拖入时间线最上层轨道

  3. 选中下雨视频,点击 “画面” → “混合” → 选择“滤色”

  4. 按 Ctrl+B 分割工具,截取与江南水乡视频相同的时长。

  5. 将第三步生成的 下雨声音频 拖入时间线。

  6. 右键点击该音频,选择 “分离音频”

  7. 删除原视频轨道(只保留分离出的音频)。

  8. 按 Ctrl+B 截取与视频相同的时长。

  9. 添加背景音乐

    • 点击素材面板的 “音频” → “音乐素材”

    • 搜索“江南”或“古风”,选择一个可商用的轻音乐

    • 添加到时间线,拖动音频中间的白线(音量线)向下,降低背景音乐音量

第五步:添加文字标题

  1. 点击素材面板的 “文本” → “默认文本”,点击 + 号添加。

  2. 文字修改为:“江南水乡”

  3. 拖动文字轨道右边缘,使其与视频时长相同。

  4. 设置字体

    • 在功能面板点击 “字体”

    • 搜索 “金刚隶”(可商用字体)

    • 如有提示,先点击“可商用”筛选确保版权安全

  5. 设置字号和样式

    • 字号:15

    • 样式:选择 “枣红白边”(或类似效果)

  6. 添加动画

    • 点击 “动画” 选项卡

    • 入场动画:选择 “随机落下”

    • 出场动画:选择 “向右擦除”

  7. 精细调整动画时长

    • 选中“江南水乡”文本轨道

    • 点击 “动画”,看到两个滑块:

      • 左端滑块:控制入场动画时长

      • 右端滑块:控制出场动画时长

    • 向右拖动左端滑块,同时观察文本轨道下部的白线(代表入场动画持续时间)

    • 当白线到达轨道中间位置时停止

    • 向左拖动右端滑块,让出场动画的白线与入场动画的白线接近(中间留一小段静止时间)

第六步:添加诗句

  1. 再次点击 “文本” → “默认文本”,添加第二个文本轨道。

  2. 输入诗句:

闲梦江南梅熟日
夜船吹笛雨萧萧

  1. (可以分两行,或分两个轨道添加)

  2. 设置时长与视频相同。

  3. 设置字体、字号、样式(建议比标题小一些)。

  4. 添加合适的入场/出场动画(如“羽化向右”等)。

  5. 调整文字在画面中的位置(通常放在底部或左下角)。

第七步:预览与导出

  1. 点击播放按钮,预览整体效果。

  2. 检查:

    • 雨丝是否清晰叠加(滤色效果正常)

    • 雨声音量是否合适

    • 背景音乐是否压过了雨声

    • 文字动画是否自然

  3. 如需调整,微调各轨道参数。

  4. 满意后,点击右上角 “导出”

为什么AI生成的“黑色背景”下雨视频用滤色无效?

这是一个非常常见的问题。很多人在用AI生成下雨素材后,发现应用滤色模式时黑色背景无法去除,效果很差。

原因分析

滤色模式只认“纯黑”(RGB 0,0,0),而AI生成的视频存在两个问题:

问题 原因 后果
背景不是纯黑 AI生成视频在压缩编码时,黑色区域往往被处理成深灰色(如RGB 5,5,5)而非纯黑 滤色后背景无法完全透明,残留灰蒙蒙的底
雨丝不够亮 AI生成的雨丝偏灰,而非亮白 滤色后雨丝不明显,效果微弱
边缘有渐变 AI为了让雨丝边缘自然,会产生半透明过渡 滤色后出现脏兮兮的半透明轮廓

验证方法

把AI生成的下雨视频放到纯白色背景上:

  • 如果黑色背景部分完全消失 → 是纯黑

  • 如果能看到淡淡的灰色底 → 不是纯黑

解决方案

如果用AI生成下雨素材,需要做预处理:

  1. 在剪映中调整对比度(+50以上)

  2. 大幅降低阴影黑色色阶(-50到-80)

  3. 适当增加曝光让雨丝变亮

  4. 然后再应用滤色模式

最稳妥的方案:用代码生成(如本教程方案二),确保背景是严格的纯黑(RGB 0,0,0),导出时使用高质量编码,避免压缩算法破坏纯黑。


两种方案对比

维度 方案一(素材库) 方案二(代码生成)
操作难度 ⭐ 简单,几分钟完成 ⭐⭐⭐ 需要一点技术操作
效果可控性 ⭐⭐ 只能选现成素材 ⭐⭐⭐⭐⭐ 雨量、速度、方向都可控
版权风险 ⭐ 有侵权风险(无商用授权) ⭐⭐⭐⭐⭐ 完全原创,可商用
成本 免费但有风险 免费且安全
真实感 ⭐⭐⭐ 素材库的雨较假 ⭐⭐⭐⭐ 可调出暴雨的真实感

结语

通过本教程,你学会了:

  1. 滤色混合模式的原理和应用

  2. 两种制作暴雨效果的方法

  3. 用代码生成纯黑背景视频的技巧

  4. 文字动画的精细时长控制

  5. AI生成素材与滤色模式的兼容性问题

掌握这些技巧后,你可以举一反三,制作更多类型的特效视频——下雪、光效、粒子效果等,都可以用滤色模式叠加。

如果你在制作过程中遇到问题,欢迎在评论区留言交流。


计算机科学与技术 & 计算机网络技术:双专业课程体系完全导航指南

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐