遠景〜中景の草原を、ジオメトリを一切使わず地形フラグメントシェーダーの
テクスチャ参照数回で描くシステム。実装は grass.js(WebGPU/WGSL、単一ファイル)。
草を「一様色・一定長・鉛直の棒」とみなすと、遮蔽の順序が意味を失い、 1本のレイが受ける草の遮蔽量は 地面密度場 ρ をレイ足元の線分で積分したスカラー τ に潰れる。厳密積分の代わりに、**固定長の方向性ぼかし(= 定方向の Line Integral
| # Reproduces the generator-swap issue in PR #1788. | |
| # | |
| # RDoc::RubyGemsHook parses once (with the generator taken from the gem's | |
| # rdoc_options) and then generates ri AND rdoc from the same store. | |
| # If the gem's rdoc_options contain --format=ri, method source tokens are | |
| # skipped at parse time and the later aliki generation is affected. | |
| # | |
| # Usage: ruby -Ilib repro_1788.rb | |
| # master: ">>> aliki HTML: method source PRESENT" | |
| # PR branch: raises RDoc::Error "method source for Dummy#foo was not stored" |
| x = x0 = BigDecimal('1100000000000000087944964434022145632029003198634030825446485394267219165647576318369821312487531766087629873357328440099001976504255934373246955159552') | |
| def to_f(x0) | |
| 6.times do |shift| | |
| prec = 27 << shift | |
| exp = 0 | |
| x = x0r = x0.mult(1, prec) | |
| [59, 16, 4, 1].each do |bit| | |
| while bit == 1 ? x >= 2**53 : x.exponent - 1 >= (53 + bit)*0.30104 | |
| x = x.div(2**bit, prec) | |
| exp += bit |
| require 'prism' | |
| # Collect syntax-valid code snippets from the given directory | |
| def each_snippet(dir, max_size) | |
| files = Dir.glob("#{dir.delete_suffix('/')}/**/*.rb") | |
| snippets = Set.new | |
| handle_snippet = ->(code) { | |
| return if snippets.include?(code) | |
| snippets << code | |
| yield code |
| <canvas width="1600" height="1600" style="background:black"></canvas> | |
| <script> | |
| const canvas = document.querySelector('canvas') | |
| const ctx = canvas.getContext('2d') | |
| const outer = [...new Array(30)].map((_, i) => { | |
| const rot = 0.00 | |
| const th1 = Math.PI * 2 * (i - i % 6) / 30 + rot | |
| const th2 = th1 + Math.PI * 2 / 5 | |
| const th = th1 + [0, 0.335, 0.34, 0.5, 0.66, 0.665][i % 6] * (th2 - th1) | |
| const r = [1, 0.71, 0.62, 0.65, 0.62, 0.71][i % 6] |
| require 'prism' | |
| require 'irb' | |
| # Collect syntax-valid code snippets from the given directory | |
| def each_snippet(dir, max_size) | |
| files = Dir.glob("#{dir.delete_suffix('/')}/**/*.rb") | |
| snippets = Set.new | |
| handle_snippet = ->(code) { | |
| return if snippets.include?(code) | |
| snippets << code |
| # Found inconsistencies | |
| # a b do end.() | |
| # begin a => a: end; a in a: if 1; case a; in a: end | |
| # def a = a b do 1 end | |
| # a rescue b = *c | |
| # p(not a) | |
| # x = a b and c | |
| # def x = a b and c | |
| # a(a 1 do end) | |
| # a.(a 1 do end) |
| # log(10): [[(1/8), 10], [(1/15), 13], [(1/24), 7]] | |
| # log(2): [[(1/8), 3], [(1/15), 4], [(1/24), 2]] | |
| def print_logn_params(base) | |
| value_factors = {} | |
| (8..30).each do |n| | |
| num = (1+1r/n) | |
| (0..30).each do |exp| | |
| v = num ** exp | |
| break if v > 2 * base |
| def exp_bs(x, prec) | |
| # Taylor series of exp can be converted to continued fraction as: | |
| # exp(x)-1 = x*(1+x/2*(1+x/3*(1+x/4*(1+x/5*(1+...))))) | |
| # Binary splitting can be applied to this continued fraction as: | |
| # (1 + a0/a1 + x/a1 * (1 + b0/b1 + x/b1 * rest)) | |
| # (1 + ((a0+x)*b1+x*b0)/(a1*b1) + (x*x)/(a1*b1) * rest) | |
| x = BigDecimal(x) | |
| step = (1..).bsearch { |k| Math.lgamma(k)[0] / Math.log(10) - k * x.exponent > prec } | |
| ms = (1..step).map { [0, BigDecimal(it)] } | |
| while ms.size > 1 |