[HTML5] Canvasに描写 – キラキラ処理

Filed under 3D, HTML5, JavaScript



HTMLのCanvasを利用してキラキラさせてみました。

こんな感じになりました。

処理が重いのでマシンスペックが低い場合は注意してください。。

Canvasを2つ用意して、片方は「display:none;」にして見えなくしています。

以下、ソースです。

また、jsdo.itにも同じものを投稿しました(こちら)。

HTMLのソース(index.html)

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">
    <head>
        <title>Canvas sample 01 Simple 3D Pixels with KIRAKIRA !.</title>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8">
        <meta http-equiv="Content-Style-Type" content="text/css">
        <meta http-equiv="Content-Script-Type" content="text/javascript">
        <link rel="stylesheet" type="text/css" href="style.css"/>
        <script type="text/javascript" src="script.js"></script>
    </head>
    <body>
        <div id="wrapper">
        	<p>Source code is <a href = "src.zip">Here.</a></p>
        	<p>AS3 version:  <a href="http://wonderfl.net/c/rwYK">キラキラPixel3D! - wonderfl build flash online</a></p>
        	<canvas id="sCanvas" width="300" height="200"></canvas>
        	<canvas id="mainCanvas" width="600" height="400"></canvas>
        </div>
    </body>
</html>

JavaScriptのソース(script.js)

// 計算用の定数
var N_POINT=3000;
var RADIUS = 100;
var RADIAN = Math.PI / 180; 
var FOCUS = 280;
var A1 = 4.5;
var A2 = 1/4.5;
	
// 変数
var center_x;
var center_y;
var points;
var bmpd;
var bmpdArray;
var theta;
var i, j, p, xx, yy, zz, scale;
var mainCanvas;
var mainContext;
var sCanvas;
var sContext;
var mainWidth;
var mainHeight;
var sWidth;
var sHeight;

window.onload = function()
{
	mainCanvas = document.getElementById('mainCanvas');
	sCanvas = document.getElementById('sCanvas');
	
	if (! mainCanvas || ! mainCanvas.getContext || ! sCanvas || ! sCanvas.getContext) {return false;}
	else
	{
		mainWidth = mainCanvas.width;
		mainHeight = mainCanvas.height;
		sWidth = sCanvas.width;
		sHeight = sCanvas.height;
		center_x = (mainWidth * 0.5) | 0;
		center_y = (mainHeight * 0.5) | 0;
		theta = 0;
		points = [];
		
		// contextの初期化
		mainContext = mainCanvas.getContext('2d');
		sContext = sCanvas.getContext('2d');
		
		// 3Dポイントの初期化
		var theta1, theta2;
		for(i=0; i < N_POINT; i++)
		{
			theta1=360 * Math.random() * RADIAN;
			theta2=(180 * Math.random() - 90) * RADIAN;
			xx = RADIUS * Math.cos(theta2) * Math.sin(theta1);
			yy = RADIUS * Math.sin(theta2);
			zz = RADIUS * Math.cos(theta2) * Math.cos(theta1);
			points[i]=new Point3D(xx, yy, zz, "#00FF00");
		}
		
		// レンダリング開始
		setInterval("onFrame()", 30);
	}
}

function onFrame()
{
	mainContext.globalCompositeOperation = "source-over";
	mainContext.fillStyle = "#000000";	
	mainContext.fillRect(0,0,mainWidth, mainHeight);
	mainContext.globalCompositeOperation = "lighter";
	bmpd = mainContext.getImageData(0, 0, mainWidth, mainHeight);
	bmpdArray = bmpd.data;
	
	for(i=0 ; i < N_POINT; i++)
	{
		p=points[i];

		// 回転行列で回転 (x軸回転とy軸回転の積を展開したもの)
		xx=p.x * Math.cos(theta * RADIAN) + p.y * Math.sin(theta * RADIAN) * Math.sin(theta * RADIAN) - p.z * Math.sin(theta * RADIAN) * Math.cos(theta * RADIAN);
		yy=p.y * Math.cos(theta * RADIAN) + p.z * Math.sin(theta * RADIAN);
		zz=p.x * Math.sin(theta * RADIAN) - p.y * Math.sin(theta * RADIAN) * Math.cos(theta * RADIAN) + p.z * Math.cos(theta * RADIAN) * Math.cos(theta * RADIAN);
		         		  
		scale = FOCUS * 1.5 / (FOCUS - zz);
		xx = ((xx * scale)|0) + center_x;
		yy = ((yy * scale)|0) * (-1) + center_y;

		// 範囲内なら点を打つ
		if (xx >= 0 && yy >= 0 && xx < mainWidth && yy < mainHeight) 
		{
			j = (yy * mainWidth + xx)*4;
			bmpdArray[j] = p.cR;
			bmpdArray[j + 1] = 255;
			bmpdArray[j + 2] = p.cB;
			bmpdArray[j + 3] = 255;
		}
	}
	
	mainContext.putImageData(bmpd,0,0);
	theta ++;
	
	// キラキラ用のCanvas作成
	sContext.fillStyle = "#000000";	
	sContext.fillRect(0,0,sWidth, sHeight);
	sContext.scale(A2,A2);
	sContext.drawImage(mainCanvas, 0, 0);
	sContext.scale(A1,A1);
	
	// キラキラ
	mainContext.scale(A1,A1);
	mainContext.drawImage(sCanvas, 0, 0);
	mainContext.scale(A2,A2);
}

function Point3D(x, y, z, color)
{
	this.x = x;
	this.y = y;
	this.z = z;
	
	this.cR = Math.random() * 255;
	this.cB = Math.random() * 255;
}

CSSのソース(style.css)

*{
	margin:0;
	padding:0;
	border: none;
	text-decoration:none;
	list-style:none;
	font-size:100%;
	font-style:normal;
	font-weight:normal;
}
a:link 
{
	text-decoration:underline;
	color: #289000;
}
a:visited 
{
	text-decoration:underline;
	color: #599000;
}
a:hover 
{
	text-decoration:underline;
	color: #982000;
}
a:active 
{
	text-decoration:underline;
	color: #599000;
}
body {
	text-align:left;
	background-color:#ffffff;
}

#wrapper {
	font-size:14px;
	color: #555555;
	width: 600px;
	height:500px;
	margin-top:100px;
	margin-left : auto; 
	margin-right : auto ;
}

#mainCanvas {
	margin-top:5px;
	border: 1px solid #777777;
}

#sCanvas {
	display:none;
}

One Comment

  1. Posted 2016/08/09 at 03:35 | Permalink

    Great ingiths! That’s the answer we’ve been looking for.

Post a Comment

Your email is never published nor shared.