page flip with transparent background
This is an edited version of 50tu’s shader that fixes the tranparency issue.
This can be put in a _ready() function or the scale parameter can be set to 1 on both x and y:
material.set_shader_parameter("scale",global_scale)
the mouse position can be tied to your cursor or manually set and attached to an animation player to get your effect.
mousePos = event.position-global_position
Shader code
shader_type canvas_item;
uniform vec2 scale;
uniform vec2 mouse_pos = vec2(-1.,-1.);
vec2 Line2point(vec2 linePoint,vec2 lineDire,vec2 point) {
lineDire = normalize(lineDire);
vec2 line2Ori = - linePoint - dot(-linePoint,lineDire)*lineDire;
vec2 p2Ori = - point - dot(-point,lineDire)*lineDire;
return line2Ori-p2Ori;
}
vec4 ColorWithA(vec4 oldCol,vec4 newCol){
vec4 finalCol;
if((newCol.a + oldCol.a)>=1.)
{
finalCol.rgb = newCol.rgb ;
finalCol.a =1.0;
}
else{
finalCol.rgb = newCol.a/(newCol.a + oldCol.a)*newCol.rgb + oldCol.a/(newCol.a + oldCol.a)*oldCol.rgb;
finalCol.a = oldCol.a +newCol.a;
}
return finalCol;
}
void fragment() {
vec2 uv = UV;
// vec2 mouse_uv = mouse_pos ;
vec4 finalColor = vec4(0.0); // Initialize with transparent color
//拉伸变形校正
float scale_min = scale.x/scale.y;
vec2 uv_max = vec2(scale_min,1.);
float trueScale;
if(scale.y<scale.x){
scale_min = scale.y/scale.x;
uv.y = uv.y * scale_min;
uv_max = vec2(1.,scale_min);
// mouse_uv = mouse_pos * TEXTURE_PIXEL_SIZE /scale.x;
trueScale = scale.x;
}
else{
uv.x = uv.x*scale_min;
// mouse_uv = mouse_pos * TEXTURE_PIXEL_SIZE /scale.y;
trueScale = scale.y;
}
COLOR= texture(TEXTURE,uv);
//鼠标响应
vec2 pPos = uv / TEXTURE_PIXEL_SIZE * trueScale;
if (mouse_pos.x>-0.0001)
{
vec2 left_bottom = vec2(0.,uv_max.y/TEXTURE_PIXEL_SIZE.y * trueScale);
vec2 midpoint = (mouse_pos - left_bottom)/2. + left_bottom;
// vec2 midDirect = vec2(-1.,-1.)/1.414;
vec2 midDirect = normalize(vec2(-(mouse_pos-left_bottom).y,(mouse_pos-left_bottom).x));
//bg
//pageback
vec2 sharpPoint = vec2(0.,midpoint.y - midDirect.y/midDirect.x * midpoint.x);
vec2 flipEdgeDire = normalize(sharpPoint - mouse_pos);
//pagebackBottom
vec2 sharpPointB = vec2(midpoint.x-midDirect.x/midDirect.y * (midpoint-left_bottom).y,left_bottom.y);
vec2 flipEdgeDireB = normalize(sharpPointB - mouse_pos);
//圆柱
float cyOriOff = length(mouse_pos-left_bottom);
if (cyOriOff>100.) cyOriOff = 100.;//圆柱向里面缩进
float cyR = cyOriOff*2./PI;
float pageHDire = PI/6.;
vec2 midlineToP = Line2point(midpoint,midDirect,pPos);
vec2 sideEdgeToP = Line2point(mouse_pos,flipEdgeDire,pPos);
vec2 BottomEdgeToP = Line2point(mouse_pos,flipEdgeDireB,pPos);
vec2 cyOriToP = midlineToP - normalize(mouse_pos- left_bottom)*cyOriOff;
vec2 cyEdgeToP = midlineToP - normalize(mouse_pos- left_bottom)*(cyOriOff-cyR);
bool atBG = (cyOriToP).x<=-0.01;
bool atPageBack = !atBG&&(sideEdgeToP.y>0.)&&(BottomEdgeToP.x<=0.);
// bool atCy = (cyOriToP).x<=0.;
bool atCy = cyEdgeToP.x >=0. && (cyOriToP).x<=0.;
bool atCyPage = false;
vec2 uvCy ;
vec2 uvCyB ;
float shadow = 1.;
if (atCy){
vec2 cyOri = pPos-cyOriToP;
vec2 trueDis = cyR* asin(length(cyOriToP)/cyR)*normalize(cyOriToP);
vec2 truePos = cyOri+trueDis;
vec2 sideEdgeToTP = Line2point(mouse_pos,flipEdgeDire,truePos);
vec2 BottomEdgeToTP = Line2point(mouse_pos,flipEdgeDireB,truePos);
uvCyB = truePos * TEXTURE_PIXEL_SIZE /trueScale;
shadow *= 1.-pow(length(trueDis)/(cyR*PI/2.),3.);
if ((BottomEdgeToTP.x<0.)&& (sideEdgeToTP.y>0.))
{
atCyPage = true;
uvCy = vec2(length(sideEdgeToTP),left_bottom.y-length(BottomEdgeToTP))*TEXTURE_PIXEL_SIZE /trueScale;
}
if ((uvCyB.x > uv_max.x)||(uvCyB.y > uv_max.y)||(uvCyB.x <= 0.)|| (uvCyB.y <= 0.))
atCy =false;
}
//色彩
COLOR = vec4(0.);
// Page
if (!atBG && !atCy) {
vec4 color = texture(TEXTURE, uv);
finalColor = color;
}
// cyBottom
if (atCy) {
vec4 cyColor = texture(TEXTURE, uvCyB);
finalColor = cyColor;
}
if (atCyPage) {
vec4 cyPageColor = texture(TEXTURE, uvCy);
cyPageColor.xyz *= 0.8;
// Blend based on the alpha value of cyPageColor
finalColor = mix(finalColor, cyPageColor, cyPageColor.a);
} else if (atPageBack) {
uv = vec2(length(sideEdgeToP), left_bottom.y - length(BottomEdgeToP)) * TEXTURE_PIXEL_SIZE / trueScale;
vec4 pageBackColor = texture(TEXTURE, uv);
pageBackColor.xyz *= 0.8;
// Blend based on the alpha value of pageBackColor
finalColor = mix(finalColor, pageBackColor, pageBackColor.a);
}
COLOR = finalColor;
}
// Place fragment code here.
// FRAGCOORD.xy;
}
Awesome, interesting how you made it turn from the left corner. Is there a simple way to have it turn from the right corner instead?
See my solution bellow.
I have the same question as below. How can I get it to turn down from the top of the page? (sorry if this is obvious to do, couldn’t get it done from the params)
The easier way that I found is to use a viewport and play with the scale signs of the node displaying the viewport. For example, if you want to flip from the bottom-right to the upper-left, mirror the X-axis. Doing it like this, you don’t have to touch the shader code at all.
main
___TextureRect displaying viewport <—– mirror/flip_h here
___SubViewport
______Sprite2D <—- the shader goes here
This seems really cool and I’d love to use it but I’m uncertain how to setup the scene. I set one up similar to how you show in your diagram here, with TextureRect, SubViewport and Sprite2D but it’s not working. Any help would be appreciated
This itch.io asset uses the same setup. It works like a charm. Not free, tho.
I applied flip_h to Sprite2D instead. Works with SubViewport too. However, I’m using a Tween to activate the shader instead of using my cursor.
Here’s a demo project if you get in further trouble:
https://github.com/AltayCanOzsan/page-shader-godot