2017/12/20(水) [n年前の日記]
#1 [love2d] 直線と球の交点の求め方を調べてたり
昨日、直線と球の交点をatan()やcos()で求めてたけど。もっと簡単(?)に求める方法があるはずだよなとググって調べてみたり。以下のページが参考になった。
_球面と直線の交点 -点P(Px,Py,Pz)から方向ベクトル(x,y,z)にのびた直線- 数学 | 教えて!goo
直線の原点が P(Px, Py, Pz) で、方向ベクトルが (x, y, z) の場合、直線は (X,Y,Z) = (Px, Py, Pz) + t * (x, y, z) と書ける…けど、今回は原点を (0, 0, 0) としてるので、
そして球は、X^2 + Y^2 + Z^2 = r^2 だから…。X,Y,Zに直線のソレを代入して…。
ということは、x, y が決まっている時、z値は…。
_球面と直線の交点 -点P(Px,Py,Pz)から方向ベクトル(x,y,z)にのびた直線- 数学 | 教えて!goo
直線の原点が P(Px, Py, Pz) で、方向ベクトルが (x, y, z) の場合、直線は (X,Y,Z) = (Px, Py, Pz) + t * (x, y, z) と書ける…けど、今回は原点を (0, 0, 0) としてるので、
X = t * x Y = t * y Z = t * zと書けるなと。
そして球は、X^2 + Y^2 + Z^2 = r^2 だから…。X,Y,Zに直線のソレを代入して…。
X^2 + Y^2 + Z^2 = r^2 (t * x) * (t * x) + (t * y) * (t * y) + (t * z) * (t * z) = r * r t^2 * (x^2 + y^2 + z^2) = r^2 t^2 = (r^2) / (x^2 + y^2 + z^2) t = sqrt( (r^2) / (x^2 + y^2 + z^2) )例えば、直線が x = 0, y = 0 の時、z = 1.0 になるだろうから…。
t = sqrt( (r^2) / (0^2 + 0^2 + 1.0^2) ) = sqrt( (r^2) / 1.0 ) = sqrt( r^2 ) = rt = r にしちゃっていい、のかなと。ホントかな。怪しいな。
ということは、x, y が決まっている時、z値は…。
(t * x)^2 + (t * y)^2 + (t * z)^2 = r^2 (t * z)^2 = r^2 - (t * x)^2 - (t * y)^2 t = r (r * z)^2 = r^2 - (r * x)^2 - (r * y)^2 r^2 * z^2 = r^2 * (1.0 - x^2 - y^2) z^2 = (1.0 - x^2 - y^2) z = sqrt(1.0 - x^2 - y^2)アレ? 球の半径 r が式の中から無くなってしまった…。これで合ってるのかな…? どうなのよ。
◎ love2d の Shader で動作確認。 :
love2d の Shader を使って、どんな結果になるか確認。
歪み方は以前のやり方と似たような感じになった。ただ、球の半径 r を変更してもテクスチャの拡大縮小はされなくなった。式の中に r が入ってないから当たり前だろうけど。
どこかで何かを間違えてる気がしないでもないけど、それっぽく表示されたから、まあ、いいか…。
ソースは以下。
_conf.lua
_main.lua
変更したところだけメモ。
歪み方は以前のやり方と似たような感じになった。ただ、球の半径 r を変更してもテクスチャの拡大縮小はされなくなった。式の中に r が入ってないから当たり前だろうけど。
どこかで何かを間違えてる気がしないでもないけど、それっぽく表示されたから、まあ、いいか…。
ソースは以下。
_conf.lua
_main.lua
変更したところだけメモ。
function love.load() love.graphics.setDefaultFilter("nearest", "nearest") scr_w, scr_h = 640, 480 canvas = love.graphics.newCanvas(scr_w, scr_h) img = love.graphics.newImage("star_bg_1024x1024.png") -- img = love.graphics.newImage("uvcheckermap01-1024.png") img:setFilter("linear", "linear") -- make shader local shadercode = [[ extern number scr_dist; extern number scale; extern number start_x; extern number start_y; // extern number r; vec4 effect( vec4 color, Image texture, vec2 texture_coords, vec2 screen_coords ) { float sx = (screen_coords.x - (love_ScreenSize.x / 2)) / love_ScreenSize.x; float sy = (screen_coords.y - (love_ScreenSize.y / 2)) / love_ScreenSize.x; vec3 ray = normalize(vec3(sx, sy, scr_dist)); // float qz = sqrt( r * r * (1.0 - ray.x * ray.x - ray.y * ray.y) / (r * r)); float qz = sqrt( 1.0 - ray.x * ray.x - ray.y * ray.y); float u = sx * qz / scr_dist; float v = sy * qz / scr_dist; texture_coords.x = mod((u + start_x) * scale + 0.5, 1.0); texture_coords.y = mod((v + start_y) * scale + 0.5, 1.0); vec4 texcolor = Texel(texture, texture_coords); return texcolor * color; } ]] myshader = love.graphics.newShader(shadercode) local angle_of_view = 60 local scr_dist = math.cos(math.rad(angle_of_view/2)) myshader:send("scr_dist", scr_dist) -- myshader:send("r", scr_dist + 0.1) myshader:send("scale", 0.4) myshader:send("start_x", 0.0) myshader:send("start_y", 0.0) ang_a = 0.0 ang_b = 0.0 px = (scr_w - img:getWidth()) / 2 py = (scr_h - img:getHeight()) / 2 end
[ ツッコむ ]
以上です。