找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 236|回复: 1

[教程] 【变换组件】3D倾斜

[复制链接]
发表于 2026-4-21 14:29:55 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

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

×
本帖最后由 Maz马 于 2026-5-2 20:58 编辑

写了一个类3D正倾斜效果的transform
预览

                               
登录/注册后可看大图

变换组件
    鼠标视差
    3D 倾斜
    边缘渐变

效果类似于3D舞台中的RotateMatrix(),即绕着某一轴做3d旋转
但是应用了3d舞台后的一些组件会失去交互功能,例如按钮(原理暂时不明,我对3d舞台没有过多了解)
因为这个原因使用Shader来进行模仿

因为透视形变是UI,UX美术中非常泛用的功能,却没有看人做过
更多的替代方案是直接photoshop启动,输出具有透视的图片

用了shader之后就可以应用在screen下的容器,按钮,并维持交互
但是本质上是shader,所以按钮的矩形交互区域尺寸并没有实际改变,只是视觉欺骗
如果需求十分严谨的话也可以使用按钮自带的focus_mask特性callable来计算(未尝试)
[RenPy] 纯文本查看 复制代码
init python:
    # 3D倾斜
    renpy.register_shader("Maz.Side3D",
        variables = """
            uniform sampler2D tex0;
            uniform float u_s3d_t;
            uniform float u_s3d_d;
            uniform float u_s3d_s;
            attribute vec2 a_tex_coord;
            varying vec2 v_tex_coord;
        """,
        vertex_300="""
            v_tex_coord = a_tex_coord;
        """,
        fragment_300="""
            vec2 uv = v_tex_coord;
            vec2 final_uv = uv;
            
            float depth = max(u_s3d_d,0.001);
            //不允许向外倾斜,向外倾斜应该使用对边,否则内容会被裁切
            float tilt = max(u_s3d_t,0.0);
            
            if (u_s3d_s == 1.0) {
                float slope = 1.0 - tilt * uv.x;
                float tilted_y = (uv.y - 0.5) / slope + 0.5;
                float contracted_x = uv.x / depth;
                final_uv = vec2(contracted_x,tilted_y);
            }
            else if (u_s3d_s == 2.0) {
                float slope = 1.0 - tilt * (1.0 - uv.x);
                float tilted_y = (uv.y - 0.5) / slope + 0.5;
                float contracted_x = 1.0 - (1.0 - uv.x) / depth;
                final_uv = vec2(contracted_x,tilted_y);
            }
            else if (u_s3d_s == 3.0) {
                float slope = 1.0 - tilt * uv.y;
                float tilted_x = (uv.x - 0.5) / slope + 0.5;
                float contracted_y = uv.y / depth;
                final_uv = vec2(tilted_x,contracted_y);
            }
            else if (u_s3d_s == 4.0) {
                float slope = 1.0 - tilt * (1.0 - uv.y);
                float tilted_x = (uv.x - 0.5) / slope + 0.5;
                float contracted_y = 1.0 - (1.0 - uv.y) / depth;
                final_uv = vec2(tilted_x,contracted_y);
            }
            
            if (final_uv.x < 0.0 || final_uv.x > 1.0 || final_uv.y < 0.0 || final_uv.y > 1.0) {
                gl_FragColor = vec4(0.0);
            } else {
                gl_FragColor = texture2D(tex0,final_uv);
            }
        """)

transform MDX_s3d:
    # 可选:
    # 压缩图片时,临近像素颜色混合,会逐渐模糊
    # 可以使用近邻取样(nearest-neighbor)过滤绘制来强化锐利边缘,但锯齿强烈的演出效果不如模糊...
    nearest True
    # 必须:
    # 应对shader无法正确处理网格顶点的容器组件,例如Fixed(),或Solid()这种不是容器但同样处理不了顶点的
    # 同时,打开后可以把子组件压成纹理,即整个组件整体应用,而不是每个子组件分别应用
    mesh True
    shader 'Maz.Side3D'
    u_s3d_s 1     # side  轴向边,1234对应左右上下
    u_s3d_t 0.0   # tilt  倾斜度
    u_s3d_d 1.0   # depth 纵深度
    linear 3.0 u_s3d_t 0.5 u_s3d_d 0.5
    linear 3.0 u_s3d_t 0.0 u_s3d_d 1.0
    repeat

#测试

screen abc():
    fixed:
        align(0.5,0.5)
        xysize(500,400)
        at MDX_s3d
        frame:
            xysize(500,400)
    fixed:
        align(0.55,0.55)
        xysize(500,400)
        at MDX_s3d
        vbox:
            text _("{size=68}画廊{/size}"):
                outlines [ (1, "#f00", 0, 0 ) ]
            textbutton "text" action NullAction()


额外内容:
我查阅了RotateMatrix()的源码
但也许由于我对矩阵以这类内容水平低下...效果十分奇怪
然后查阅了另一篇使用矩阵模仿3D的效果shader帖子,效果也很奇怪
都没能复现RotateMatrix(),在重复调试后无果,所以就放弃矩阵了

使用2D的思维,也就是实际上是两边分别倾斜,对边靠近,即宽度缩减的方式来模拟透视效果
虽然在数值上更加可控,但对3D来说是不严谨的...

但总归是搓出一个看起来是那么回事的东西(

#点击头像 查看我写的更多屎
粉身碎骨浑不怕,要留答辩在人间












评分

参与人数 2活力 +300 干货 +6 收起 理由
ZYKsslm + 3 鼓励原创!
被诅咒的章鱼 + 300 + 3 感谢分享!

查看全部评分

发表于 2026-4-22 10:46:12 | 显示全部楼层
本帖最后由 被诅咒的章鱼 于 2026-4-22 13:49 编辑

这个厉害了!我要偷来用……

另外,查了下使用 matrixtransform 导致组件不接受鼠标事件的问题。
Tom在 issue#6424 中解释,目前使用3D变换后的东西都不能获得焦点,也就不处理任何鼠标事件。
回复 支持 1 抱歉 0

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|RenPy中文空间 ( 苏ICP备17067825号 )

GMT+8, 2026-5-18 01:56 , Processed in 0.019776 second(s), 8 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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