پرش به محتوا

کاربر:Ebrahim/glsandbox2.js

از ویکی‌پدیا، دانشنامهٔ آزاد
نکته: برای دیدن تغییرات، ممکن است نیاز باشد که حافظهٔ نهانی مرورگر خود را پس از انتشار پاک‌سازی کنید. گوگل کروم، فایرفاکس، مایکروسافت اج و سافاری: کلید Shift را نگه دارید و روی دکمهٔ Reload در نوار ابزار مرورگر کلیک کنید. برای آگاهی از جزئیات و نحوهٔ پاک‌سازی حافظهٔ نهانی سایر مرورگرها، صفحهٔ ویکی‌پدیا:میانگیر مرورگرتان را خالی کنید را ببینید.
// Author: [[User:Ebrahim]]
document.getElementById('content').innerHTML = `<canvas id="canvas" width="640" height="480"></canvas>
<br>
<input type="checkbox" id="wireframe" onclick="onlyWireframe = this.checked"></option>
<label for="wireframe">Only wireframe?</label>
<br>
<input type="checkbox" id="rotation" onclick="gl.uniform1f(enableRotation, this.checked)"></option>
<label for="rotation">Rotation?</label>
<br>
Speed: <input id="number" type="number" value="0" onchange="gl.uniform1f(speed, this.value)">`;

var onlyWireframe = false;
var canvas = document.getElementById('canvas');
var gl = canvas.getContext('webgl');


// Build a vertex shader
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, `
precision mediump float;
attribute vec3 pos;
//varying vec3 colour;
uniform float time;
uniform bool enableRotation;
uniform float speed;
void main() {
  gl_Position = vec4(
    pos.x / 2.0 + sin(time * speed) / 2.0,
    pos.y / 2.0 + sin(time * speed * 1.5) / 2.0,
    pos.z / 2.0,
    1.0
  );
  if (enableRotation) {
    // https://www.cs.helsinki.fi/group/goa/mallinnus/3dtransf/3drot.html
    gl_Position *= mat4(
        1.0,        0.0,       0.0, 0.0,
        0.0,  cos(time), sin(time), 0.0,
        0.0, -sin(time), cos(time), 0.0,
        0.0,        0.0,       0.0, 1.0
    );
    
    gl_Position *= mat4(
        cos(time), 0.0, -sin(time), 0.0,
        0.0,       1.0,        0.0, 0.0,
        sin(time), 0.0,  cos(time), 0.0,
        0.0,       0.0,        0.0, 1.0
    );
    
    gl_Position *= mat4(
         cos(time), sin(time), 0.0, 0.0,
        -sin(time), cos(time), 0.0, 0.0,
        0.0,              0.0, 1.0, 0.0,
        0.0,              0.0, 0.0, 1.0
    );
  }
}
`);
gl.compileShader(vertexShader);


// Build a fragment shader
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, `
// http://glslsandbox.com/e#43762.0
precision mediump float;

uniform float time;
uniform bool wireframe;

const float color_intensity = 0.45;
const float Pi = 3.14159;

void main() {
  if (wireframe) {
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
    return;
  }

  vec2 p = gl_FragCoord.xy / 100.0;
  for (float i = 1.0; i < 9.0; i++) {
    vec2 newp = p;
    newp.x += 0.55 / i * sin(i * Pi * p.y + time * .01 + cos((time / (10. * i)) * i));
    newp.y += 0.55 / i * cos(i * Pi * p.x + time * .01 + sin((time / (10. * i)) * i));
    p = newp;
  }
  vec3 col = vec3(
    cos(p.x + p.y + 3.) * .5 + .5,
    sin(p.x + p.y + 6.) * .5 + .5,
    (sin(p.x + p.y + 9.) + cos(p.x + p.y + 12.)) * .25 + .5
  );
  gl_FragColor = vec4(col * col, 0.5);
}

`);
gl.compileShader(fragmentShader);


// Link vertex and fragment shader to form a program, a.k.a. graphic pipeline
var program = gl.createProgram();

gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);


// Create a uniform, a shared variable between CPU and GPU
var time = gl.getUniformLocation(program, 'time');
var enableRotation = gl.getUniformLocation(program, 'enableRotation');
var speed = gl.getUniformLocation(program, 'speed');
var wireframe = gl.getUniformLocation(program, 'wireframe');
var vertexBufferAttribute = gl.getAttribLocation(program, 'pos');


// Create and send our model to GPU as a buffer
// http://antongerdelan.net/opengl/images/colour_buffer.png
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
var vertices = [
    // Front
    0.0, 1.0, 0.0,
    -1.0, -1.0, 1.0,
    1.0, -1.0, 1.0,

    // Right
    0.0, 1.0, 0.0,
    1.0, -1.0, 1.0,
    1.0, -1.0, -1.0,
    
    // Back
    0.0, 1.0, 0.0,
    1.0, -1.0, -1.0,
    -1.0, -1.0, -1.0,

    // Left
    0.0, 1.0, 0.0,
    -1.0,-1.0,-1.0,
    -1.0,-1.0, 1.0
];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);


// Our game loop, a game loop should be as light as possible
setInterval(function () {
    // Clear our screen
    gl.clearColor(0.3, 0.3, 0.3, 1); // R, G, B, A
    gl.clear(gl.COLOR_BUFFER_BIT);

    // Select a pipeline, we created only one but on a real application there could many
    gl.useProgram(program);

    // Select a sent buffer as a model
    gl.enableVertexAttribArray(vertexBufferAttribute);
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.vertexAttribPointer(vertexBufferAttribute, 3, gl.FLOAT, false, 0, 0);

    // Set time on our pipeline so our GPU can have an understanding of time
    gl.uniform1f(time, (Date.now() / 1000) % 10000);

    // Now that everything is set, draw our shape
    // What TRIANGLES or LINE_STRIP mean?
    // See: http://antongerdelan.net/opengl/images/draw_modes.png
    if (!onlyWireframe) {
        gl.uniform1f(wireframe, false);
        gl.drawArrays(gl.TRIANGLES, 0, vertices.length / 3);
    }

    gl.uniform1f(wireframe, true);
    gl.drawArrays(gl.LINE_STRIP, 0, vertices.length / 3);

}, 1000 / 60);
// "1000 / 60" means 60 times per second, 60 Frame Per Second (FPS)