GearVR Frameworkのカスタムシェーダーを使うやり方のWebページの内容が古くてそのままやってもエラーで動かなかったのでいろいろ試行錯誤した結果、以下のようにしてうまくいきました。
ソースファイル中に定数文字列でシェーダーコードを書くと読みづらいのでリソースファイルから読み込むようにしました。
まず、res/raw以下にシェーダーを記述したファイルを作ります。
precision highp float;
in vec3 a_position;
uniform mat4 u_mvp;
void main()
{
gl_Position = u_mvp * vec4(a_position, 1.0);
}
precision mediump float;
uniform vec4 u_color;
out vec4 fragColor;
void main()
{
fragColor = u_color;
}
次に、GVRShaderTemplate
を継承したクラスを作り、コンストラクタの中でsetSegment("FragmentTemplate",...)
,setSegment("VertexTemplate",...)
に各シェーダーのソースコードを渡すようにします。
GVRShaderTemplate
のコンストラクタ引数には、このシェーダーが取りうるパラメーターを第一引数に、シェーダーのバージョンを第二引数に渡します。
リソースから文字列を読み込むのにKotlinの方が楽だったのでKotlinで実装しました。
import android.content.Context
import org.gearvrf.GVRContext
import org.gearvrf.GVRShaderTemplate
import java.io.InputStream
import java.nio.charset.Charset
class ColorShader(gvr: GVRContext) : GVRShaderTemplate("int u_right", 300) {
init {
setSegment("FragmentTemplate", shaderSource(gvr.context, R.raw.fragmentshader))
setSegment("VertexTemplate", shaderSource(gvr.context, R.raw.vertexshader))
}
private fun shaderSource(context: Context, rawRes: Int): String = readTextAndClose(context.resources.openRawResource(rawRes))
private fun readTextAndClose(inputStream: InputStream, charset: Charset = Charsets.UTF_8): String {
return inputStream.bufferedReader(charset).use { it.readText() }
}
}
そして、このシェーダーを使って描画したいオブジェクトのGVRRenderData
に、setShaderTemplate()
で先ほど作ったクラスを渡します。
// Kotlin
sceneObject.renderData.setShaderTemplate(ColorShader::class.java)
// Java
sceneObject.getRenderData().setShaderTemplate(ColorShader.class);
それから、このオブジェクトに適用するマテリアルはコンストラクタでGVRMaterial(gvrContext, GVRMaterial.GVRShaderType.BeingGenerated.ID)
のようにして、シェーダーがまだ設定されていないことを明示することが推奨されています。