已实现色彩调整代码,求gl-react/gl-react-native多图片贴纸方案
在gl-react/gl-react-native中实现贴纸多图片叠加功能
嘿,很高兴你已经搞定了图片色彩调整的部分!关于实现贴纸风格的多图片叠加,核心思路就是利用gl-react的嵌套Node组件+多层纹理混合渲染,我给你梳理具体的实现步骤和代码示例:
核心原理
gl-react的Node组件可以像普通React组件一样嵌套,每个Node可以绑定不同的纹理(图片资源),通过GLSL片段着色器控制每层图片的位置、缩放、透明度以及和下层图像的混合模式,最终在Surface中合成一张完整的叠加效果。
步骤1:创建贴纸渲染的Shader
首先我们需要一个处理贴纸的Shader,它负责接收贴纸纹理、位置、缩放、透明度等参数,同时处理贴纸与底层图像的混合:
import React, { Component } from "react"; import { Shaders, Node, GLSL, vec2 } from "gl-react"; import { Surface } from "gl-react-native"; const shaders = Shaders.create({ // 你已有的色彩调整Shader Saturate: { frag: GLSL` precision highp float; varying vec2 uv; uniform sampler2D t; uniform float contrast, saturation, brightness; const vec3 L = vec3(0.2125, 0.7154, 0.0721); void main() { vec4 c = texture2D(t, uv); // 补全色彩调整逻辑 vec3 brt = c.rgb * brightness; vec3 sat = mix(L, brt, saturation); vec3 con = (sat - 0.5) * contrast + 0.5; gl_FragColor = vec4(con, c.a); } `, }, // 新增的贴纸Shader Sticker: { frag: GLSL` precision highp float; varying vec2 uv; uniform sampler2D baseTexture; // 底层图像纹理 uniform sampler2D stickerTexture; // 贴纸纹理 uniform vec2 stickerPos; // 贴纸位置(0-1范围,基于画布) uniform vec2 stickerScale; // 贴纸缩放比例 uniform float opacity; // 贴纸透明度 void main() { // 获取底层图像颜色 vec4 baseColor = texture2D(baseTexture, uv); // 计算贴纸的UV坐标:将画布UV转换为贴纸自身的UV,处理位置和缩放 vec2 stickerUv = (uv - stickerPos) / stickerScale + 0.5; // 超出贴纸范围的部分不渲染(避免黑边) if (stickerUv.x < 0.0 || stickerUv.x > 1.0 || stickerUv.y < 0.0 || stickerUv.y > 1.0) { gl_FragColor = baseColor; return; } // 获取贴纸颜色 vec4 stickerColor = texture2D(stickerTexture, stickerUv); // 混合底层和贴纸颜色(正常混合模式,可按需修改) vec4 finalColor = mix(baseColor, stickerColor, stickerColor.a * opacity); gl_FragColor = finalColor; } `, }, });
步骤2:在组件中嵌套渲染多层图像
接下来在你的React组件中,用Surface作为渲染容器,先渲染经过色彩调整的底层图片,再在其上叠加贴纸Node(支持多个贴纸叠加):
class ImageEditor extends Component { render() { // 示例图片资源,替换成你自己的图片路径 const baseImage = require("./assets/base-photo.png"); const stickerImage = require("./assets/sticker.png"); // 贴纸参数:位置、缩放、透明度(可根据交互动态修改) const stickerParams = { stickerPos: vec2(0.2, 0.3), // 贴纸左上角在画布的相对位置 stickerScale: vec2(0.3, 0.3), // 贴纸缩放比例 opacity: 0.8, }; return ( <Surface style={{ width: 300, height: 300 }}> {/* 第一层:色彩调整后的底层图片 */} <Node shader={shaders.Saturate} uniforms={{ t: baseImage, contrast: 1.2, saturation: 1.5, brightness: 1.1, }} > {/* 第二层:贴纸,将底层图像作为baseTexture传入 */} <Node shader={shaders.Sticker} uniforms={{ baseTexture: Shaders.getChildOutput(), // 获取父级Node的渲染结果作为底层纹理 stickerTexture: stickerImage, ...stickerParams, }} > {/* 可以继续叠加更多贴纸Node */} {/* <Node shader={shaders.Sticker} uniforms={...} /> */} </Node> </Node> </Surface> ); } } export default ImageEditor;
关键细节说明
- 纹理传递:使用
Shaders.getChildOutput()可以获取父级Node的渲染结果,作为子Node的底层纹理,实现多层叠加。 - UV变换:通过
stickerPos和stickerScale参数,我们可以将画布的UV坐标转换为贴纸自身的UV,实现贴纸的位置和缩放控制。如果需要旋转,可以添加旋转矩阵参数在着色器中计算UV。 - 混合模式:示例中用
mix函数实现正常混合,你可以根据需求修改混合逻辑,比如正片叠底(baseColor * stickerColor)、滤色(1.0 - (1.0 - baseColor) * (1.0 - stickerColor))等。 - React Native图片加载:确保图片资源是gl-react-native支持的格式,可以直接传入
require()加载的本地图片,或者网络图片的URI。
交互扩展
如果需要实现贴纸的拖动、缩放、旋转交互,可以通过React的状态管理(比如useState或this.state)动态修改stickerPos、stickerScale等参数,结合react-native-gesture-handler之类的手势库监听用户手势事件,实时更新参数即可。
内容的提问来源于stack exchange,提问作者Green Eagle
相关产品推荐
相关产品推荐

