Mac + pyOpenGLでシェーダーアニメーション描く


# はじめに

ご覧になった方も多いかと思います。macOS 10.14のOpenGLへのDeprecation
[What’s New in macOS（10.14で変わったこと）](https://developer.apple.com/macos/whats-new/)
Macでの今後のoFの対応、諸々のアプリ開発者の不安が囁かれていますが．．．
私も今朝、まさにopenGLをpythonで動かしていたこともあり、
ニーズアピールの意味も込めてサンプルをアップします。

# できること

LiveCoding用のソフトを使わず、
python のみで [GLSL sandbox](http://glslsandbox.com/)にあるような時間変化するシェーダープログラムを実行できる。
意外とLiveCodingのように動くpythonコードがなかったです。


<img width="６00" src="https://qiita-image-store.s3.amazonaws.com/0/197729/d4710bc1-bdee-f2a9-c9cc-4a5ae66d271f.png">

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">こんな日だからMac + OpenGLでシェーダーアニメーションする pythonコード書いた。<a href="https://t.co/oJPV7wASgp">https://t.co/oJPV7wASgp</a><a href="https://twitter.com/hashtag/opengl?src=hash&amp;ref_src=twsrc%5Etfw">#opengl</a> <a href="https://twitter.com/hashtag/creativecoding?src=hash&amp;ref_src=twsrc%5Etfw">#creativecoding</a> <a href="https://twitter.com/hashtag/livecoding?src=hash&amp;ref_src=twsrc%5Etfw">#livecoding</a> <a href="https://twitter.com/hashtag/shader?src=hash&amp;ref_src=twsrc%5Etfw">#shader</a> <a href="https://twitter.com/hashtag/python?src=hash&amp;ref_src=twsrc%5Etfw">#python</a> <a href="https://twitter.com/hashtag/generative?src=hash&amp;ref_src=twsrc%5Etfw">#generative</a> <a href="https://t.co/75zz8Y98pU">pic.twitter.com/75zz8Y98pU</a></p>&mdash; mizumasa (@_mizumasa) <a href="https://twitter.com/_mizumasa/status/1003966982188818433?ref_src=twsrc%5Etfw">2018年6月5日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>




# 環境
- MacBook Pro (2.7 GHz Intel Core i5,16 GB 1867 MHz DDR3)
- macOS Sierra
- python 2.7

# 手順

### 環境構築

インストールはnumpyなどの基本的なものを除けば、以下の２つです。

```
brew install glfw
pip install PyOpenGL
```
PyOpenGLがpipで入らない場合は、[ここ](http://pyopengl.sourceforge.net/documentation/installation.html)を頼りに手で入れましょう。

実装コードはこちらに置いてあります。

```
git clone https://github.com/mizumasa/pyShaderSample.git
cd pyShaderSample
python shader_loop.py shader_loop.vert shader_loop.frag
```
### import でエラーが出た時

:::note alert
Big Sur 以降、確実にインストールそのままではエラーが出ます
:::

https://qiita.com/mizumasa/items/668a47804f33dd795db4

こちらの対策で使えるようになる可能性が高いです。
(2021/11更新 M1 macOS Monterey でもこの修正をすれば使えました！)


### コード説明

[pyOpenGLでシェーダープログラミング](https://qiita.com/ar90n@github/items/934b1048b3173d2a3b04)こちらを参考に書きました。
不要な部分などあるかもしれませんが、とりあえずこれで動きます。

重要な部分としては DrawGLScene()の中で毎回呼ばれている、time 変数への値の送信です。

```shader_loop.py
glUniform1f( glGetUniformLocation( program, "time" ), time.time() - startTime)
```

このように time 変数を、毎回描画時にtime.time()関数などの値を利用して更新してあげると、時間変化のあるシェーダープログラムが実行できます。
簡潔に書くために、program変数はglobal化してしまいました。


続いて、シェーダー本体を見ていきます。

```shader_loop.frag
uniform float texture_width;
uniform float texture_height;
uniform float time;

void main() {
    vec2 resolution = vec2( texture_height, texture_width );
    vec2 uv = -1. + 2. * gl_FragCoord.xy / resolution.xy;
    gl_FragColor = vec4(
        abs( sin( cos( time + 3. * uv.y ) * 2. * uv.x + time)),
        abs( cos( sin( time + 2. * uv.x ) * 3. * uv.y + time)),
        2.0,
        1.0);
}
```

texture_width,texture_heightは画面サイズで、InitGL()関数の中でシェーダーに設定しています。KodeLifeやGLSL sandboxなどのLiveCodingソフトでは一般的にtime と resolution変数が使用されているので、resolution変数を作成しています。また、gl_FragCoord.xyが入力の二次元マップ、gl_FragColorが出力のRGBAとなります。(KodeLifeなどからの移植で、出力変数名がfragColorとなっている場合はgl_FragColorと書き換えてください)

shader_loop.frag の中を自由に書き換えれば様々な映像が生成可能です！


### 実行

```
python shader_loop.py shader_loop.vert shader_loop.frag
```

サンプルコードでは、ESCキーを押すと、その時の画像をキャプチャして保存します(output.png)。
<img width="400" src="https://qiita-image-store.s3.amazonaws.com/0/197729/d4710bc1-bdee-f2a9-c9cc-4a5ae66d271f.png">

以上です！