Voie Lactée

Panorama

Depuis https://bl.ocks.org/mbostock/5446416 Avec une une image de l'ESO https://www.eso.org/public/images/eso0932a/ ATTENTION PAS DE PDF

Retour

Code Javascript

var vertex_shader = `
attribute vec2 a_position;

void main(void) {
  gl_Position = vec4(a_position, 0.0, 1.0);
}`;

var fragment_shader = `
precision mediump float;

uniform sampler2D u_image;
uniform vec2 u_translate;
uniform float u_scale;
uniform vec2 u_rotate;

const float c_pi = 3.14159265358979323846264;
const float c_halfPi = c_pi * 0.5;
const float c_twoPi = c_pi * 2.0;

float cosphi0 = cos(u_rotate.y);
float sinphi0 = sin(u_rotate.y);

void main(void) {
float x = (gl_FragCoord.x - u_translate.x) / u_scale;
float y = (u_translate.y - gl_FragCoord.y) / u_scale;

// inverse stereographic projection
float rho = sqrt(x * x + y * y);
float c = 2.0 * atan(rho);
float sinc = sin(c);
float cosc = cos(c);
float lambda = atan(x * sinc, rho * cosc);
float phi = asin(y * sinc / rho);

// inverse rotation
float cosphi = cos(phi);
float x1 = cos(lambda) * cosphi;
float y1 = sin(lambda) * cosphi;
float z1 = sin(phi);
lambda = atan(y1, x1 * cosphi0 + z1 * sinphi0) + u_rotate.x;
phi = asin(z1 * cosphi0 - x1 * sinphi0);

gl_FragColor = texture2D(u_image, vec2((lambda + c_pi) / c_twoPi, (phi + c_halfPi) / c_pi));
}`;


const width = 960, height = 540;

// Create the canvas
var canvas = document.createElement("canvas");
document.body.appendChild(canvas);
canvas.width = width;
canvas.height = height;

// Create the WebGL context, with fallback for experimental support.
var context = canvas.getContext("webgl") ||
    canvas.getContext("experimental-webgl");

// Compile the vertex shader.
var vertexShader = context.createShader(context.VERTEX_SHADER);
context.shaderSource(vertexShader, vertex_shader);

context.compileShader(vertexShader);
if (!context.getShaderParameter(vertexShader, context.COMPILE_STATUS)) throw new Error(context.getShaderInfoLog(vertexShader));

// Compile the fragment shader.
var fragmentShader = context.createShader(context.FRAGMENT_SHADER);
context.shaderSource(fragmentShader, fragment_shader);
context.compileShader(fragmentShader);
if (!context.getShaderParameter(fragmentShader, context.COMPILE_STATUS)) throw new Error(context.getShaderInfoLog(fragmentShader));

// Link and use the program.
var program = context.createProgram();
context.attachShader(program, vertexShader);
context.attachShader(program, fragmentShader);
context.linkProgram(program);
if (!context.getProgramParameter(program, context.LINK_STATUS)) throw new Error(context.getProgramInfoLog(program));
context.useProgram(program);

// Define the positions (as vec2) of the square that covers the canvas.
var positionBuffer = context.createBuffer();
context.bindBuffer(context.ARRAY_BUFFER, positionBuffer);
context.bufferData(context.ARRAY_BUFFER, new Float32Array([
    -1.0, -1.0,
    +1.0, -1.0,
    +1.0, +1.0,
    -1.0, +1.0
]), context.STATIC_DRAW);

// Bind the position buffer to the position attribute.
var positionAttribute = context.getAttribLocation(program, "a_position");
context.enableVertexAttribArray(positionAttribute);
context.vertexAttribPointer(positionAttribute, 2, context.FLOAT, false, 0, 0);

// Extract the projection parameters.
var translateUniform = context.getUniformLocation(program, "u_translate"),
    scaleUniform = context.getUniformLocation(program, "u_scale"),
    rotateUniform = context.getUniformLocation(program, "u_rotate");

// Load the reference image.
var image = new Image;
image.src = window.location.origin + "/storage/medias/images/Gj451bW9Sy97EdLtBpwdO85p02K9EQHbwOlw3HKe.jpg";
image.onload = readySoon;
self.onresize = resize;

// Hack to ensure correct inference of window dimensions.
function readySoon() {
    setTimeout(function() {
        resize();
        ready();
    }, 10);
}

function resize() {
    var width = Math.max(960, self.innerWidth),
        height = Math.max(500, self.innerHeight);
    canvas.setAttribute("width", width);
    canvas.setAttribute("height", height);
    context.uniform2f(translateUniform, width / 2, height / 2);
    context.uniform1f(scaleUniform, 500);
    context.viewport(0, 0, width, height);
}

function ready() {

    // Create a texture and a mipmap for accurate minification.
    var texture = context.createTexture();
    context.bindTexture(context.TEXTURE_2D, texture);
    context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MAG_FILTER, context.LINEAR);
    context.texParameteri(context.TEXTURE_2D, context.TEXTURE_MIN_FILTER, context.LINEAR_MIPMAP_LINEAR);
    context.texImage2D(context.TEXTURE_2D, 0, context.RGBA, context.RGBA, context.UNSIGNED_BYTE, image);
    context.generateMipmap(context.TEXTURE_2D);

    // The current rotation and speed.
    var rotate = [0, 0],
        speed = [-.001, .0004];

    redraw();

    // Rotate and redraw!
    function redraw() {
        rotate[0] += speed[0], rotate[1] += speed[1];
        context.uniform2fv(rotateUniform, rotate);
        context.bindTexture(context.TEXTURE_2D, texture); // XXX Safari
        context.drawArrays(context.TRIANGLE_FAN, 0, 4);
        requestAnimationFrame(redraw);
    }
}

// A polyfill for requestAnimationFrame.
if (!self.requestAnimationFrame) requestAnimationFrame =
    self.webkitRequestAnimationFrame ||
    self.mozRequestAnimationFrame ||
    self.msRequestAnimationFrame ||
    self.oRequestAnimationFrame ||
    function(f) {
        setTimeout(f, 17);
    };