Created
February 5, 2023 15:44
-
-
Save inspirnathan/aec5d735194ba556cad69af15d76c831 to your computer and use it in GitHub Desktop.
Comparison between two approaches of creating a calcNormal function as seen on https://inspirnathan.com/posts/52-shadertoy-tutorial-part-6/
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
class Vector2 { | |
constructor(x = 0, y = 0) { | |
this.x = x; | |
this.y = y; | |
} | |
'+'(value) { | |
// value can be Vector2 or number | |
if (value instanceof Vector2) { | |
return new Vector2(this.x + value.x, this.y + value.y); | |
} | |
return new Vector2(this.x + value, this.y + value); | |
} | |
'*'(value) { | |
// value can be Vector2 or number | |
if (value instanceof Vector2) { | |
return new Vector2(this.x * value.x, this.y * value.y); | |
} | |
return new Vector2(this.x * value, this.y * value); | |
} | |
get xxx() { | |
return new Vector3(this.x, this.x, this.x); | |
} | |
get xxy() { | |
return new Vector3(this.x, this.x, this.y); | |
} | |
get xyx() { | |
return new Vector3(this.x, this.y, this.x); | |
} | |
get xyy() { | |
return new Vector3(this.x, this.y, this.y); | |
} | |
get yxx() { | |
return new Vector3(this.y, this.x, this.x); | |
} | |
get yxy() { | |
return new Vector3(this.y, this.x, this.y); | |
} | |
get yyx() { | |
return new Vector3(this.y, this.y, this.x); | |
} | |
get yyy() { | |
return new Vector3(this.y, this.y, this.y); | |
} | |
} | |
class Vector3 { | |
constructor(x = 0, y = 0, z = 0) { | |
this.x = x; | |
this.y = y; | |
this.z = z; | |
} | |
'+'(value) { | |
// value can be Vector3 or number | |
if (value instanceof Vector3) { | |
return new Vector3(this.x + value.x, this.y + value.y, this.z + value.z); | |
} | |
return new Vector3(this.x + value, this.y + value, this.z + value); | |
} | |
'*'(value) { | |
// value can be Vector3 or number | |
if (value instanceof Vector3) { | |
return new Vector3(this.x * value.x, this.y * value.y, this.z * value.z); | |
} | |
return new Vector3(this.x * value, this.y * value, this.z * value); | |
} | |
get xxx() { | |
return new Vector3(this.x, this.x, this.x); | |
} | |
get xxy() { | |
return new Vector3(this.x, this.x, this.y); | |
} | |
get xxz() { | |
return new Vector3(this.x, this.x, this.z); | |
} | |
get xyx() { | |
return new Vector3(this.x, this.y, this.x); | |
} | |
get xyy() { | |
return new Vector3(this.x, this.y, this.y); | |
} | |
get xyz() { | |
return new Vector3(this.x, this.y, this.z); | |
} | |
get xzx() { | |
return new Vector3(this.x, this.z, this.x); | |
} | |
get xzy() { | |
return new Vector3(this.x, this.z, this.y); | |
} | |
get xzz() { | |
return new Vector3(this.x, this.z, this.z); | |
} | |
get yxx() { | |
return new Vector3(this.y, this.x, this.x); | |
} | |
get yxy() { | |
return new Vector3(this.y, this.x, this.y); | |
} | |
get yxz() { | |
return new Vector3(this.y, this.x, this.z); | |
} | |
get yyx() { | |
return new Vector3(this.y, this.y, this.x); | |
} | |
get yyy() { | |
return new Vector3(this.y, this.y, this.y); | |
} | |
get yyz() { | |
return new Vector3(this.y, this.y, this.z); | |
} | |
get yzx() { | |
return new Vector3(this.y, this.z, this.x); | |
} | |
get yzy() { | |
return new Vector3(this.y, this.z, this.y); | |
} | |
get yzz() { | |
return new Vector3(this.y, this.z, this.z); | |
} | |
get zxx() { | |
return new Vector3(this.z, this.x, this.x); | |
} | |
get zxy() { | |
return new Vector3(this.z, this.x, this.y); | |
} | |
get zxz() { | |
return new Vector3(this.z, this.x, this.z); | |
} | |
get zyx() { | |
return new Vector3(this.z, this.y, this.x); | |
} | |
get zyy() { | |
return new Vector3(this.z, this.y, this.y); | |
} | |
get zyz() { | |
return new Vector3(this.z, this.y, this.z); | |
} | |
get zzx() { | |
return new Vector3(this.z, this.z, this.x); | |
} | |
get zzy() { | |
return new Vector3(this.z, this.z, this.y); | |
} | |
get zzz() { | |
return new Vector3(this.z, this.z, this.z); | |
} | |
} | |
function length(vec) { | |
if (vec instanceof Vector2) { | |
return Math.sqrt(vec.x ** 2 + vec.y ** 2); | |
} | |
return Math.sqrt(vec.x ** 2 + vec.y ** 2 + vec.z ** 2); | |
} | |
function normalize(vec) { | |
const vecLength = length(vec); | |
if (vec instanceof Vector2) { | |
return new Vector2(vec.x / vecLength, vec.y / vecLength); | |
} | |
return new Vector3(vec.x / vecLength, vec.y / vecLength, vec.z / vecLength); | |
} | |
function sdSphere(p, r) { | |
// p is the test point on the surface of the sphere | |
// r is the radius of the sphere | |
return length(p) - r; | |
} | |
function calcNormal1(p) { | |
const e = 0.0005; // epsilon | |
const r = 1.0; // radius of sphere | |
return normalize( | |
new Vector3( | |
sdSphere(new Vector3(p.x + e, p.y, p.z), r) - | |
sdSphere(new Vector3(p.x - e, p.y, p.z), r), | |
sdSphere(new Vector3(p.x, p.y + e, p.z), r) - | |
sdSphere(new Vector3(p.x, p.y - e, p.z), r), | |
sdSphere(new Vector3(p.x, p.y, p.z + e), r) - | |
sdSphere(new Vector3(p.x, p.y, p.z - e), r) | |
) | |
); | |
} | |
function calcNormal2(p) { | |
const e = new Vector2(1.0, -1.0)['*'](0.0005); // epsilon | |
const r = 1.0; // radius of sphere | |
const operand1 = e.xyy['*'](sdSphere(p['+'](e.xyy), r)); | |
const operand2 = e.yyx['*'](sdSphere(p['+'](e.yyx), r)); | |
const operand3 = e.yxy['*'](sdSphere(p['+'](e.yxy), r)); | |
const operand4 = e.xxx['*'](sdSphere(p['+'](e.xxx), r)); | |
const sum = operand1['+'](operand2)['+'](operand3)['+'](operand4); | |
return normalize(sum); | |
} | |
const p = new Vector3(1, 2, 3); | |
console.log('calcNormal1:', calcNormal1(p)); | |
console.log('calcNormal2:', calcNormal2(p)); | |
/* OUTPUT: | |
calcNormal1: Vector3 { | |
x: 0.26726124089009934, | |
y: 0.534522482802048, | |
z: 0.8017837267599155 | |
} | |
calcNormal2: Vector3 { | |
x: 0.26721624351172774, | |
y: 0.5345183943192493, | |
z: 0.8018014500721813 | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment