| 
UID2积分8682帖子2905主题199论坛币13044 威望16 EP值2349 MP值15 阅读权限200注册时间2011-8-3在线时间2597 小时最后登录2024-8-28
 
   
 | 
5. 如何编写TCAS特效
| 5.1 什么是PIX 
 从上面的例子中, 我们看出TCAS特效离不开一种结构, PIX. 下面就来详解一下PIX.
 
 从宏观角度来看, PIX就是一张存放在内存中的图片, 至于图片的内容, 既可以是字符, 也可以是纹理, 或者就是单纯一张普通图片. PIX是编写TCAS特效要操作的主要对象. 作个类比, 在ASS中, 我们可以对文字或者绘图代码通过特效代码施加各种特殊效果, 如"{\blur2}好", 可以给"好"这个对象增加模糊效果. 在TCAS中, 我们可以使用各种PIX操作函数来操作PIX, 如PixBlur(PIX, 2), 可以返回一个新的PIX, 如果原来的PIX是一个写有"好"字的图片, 则返回的PIX效果就相当于"{\blur2}好"
 
 从微观角度来看, PIX就是一个Python的复合Tuple(元组)对象, 其具体结构如下:
 ((x, y), (width, height), (r, g, b, a, r, g, b, a, ....))
 PIX[0], 即(x, y), 保存的是这个PIX的相对位置信息
 PIX[1], 即(width, height), 保存的是这个PIX的宽高
 PIX[2], 即(r, g, b, a, r, g, b, a, ....), 保存的是实际像素信息, 存放方式是r, g, b, a(红, 绿, 蓝, 不透明度)四个一组, 按照行存储. 像素是一个重要概念, 如果对此还不太了解, 可以参考 http://zh.wikipedia.org/zh/像素
 PIX的内部细节可参考如下代码:
 补充: 关于PIX[2]的结构, 以及idx的计算.复制代码    # 像素字特效固定代码框架 开始
    PIX = TextPix(_Font, _txt)      # 获取当前文字的PIX结构
    initPosX = _x - int(_a / 2 + 0.5) + PIX[0][0]        # 第一个像素的X轴坐标
    initPosY = _y - int(_Fs / 2 + 0.5) + PIX[0][1]       # 第一个像素的Y轴坐标
    for h in range(PIX[1][1]):                           # 开始纵向扫描
        posY = initPosY + h                               # 当前像素Y轴坐标
        for w in range(PIX[1][0]):                       # 开始横向扫描
            posX = initPosX + w                           # 当前像素X轴坐标
            idx  = 4 * (h * PIX[1][0] + w)                # 脚标
            pixR = PIX[2][idx + 0]                        # 当前像素的红色分量
            pixG = PIX[2][idx + 1]                        # 当前像素的绿色分量
            pixB = PIX[2][idx + 2]                        # 当前像素的蓝色分量
            pixA = PIX[2][idx + 3]                        # 当前像素的透明度
            if pixA != 0:                                # 如果当前像素不为透明则进行如下操作
                # 增加你的效果, 注意Style使用Pix_Style
                ass_main(ASS_BUF, SubL(_start, _end, 0, Pix_Style), pos(posX, posY) + color1(FmtRGB(pixR, pixG, pixB)) + alpha1(255 - pixA), PixPt())
    # 像素字特效固定代码框架 结束
 
  (图片改为 忘却の小伊 的了)
 
 图片是由一个一个像素点构成的, 我们可以把它当做是放置于直角坐标系中的一个矩形. 如果我们固定矩形的左下角顶点为坐标原点, 则图片上的每一个像素点都对应一个整数坐标(x, y), 其中0<=x<width, 0<=y<height. 如图, 红色标示的像素点, 其坐标为(1, 2), 但我们用的是一维数组来存储这个二维图片, 并且是按照行来存储的, 也即, PIX[2]中的第0~(width-1)号元素存的是图片的第一行像素, width~(2*width - 1)号元素存的是第二行像素, 依次类推. 所以在PIX[2]中, 图片的红色点坐标可以转换为2 * 5 + 1. 之所以计算idx需要乘上4, 是因为对于一个像素点, 我们需要4个元素来分别存储它的红, 绿, 蓝, 不透明度分量.
 
 通常我们不需要关心PIX的细节, 因为PIX的操作函数是把PIX当做一个整体来操作的, 返回的结果仍然是一个PIX.
 
 
 5.2 如何得到PIX
 
 由基本函数构造原始PIX
 TextPix()函数, 可以由字符来构造PIX, 如 PIX = TextPix(Font, "你好"), 则PIX是一张包含"你好"二字的图片
 ImagePix()函数, 可以读入一张png格式的图片, 如 PIX = ImagePix(abspath('test.png')), 则PIX是一张包含test.png内容的图片
 BlankPix()函数, 可以构造一张纯色的图片, 如 PIX = BlankPix(width, height, MakeRGBA(255, 0, 0, 128)), 则PIX是一张红色的半透明图片
 util.cairo模块的surface.get_pix()函数可以由cairo的surface对象构造PIX
 util.magick模块的pmgToPix()函数可以由magick的image对象构造PIX
 
 由PIX操作函数转换已有PIX而得
 如PixBlur()等函数, 该类型函数可接受一个或多个PIX对象, 以及一些额外参数, 进行适当的变换后返回一个新的PIX对象.
 
 自己手动构造
 即, 不使用内部函数, 直接用Python脚本编写代码构造出一个满足条件的PIX对象. 需要对PIX的内部细节有较为详细的了解, 并熟悉Python的tuple及list等操作, 在此基础上, 就可以自由构造PIX对象了.
 
 
 5.3 TCAS特效相关函数参考
 
 tcaxLib.pyd模块文档
 编译版 (更适合查看)
 原始文档
 
 pixStone.pyd模板文档
 未整理, 仅作参考
 
 util.cairo模块文档
 Pycairo Documentation
 
 util.magick模板文档
 Magick++ Documentation
 
 
 5.4 实例教程
 
 完整工程下载:
  tcas_example.rar
