Jez
03/13/2023, 7:51 PMromainguy
03/13/2023, 8:38 PMJez
03/13/2023, 9:26 PMconst val SphereShaderSource = """
uniform shader composable;
uniform float iTime;
uniform float2 iResolution;
half4 main(float2 fragCoord) {
vec2 p,c,u=fragCoord*2.-iResolution;
half4 o = half4(0.,0.,0.,1.);
for(float i=0;i<4e2;i++) {
// for(float i=100;i<101;i++) {
float a=i/2e2-1.;
p = cos(i*2.4 + iTime + vec2(0.,11.))*sqrt(1.-a*a);
c = u/iResolution.y+vec2(p.x,a)/(p.y+2.);
o +=(cos(i+half4(0.,2.,4.,0.))+1.)/dot(c,c)*(1.-p.y)/3e4;
}
return o;
}
"""
I'm executing it in a simple activity like this:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val shader = RuntimeShader(SphereShaderSource)
setContent {
EmptyComposeTheme {
// A surface container using the 'background' color from the theme
Surface(
color = MaterialTheme.colors.background
) {
BoxWithConstraints(modifier = Modifier.fillMaxSize()) {
ShaderSurface(shader)
}
}
}
}
}
@Composable
fun ShaderSurface(shader: RuntimeShader) {
val time by produceState(0f) {
while (true) {
withInfiniteAnimationFrameMillis {
value = it / 1000f
}
}
}
Surface(
modifier = Modifier
.fillMaxSize()
.onSizeChanged { size ->
shader.setFloatUniform(
"iResolution",
size.width.toFloat(),
size.height.toFloat()
)
shader.setLocalMatrix(
Matrix().apply {
postScale(1f, -1f)
postTranslate(0f, size.height.toFloat())
}
)
}
.graphicsLayer {
shader.setFloatUniform("iTime", time)
renderEffect = RenderEffect.createRuntimeShaderEffect(
shader,
"composable"
).asComposeRenderEffect()
}
) {}
}
}
With this setup I get about 1 frame rendered per second. I tried adjusting the loop in the shader to only draw one point, see commented-out line, and it still only ran at about 5 fps, and I can see some jitter in the movement.romainguy
03/13/2023, 9:31 PMJez
03/13/2023, 9:42 PMgraphicsLayer can be used to apply effects to content, such as scaling, rotation, opacity, shadow, and clipping. Prefer this version when you have layer properties backed by a androidx.compose.runtime.State or an animated value as reading a state inside block will only cause the layer properties update without triggering recomposition and relayout.
what's more this is the method shown in Rebecca Franks' jellyfish example (ctrl-f for "createRuntimeShaderEffect")produceState()
in some way?romainguy
03/13/2023, 9:52 PMJez
03/15/2023, 9:43 AMromainguy
03/15/2023, 7:37 PM