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;
}
Tags
flip, page, turning
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

More from kcfresh53

Animated Diamond Pattern

Plasma waves

Related shaders

page flip turing

Transparent noise border

Transparent Ripples

Subscribe
Notify of
guest

7 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
ikuffer
ikuffer
9 months ago

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?

alsj97ty
alsj97ty
5 months ago
Reply to  ikuffer

See my solution bellow.

jduke99
5 months ago

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)

alsj97ty
alsj97ty
5 months ago
Reply to  jduke99

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

Last edited 5 months ago by alsj97ty
shinbo
shinbo
3 months ago
Reply to  alsj97ty

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

alsj97ty
alsj97ty
2 months ago
Reply to  shinbo

This itch.io asset uses the same setup. It works like a charm. Not free, tho.

edgyneer
edgyneer
1 month ago
Reply to  shinbo

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