(7.12 MB, 下载次数: 8365) 
 编写一个TCAS特效, 可以归结为创建PIX, 变换PIX, 将PIX写入文件, 这三个主要步骤, 额外的, 我们一般需要先利用InitFont()函数创建至少一个字体.
 
 教程实例代码如下:
 该代码中使用的函数的具体描述, 可以参考本教程的5.3节复制代码##################################################################
## 声明: 本脚本为TCAS特效使用教程所编写, 请广泛传播             ##
## 教程: http://www.tcax.org/forum.php?mod=viewthread&tid=220 ##
## 讨论: http://www.tcax.org/forum.php?mod=viewthread&tid=226 ##
## 版本: 1.0                                                    ##
## 作者: milkyjing                                              ##
## 日期: 2012-01-26                                             ##
##################################################################
##### 基本函数库, 必须包含 #####
from tcaxPy import *
##### 拓展函数库, 本特效需要包含 #####
from pixLibs.ImageStone import *
##### 初始化函数, 用于设定一些全局变量 #####
def tcaxPy_Init():
    ##### 声明全局变量 #####
    global _FD          # Frame Duration, 即一帧的长度, 单位是毫秒, 对于FPS=23.976的特效来说, _FD约为42毫秒
    global _Fs          # Font Size, 即字体大小
    global _Spacing     # 字体间距
    global Font         # 主要字体
    global FontOut      # 字体边框
    global PIX_tex1     # 纹理1, 因为本特效只用到两个静态纹理, 故直接在tcaxPy_Init()函数中定义以提高脚本执行效率
    global PIX_tex2     # 纹理2
    ##### 获取预定义的值 #####
    _FD          = 1000 / GetVal(val_FXFPS)
    _Fs          = GetVal(val_FontSize)
    _Spacing     = GetVal(val_Spacing)
    fontFileName = GetVal(val_FontFileName)    # 字体文件名
    faceID       = GetVal(val_FaceID)          # 字体face序号
    ##### 设置自定义变量的值 #####
    Font     = InitFont(fontFileName, faceID, _Fs, _Spacing, GetVal(val_SpaceScale), MakeRGB(0, 0, 0), 1, False)    # 通过InitFont()函数初始化一个字体
    FontOut  = InitFont(fontFileName, faceID, _Fs, _Spacing, GetVal(val_SpaceScale), MakeRGB(0, 0, 0), 5, True)     # 后三个参数分别为颜色, 边框厚度, 是否只保留边框
    PIX_tex1 = ImagePix(abspath('tex1.png'), _Fs, 0)    # 通过ImagePix()函数载入一张图片作为纹理, abspath()函数用于展开相对路径为绝对路径
    PIX_tex2 = ImagePix(abspath('tex2.png'))            # 后两个参数为目标宽高, 其中之一为0, 表示其值按照保持目标的宽高比不变, 自动进行计算
##### 结束函数, 用于一些收尾工作 #####
def tcaxPy_Fin():
    ##### 清理一些全局变量 #####
    FinFont(Font)        # 通过InitFont()函数创建的字体必须通过FinFont()函数进行销毁
    FinFont(FontOut)
