## 码农干货系列【9】--javascript光线追踪基础

2013-03-12 16:31  【当耐特】  阅读(3284)  评论(4编辑  收藏

# 射线与球体相交检测

var Vector3 = function (x, y, z) { this.x = x; this.y = y; this.z = z; };
Vector3.prototype ={
dot: function (v) { return this.x * v.x + this.y * v.y + this.z * v.z; },
sub: function (v) { return new Vector3(this.x - v.x, this.y - v.y, this.z - v.z); },
normalize: function () {      return this.divideScalar(this.length());  },
divideScalar: function (s) {  return new Vector3(this.x/s, this.y/s, this.z/s);   },
length: function () {     return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);  },
sqrDistanceToline:function(a,b){
var ab = b.sub(a), ac = this.sub(a), bc = this.sub(b);
var e = ac.dot(ab.normalize());
var f = ac.length();
return f * f - e * e;
}
} 

ball.p.sqrDistanceToline(v, camera.p) < sqrBallR

# 相交测试

for (var y = 0; y < canvas.height; y++) {
for (var x = 0; x < canvas.width; x++) {
var v = new Vector3(-canvas.width / 2 + x, canvas.height - y, 0);
var cv = new Vector3(camera.p.y * v.x / (camera.p.y - v.y), 0, camera.p.z * v.y / (v.y - camera.p.y));

if (cv.z > -planeLength && cv.z < 0) {
if (ball.p.sqrDistanceToline(v, camera.p) < sqrBallR) {
pixels[i] = pixels[i + 1] = pixels[i + 2] = 111;
} else {
pixels[i] = pixels[i + 1] = pixels[i + 2] = (Math.ceil(cv.x / sideLength) + Math.ceil(cv.z / sideLength)) % 2 === 0 ? 148 : 0;
}
pixels[i + 3] = 255 * (planeLength - Math.abs(cv.z)) / planeLength;
}
i += 4;
}
}

# 获取交点

1.交点在在光线上
x=S+dt

2.交点在球上
|x-C|=r

C 表示球心，r 表示半径，光线起点是 S，方向是 d（单位向量），交点 x。

var Ball = function (p, r) {
this.p = p;
this.r = r;
this.sqrR = this.r * this.r;
}
Ball.prototype = {
intersect: function (p1, p2) {
var v = p1.sub(this.p);
var a0 = v.sqrLength() - this.sqrR;
var np = p2.sub(p1).normalize();
var dotV = np.dot(v);
if (dotV <= 0) {
var discr = dotV * dotV - a0;
if (discr >= 0) {
}
}
return null;
}
}.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }


var result = ball.intersect(camera.p, screenP);
if (result) {
(pixels[i] = pixels[i + 1] = pixels[i + 2] = ((result.z - ball.p.z) / ball.r) * 255)
pixels[i + 3] = 255;
}

Have Fun!