Skip to content

Instantly share code, notes, and snippets.

@greenfox1505
Forked from securas/spritestack.shader
Created June 30, 2020 03:30
Show Gist options
  • Save greenfox1505/208bac0e7bae4ceed0ec9a1f91346af2 to your computer and use it in GitHub Desktop.
Save greenfox1505/208bac0e7bae4ceed0ec9a1f91346af2 to your computer and use it in GitHub Desktop.
shader_type canvas_item;
uniform sampler2D spritesheet; // Should be a slice image as exported from Magica Voxel
uniform int slice_count = 1; // The number of slices
uniform vec2 camera_vec = vec2( 1., 1. ); // Recomend using (1,1) or (1,1.5)
uniform float camera_ang = 0.0; // change this to change the view angle of the object
uniform bool flip_stack_order = true;
const int MAX_SLICE_COUNT = 1000;
const vec2 center = vec2( 0.5 );
bool scale_and_rotate_with_offset( inout vec2 uv, vec2 sxy, float ang, vec2 cent, vec2 offset )
{
mat2 trmat = mat2( vec2( sxy.x * cos( ang ), -sxy.x * sin( ang ) ), vec2( sxy.y * sin( ang ), sxy.y * cos( ang ) ) );
uv = trmat * ( uv - cent ) + cent - ( offset * sxy ) * inverse( trmat );
if( uv.x < 0. || uv.x > 1. || uv.y < 0. || uv.y > 1. ) return false;
return true;
}
vec4 texture_slice( vec2 uv, int sliceno )
{
if( flip_stack_order )
sliceno = slice_count - sliceno;
float slice_height_uv = 1. / float( slice_count );
vec2 sliceuv = uv;
sliceuv.y *= slice_height_uv;
sliceuv.y += float( sliceno ) * slice_height_uv;
return textureLod( spritesheet, sliceuv, 0. );
}
void vertex()
{
VERTEX *= 4.0;
}
void fragment()
{
vec2 uvx = UV;//floor( UV / ( TEXTURE_PIXEL_SIZE / 4.0 ) ) * ( TEXTURE_PIXEL_SIZE / 4.0 );
//uvx.y = floor( uvx.y / ( TEXTURE_PIXEL_SIZE.y / 4.0 ) ) * TEXTURE_PIXEL_SIZE.y / 4.0;
vec2 uv = ( uvx - vec2( 0.5 ) ) * 4.0 + vec2( 0.5 );
vec4 c;
vec2 py = vec2( 0., 1.*TEXTURE_PIXEL_SIZE.y );
vec2 camera_vec_norm = normalize( camera_vec );
float sliceno = 0.0;
for(int i = 0; i < MAX_SLICE_COUNT; i++){
if(sliceno >= float(slice_count)){break;}
sliceno = 0.25 * float(i);
vec2 uv1 = uv;
if( scale_and_rotate_with_offset( uv1, camera_vec, camera_ang, center, -camera_vec.y * float( sliceno ) * py ) )
{
//vec2 pxs =
vec4 c1 = texture_slice( uv1, slice_count - int( sliceno ) - 1 );
if( c1.a > 0. ) c = c1;
}
}
COLOR = c;
}
@greenfox1505
Copy link
Author

Godot on GLES2 in WebGL failed at the unbounded for loop. For loops in WebGL must have hard limits (not uniforms). I fixed this with line 46-48.

for( sliceno = 0.0; sliceno < float( slice_count ); sliceno += 0.25 )

I also added a stack inverter (flip_stack_order). SpriteStack.io exports stacks in the reverse order, so this now is now compatible with that.

@securas
Copy link

securas commented Jun 30, 2020

great!

@nmearl
Copy link

nmearl commented Nov 9, 2020

Hey @greenfox1505, @securas. This is awesome, thanks for putting this together. However, I'm having an issue where the result isn't really what I expect? Here's what I see:

image

This is just a slice export from one of the default MagicaVoxel models. The sprite sheet result is 20x420, with 20 slices (the sprite itself is 20x21, which is the sprite I have in the Sprite Node). As you can see, I'm getting gaps in the helmet and things look a bit skewed.

Any obvious reason why I might be experiencing this?

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment