放大鏡縮小鏡效果
原理:根據縮放比例,判斷鏡面範圍內的點實際應該顯示哪個點的顏色值,問題就變成怎麼根據縮放比例進行座標轉換!
頂點着色器代碼不用修改。
片元着色器代碼如下:
CCProgram fs %{
precision highp float;
#include <alpha-test>
in vec4 v_color;
#if USE_TEXTURE
in vec2 v_uv0;
uniform sampler2D texture;
#endif
uniform inputData{
float scale; //縮放比例 0~1~2
float showRadius; //顯示半徑
vec2 imageSize; //圖片實際尺寸
vec2 point; //縮放中心點
};
//檢查pos點是否在顯示圓內
bool checkPointInCircle(vec2 pos){
//pos是ndc座標,轉換成實際座標
pos.x *= imageSize.x;
pos.y = (1.0 - pos.y)*imageSize.y;
//計算pos到point的距離
float distance = sqrt(pow(pos.x - point.x, 2.0) + pow(pos.y - point.y, 2.0));
return distance <= showRadius;
}
//根據縮放比例轉換座標
vec2 getPointTransition(vec2 pos){
vec2 uv = vec2(point.x/imageSize.x, 1.0 - point.y/imageSize.y);
uv.x = uv.x - (uv.x - pos.x)/scale;
uv.y = uv.y - (uv.y - pos.y)/scale;
return uv;
}
void main () {
vec4 o = vec4(1, 1, 1, 1);
#if USE_TEXTURE
if(checkPointInCircle(v_uv0)){
vec2 uv = getPointTransition(v_uv0);
if(uv.x > 1.0 || uv.x < 0.0 || uv.y > 1.0 || uv.y < 0.0){
//超出紋理範圍的用黑色填充
o = vec4(0, 0, 0, 1);
}else{
o *= texture(texture, uv);
if(o.a == 0.0){
//發現透明度爲0的座標,直接用黑色填充
o = vec4(0, 0, 0, 1);
}
}
}else{
//不在圓內的點直接獲取紋理
o *= texture(texture, v_uv0);
}
#if CC_USE_ALPHA_ATLAS_TEXTURE
o.a *= texture2D(texture, v_uv0 + vec2(0, 0.5)).r;
#endif
#endif
o *= v_color;
ALPHA_TEST(o);
gl_FragColor = o;
}
}%
腳本代碼如下:
const {ccclass, property} = cc._decorator;
@ccclass
export default class Cocos3 extends cc.Component {
@property(cc.Label)
label: cc.Label = null;
@property(cc.Slider)
slider: cc.Slider = null;
material: cc.Material = null;
scale: number = 1.0;
start () {
this.material = this.node.getComponent(cc.Sprite).getMaterial(0);
//設置初始縮放比例
this.material.setProperty("scale", this.scale);
//設置縮放顯示圓的半徑
this.material.setProperty("showRadius", 50.0);
//設置圖片寬高
this.material.setProperty("imageSize", cc.v2(this.node.width, this.node.height));
this.label.string = this.scale.toFixed(2);
this.slider.progress = 0.5;
this.slider.node.on("slide", this.sliderMoveCallBack, this);
this.node.on(cc.Node.EventType.TOUCH_MOVE, this.touchMoveCallBack, this);
}
// update (dt) {}
private sliderMoveCallBack(slider: cc.Slider)
{
this.scale = slider.progress*1.9 + 0.1;
this.label.string = this.scale.toFixed(2);
//修改縮放比例
this.material.setProperty("scale", this.scale);
}
private touchMoveCallBack(event: cc.Event.EventTouch){
//當前獲取到的觸摸點是相對於左下角爲原點的座標,
//需要經過一系列換算成相對於當前精靈左下角爲原點的座標。
let pos: cc.Vec2 = event.getLocation();
pos = pos.sub(cc.v2(cc.winSize.width/2, cc.winSize.height/2));
pos = pos.sub(this.node.getPosition());
pos = pos.add(cc.v2(this.node.getContentSize().width/2, this.node.getContentSize().height/2));
//修改縮放中心點
this.material.setProperty("point", pos);
}
}
效果圖如下: