Last active
August 29, 2015 14:06
-
-
Save Akiyah/1ddf2fac50f4bcebea45 to your computer and use it in GitHub Desktop.
forked: レイトレーシング練習
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
todo: | |
* -影をぼんやりさせる- | |
* 押しているモノも表示する | |
* へこみ関数の最適化(押した感じにする) | |
* シワをつける(丸くする) | |
* -倍精度で計算する- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html { | |
height:100%; | |
} | |
body { | |
background: gray; | |
width:100%; | |
height:100%; | |
overflow : hidden; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<span class="building">準備中</span><br/> | |
<img id="image" src="http://jsrun.it/assets/z/M/0/K/zM0Kl.jpg" /> | |
<br/> | |
<div id="shadow_div" style="position:absolute; display:none; border:solid 0px red; overflow:hidden; width:200px; height:200px;"> | |
<canvas id="shadow" style="width:200px; height:2000px;" width="200px" height="2000px"></canvas> | |
</div> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var HOLE_SIZE = 50/2; | |
var HOLE_DEPTH = 50*2; | |
var SHADOW_BOX_SIZE = 100; | |
var light = [-1,1,-1]; | |
function innerProduct(p, q) { | |
return p[0]*q[0] + p[1]*q[1] + p[2]*q[2]; | |
} | |
function multi(p, a) { | |
return [p[0]*a, p[1]*a, p[2]*a]; | |
} | |
function norm(p) { | |
return Math.sqrt(innerProduct(p, p)); | |
} | |
function cos(v, w) { | |
return innerProduct(v, w)/norm(v)/norm(w); | |
} | |
function diffuseReflection(normal, light) { | |
return Math.max(cos(multi(light, -1), normal), 0); | |
} | |
function atan(x, y) { // 0 ~ Math.PI * 2 | |
var c; | |
if (x == 0) { | |
c = Math.PI / 2; | |
} else if (x > 0) { | |
if (y > 0) { | |
c = Math.atan(y/x); | |
} else { | |
c = Math.atan(y/x) + Math.PI * 2; | |
} | |
} else { | |
c = Math.atan(y/x) + Math.PI; | |
} | |
//if (c < 0 || Math.PI * 2 < c) {console.log(x, y, c);} | |
return c; | |
} | |
// t = 0 .. 9 | |
function fxy(x, y, t) { | |
var z; | |
var r = Math.sqrt(x*x + y*y); | |
var l = HOLE_SIZE * (t + 1) / 10; | |
var l3 = l/3; | |
var d = HOLE_DEPTH * (t + 1) / 10; | |
if (l < r) { | |
z = 0; | |
} | |
if (l3 < r) { | |
z = -l*l3/r + l3; | |
} else { | |
z = -(l - l3) - Math.sqrt(l3*l3 - r*r); | |
} | |
// シワ | |
var c = atan(x, y); | |
while (Math.PI * 2 / 5 < c) { | |
c -= Math.PI * 2 / 5; | |
} | |
c = Math.abs(c - Math.PI * 2 / 5 / 2); | |
if (c < Math.PI * 2 / 5 / 2 / 2) { | |
z += (Math.PI * 2 / 5 / 2 / 2 - c) * 10; | |
} | |
return z; | |
} | |
function updateData(data, x, y, value) { | |
var l = SHADOW_BOX_SIZE; | |
var x1 = x + l; // 右が大きくなる方向 | |
var y1 = y + l; // 上が大きくなる方向 | |
var i = (y1 * l*2 + x1) * 4; | |
if (x1 < 0 || l*2 <= x1) { return; } | |
if (y1 < 0 || l*2 <= y1) { return; } | |
var d = 255*2/3/2; | |
if (value-0.5 < 0) { | |
data[i+0] = 0; | |
data[i+1] = 0; | |
data[i+2] = 0; | |
data[i+3] = -(value-0.5)*d*2; | |
} else { | |
data[i+0] = 255; | |
data[i+1] = 255; | |
data[i+2] = 255; | |
data[i+3] = (value-0.5)*d*2; | |
} | |
} | |
var c10 = diffuseReflection([0,0,1], light); | |
function calcShadowValue(x, y, z, t) { | |
function shadowValue(d) { | |
var z1 = fxy(x - d*light[0], y - d*light[1], t); | |
var z2 = z - d*light[2]; | |
return z2 - z1; // z2(light直線上) より z1(fxy表面上) が大きい(こちら側)なら影(s<0)になる | |
} | |
var s = 1; | |
for (var d = 1; d < SHADOW_BOX_SIZE; d += 1) { | |
s = Math.min(s, shadowValue(d / Math.abs(light[0]))); // x方向 | |
s = Math.min(s, shadowValue(d / Math.abs(light[1]))); // y方向 | |
} | |
return s; | |
} | |
function calcLightValue(x, y, t) { | |
var z = fxy(x, y, t); | |
var s = calcShadowValue(x, y, z, t); | |
var c = (s <= 0) ? 0 : 1; | |
var d = 0.1; | |
var dz_x = fxy(x+d,y,t) - fxy(x-d,y,t); | |
var dz_y = fxy(x,y+d,t) - fxy(x,y-d,t); | |
var normal = [-dz_x, -dz_y, d*2]; | |
var c1 = diffuseReflection(normal, light) / c10; // 0 ~ 1(平らな面) ~ ?(一番明るい面。2程度を想定している) | |
return c*c1 - 0.5; | |
} | |
function draw_light_shadow(canvas, context) { | |
var l = SHADOW_BOX_SIZE; | |
var imageData = context.createImageData(l*2, l*2); | |
var data = imageData.data; | |
for (var t = 0; t < 1; t += 1) { | |
for (var y = -l; y < l; y += 1) { | |
for (var x = -l; x < l; x += 1) { | |
var c1 = calcLightValue(x, y, t); | |
var c2 = c1;//calcLightValue(x + .5, y, t); | |
var c3 = c1;//calcLightValue(x, y + .5, t); | |
var c4 = c1;//calcLightValue(x + .5, y + .5, t); | |
updateData(data, x, y, (c1+c2+c3+c4)/4); | |
} | |
} | |
context.putImageData(imageData, 0, t*l*2); | |
} | |
} | |
$(function() { | |
var canvas = $('#shadow').get(0); | |
var context = canvas.getContext("2d"); | |
var touching = false; | |
var time = 0; | |
var x = 0; | |
var y = 0; | |
draw_light_shadow(canvas, context); | |
$(".building").hide(); | |
var r = SHADOW_BOX_SIZE; | |
$("#image, #shadow_div").mousedown(function(e){ | |
touching = true; | |
x = e.pageX; | |
y = e.pageY; | |
}); | |
$("#image, #shadow_div").mousemove(function(e){ | |
x = e.pageX; | |
y = e.pageY; | |
}); | |
$("#image, #shadow_div").mouseup(function(){ | |
touching = false; | |
}); | |
setInterval(function(){ | |
if (touching) { | |
time++; | |
time = Math.min(time, 9); | |
} else { | |
time--; | |
time = Math.max(time, -1); | |
} | |
if (touching || 0 <= time) { | |
$("#shadow_div").css({left:x-r, top:y-r}); | |
$("#shadow").css({marginTop:-time*2*r}); | |
$("#shadow_div").show(); | |
} else { | |
$("#shadow_div").hide(); | |
} | |
},10); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment