WebGL - 缩放到鼠标位置

时间:2016-05-15 14:35:58

标签: canvas opengl-es webgl opengl-es-2.0 fragment-shader

我试图找到一种方法,将我的场景缩放到用户鼠标所在的位置。我发送到我的片段着色器uniform float scale变量,并通过此变量乘以全景图和图像的坐标。但它只能缩放到画布中间。 Scale变量的值可以达到1.到0.2。

这是我的画布里面有全景和图像的场景:

<a href="https://s32.postimg.org/533grk1ol/anoscale.png">panorama</a><br>

这是我的片段着色器:

precision highp float;

uniform float used_img_width;        
uniform float used_img_height;       
uniform float used_pano_width;       
uniform float used_pano_height;      

uniform float yaw;      
uniform float pitch;    
uniform float roll;     
uniform float scale;    
uniform float hfov;     

varying vec2 screenPos;
uniform float cyl_radius;
uniform sampler2D foto;
uniform sampler2D panorama;
#define M_PI 3.1415926535897932384626433832795

mat4 makeTranslation(float tx, float ty, float tz) {
    return mat4(
         1.,  0.,  0.,  0.,
         0.,  1.,  0.,  0.,
         0.,  0.,  1.,  0.,
         tx, ty, tz, 1.
    );
}

mat4 makeZRotation(float angleInDegrees) {
    float angleInRadians = angleInDegrees * M_PI / 180.;
    float c = cos(angleInRadians);
    float s = sin(angleInRadians);
    return mat4(
         c, s, 0., 0.,
        -s, c, 0., 0.,
         0., 0., 1., 0.,
         0., 0., 0., 1.
    );
}

mat4 makeScale(float s) {
    return mat4(
        s, 0.,  0.,  0.,
        0., s,  0.,  0.,
        0.,  0., s,  0.,
        0.,  0.,  0., 1.
    );
}

mat4 myW2N(float ax, float ay, float zNear, float zFar) {
    float cx = 1.0 / ax;
    float cy = 1.0 / ay;
    float z0 = -zNear;
    float z1 = -zFar;
    float az = (z0 + z1) / (z0 - z1);
    float bz = (1. - az) * z0;
    return mat4(
        cx, 0., 0., 0.,
        0., cy, 0., 0.,
        0., 0., az, bz,
        0., 0., -1., 0.
    );
}

mat3 rotationW2R() {
    return mat3(
        0., 0., 1.,
        1., 0., 0.,
        0., 1., 0.
    );
}

void main() {

    float move_y = -1. * (pitch / (90. / (used_pano_height / used_img_height)));    // pro pohyb po y-ove ose
    float centre_y = pitch / 90.;
    float condition_width = (used_img_width*0.6) / (used_pano_width*0.5) + ((1.-scale)*0.5);
    float condition_height = (used_img_height*1.) / (used_pano_height*0.1) + (1.-scale);
    float yaw2 = yaw + 270.;

    if(yaw2 > 360.) yaw2 = yaw2 - 360.;
    if(yaw2 < 0.) yaw2 = 360.- yaw2;

    vec2 q = vec2(used_pano_width / used_img_width, used_pano_height / used_img_height);
    vec2 fotoCoord = screenPos * q * scale; // image zoom

    vec2 panoramaCoord = (screenPos * scale + 1.) * 0.5; // panorama zoom
    panoramaCoord.x += yaw2 / 360.;
    if( panoramaCoord.x > 1. )      panoramaCoord.x--;

    if( screenPos.x > condition_width || screenPos.x < -condition_width || screenPos.y > (centre_y + condition_height) ||
        screenPos.y < (centre_y - condition_height) ) {
        vec4 c = texture2D(panorama, panoramaCoord);
        gl_FragColor = vec4(c.rgb, 1.);
        return;
    }
    else {
        float a = fotoCoord.x;
        float z = fotoCoord.y;
        float radius = used_pano_width / (2. * M_PI);
        vec3 d =  rotationW2R() * radius * vec3(cos(a), sin(a), z);

        float hFOV = hfov * 0.1;        //TODO: based on EXIF
        float aspectRatio = 1.5;        //TODO: based on EXIF (used_img_width/used_img_height)
        float ax = tan(hFOV * M_PI);
        float ay = ax / aspectRatio;

        mat4 res = makeZRotation(roll) * makeTranslation(0., move_y, 0.) * myW2N(ax,ay,6.,2.);
        vec4 q1 = res * vec4(d, 1.);

        vec2 p = q1.xy / q1.w;
        p = 0.5 * (p + 1.0);

        if (q1.w < 0. || any(lessThan(p, vec2(0.0,0.0))) || any(greaterThan(p, vec2(1.0,1.0)))) {
            vec4 c = texture2D(panorama, panoramaCoord);
            gl_FragColor = vec4(c.rgb, 1.0);
            return;
        }

        vec4 c = texture2D(foto, p);
        gl_FragColor = vec4(c.rgb, 1.0);
        return;
    }
}

拜托,有什么方法可以解决它吗?

0 个答案:

没有答案