Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible improvements: realistic shadow and texture for backside #6

Open
taublast opened this issue Nov 5, 2023 · 0 comments
Open

Comments

@taublast
Copy link

taublast commented Nov 5, 2023

  1. When i ported the shader to be used in .net maui my shadow couldn't perform realistically on a background other than black, so i have corrected that by passing margins that surround the image. My texture to be folded consists of an image surrounded by transparent margins.. Maybe might be missing something, ready for that.

  2. Also wanted to have a backside texture to be shown when front texture curls. Could well be optional..

devenv_xFyDNzgFoW.mp4

Proposing to edit:
https://github.com/Rahiche/riveo_page_curl/blob/main/shaders/page_curl.frag

  1. shadow accounting for margins
  • adding uniform for backside texture
    uniform float4 iMargins;

  • using it in two places:
    inserting in the beginning of inRect:

    rct.y += iMargins.y; //topMargin;
    rct.w -= iMargins.w; //bottomMargin

then inside the main:

    float topMargin = iMargins.y; 
    float bottomMargin = iMargins.w;

and consuming it in line 111 replacing:
fragColor = vec4(0.0, 0.0, 0.0, 0.5);
with:

            float adjustedY = xy.y - topMargin;  
            float shadowHeight = max(0.0, min(1.0, (iResolution.y - bottomMargin - adjustedY) / (iResolution.y - topMargin - bottomMargin)));
            fragColor = vec4(0.0, 0.0, 0.0, 0.5 * shadowHeight);  
  1. backside texture
  • adding uniform for backside texture
    uniform sampler2D imageBackside;

  • using it in two places:
    line 106: fragColor = texture(imageBackside, p2 / resolution);
    line 122: fragColor = texture(imageBackside, p / resolution);

Unfortunately can't create a push myself as i never used flutter and my outdated v2 sksl couldn't be used by flutter, hoping the provided info will still be helpful.

Using skia v2 in .net (v3 bindings still in preview) and flutter might be using v3, so my script is just full of workarounds. Just for the fun of it:

uniform float2 iOrigin;  
uniform float4 iMouse;           // Mouse drag pos=.xy Click pos=.zw (pixels)
uniform float2 iResolution;      // Viewport resolution (pixels)
uniform float2 iImageResolution; // iImage1 resolution (pixels)
uniform shader iImage1;  // Texture
uniform shader iImage2;  // Texture for backside
uniform float2 iOffset;  // Top-left corner of DrawingRect
uniform float4 iMargins;  

const float cornerRadius = 0;

const float r = 150.0;  
const float scaleFactor = 0.2;  

const float  PI = 3.14159265359;
const vec4 backgroundColor = vec4(0.0, 0.0, 0.0, 0.0);

mat3 translate(vec2 p) {
    return mat3(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, p.x, p.y, 1.0);
}

mat3 scale(vec2 s, vec2 p) {
    return translate(p) * mat3(s.x, 0.0, 0.0, 0.0, s.y, 0.0, 0.0, 0.0, 1.0) * translate(-p);
}

vec2 project(vec2 p, mat3 m) {
    return (inverse(m) * vec3(p, 1.0)).xy;
}

float inRect(vec2 p, vec4 rct) {

    rct.y += iMargins.y; //topMargin;
    rct.w -= iMargins.w; //bottomMargin

    bool inRct = p.x > rct.x && p.x < rct.z && p.y > rct.y && p.y < rct.w;
    if (!inRct) {
        return 0.0;
    }
    // Top left corner
    if (p.x < rct.x + cornerRadius && p.y < rct.y + cornerRadius) {
        return length(p - vec2(rct.x + cornerRadius, rct.y + cornerRadius)) < cornerRadius ? 1.0 : 0.0;
    }
    // Top right corner
    if (p.x > rct.z - cornerRadius && p.y < rct.y + cornerRadius) {
        return length(p - vec2(rct.z - cornerRadius, rct.y + cornerRadius)) < cornerRadius ? 1.0 : 0.0;
    }
    // Bottom left corner
    if (p.x < rct.x + cornerRadius && p.y > rct.w - cornerRadius) {
        return length(p - vec2(rct.x + cornerRadius, rct.w - cornerRadius)) < cornerRadius ? 1.0 : 0.0;
    }
    // Bottom right corner
    if (p.x > rct.z - cornerRadius && p.y > rct.w - cornerRadius) {
        return length(p - vec2(rct.z - cornerRadius, rct.w - cornerRadius)) < cornerRadius ? 1.0 : 0.0;
    }
    return 1.0;
}

//------------------------------------------
half4 main(float2 fragCoord) {
//------------------------------------------

    // Margins uniform (left, top, right, bottom)  x, y, z, w 
    float topMargin = iMargins.y; 
    float bottomMargin = iMargins.w;

    float2 renderingScale = iImageResolution.xy / iResolution.xy;
	 float2 inputCoord = (fragCoord - iOffset) * renderingScale;

    float origin = iOrigin.x;          
    float pointer = iMouse.x;  // Animation parameter

    vec4 container = vec4(0.0, 0.0, iResolution.x, iResolution.y); // Covering the entire viewport
    vec2 center = iResolution.xy * 0.5;

    half4 fragColor = backgroundColor;
               
    vec2 xy = inputCoord;//fragCoord.xy;             
    float dx = origin - pointer;
    float x = container.z - dx;
    float d = xy.x - x;
   
    if (d > r) {
        fragColor = backgroundColor;
        if (inRect(xy, container) != 0) {
            fragColor.a = mix(0.5, 0.0, (d-r)/r);
        }
    }

    else
    if (d > 0.0) {
        float theta = asin(d / r);
        float d1 = theta * r;
        float d2 = (PI - theta) * r;

        vec2 s = vec2(1.0 + (1.0 - sin(3.14159265/2.0 + theta)) * 0.1);
        mat3 transform = scale(s, center);
        vec2 uv = project(xy, transform);
        vec2 p1 = vec2(x + d1, uv.y);

        s = vec2(1.1 + sin(PI / 2.0 + theta) * 0.1);
        transform = scale(s, center);
        uv = project(xy, transform);
        vec2 p2 = vec2(x + d2, uv.y);

        if (inRect(p2, container)!= 0) {

            fragColor = sample(iImage2, p2); //backside

        } else if (inRect(p1, container)!= 0) { //folded part

            fragColor = sample(iImage1, p1);
            fragColor.rgb *= pow(clamp((r - d) / r, 0.0, 1.0), 0.2);
        } 
        else if (inRect(xy, container)!= 0) {   //shadow
            
            float adjustedY = xy.y - topMargin;  
            float shadowHeight = max(0.0, min(1.0, (iResolution.y - bottomMargin - adjustedY) / (iResolution.y - topMargin - bottomMargin)));
            fragColor = vec4(0.0, 0.0, 0.0, 0.5 * shadowHeight);  
        }    
    }
    else {
        vec2 s = vec2(1.2);
        mat3 transform = scale(s, center);
        vec2 uv = project(xy, transform);
        vec2 p = vec2(x + abs(d) + PI * r, uv.y);

        if (inRect(p, container)!= 0) {
            fragColor = sample(iImage2, p); //continue backside
        } else {
            fragColor = sample(iImage1, xy);
        }

    }
           
    return fragColor;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant