HTML5のCanvasで簡易ソフトウェアレンダラ
こんなん
http://saggie.github.io/javascripts/renderer/
function main() { var canvas = document.getElementById('main'); var context = canvas.getContext('2d'); var sourcePolygon = { vertex: [ { x: -50, y: 50, z: -50 }, { x: 50, y: -50, z: -50 }, { x: -50, y: -50, z: 50 } ], color: [ { r: 255, g: 0, b: 0 }, { r: 0, g: 255, b: 0 }, { r: 0, g: 0, b: 255 } ] } function Vertex() { this.x = 0; this.y = 0; this.z = 0; } function Color(color) { this.r = color.r; this.g = color.g; this.b = color.b; } var angleX = parseInt(Math.random() * 180); var angleY = parseInt(Math.random() * 180); function toRadians(degrees) { return degrees * Math.PI / 180; } function rotatePolygonForX(sourcePolygon, numVertex, angle) { var rotatedPolygon = { vertex: [ new Vertex(), new Vertex(), new Vertex() ], color: [ new Color(sourcePolygon.color[0]), new Color(sourcePolygon.color[1]), new Color(sourcePolygon.color[2]) ] } var cos = Math.cos(toRadians(angle)); var sin = Math.sin(toRadians(angle)); for (var i = 0; i < numVertex; i++) { rotatedPolygon.vertex[i].x = sourcePolygon.vertex[i].x; rotatedPolygon.vertex[i].y = sourcePolygon.vertex[i].y * cos - sourcePolygon.vertex[i].z * sin; rotatedPolygon.vertex[i].z = sourcePolygon.vertex[i].y * sin + sourcePolygon.vertex[i].z * cos; } return rotatedPolygon; } function rotatePolygonForY(sourcePolygon, numVertex, angle) { var rotatedPolygon = { vertex: [ new Vertex(), new Vertex(), new Vertex() ], color: [ new Color(sourcePolygon.color[0]), new Color(sourcePolygon.color[1]), new Color(sourcePolygon.color[2]) ] } var cos = Math.cos(toRadians(angle)); var sin = Math.sin(toRadians(angle)); for (var i = 0; i < numVertex; i++) { rotatedPolygon.vertex[i].x = sourcePolygon.vertex[i].x * cos + sourcePolygon.vertex[i].z * sin; rotatedPolygon.vertex[i].y = sourcePolygon.vertex[i].y; rotatedPolygon.vertex[i].z = -sourcePolygon.vertex[i].x * sin + sourcePolygon.vertex[i].z * cos; } return rotatedPolygon; } function movePolygonToCenter(sourcePolygon, numVertex) { var movedPolygon = { vertex: [ new Vertex(), new Vertex(), new Vertex() ], color: [ new Color(sourcePolygon.color[0]), new Color(sourcePolygon.color[1]), new Color(sourcePolygon.color[2]) ] } for (var i = 0; i < numVertex; i++) { movedPolygon.vertex[i].x = sourcePolygon.vertex[i].x + canvas.width / 2; movedPolygon.vertex[i].y = sourcePolygon.vertex[i].y + canvas.height / 2; } return movedPolygon; } var xBufL = {}; var xBufR = {}; var rBufL = {}; var rBufR = {}; var gBufL = {}; var gBufR = {}; var bBufL = {}; var bBufR = {}; function scanEdge(vertex0, vertex1, color0, color1) { var span = Math.abs(parseInt(vertex1.y - vertex0.y)) + 1; var addx = (vertex1.x - vertex0.x) / span; var addy = (vertex1.y - vertex0.y) / span; var addr = (color1.r - color0.r) / span; var addg = (color1.g - color0.g) / span; var addb = (color1.b - color0.b) / span; var xi = vertex0.x; var yi = vertex0.y; var ri = color0.r; var gi = color0.g; var bi = color0.b; for (var i = 0; i < span; i++, xi += addx, yi += addy, ri += addr, gi += addg, bi += addb) { var px = parseInt(xi); var py = parseInt(yi); if (py < 0 || py > canvas.height) { continue; } if (xBufL[py] > px) { xBufL[py] = px; rBufL[py] = ri; gBufL[py] = gi; bBufL[py] = bi; } if (xBufR[py] < px){ xBufR[py] = px; rBufR[py] = ri; gBufR[py] = gi; bBufR[py] = bi; } } } function scanEdges(polygon) { scanEdge(polygon.vertex[0], polygon.vertex[1], polygon.color[0], polygon.color[1]); scanEdge(polygon.vertex[1], polygon.vertex[2], polygon.color[1], polygon.color[2]); scanEdge(polygon.vertex[2], polygon.vertex[0], polygon.color[2], polygon.color[0]); } function drawDot(x, y, color) { context.beginPath(); context.moveTo(x, y); context.lineTo(x, y+1); context.closePath(); context.strokeStyle = 'rgb(' + color.r + ', ' + color.g + ', ' + color.b + ')'; context.stroke(); } function render() { // clear the edge-bufferes for(var i = 0; i < canvas.height; i++) { xBufL[i] = Number.MAX_VALUE; xBufR[i] = Number.MAX_VALUE * -1; } // rotate and move the polygon var translatedPolygon = rotatePolygonForX(sourcePolygon, 3, angleX); translatedPolygon = rotatePolygonForY(translatedPolygon, 3, angleY); translatedPolygon = movePolygonToCenter(translatedPolygon, 3); scanEdges(translatedPolygon); // clear the screen context.clearRect(0, 0, canvas.width, canvas.height); context.strokeStyle = 'rgb(0, 0, 0)'; context.strokeRect(0, 0, canvas.width, canvas.height); // draw the polygon along with its edge-buffer for(var yi = 0; yi < canvas.height; yi++) { if (xBufL[yi] > xBufR[yi]) { continue; } var span = xBufR[yi] - xBufL[yi] + 1; var addr = (rBufR[yi] - rBufL[yi]) / span; var addg = (gBufR[yi] - gBufL[yi]) / span; var addb = (bBufR[yi] - bBufL[yi]) / span; var ri = rBufL[yi]; var gi = gBufL[yi]; var bi = bBufL[yi]; for (var xi = xBufL[yi]; xi <= xBufR[yi]; xi++, ri += addr, gi += addg, bi += addb ) { drawDot(xi, yi, { r: parseInt(ri), g: parseInt(gi), b: parseInt(bi) }); } } context.fillText("angleX: " + angleX % 360, 10, 10); context.fillText("angleY: " + angleY % 360, 10, 20); } function loop() { render(); angleX += 1; angleY += 2; } var flameRate = 30; var sleepTime = parseInt(1000 / flameRate); setInterval(loop, sleepTime); } main();