-
Notifications
You must be signed in to change notification settings - Fork 144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create minimum_lowpoly.gdshader #609
Conversation
Pretty cool, how is the performance difference? |
I am very inexperienced with performance topics in games admittedly, but I'll be doing some random experiments today and will see if I can learn how to do performance measurements on the way! |
This is a useful contribution, but to complete #422 it should include texturing, with the unnecessary features of the main shader stripped out as described at the bottom here #422 (comment). This could be done without textures, using the colormap. That's an acceptable solution. So that needs to be included in the shader, as well as documented instructions in the shader comments so they don't try adding textures. |
@CrowhopTech I belive this would be a good example: shader_type spatial;
render_mode blend_mix,depth_draw_opaque,cull_back,diffuse_burley,specular_schlick_ggx,skip_vertex_transform;
/* This shader is an example of a minimal, low-poly style.
* The terrain function depends on this shader. So don't change:
* - vertex positioning in vertex()
* - terrain normal calculation in fragment()
*
* Uniforms that begin with _ are private and will not display in the inspector. However,
* you can set them via code. You are welcome to create more of your own hidden uniforms.
*
* This shader only supports the color map.
*
*/
// Defined Constants
#define SKIP_PASS 0
#define VERTEX_PASS 1
#define FRAGMENT_PASS 2
// Private uniforms
uniform uint _background_mode = 1u; // NONE = 0, FLAT = 1, NOISE = 2
uniform uint _mouse_layer = 0x80000000u; // Layer 32
uniform float _vertex_spacing = 1.0;
uniform float _vertex_density = 1.0; // = 1/_vertex_spacing
uniform float _region_size = 1024.0;
uniform float _region_texel_size = 0.0009765625; // = 1/1024
uniform int _region_map_size = 32;
uniform int _region_map[1024];
uniform vec2 _region_locations[1024];
uniform highp sampler2DArray _height_maps : repeat_disable;
uniform highp usampler2DArray _control_maps : repeat_disable;
uniform highp sampler2DArray _color_maps : source_color, filter_nearest_mipmap, repeat_disable;
// Public uniforms
uniform float default_roughness : hint_range(0.0, 1.0, 0.01) = 0.8;
varying flat vec3 v_camera_pos; // required for editor functions
varying vec3 v_vertex; // required for editor functions
varying flat vec2 v_uv_offset;
varying flat vec2 v_uv2_offset;
////////////////////////
// Vertex
////////////////////////
// Takes in UV world space coordinates & search depth (only applicable for background mode none)
// Returns ivec3 with:
// XY: (0 to _region_size) coordinates within a region
// Z: layer index used for texturearrays, -1 if not in a region
ivec3 get_region_uv(const vec2 uv, const int search) {
vec2 r_uv = uv;
vec2 o_uv = mod(r_uv,_region_size);
ivec2 pos;
int bounds, layer_index = -1;
for (int i = -1; i < clamp(search, SKIP_PASS, FRAGMENT_PASS); i++) {
if ((layer_index == -1 && _background_mode == 0u ) || i < 0) {
r_uv -= i == -1 ? vec2(0.0) : vec2(float(o_uv.x <= o_uv.y), float(o_uv.y <= o_uv.x));
pos = ivec2(floor((r_uv) * _region_texel_size)) + (_region_map_size / 2);
bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
layer_index = (_region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1);
}
}
return ivec3(ivec2(mod(r_uv,_region_size)), layer_index);
}
// Takes in UV2 region space coordinates, returns vec3 with:
// XY: (0 to 1) coordinates within a region
// Z: layer index used for texturearrays, -1 if not in a region
vec3 get_region_uv2(const vec2 uv2) {
// Remove texel offset to ensure correct region index
ivec2 pos = ivec2(floor(uv2 - vec2(_region_texel_size * 0.5))) + (_region_map_size / 2);
int bounds = int(uint(pos.x | pos.y) < uint(_region_map_size));
int layer_index = _region_map[ pos.y * _region_map_size + pos.x ] * bounds - 1;
return vec3(uv2 - _region_locations[layer_index], float(layer_index));
}
void vertex() {
// Get camera pos in world vertex coords
v_camera_pos = INV_VIEW_MATRIX[3].xyz;
// Get vertex of flat plane in world coordinates and set world UV
v_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
// UV coordinates in world space. Values are 0 to _region_size within regions
UV = round(v_vertex.xz * _vertex_density);
// UV coordinates in region space + texel offset. Values are 0 to 1 within regions
UV2 = fma(UV, vec2(_region_texel_size), vec2(0.5 * _region_texel_size));
// Discard vertices for Holes. 1 lookup
ivec3 region = get_region_uv(UV, VERTEX_PASS);
uint control = texelFetch(_control_maps, region, 0).r;
bool hole = bool(control >>2u & 0x1u);
// Show holes to all cameras except mouse camera (on exactly 1 layer)
if ( !(CAMERA_VISIBLE_LAYERS == _mouse_layer) &&
(hole || (_background_mode == 0u && region.z < 0))) {
v_vertex.x = 0. / 0.;
} else {
// Set final vertex height & calculate vertex normals. 3 lookups
v_vertex.y = texelFetch(_height_maps, region, 0).r;
}
// Transform UVs to local to avoid poor precision during varying interpolation.
v_uv_offset = MODEL_MATRIX[3].xz * _vertex_density;
UV -= v_uv_offset;
v_uv2_offset = v_uv_offset * _region_texel_size;
UV2 -= v_uv2_offset;
// Convert model space to view space w/ skip_vertex_transform render mode
VERTEX = (VIEW_MATRIX * vec4(v_vertex, 1.0)).xyz;
NORMAL = normalize((MODELVIEW_MATRIX * vec4(NORMAL, 0.0)).xyz);
BINORMAL = normalize((MODELVIEW_MATRIX * vec4(BINORMAL, 0.0)).xyz);
TANGENT = normalize((MODELVIEW_MATRIX * vec4(TANGENT, 0.0)).xyz);
}
////////////////////////
// Fragment
////////////////////////
void fragment() {
// Recover UVs
vec2 uv = UV + v_uv_offset;
vec2 uv2 = UV2 + v_uv2_offset;
// Apply terrain normals
NORMAL = normalize(cross(dFdyCoarse(VERTEX),dFdxCoarse(VERTEX)));
TANGENT = normalize(cross(NORMAL, vec3(0.0, 0.0, 1.0)));
BINORMAL = normalize(cross(NORMAL, TANGENT));
// Determine if we're in a region or not (region_uv.z>0)
vec3 region_uv = get_region_uv2(uv2);
// Colormap. 1 lookup
vec4 color_map = vec4(1., 1., 1., .5);
if (region_uv.z >= 0.) {
float lod = textureQueryLod(_color_maps, uv2.xy).y;
color_map = textureLod(_color_maps, region_uv, lod);
}
// Wetness/roughness modifier, converting 0 - 1 range to -1 to 1 range
float roughness = fma(color_map.a - 0.5, 2.0, default_roughness);
// Apply PBR
ALBEDO = color_map.rgb;
ROUGHNESS = roughness;
SPECULAR = 1.0 - roughness;
} |
Agreed! I had already been thinking about contributing my hacked textured shader, but I feel better with your "official" guidance. I'll take a crack at that tonight, thanks! |
Yes, the color map shader you provided works out of the box 🎉 working on whittling down my texture shader |
@TokisanGames @Xtarsia I have trimmed down the minimal low-poly, used your colormap one out of the box, and updated the initial comment with new screenshots. I am still hacking away at the texture one but will save that for another change request. Thanks so much for your guidance! |
Did you commit it properly? The attached shader is still grey, and has uniforms that aren't used. |
No, I did not... derp. Fixed! There are now two files, the grayscale low-poly and the colormap version. |
Thanks for putting this together. Note you pushed into the main branch. You should never do that as documented in the contributor guidelines. Normally I'm able to fix it, but somehow your repo rejected the change and github force closed this PR. I was able to merge without the PR. You were credited as a contributor. Please review all the contributor guidelines in the future. |
Noted! If I make contributions in the future I will do better. |
Fixes #422.
Based on the existing minimum.gdshader, but with the lowpoly modifications suggested in #422. Also adds a colormap version entirely provided based on the comments here: thanks @Xtarsia !
With the
minimal.gdshader
in the current main of the repo:With this modified
minimal_lowpoly.gdshader
:With
minimum_lowpoly_colormap.gdshader
: