项目中需要用skew做特效,但是3.x中移除了这个属性,想知道有没有大佬实现过分享下
1赞
类似这样
let skewX = 0, skewY = 0;
const wm = this.node.worldMatrix;
const tm = Mat4.toArray([], wm);
let a = tm[0], b = tm[1], c = tm[4], d = tm[5];
const ONE_DEGREE = Math.PI / 180;
let skx = Math.tan(skewX * ONE_DEGREE);
let sky = Math.tan(skewY * ONE_DEGREE);
if (skx === Infinity)
skx = 99999999;
if (sky === Infinity)
sky = 99999999;
tm[0] = a + c * sky;
tm[1] = b + d * sky;
tm[4] = c + a * skx;
tm[5] = d + b * skx;
Mat4.fromArray(wm, tm);
3赞
稍等,我试下
这个只能让节点自身3D翻转,我是希望节点及其所有子节点一起翻转。
所以需要skew配合scale来实现翻转效果
成功了,这个方法非常赞。
手工构建 skew矩阵,666.
有个瑕疵,这个只有在项目启动的时候生效。
如果在游戏中动态修改skewX和skewY就没有作用。
初步判断是节点初始化的时候会更新一次矩阵,但游戏中更新skewX和skewY没有通知底层节点矩阵更新了。
目前在解决这个问题。
如果要正式使用的话应该是类似这样
let skewX = 0, skewY = 0;
// 需要重置矩阵,否则重复 skew 时会在上次 skew 的基础上 skew
this.node._transformFlags |= TransformBit.SCALE;
// ...
// 标记当前帧的变动,通知 render component 更新位置
this.node.hasChangedFlags |= TransformBit.SCALE;
好,一会试试
自身能变换了,但是子节点不会跟着变换
尝试改完矩阵后,用 node.invalidateChildren(TransformBit.SCALE) 设置看看。
收到,我排查下。
@ccclass('HelloWorld')
export class HelloWorld extends Component {
start() {
let rootNode = this.node.getChildByName('RootNode');
const PI180 = Math.PI/180;
let skewX = 0,skewY = 0;
this.schedule(()=>{
skewY++;
let skX = Math.tan(skewX*PI180);
let skY = Math.tan(skewY*PI180);
(rootNode as any)._transformFlags |= TransformBit.SCALE;
rootNode.hasChangedFlags |= TransformBit.SCALE;
rootNode.updateWorldTransform();
let m = rootNode['_mat'],a = m.m00,b = m.m01,c = m.m04,d = m.m05;
m.m00 = a+c*skY;
m.m01 = b+d*skY;
m.m04 = c+a*skX;
m.m05 = d+b*skX;
for (const child of rootNode.children) { // 一起变要加上更新子节点
child.invalidateChildren(TransformBit.SCALE | TransformBit.ROTATION);
}
},0.1);
}
}
1赞
因为 setScale 内部会设置local scale,在下一帧会重新更新 world matrix 导致 你hack 的 matrix 失效。
import { _decorator, Component, Node, TransformBit } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('HelloWorld')
export class HelloWorld extends Component {
start() {
let rootNode = this.node.getChildByName('RootNode');
const PI180 = Math.PI / 180;
let skewX = 0, skewY = 0;
let scaleX = 1;
this.schedule(() => {
skewY++;
let skX = Math.tan(skewX*PI180);
let skY = Math.tan(skewY*PI180);
//如果下面两句注释放开,skew的变更会失效,因为TransformBit.SCALE冲突了
scaleX-=0.02;
rootNode.setScale(scaleX,scaleX);
(rootNode as any)._transformFlags |= TransformBit.SCALE;
rootNode.hasChangedFlags |= TransformBit.SCALE;
rootNode.updateWorldTransform();
let m = rootNode['_mat'],a = m.m00,b = m.m01,c = m.m04,d = m.m05;
m.m00 = a+c*skY;
m.m01 = b+d*skY;
m.m04 = c+a*skX;
m.m05 = d+b*skX;
for (const child of rootNode.children) { // 一起变要加上更新子节点
child.invalidateChildren(TransformBit.SCALE | TransformBit.ROTATION);
}
}, 0.1);
}
}
这样就可以了
1赞
还是存在我刚才说的这个问题:
只有skew单独改变有效
skew和scale一起变,skew会失效