I am doing a particle system in WebGL using Three.js, and I want to do all the computation of the particles in the shaders. To achieve that, the positions (for example) of the particles are stored in a texture which is sampled by the vertex shader of each particle (POINT primitive).
The position texture is in fact two render targets which are swapped each frame after being updated off screen. Each pixel of this texture represent a particle.
To update a position, I read one of he render targets (texture2D), do some computation, and write on the other render target (fragment output).
To perform the "do some computation" step, I need some per particle attributes, like its velocity (and a lot of others). Since this step is done in the fragment shader, I can't use the vertex attributes buffers, so I have to store these properties in separate textures and sample each of them in the fragment shader.
It works, but sampling textures is slow as far as I know, and I wonder if there is some better ways to do this, like having one vertex per particle, each rendering a single fragment of the position texture.
I know that OpenGL 4 as some alternative ways to deal with this, like UBO or SSBO, but I'm not sure about WebGL.
Related
I have been working on programming a game where everything is rendered in 3d. Though the bullets are 2d sprites. this poses a problem. I have to rotate the bullet sprite by rotating the material. This turns every bullet possessing that material rather than the individual sprite I want to turn. It is also kind of inefficient to create a new sprite clone for every bullet. is there a better way to do this? Thanks in advance.
Rotate the sprite itself instead of the texture.
edit:
as OP mentioned.. the spritematerial controls the sprites rotation.y, so setting it manually does nothing...
So instead of using the Sprite type, you could use a regular planegeometry mesh with a meshbasic material or similar, and update the matrices yourself to both keep the sprite facing the camera, and rotated toward its trajectory..
Then at least you can share the material amongst all instances.
Then the performance bottleneck becomes the number of drawcalls.. (1 per sprite)..
You can improve on that by using a single BufferGeometry, and computing the 4 screen space vertices for each sprite, each frame. This moves the bottleneck away from drawCalls, and will be limited by the speed at which you can transform vertices in javascript, which is slow but not the end of the world. This is also how many THREE.js particle systems are implemented.
The next step beyond that is to use a custom vertex shader to do the heavy vertex computation.. you still update the buffergeometry each frame, but instead of transforming verts, you're just writing the position of the sprite into each of the 4 verts, and letting the vertex shader take care of figuring out which of the 4 verts it's transforming (possibly based on the UV coordinate, or stored in one of the vertex color channels..., .r for instace) and which sprite to render from your sprite atlas (a single texture/canvas with all your sprites layed out on a grid) encoded in the .g of the vertex color..
The next step beyond that, is to not update the BufferGeometry every frame, but store both position and velocity of the sprite in the vertex data.. and only pass a time offset uniform into the vertex shader.. then the vertex shader can handle integrating the sprite position over a longer time period. This only works for sprites that have deterministic behavior, or behavior that can be derived from a texture data source like a noise texture or warping texture. Things like smoke, explosions, etc.
You can extend these techniques to draw gigantic scrolling tilemaps. I've used these techniques to make multilayer scrolling/zoomable hexmaps that were 2048 hexes square, (which is a pretty huge map)(~4m triangles). with multiple layers of sprites on top of that, at 60hz.
Here the original stemkoski particle system for reference:
http://stemkoski.github.io/Three.js/Particle-Engine.html
and:
https://stemkoski.github.io/Three.js/ParticleSystem-Dynamic.html
I am using three.js to render a voxel representation as a set of triangles. I have got it render 5 million triangles comfortably but that seems to be the limit. you can view it online here.
select the Dublin model at resolution 3 to see a lot of triangles being drawn.
I have used every trick to get it this far (buffer geometry, voxel culling, multiple buffers) but I think it has hit the maximum amount that openGL triangles can accomplish.
Large amounts of voxels are normally rendered as a set of images in a 3D texture and while there are several posts on how to hack 2d textures into 3D textures but they seem to have a maximum limit on the texture size.
I have searched for tutorials or examples using this approach but haven't found any. Has anyone used this approach before with three.js
Your scene is render twice, because SSAO need depth texture. You could use WEBGL_depth_texture extension - which have pretty good support - so you just need a single render pass. You can stil fallback to low-perf-double-pass if extension is unavailable.
Your voxel's material is double sided. It's may be on purpose, but it may create a huge overdraw.
In your demo, you use a MeshPhongMaterial and directional lights. It's a needlessly complex material. Your geometries don't have any normals so you can't have any lighting. Try to use a simpler unlit material.
Your goal is to render a huge amount of vertices, so assuming the framerate is bound by vertex shader :
try stuff like https://github.com/GPUOpen-Tools/amd-tootle to preprocess your geometries. Focusing on prefetch vertex cache and vertex cache.
reduce the bandwidth used by your vertex buffers. Since your vertices are aligned on a "grid", you could store vertices position as 3 Shorts instead of 3 floats, reducing your VBO size by 2. You could use a same tricks if you had normals since all normals should be Axis aligned (cubes)
generally reduce the amount of varyings needed by fragment shader
if you need more attributes than just vec3 position, use one single interleaved VBO instead of one per attrib.
I happened to see this shader on shader toy.
https://www.shadertoy.com/view/ldf3W8
I wanted to know what:
uniform samplerXX iChannel0..3;
is?
I tried to look at the vertex shader, but I don't find any thing there.
Also how can I convert audio waves to a texture? (which is being done here)
I wanted to know what uniform samplerXX iChannel0..3; is?
uniforms are externally set variables that have the same value for invocations of the shader during a primitive draw (a vertex shader gets called for each vertex a primitive consists of, fragment shaders for each fragment (which is roughly translates to pixels) drawn to by the primitive).
samplers are OpenGL's way of binding texture units to a shader. In the actual OpenGL program you're loading the texture using glGenTextures, glActiveTexture, glBindTexture, glTexImage (and a bunch of other functions, but those are the important ones) and bind the texture unit selected with glActiveTexture to a sampler uniform.
Also how can I convert audio waves to a texture?
Textures are just interpolated lookup tables. You can place any data you like in a LUT. Most of the time a texture is used for image data, but you can loac PCM samples into it just as well. So you simply fetch PCM data from the audio API and pass it into a texture as data.
I want to make a toon border effect. For it, I'll use the depth value of the neighbor pixels of each pixel to determine if it is or isn't supposed to be blacked. How can I access that information inside the fragment shader?
When you render your scene in a normal way (vertex shader, then fragment shader - single pass) then in the fragment shader there is no way to access depth values for another pixels.
But:
You can render scene twice and perform some postprocessing effects. In the first run you store depth values and others (like normals, etc) in RenderTarget (in texture) then you use those textures in the second pass.
Here you have effect from XNA, but can be quickly ported to GLSL: http://xnameetingpoint.weebly.com/shader7f31.html
Here some link about Render to Texture: http://learningwebgl.com/blog/?p=1786
Hint: depth values will not be enough for border detection, you have to use normals as well. But it is covered in the above tutorial from XNA.
I'm writing a 2D RPG using the LWJGL and Java 1.6. By now, I have a 'World' class, which holds an ArrayList of Tile (interface with basic code for every Tile) and a GrassTile class, which makes the use of a Spritesheet.
When using Immediate mode to draw a grid of 64x64 GrassTiles I get around 100 FPS and do this by calling the .draw() method from each tile inside the ArrayList, which binds the spritesheet and draws a certain area of it (with glTexCoord2f()). So I heard it's better to use VBO's, got a basic tutorial and tried to implement them on the .draw() method.
Now there are two issues: I don't know how to bind only a certain area of a texture to a VBO (the whole texture would be simply glBindTexture()) so I tried using them with colours only.
That takes me to second issue: I got only +20 FPS (120 total) which is not really what I expected, so I suppose I'm doing something wrong. Also, I am making a single VBO for each GrassTile while iterating inside the ArrayList. I think that's kind of wrong, because I can simply throw all the tiles inside a single FloatBuffer.
So, how can I draw similar geometry in a better way and how can I bind only a certain area of a Texture to a VBO?
So, how can I draw similar geometry in a better way...
Like #Ian Mallett described; put all your vertex data into a single vertex buffer object. This makes it possible to render your map in one call. If your map get 1000 times bigger you may want to implement a camera solution which only draws the vertices that are being shown on the screen, but that is a question that will arise later if you're planning on a significantly bigger map.
...and how can I bind only a certain area of a Texture to a VBO?
You can only bind a whole texture. You have to point to a certain area of the texture that you want to be mapped.
Every texture coordinate relates to a specific vertex. Every tile relates to four vertices. Common tiles in your game will share the same texture, hence the 'tile map' name. Make use of that. Place all your tile textures in a texture sheet and bind that texture sheet.
For every new 'tile' you create, check whether the area is meant to be air, grass or ground and then point to the part of the texture that corresponds to what you intend.
Let's say your texture area in pixels are 100x100. The ground area is 15x15 from the lower left corner. Follow the logic above explains the example code being shown below:
// The vertexData array simply contains information
// about a tile's four vertices (or six
// vertices if you draw using GL_TRIANGLES).
mVertexBuffer.put(0, vertexData[0]);
mVertexBuffer.put(1, vertex[1]);
mVertexBuffer.put(2, vertex[2]);
mVertexBuffer.put(3, vertex[3]);
mVertexBuffer.put(4, vertex[4]);
mVertexBuffer.put(5, vertex[5]);
mVertexBuffer.put(6, vertex[6]);
mVertexBuffer.put(7, vertex[7]);
mVertexBuffer.put(8, vertex[8]);
mVertexBuffer.put(9, vertex[9]);
mVertexBuffer.put(10, vertex[10]);
mVertexBuffer.put(11, vertex[11]);
if (tileIsGround) {
mTextureCoordBuffer.put(0, 0.0f);
mTextureCoordBuffer.put(1, 0.0f);
mTextureCoordBuffer.put(2, 0.15f);
mTextureCoordBuffer.put(3, 0.0f);
mTextureCoordBuffer.put(4, 0.15f);
mTextureCoordBuffer.put(5, 0.15f);
mTextureCoordBuffer.put(6, 0.15f);
mTextureCoordBuffer.put(7, 0.0f);
} else { /* Other texture coordinates. */ }
You actually wrote the solution. The only difference is that you should upload the texture coordinates data to the GPU.
This is the key:
I am making a single VBO for each GrassTile while iterating inside the ArrayList.
Don't do this. You make a VBO once, and then you update it if necessary. Making textures, VBOs, shaders, is the slowest possible use of OpenGL--no wonder you're getting problematic framerates--you're doing it O(n) times, each frame.
I think that's kind of wrong, because I can['t?] simply throw all the tiles inside a single FloatBuffer.
You only gain performance when you batch draw calls. This means that when you draw your tiles, you should draw all of them at once with one VBO.
//Initialize
Make a single VBO (or two: one for vertex, one for texture
coordinates, whatever--the key point is O(1) VBOs).
Fill your VBO with ALL of your tiles' data.
//Main loop
while (true) {
Draw the VBO with a single draw call,
thus drawing all your tiles all at once.
}