Sources
Main html file: | dhtml/inner-cube.html |
ge1doot mini library: | /library/ge1doot.js |
projective transformation: | http://math.stackexchange.com/questions/296794/finding-the-transform-matrix-from-4-projected-points-with-javascript |
CSS
html {
overflow: hidden;
-ms-touch-action: none;
-ms-content-zooming: none;
}
body {
position: absolute;
margin: 0px;
padding: 0px;
background: #000;
width: 100%;
height: 100%;
}
#screen {
position: absolute;
left:0;
top:0;
width: 100%;
height: 100%;
cursor: pointer;
background: #000;
overflow:hidden;
}
#screen img {
position:absolute;
visibility:hidden;
}
#screen .in {
}
HTML
<div id="screen">
<img id="i1" class="in" src="../images/monsieur-e.jpg" alt="">
<img id="i2" class="in" src="../images/monsieur-e.jpg" alt="">
<img id="i3" class="in" src="../images/monsieur-e.jpg" alt="">
<img id="i4" class="in" src="../images/monsieur-e.jpg" alt="">
<img id="i5" class="in" src="../images/monsieur-e.jpg" alt="">
<img id="i6" class="in" src="../images/monsieur-e.jpg" alt="">
<img id="i7" src="../images/monsieur-e.jpg" alt="">
<img id="i8" src="../images/monsieur-e.jpg" alt="">
<img id="i9" src="../images/monsieur-e.jpg" alt="">
<img id="i10" src="../images/monsieur-e.jpg" alt="">
<img id="i11" src="../images/monsieur-e.jpg" alt="">
<img id="i12" src="../images/monsieur-e.jpg" alt="">
</div>
JS
/* =======================================================
* ---- HTML5 CSS 3D projective transformation demo ----
* script: Gerard Ferrandez - 4 January 2015
* Released under the MIT license
* http://www.dhteumeuleu.com/LICENSE.html
* ======================================================= */
"use strict";
(function () {
/* ==== definitions ==== */
var pointer, scr, nw, nh, Xi = 0, Yi = 0, Zi = 0;
var cameraView = {
x: 0,
y: 0,
z: 140,
rotation: 0,
upAngle: 0,
xcos: 0,
xsin: 0,
ycos: 0,
ysin: 0,
zoom: 0,
rotate: function (rotation, upAngle) {
this.rotation = rotation;
this.upAngle = upAngle;
this.xcos = Math.cos(rotation);
this.xsin = Math.sin(rotation);
this.ycos = Math.cos(upAngle);
this.ysin = Math.sin(upAngle);
}
}
var Point = function (x, y, z) {
this.x = x;
this.y = y;
this.z = z;
this.X = 0;
this.Y = 0;
}
Point.prototype.project = function () {
var x = this.x;
var y = this.y;
var z = this.z;
var tx = cameraView.xcos * x - cameraView.xsin * z;
var tz = cameraView.xsin * x + cameraView.xcos * z;
x = tx;
z = tz;
var ty = cameraView.ycos * y - cameraView.ysin * z;
tz = cameraView.ysin * y + cameraView.ycos * z;
y = ty;
z = tz;
this.X = nw * 0.5 + ((cameraView.z * ((x * cameraView.zoom) - cameraView.x) / (cameraView.z + z))) + cameraView.x;
this.Y = nh * 0.5 + ((cameraView.z * ((y * cameraView.zoom) - cameraView.y) / (cameraView.z + z))) + cameraView.y;
}
var Polygon = function (points, id) {
this.points = [];
for (var i = 0, n = points.length; i < n; i++) {
this.points.push(listPoints.points[points[i]]);
}
this.img = new CSS3Dtransform(document.getElementById(id));
}
Polygon.prototype.draw = function () {
var
x0 = this.points[0].X,
y0 = this.points[0].Y,
x1 = this.points[1].X,
y1 = this.points[1].Y,
x2 = this.points[2].X,
y2 = this.points[2].Y,
x3 = this.points[3].X,
y3 = this.points[3].Y;
if ((x1-x0)*(y2-y0) < (x2-x0)*(y1-y0)) {
this.img.elem.style.visibility = "hidden";
} else {
this.img.elem.style.visibility = "visible";
this.img.transform(x0, y0, x1, y1, x2, y2, x3, y3);
}
}
var listPoints = {
points: [],
add: function (p) {
this.points.push(new Point(p[0], p[1], p[2]));
},
project: function () {
for (var i = 0, n = this.points.length; i < n; i++ ) {
this.points[i].project();
}
}
}
var listPolygons = {
polygons: [],
add: function (points, id) {
this.polygons.push(new Polygon(points, id));
},
draw: function () {
for (var i = 0, n = this.polygons.length; i < n; i++ ) {
this.polygons[i].draw();
}
}
}
var CSS3Dtransform = function (element) {
this.elem = element;
this.w = element.offsetWidth;
this.h = element.offsetHeight;
var t = ["transform", "msTransform", "MozTransform", "WebkitTransform", "OTransform"];
for (var test, i = 0; test = t[i++];) {
if (typeof document.body.style[test] != "undefined") {
this.CSSTransform = test;
break;
}
}
this.elem.style[this.CSSTransform+"Origin"] = "0 0";
}
CSS3Dtransform.prototype.transform = function (x1, y1, x2, y2, x3, y3, x4, y4) {
// projective transformation
// reference: http://math.stackexchange.com/questions/296794/finding-the-transform-matrix-from-4-projected-points-with-javascript
var v0, v1, v2;
var m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15, m16, m17, m18, m19, m20, m21, m22, m23;
var a0, a1, a2, a3, a4, a5, a6, a7, a8, b0, b1, b2, b3, b4, b5, b6, b7, b8;
v0 = (y2-y3)*x4+(x3-x2)*y4+(x2*y3-x3*y2);
v1 = (y3-y1)*x4+(x1-x3)*y4+(x3*y1-x1*y3);
v2 = (y1-y2)*x4+(x2-x1)*y4+(x1*y2-x2*y1);
m1 = (x1+x2+x3-y1-y2-2)*v1;
m2 = (x1-y1)*v1;
m3 = y2*(-v0-v1+v2);
m4 = (-x1+y1+y2)*(v0+v1);
m5 = -(y1+y2)*v0;
m6 = x1*v0;
m7 = (-x1+2)*v0;
m9 = -2*v0;
m11 = -v0-v1;
m12 = (-x3+2)*v1;
m13 = (x3-1)*v1;
m16 = -(-x3+y2+y3)*v2;
m17 = -(x3-y3)*v2;
m18 = (y2+y3)*v2;
a0 = m6;
a1 = m1+m4+m5+m6+m12;
a2 = m6+m7+m9+m16+m18;
a3 = m2+m3+m4+m6+m16+m17;
a4 = m2+m4+m5+m6;
a5 = m16+m17+m18;
a6 = m6+m7+m11+m12+m13;
a7 = m12+m13;
a8 = m6+m7+m9+v2;
b0 = this.h;
b2 = -this.w*this.h;
b4 = -this.w;
m1 = (a0+a1+a2-a3-a4-a7-a8)*b4;
m2 = (a0-a3)*b4;
m3 = -a4*b4;
m4 = (-a0+a3+a4)*(b0+b4);
m5 = -(a3+a4)*b0;
m6 = a0*b0;
m7 = (-a0+a6+a7)*(b0-b2);
m8 = (-a0+a6)*b2;
m9 = (a6+a7)*(-b0+b2);
m11 = a7*b2;
m15 = (a7+a8)*b4;
m19 = a1*b0;
m20 = a5*b4;
m21 = a3*b2;
a8 = m6+m7+m8+m9;
a0 = (m6+m19)/a8;
a1 = (m1+m4+m5+m6+m15)/a8;
a2 = (m6+m7+m9)/a8;
a3 = (m2+m3+m4+m6)/a8;
a4 = (m2+m4+m5+m6+m20)/a8;
a5 = m21/a8;
a6 = (m6+m7+m8+m11)/a8;
a7 = m15/a8;
var t = "matrix3d(" +
a0 + ", " + a3 + ", 0, " + a6 + ", " +
a1 + ", " + a4 + ", 0, " + a7 + ", 0, 0, 1, 0, " +
a2 + ", " + a5 + ", 0, 1)";
this.elem.style[this.CSSTransform] = t;
}
// ---- init section ----
var init = function (param) {
// ---- init screen ----
scr = new ge1doot.Screen({
container: "screen",
resize: function () {
nw = scr.width;
nh = scr.height;
cameraView.zoom = nw / 170;
}
});
scr.resize();
// ---- init pointer ----
pointer = new ge1doot.Pointer({
});
// ---- init param ----
for (var i = 0; i < param.points.length; i++) {
listPoints.add(param.points[i]);
}
for (var i = 0; i < param.poly.length; i++) {
listPolygons.add(param.poly[i][0], param.poly[i][1]);
}
// ---- start ----
cameraView.rotate(0, 0);
run();
}
// ---- main loop ----
var run = function () {
Xi += (pointer.Xi - Xi) / 10;
Yi += (pointer.Yi - Yi) / 10;
cameraView.rotate(Zi + Xi / 100, Zi / 4 + Yi / 100);
listPoints.project();
listPolygons.draw();
Zi += 0.01;
requestAnimFrame(run);
};
return {
// --- load data ----
load : function (p) {
window.addEventListener('load', function () {
init(p);
}, false);
}
}
})().load({
points: [
[-80,-80,80],[80,-80,80],[80,80,80],[-80,80,80],[-80,-80,-80],[80,-80,-80],[80,80,-80],[-80,80,-80],
[-15,-15,15],[15,-15,15],[15,15,15],[-15,15,15],[-15,-15,-15],[15,-15,-15],[15,15,-15],[-15,15,-15]
],
poly: [
[[0, 1, 2, 3], "i1"],[[1, 5, 6, 2], "i2"],[[4, 0, 3, 7], "i3"],[[5, 4, 7, 6], "i4"],[[7, 3, 2, 6], "i5"],[[5, 1, 0, 4], "i6"],
[[9, 8, 11, 10], "i7"],[[13, 9, 10, 14], "i8"],[[8, 12, 15, 11], "i9"],[[12, 13, 14, 15], "i10"],[[14, 10, 11, 15], "i11"],[[12, 8, 9, 13], "i12"]
]
});