Soyukke.Dev

2020-07-19

JuliaでGLSLを使う

Julia言語を使ってGLSLフラグメントシェーダを以下のように動かすまで.

GLSLとは

GLSL(OpenGL Shading Language)はC言語ライクな言語で画像の点や頂点の情報を利用して色などを演算することに使う.GLSLファイルを使ってOpenGLで描画することができる.

JuliaでOpenGL

JuliaでOpenGLを使うにはModernGL.jlと,Windowで描画するためにGLFW.jlというライブラリを使用する. ソースコード https://github.com/Soyukke/glsl

ここで利用したバージョンは

  • Julia 1.3.1

  • GLFW v3.2.2

  • ModernGL v1.1.2

githubにProject.tomlもアップロードしているので,Project.tomlがあるフォルダでjulia --project=.というようにオプションを指定するとその依存関係で実行できる.

最初にパッケージを環境にインストールするときは

julia --project=. "using Pkg;Pkg.instantiate()"

と実行すればよい.Pkg.instantiate()がProject.tomlに記述されたパッケージをその環境にインストールする関数である.

フラグメントシェーダを実行できるようにする

フラグメントシェーダ例

フラグメントシェーダのコード内で実行してからの時間経過[秒]マウスの座標画面のピクセル数を受け取りこれらの値だけを使用してフラグメントシェーダを書く.

#version 450

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

void main( void ) {
    // normalize gl_FragCoord [[0, 0], resolution.xy] -> [[-1, -1], [1, 1]]
    vec2 p_pixel = (2 * gl_FragCoord.xy - resolution.xy) / min(resolution.x, resolution.y);
    vec2 p_mouse = (2 * mouse.xy - resolution.xy) / min(resolution.x, resolution.y);
    gl_FragColor = vec4(abs(p_pixel.x), abs(p_mouse.x), sin(time), 1.0);
}

頂点シェーダでは座標をそのまま返す.

#version 450

in vec3 position;

void main(void)
{
    gl_Position = vec4(position, 1.0);
}

時間経過をJuliaから渡す

コードから該当部分を抜粋

using Dates

# 描画を始めるときに現在時刻を取得する
time_start = time()
# 時間経過を格納する変数
time_count = time_start

# 描画開始からの経過時間[秒]
time_count = time() - time_start

この変数time_countglUniform1f関数でフラグメントシェーダの変数timeに渡す.

glUniform1f(glGetUniformLocation(shader, "time"), time_count)

マウスの座標を渡す

マウス座標はGLFW.GetCursorPosで取得できる.しかしフラグメントシェーダでは右下が(-x, -y)方向なのに対し,GLFWのGetCursorPosは右上が(-x, -y)方向.なので,取得したマウスのy座標を反転して原点を右下の0, 0にする.

mouse = [0, 0]
# GetCursorPosは右上が (x, y) = (1, 1)なので,yを反転してシフトして左下を0, 0とする
# window外もあるので0 - width - 1にする
x, y = GLFW.GetCursorPos(window) 
x = GLfloat(x - 1)              # x [1, width]  -> [0, width-1]
y = GLfloat(height - y)         # y [1, height] -> [0, height-1]

juliaでの変数mouseをフラグメントシェーダの変数mousevec2で渡す.

glUniform2f(glGetUniformLocation(shader, "mouse"), x, y)

画面の解像度を渡す

windowの解像度widthheightGLFWwindowを作成するときに渡す.

width, height = 512, 512
window = GLFW.CreateWindow(width, height, "GLFW.jl")

これをvec2でフラグメントシェーダの変数resolutionに渡す.

glUniform2f(glGetUniformLocation(shader, "resolution"), width, height)

その他

GPUを使用して実行

Juliaを起動するときにグラフィックプロセッサとともに実行をすればOK. タスクマネージャーからGPUを使用していることを確認できる.

カテゴリー