Jump to content

Passing array into shader/filter


Recommended Posts

I've recently started learning about shaders to create a lighting system for my new game(Will probably release it for other Phaser developers to use in their game when it's done).

I've got the basics down but have a question about how to use shaders/filters in Phaser.

I managed to figure out how to pass floats and different sized vectors to a shader as a 'Uniform,' and wrote a simple shader to create a single light by passing in a vec4 containing data describing the light, but now I want to expand that to implement any number of lights in a given level and add functionality to my level editor to create/modify lights. I figured the easiest way to do this would be to just have an array of vec4's containing data for each light. I managed to create 2 lights in a level just to test that it worked with my shader algorithm and it did, but to do that I just had 2 uniforms named light1 and light2, which obviously isn't expandable.


I know GLSL supports matrixes, which are basically an array of vectors(which in turn is a basically an array of floats). If I could find out how to create matrices that MIGHT work, unless I'm limited to 4x4 matrices. It'd be preferable to create an array of vectors but if anyone knows how to create a Uniform of either type it'd be helpful. Basically, what I need to know is 1. how to define the type (e.g: type: '4f', for a 4d vector), how to define the uniform object (e.g: {x: 1, y: 2, z: 3, w: 4, for a 4d vector), and how to access it in GLSL(though I could probably look this one up on my own if I could figure out how to create array uniforms in phaser).

Btw - right now I'm applying a single shader to the world that creates all of the lighting effects. I just thought while I was typing this up, instead of using an Array would it be possible/more optimal to either create a separate shader for each light and apply it to the world, therefore cutting out the need for array uniforms because I'd just have an array of shaders instead? Or maybe create a tiny transparent sprite for each light, add the lighting shader to the sprite, and position the sprite wherever I want? that would make it easier to implement creating/editing lights in my level editor, but I've had some confusing results when applying shaders/filters directly to sprites in Phaser and also I don't know how that would effect performance.


Sorry this was a bit of a long post, thanks for the help - I have more questions below but this was already pretty long and this first question is the only one that I might not be able to figure out on my own eventually.




A few bonus questions for anyone who is experienced with shaders and wouldn't mind answering some questions to save me a lot of time looking stuff up:
Right now my lights are very basic, they have x/y for position, z for strength, and w for size. I'd like to include more data to define color, dropoff, etc. Is there a better way to do this? I was thinking I'd just make 2 vector arrays, one for the position, strength, and size of the light, and another for rgb values and dropoff rate, and just make the indices match for each light and grab data from each array.


Also, it seems 'Filters' are only capable of fragment shaders, is this correct?(I don't quite know all the difference between the different types of shaders yet but I'd like to know as I learn more because it will probably become relevant).


I've also noticed some weird behavior when applying a shader to a sprite directly(as opposed to the world). Specifically, something seems off the the coordinates of the sprite/fragments in the world. I don't know enough to figure out what yet, but is there any known quirks/issues there that I should know about or am I probably just doing something wrong?


And finally, as I was writing this post I thought of another approach to creating multiple lights(if the array thing doesn't work out, or even if it does this may be a better approach): I could make a blank sprite for each light, and apply the shader to that sprite. Then I don't need to use arrays to define all of the lights, each sprite will have a shader with one light. Would this work? Would it be better/worse performance-wise than just applying the light shaders to the world? And would that mean I would have to have a blank sprite that is as big or bigger than the entire area the light effects, could I just have a 1x1 transparent sprite and apply the light effect all around, or can shaders only effect pixels that are a part of the sprite(I'm thinking that since the shader runs for every pixel on the sprite, and you use gl_FragCoord to get the coordinates of the current pixel, there'd be no way to access and modify sprites outside of the sprites area. However I think I've seen shaders that do effect a greater area than the image they are applied to, is there a function in GLSL that retrieves different fragments/pixels given their coordinates and allows you to modify the gl_FragColor of any fragment you choose?

Link to comment
Share on other sites

SOLVED - In case anyone else stumbles across this trying to solve a similar problem.


to pass an array of vecs to a shader, use type: '3fv', for e.g. a 3d vector. basically just add v to the end. Then for the value, pass in a straight js array of floats. In this case(3fv), pass an array with 6 elements to create an array with 2 elements(each of which is a 3d vector). GLSL automatically maps the array to the vector. e.g:

customUniforms = {
  arr: {type: "3fv", value: 
    [0.0, 0.1, 0.2,    //arr[0].x = 0.0, arr[0].y = 0.1, arr[0].z = 0.2
     0.3, 0.4, 0.5,    //arr[1].x = 0.3, arr[1].y = 0.4, arr[1].z = 0.5
     0.6, 0.7, 0.8]}    //arr[2].x = 0.6, arr[2].y = 0.7, arr[2].z = 0.8

then, in glsl, declare it like this: "uniform vec3    arr[3];" and access the elements of arr as shown in the comments of the uniform declaration above.



For a straight array of floats, just use 1fv. Then you can use it just like an array of floats in your GLSL code, instead of vectors. You can make it any length you want, just make sure when you initialize the variable in your GLSL it has the same size as the array that you are passing to the uniform(in the case of '1fv' that means if your array has 9 elements then you should declare it in your shader as 'uniform float arr[9]' - if it's a vec3('3fv') and you pass an array with 9 elements, it should only have length 3: 'uniform vec3 arr[3];' because each 3 elements of the array creates a single vec3 element).


If anyone has any more questions reply here and I'll try to answer you if I can

Edited by moe091
Link to comment
Share on other sites


  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Create New...