Godot Version
v4.2.1.stable.official [b09f793f5]
Project Details
Just to make the two topic questions easier to understand, I’m going to lay out my general intention with the visual aesthetics of the project I am working on.
- I am using a top-down orthogonal camera with a viewport size of 1920x1080p
- I have low-poly environmental and player assets that should be then pixelated on the player’s screen, as if they were rendered from a lower resolution then scaled up ( with no blurring) to fit the screen.
( I am drawing massive inspiration from T3ssel8r and Eduardo Schildt if you are curious, I sadly can’t link them because I am a new user but I suggest looking them up on youtube since they do the style I want to emulate amazingly.) - I have sprites, specifically enemy and player projectile sprites, that I do not want to be pixelated, remaining as their original resolution always.
- I have VFX and other 3D Mesh material overlays / shader texture work that I want to get pixelated to the same effect as the low-poly assets.
- I want to be able to apply other shader FX to the screen like warping, distortion, screen shake, etc. (Not too important though.)
Right now I cannot achieve 3-5 with what I have currently.
Question(s)
So my questions come from mostly all of my roadblocks because this is my first time doing anything ever with shaders in Godot.
So to start, here is the pixelation shader that I am working with right now. It is applied as a mesh shader material. The mesh is placed like this in the node tree:
CameraPivot
>Camera3D
>>MeshInstance3D
shader_type spatial;
render_mode unshaded;
uniform int pixel_size = 4; //Resolution must be divisible by pixel_size
uniform sampler2D SCREEN_TEXTURE : source_color, hint_screen_texture, filter_nearest;
//To make the mesh cover the camera always.
void vertex(){
POSITION = vec4(VERTEX, 1.0);
}
void fragment(){
float x = float(int(FRAGCOORD.x) % pixel_size);
float y = float(int(FRAGCOORD.y) % pixel_size);
x = FRAGCOORD.x + floor(float(pixel_size) / 2.0) - x;
y = FRAGCOORD.y + floor(float(pixel_size) / 2.0) - y;
ALBEDO = texture(SCREEN_TEXTURE, vec2(x, y) / VIEWPORT_SIZE).xyz;
}
I can’t embed more than 1 image but you’re just going to have to take my word for it that everything is getting pixelated as intended, except for the Sprite3D, it shouldn’t be pixelated at all. I have tried fixing this with creating seperate viewports, one that rendered the world object to be pixelated and one that rendered the sprite3D. But that didn’t work, for some reason the screen was black with the pixelation mesh visible. So going back to a single viewport, I want to point out another issue happening at the same time that I can’t understand completely that also gets in the way. I have a .glb / an ArrayMesh + a GPUParticles3D (that emits another .glb) with shader textures on them that aren’t getting rendered at all when I launch the scene. It appears in the editor, but it isn’t pixelated, which from what I understand means that it isn’t getting processed by the pixelation mesh at all. Here’s an image to explain what I am talking about.
In the editor (The swirl is the Slash360 node and the red banana slash is the meshFX_banana node):
In the actual game I can’t see the Slash360 Node nor the meshFX_banana node.
From what I understand reading up on shaders and how screenspace shaders work in Godot is that in 3D, information from meshes or sprites with transparency do not get grabbed by the hint_screen_texture. So my pixelation shader is not able to grab any VFX shader stuff that I want to add to my character’s weapons or abilities.
I am going to experiment with sub-viewports and viewport textures for the next couple of days whenever I can and write a reply here if I figure anything out but for now I kindly ask if anyone can help me with the general strategy of solving these problems in Godot. How can I render transparent objects around or through a screenspace shader? How can I seperate Sprite3Ds and other objects in 3D space to be rendered as their original resolution ontop of a pixelated world / viewport?