It looks like you're new here. If you want to get involved, click one of these buttons!
Until now Codea's shaders have used GLES 2.0
Starting with 2.3.2 beta build 56, optional support for GLES 3.0 is added.
This is only available on devices with an A7 chip or newer (iPad Air onwards).
(and is currently only available to Codea beta testers).
GLES 3.0 is optional, and can be added on a shader-by-shader basis (ie you can mix 2.0 and 3.0 in the same program) by placing #version 300 es
in the string of the vertex and fragment shaders, so you should be able to add it gradually, if it's needed for your code.
This Apple page is quite a handy cheat sheet to the changes you need to make to the shader language : https://developer.apple.com/library/ios/documentation/3DDrawing/Conceptual/OpenGLES_ProgrammingGuide/AdoptingOpenGLES3/AdoptingOpenGLES3.html#//apple_ref/doc/uid/TP40008793-CH504-SW18
And regardless of which GLES version you use, you can never read this page enough times:
The most useful resource is probably the quick reference card (pages 4 to 6 is the relevant section):
https://www.khronos.org/files/opengles3-quick-reference-card.pdf
And this is the bible:
https://www.khronos.org/registry/gles/specs/3.0/GLSL_ES_Specification_3.00.4.pdf
Here's some very simple sample code:
-- test of GLES 300 Matrix Mesh Buffer Test
--
function setup()
m = mesh()
m:addRect(0,0,200,200)
m:setColors(color(255,200,0))
m.shader = shader(vert, frag)
dummy = m:buffer("dummy") --test vec4 attribute
transform = m:buffer("transform") --test mat4 attribute
local mat = matrix():translate(0,100,0) --should move rectangle up
for i=1,m.size do
dummy[i] = vec4(60,0,0,0) --works, moves rectangle to right
transform[i] = mat
end
end
function draw()
background(40, 40, 50)
perspective()
camera(0,0,400, 0,0,0)
m:draw()
end
vert=[[
#version 300 es
uniform mat4 modelViewProjection;
in mat4 transform;
in vec4 position;
in vec4 color;
in vec4 dummy;
out lowp vec4 vColor;
void main()
{
vColor = color;
gl_Position = modelViewProjection * (transform * position + dummy);
}
]]
frag=[[
#version 300 es
in lowp vec4 vColor; //NB varying becomes "in" in fragment shader
out lowp vec4 fragColor;
void main()
{
fragColor = vColor;
}
]]
Comments
One issue to be aware of:
in 3.0, the old texture2D and texture3D commands have been replaced with a single texture command. The problem is that this clashes with the uniform texture variable that the Codea Mesh API passes to the shader.
The workaround is to define your own custom texture variable eg:
Then, in the Codea code, replace
myMesh.texture = "Dropbox:grass"
with:
myMesh.shader.textureMap = "Dropbox:grass"
(note the
.shader
).How to convert a 2.0 shader to 3.0:
In the vertex shader:
#version 300 es
to startattribute
toin
varying
toout
In the fragment shader:
#version 300 es
to startvarying
toin
(nb different from the vertex shader, you can't just do a global find/replace onvarying
)gl_FragColor
variable anymore. Instead, you define any variable as anout
egout lowp vec4 fragColor;
,out lowp vec4 fragmentColor;
etctexture2D
andtexture3D
functions have been replaced with a singletexture
function. Note that this clashes with thetexture
uniform passed by the Codea mesh API, so you will have to use a custom variable, eguniform lowp sampler2D textureMap;
which you access from Codea withmyMesh.shader.textureMap
instead ofmyMesh.texture
(see post immediately above this one).Also, even if you don't use GLES 3.0, the GLES 2.0 shader specifications are now more fully supported by the Codea 2.3.2 mesh API, particularly with regard to matrices:
uniform mat4 modelMatrices[20];
attribute mat4 modelMatrix;
added a link to the first post to the quick reference card
(love the Khronos quick reference cards. Everything should have a quick reference card):
https://www.khronos.org/files/opengles3-quick-reference-card.pdf
Start your engines! B-)
Initial thoughts:
there's obviously an enormous amount to test here, and many features may require changes to the Codea API if they're going to be accessible.
Things that GLES 3.0 supports that I'm going to try when I have a spare minute:
textures on the vertex shader!
Could be a great way of creating various vertex displacement effects, displacement mapping, height mapping with a texture, very cheap noise effects ( compared to the relatively expensive ashima arts pnoise/ snoise functions), providing data for instanced drawing, building a voxel engine etc
looking forward to trying this soon, thanks for your efforts, much appreciated :bz
Ok, first test of a unique-to-GLES 3.0 feature: textures on the vertex shader! (Here being used to displace vertices).
It works!
But, when you animate it, it's jerky. Haven't worked out quite why that is yet. I thought it was to do with the resolution of the texture, but when I increased it, it stayed jittery. Anyone have any ideas how to make the animation smoother?
(Take two texture samples and interpolate between them somehow?)
Instancing is coming! While we wait, here's an interesting article with Android code examples and fps comparisons with and w/o instancing:
https://software.intel.com/en-us/articles/opengl-es-30-instanced-rendering
With regard to the vertex displacement shader (2 posts above this one). The animation is even jerkier if you set
noSmooth()
, so it is something to do with the way the texture is read. The spec says "level of detail [for texture lookup] is not implicitly computed for vertex shaders" (p93). Hmmm. I think someone needs to invest in a "GLES 3.0 programming recipes" book :-??Here's a very quick (and not terribly exciting) adaptation of @Simeon 's 2D instanced example, using 3D cubes instead of rects (GLES 2.0).
@yojimbo2000 Is this worth looking thru.
The GitHub repo for that book looks good:
https://github.com/danginsburg/opengles3-book/
in the book i read
maybe this is related to jerkiness?
Yeah I think so. I think this corresponds to smooth/ noSmooth in the Codea API, eg a low res texture in the frag shader displays pixelated with noSmooth, and blurred/smoothed out with smooth, and in this example, if you set noSmooth, you can clearly see the animation has "steps" as it goes from pixel to pixel. The problem is, it also has a jittery quality in smooth mode too (as if it's going forwards and backwards over each part of the animation instead of just smoothly moving forwards). There are loads of new texture sampling functions in GLES 3.0 so maybe I need to try one of those instead of
texture
. I'll ask on stack exchange, as there are people there with lots of 3.0 experience.I tried playing around with cloth/hair simulation, here's what I came up with
It can render 300 strands and keep a pretty stable 60 FPS...Instances seem pretty cool, and very powerful
@SkyTheCoder impressive! Looks great.
Just one note (don't have a recent enough iPad for GLES 3), but textures in vertex shaders came along I think in IOS 7/8 I did some stuff with it reasonably successfully a long time ago. They are very handy, but certainly not a ES3 only capability.
Gosh, @spacemonkey is right. I didn't realised that that had been enabled. Here's the above vertex displacement code for GLES 2.0. @spacemonkey do you know why the animation is jittery?
@SkyTheCoder good work!
I have some disappointing news about instancing. I tried it with a simple OBJ model to see what the performance was like, and using instancing was actually significantly slower than just drawing the mesh at multiple locations. A 4572 vert model, with 60 instances (so 274320 verts altogether, not all that high). Drawing the mesh at 60 locations and the framerate stays at 60, while drawing the mesh once, with 60 instances, and the framerate drops to 45-47 or so. =((
I'll post some code if I can clean it up a little.
I guess more testing (and reading) is necessary to try to work out which situations actually benefit from instancing, maybe it is the case that it's more suited for particle type systems, 100s of instances of a relatively small amount of geometry, rather than, as here, smallish batches of larger models.
@yojimbo2000 interesting, I wonder if it varies by hardware.
Edit: if you have a sample where instancing is slower, share it here and I'll put it through the profiler to see what's going on.
@Simeon here is the code:
https://gist.github.com/Utsira/5dcfd0ad57ceed56d8d2
It will download the model you choose from GitHub. 60 copies of model number 2 (the default) is what I've used for testing. If you press "Load Normal", it will load and display the number of instances by drawing repeatedly. If you press "LoadInstanced" it will display the copies with instancing. I even swapped out the specular highlight shader for just diffuse shading in the instanced version to try to get it to run faster.
I'm on an iPad Air 1.
Ok this is cool. It's the same example that @Simeon first posted, but instead of supplying an array of transformations, it calculates the positions by referring to the
gl_InstanceIDEXT
variable (It's the instance number).Interestingly, I could only access this by setting instanced drawing on with
#extension GL_EXT_draw_instanced: enable
. @Simeon I'm a bit confused, I'd assumed that the Codea mesh API must have been adding this line to the shaders automatically for instanced drawing to be accessible in GLES 2.0? How are you getting the instanced drawing in GLES 2 if you're not using this extension?@yojimbo2000 I took your code and added more instances so I could check the average frames per second. Both programs draw 16240 rects. The first program uses instanceing and the second just creates a mesh with that many rects. The instanceing runs at an average FPS of 54.5 while the non instanceing runs at an average of 59.6 . I think I did everything right.
@yojimbo2000 I imagine the
gl_InstanceID
variable might only be available in#version 300 es
shaders.One nice thing about instancing is that if you're doing some kind of procedural animation, such as a disintegrating explosion shader, you'd normally have to set up some attribute that indicates which face the vertex belongs to, and where the centre of that face is, whereas that is handled automatically with instancing.
One thing I didn't take into account with my programs above is that the non instanceing mesh is static, so the same mesh is drawn constantly making it faster. I tried two other programs based on the 2 programs above where I moved all 16240 rects around per draw cycle. The non instanceing program went from 59 FPS to 4 FPS. The instanceing program went from 54 FPS to 47 FPS. So if you want to move a lot of rects around, it looks like instanceing works well.
Here are my results on an Air 2
Dave's code with 120,000 [non moving] rects (2x2 to fit them on the screen)
Non instancing = close to 60
Instancing = 16
Yojimbo's models - instancing is about 2/3 of the speed of non instancing
I've only just started playing around, will do some more and report
@Ignatz thank you for the Air 2 results!
My suspicion is that the multi-threaded renderer allows the non-instanced rendering to feed more geometry to the GPU. That is, non-instanced is able to utilise more of the CPU to do geometry uploads to the GPU.
The Air 2 results show a bigger difference because there are 3 CPU cores. The multi-threaded Codea renderer can keep queuing up non-instanced mesh calls.
@Simeon - Thanks for the explanation
Let me know if you want any more tests
Here is an adaptation of @LoopSpace 's explosion/ disintegration shader. It blows an image up into lots of little fragments. Everything is calculated from the instance ID. It fakes some "noise" by sampling the image texture (so you can see brighter parts of the image fly further when it fragments). You'd get a better result if you uploaded an additional noise texture to the vert shader, but I wanted to keep things simple. My suspicion is that @LoopSpace 's original will perform better, because all of the trajectory calculations are performed in advance and then preloaded into buffers in that version. But I do like the simplicity of the Codea side of this version. You only have to define one rect, no buffers, and instancing does the rest.
EDIT: all calculations now done as vec2s
Here is a comment I found on a forum that may help explain why we aren't seeing better performance from instancing.
"Instancing of this form (that is, sending the same mesh data with different instance data) is generally only useful performance-wise if all of the following are true:
1) The mesh you want to render instanced is relatively small, in terms of number of vertices, but not too small (at least ~100 vertices, up to around ~5000 or so)
2) The number of instances of this specific mesh being rendered is large (>1000)"
The OpenGL wiki seems to support this
"It is often useful to be able to render multiple copies of the same mesh in different locations. If you're doing this with small numbers, like 5-20 or so, multiple draw commands with shader uniform changes between them (to tell which is in which location) is reasonably fast in performance. However, if you're doing this with large numbers of meshes, like 5,000+ or so, then it can be a performance problem, and instancing can help."
@yojimbo2000 - re your jittery example above, I just reduced the offset size until it became smooth, for me that was 0.00005
Now that 2.3.2 is out, I removed the beta tag from this thread