##### 脚本主函数, 会对每个文字执行一次 #####
# _i                第_i句, 即当前操作的文字所在的句子序号
# _j                第_i句中的第_j个文字, 即当前操作文字在该行中的序号
# _n                第_i句中有_n个文字, 即当前句子所包含的文字数
# _start        句子的开始时间, 单位为10毫秒
# _end                句子的结束时间, 单位为10毫秒
# _elapk        到第_j个字经过的时间, _start + _elapk 到 _start + _elapk + _k 即为当前文字的存在时间, 单位为10毫秒
# _k                第_j个文字的卡拉OK时间, 单位为10毫秒
# _x                第_j个文字的水平坐标
# _y                第_j个文字的垂直坐标
# _a                第_j个文字的水平跨距, 可以看作文字的宽度, 同样_Fs也可近似看成文字的高度
# _txt                第_j个文字的内容
def tcaxPy_Main(_i, _j, _n, _start, _end, _elapk, _k, _x, _y, _a, _txt):
    ASS_BUF  = []        # 保存ASS特效
    TCAS_BUF = []        # 保存TCAS特效
    ##### 主要特效编写操作 #####
    # 基本坐标的计算
    dx = _x - int((_a + _Spacing) / 2 + 0.5)         # 一个固定操作, 将an5的坐标转换为an7
    dy = _y - int(_Fs / 2 + 0.5)                     # ASS特效默认采用an5坐标, TCAS特效则采用an7坐标
    if _i == 12:          # 因为时间上有重叠, 所以需要把这一句的坐标往下移一点, 使两句歌词不至于重叠显示
        dy += _Fs + 8
    # 基本时间的计算
    ts_0 = 10 * _start - _FD * 10    # 提前显示歌词, 提前量为10帧长度, "10 * _start"只是一个单位转换, ASS特效使用了两种时间单位, 10毫秒及1毫秒, TCAS特效则统一使用1毫秒为单位
    ts   = 10 * _start
    te   = 10 * _end
    te_0 = te + _FD * 5              # 延后量为5帧长度
    tm   = 10 * (_start + _elapk)    # 当前文字特效开始的时间
    # 构造原始PIX结构对象
    PIX_t   = TextPix(Font, _txt)                   # 通过TextPix()函数从文字构造PIX结构对象
    PIX_t   = PixTexture(PIX_t, PIX_tex1)           # 为PIX_t增加纹理
    PIX_out = TextPix(FontOut, _txt)                # 获取边框
    PIX_out = PixBlur(PIX_out, 6)                   # 增加模糊
    PIX_out = PixTexture(PIX_out, PIX_tex2)         # 增加纹理
    PIX_out = PixColorMul(PIX_out, 1, 1, 1, 0.8)    # 减少不透明度, 即增加透明度
    PIX_0   = CombinePixs(PIX_out, PIX_t)           # 混合文字主体和边框 (边框作底)
    # 入场效果, 移动(用到了简单的平面几何知识) + 模糊逐渐变清晰
    center = _n / 2 - 0.5      # 根据该公式5个字符的中心索引为2, 6个字符的中心索引为2.5, 因为索引是从0开始计算的
    x = dx + 50 * (_j - center) / center
    y = dy + 10
    for i in range(10):
        x = x + (dx - x) * (i + 1) / 5      # 逐帧修改坐标
        y = y + (dy - y) * (i + 1) / 5
        PIX = PixBlur(PIX_0, 40 - i * 4)    # 逐渐减少模糊度
        tcas_main(TCAS_BUF, PIX, ts_0 + _FD * i, ts_0 + _FD * (i + 1), x, y, 0)    # 通过tcas_main()函数向TCAS_BUF缓冲带增加一个PIX对象, 最后一个参数表示Layer, 含义与ASS特效中的Layer相同
    # 存在效果, 无特殊效果
    PIX = PIX_0
    tcas_main(TCAS_BUF, PIX, ts, te, dx, dy, 0)
    # 表现效果, 闪烁特效
    for dur in range(0, 10 * _k, int(2 * _FD)):
        PIX = pstSoftGlow(PIX_0, 10, 180, 180)    # 柔光效果, 该函数定义在pixStone.pyd模块中
        tcas_main(TCAS_BUF, PIX, tm + dur, tm + dur + _FD, dx, dy, 0)    # 隔一帧显示一次
    # 出场效果, 清晰变模糊 + 淡出
    for i in range(5):
        PIX = PixBlur(PIX_0, (i + 1) * 4)    # 逐渐增加模糊度
        PIX = PixColorMul(PIX, 1, 1, 1, 0.5 + 0.5 * (5 - i - 1) / 5)    # 逐渐减少不透明度, 即逐渐变得透明
        tcas_main(TCAS_BUF, PIX, te_0 - _FD * (5 - i), te_0 - _FD * (5 - i - 1), dx, dy, 0)
    ##### 将结果返回给TCAX进行处理 #####
    return (ASS_BUF, TCAS_BUF)
 
 
 
 | 
 |