成果物
コード
def mod($d): fmod(.; $d) | if . < 0 then . + $d else . end;
def vec3Add($v): { x: (.x + $v.x), y: (.y + $v.y), z: (.z + $v.z) };
def vec3Mul($s): .[] *= $s;
def vec3Mod($s): .[] |= mod($s);
def vec3Sub($v): vec3Add($v | vec3Mul(-1));
def vec3Div($s): vec3Mul(1 / $s);
def vec3Dot($v): .x * $v.x + .y * $v.y + .z * $v.z;
def vec3Length: vec3Dot(.) | sqrt;
def vec3Normalize: vec3Div(vec3Length);
def positionToSphereDistance($r): vec3Length - $r;
. as $t |
def positionToDistance:
vec3Add({ x: (0.25 * $t), y: (0.125 * $t), z: (-0.5 * $t) }) |
vec3Add({ x: 4, y: 4, z: 4 }) | vec3Mod(8) | vec3Add({ x: -4, y: -4, z: -4 }) |
positionToSphereDistance(1.0);
def positionToNormal:
positionToDistance as $dist |
def e: 0.001;
{
x: ($dist - (.x -= e | positionToDistance)),
y: ($dist - (.y -= e | positionToDistance)),
z: ($dist - (.z -= e | positionToDistance))
} |
vec3Normalize;
({ x: -0.5, y: -0.5, z: 1 } | vec3Normalize) as $lightDirection |
def positionToLuminance:
positionToNormal | vec3Dot($lightDirection);
def screenPositionToLuminance:
def camPos: { x: 0, y: 0, z: 4 };
(vec3Sub(camPos) | vec3Normalize) as $rayDir |
def positionToLuminance(i):
positionToDistance as $dist |
if i >= 32 then 0
elif $dist < 0.0001 then positionToLuminance
else vec3Add($rayDir | vec3Mul($dist)) | positionToLuminance(i + 1)
end;
camPos | positionToLuminance(0);
def luminanceToString:
[0, ([., 1] | min)] | max |
def grayscaleStrs: [" ", ".", ":", "+", "o", "0"];
grayscaleStrs[(grayscaleStrs | length - 0.001) * . | floor];
def canvasToText: [.[] | [.[] | luminanceToString] | add] | join("\n");
def canvasSize: { x: 64, y: 32 };
def canvas:
[
range(canvasSize.y) | (2 * (. / canvasSize.y) - 1) as $y | [
range(canvasSize.x) |
{ x: (2 * (. / canvasSize.x) - 1), $y, z: 0 } | screenPositionToLuminance
]
];
canvas | canvasToText
を、raymarching.jq
として保存し、シェルスクリプトから
for t in $(jq -nr 'range(1024)'); do echo $t | jq -fr raymarching.jq; done
で呼び出す。
全体の流れ
-
raymarching.jq
は、時間を受け取りそれに対応するアスキーアートを返す- 時間は
. as $t
としてしまい、以降ファイル内どこでも参照可能にしている
- 時間は
-
canvas
で明るさを0~1で表した二次元配列を生成し、それをcanvasToText
でアスキーアートに変換しそれを結果としている - 画面位置ごとの明るさは
screenPositionToLuminance
で求める - レイの進行は
positionToLuminance
の再帰- 新しい位置で
positionToLuminance
を再度呼び、距離が一定以下になったら再帰をやめている
- 新しい位置で
その他
- 定数は、
def
かas $var
を使う- 計算があるものは
as $var
のほうが良い?
- 計算があるものは
-
fmod
は負のときに返り値も負になるのでGLSLと同じで常に正になるよう、mod
を用意した -
|
を行頭か行末どちらに書くか迷うが、関数先頭など、記述不要箇所でも自動でパイプを受け取るのであえて強調する必要性が低そうなので末尾にした - 関数はフィルタが基本になるので、
hogeToFuga
みたいな関数名にすると分かりやすい気がする