PKTJ¸JuI¢”rr index.html clifford attractor WebGL版 - js do it PKTJ¸J 'u—€€index.js"use strict"; var canvas = undefined; var gl = undefined; // WebGL コンテキスト用のグローバル変数 var shaderProgram = undefined; var vboVertex = undefined; var vboColor = undefined; var attrLocations = []; var attrSizes = []; var uniLocations = []; var count = 30000; var vertexAlpha = 0.3; onload = function () { initGL(); initShaders(); initBuffers(); var factor = [0.5, 0.4, 0.6, 0.8]; var len = count * 2; var points = new Float32Array(len); var deg = Math.PI; var a = 2; var b = -1.5; var c = undefined; var d = undefined; var x = undefined, y = undefined; var tx = undefined, ty = undefined; var scale = 1 / 4; function animation() { // clifford attractor c = 2 * Math.cos(deg * factor[2]); d = 2 * Math.cos(deg * factor[3]); x = 0; y = 0; for (var n = 0; n < len; n += 2) { tx = Math.sin(a * y) + c * Math.cos(a * x); ty = Math.sin(b * x) + d * Math.cos(b * y); x = tx; y = ty; points[n] = x * scale; // 点が[-1,1]に入るように調整 points[n + 1] = y * scale; } deg += 0.005; // 画面をクリア gl.clear(gl.COLOR_BUFFER_BIT); // バッファへ頂点情報を転送して描画 //// 注意:大量の点情報を毎フレーム転送するので重くなる gl.bindBuffer(gl.ARRAY_BUFFER, vboVertex); gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW); gl.drawArrays(gl.POINTS, 0, count); requestAnimationFrame(animation); } animation(); }; function initGL() { // GLコンテキストを初期化 canvas = document.getElementById("glcanvas"); gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); if (!gl) { throw new Error("Unable to initialize WebGL. Your browser may not support it."); } gl.clearColor(0.0, 0.0, 0.0, 1.0); // 画面を黒でクリアするように設定 gl.enable(gl.BLEND); // ブレンディングを有効化 // ブレンドファクターを設定 //gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); // アルファブレンド gl.blendFunc(gl.SRC_ALPHA, gl.ONE); // 加算 } // シェーダーの初期化 function initShaders() { // シェーダをHTMLから読み込む var fragmentShader = getShader(gl, "shader-fs"); var vertexShader = getShader(gl, "shader-vs"); // シェーダプログラムを作成 shaderProgram = gl.createProgram(); // 2 つのシェーダをシェーダープログラムに接続してリンクする gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); // 正常にリンクされたか確認 if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { throw new Error("シェーダープログラムを初期化できません。"); } // シェーダプログラムをアクティブにする gl.useProgram(shaderProgram); // attribute変数の位置を取得し有効化 attrLocations[0] = gl.getAttribLocation(shaderProgram, "position"); attrLocations[1] = gl.getAttribLocation(shaderProgram, "color"); gl.enableVertexAttribArray(attrLocations[0]); gl.enableVertexAttribArray(attrLocations[1]); attrSizes[0] = 2; attrSizes[1] = 4; // uniform変数の位置を取得し値を設定する uniLocations[0] = gl.getUniformLocation(shaderProgram, "vertexAlpha"); gl.uniform1f(uniLocations[0], vertexAlpha); } // バッファオブジェクトを作成する function initBuffers() { // 頂点情報を格納するためのVBOを作成してバインド vboVertex = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vboVertex); // attributeを関連付ける gl.vertexAttribPointer(attrLocations[0], attrSizes[0], gl.FLOAT, false, 0, 0); // 色情報を格納するためのVBOを作成してバインド vboColor = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vboColor); // attributeを関連付ける gl.vertexAttribPointer(attrLocations[1], attrSizes[1], gl.FLOAT, false, 0, 0); //// 頂点情報はanimation()内で生成して転送 // 頂点毎の色情報を生成 var colors = []; for (var i = 0; i < count; i++) { // rgba colors.push(0, 0.5, 1, 1); } // 色情報を転送 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); } /* * Utils for WebGL */ // VBOを作成し、データを転送後にVBOを返す function createVBO(data) { // バッファを生成 var vbo = gl.createBuffer(); // バッファをコンテキストにバインド gl.bindBuffer(gl.ARRAY_BUFFER, vbo); // バッファへ頂点情報を渡す gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(data), gl.STATIC_DRAW); // バッファをアンバインド gl.bindBuffer(gl.ARRAY_BUFFER, null); return vbo; } // HTMLからシェーダープログラムを取り出し、コンパイルして返す。 function getShader(gl, id) { var script = document.getElementById(id); var source = script.innerText; var shader = undefined; // MIMEtypeに応じてシェーダーを作成する if (script.type == "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER); } else if (script.type == "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER); } else { throw new Error("unknown shader type: " + script.type); } // ソースをシェーダーに渡してコンパイル gl.shaderSource(shader, source); gl.compileShader(shader); // コンパイルが成功したかを確認 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { throw new Error("compileShader failed: " + gl.getShaderInfoLog(shader)); } return shader; } PKTJ¸JÆ«Ïèmm style.css* { margin: 0; padding: 0; border: 0; } body { background: #ffd; font: 30px sans-serif; }PKTJ¸JuI¢”rr ¶index.htmlPKTJ¸J 'u—€€¶šindex.jsPKTJ¸JÆ«Ïèmm ¶@style.cssPK¥Ô