Improve shader example for outlined rect + outlined circle

This commit is contained in:
Charlie Malmqvist 2024-07-22 21:12:08 +02:00
parent e61a294960
commit 9338ec248b
4 changed files with 105 additions and 20 deletions

View file

@ -37,10 +37,10 @@ typedef struct Context_Extra {
// #include "oogabooga/examples/text_rendering.c" // #include "oogabooga/examples/text_rendering.c"
// #include "oogabooga/examples/custom_logger.c" // #include "oogabooga/examples/custom_logger.c"
#include "oogabooga/examples/renderer_stress_test.c" // #include "oogabooga/examples/renderer_stress_test.c"
// #include "oogabooga/examples/tile_game.c" // #include "oogabooga/examples/tile_game.c"
// #include "oogabooga/examples/audio_test.c" // #include "oogabooga/examples/audio_test.c"
// #include "oogabooga/examples/custom_shader.c" #include "oogabooga/examples/custom_shader.c"
// This is where you swap in your own project! // This is where you swap in your own project!
// #include "entry_yourepicgamename.c" // #include "entry_yourepicgamename.c"

View file

@ -10,12 +10,15 @@ typedef struct My_Cbuffer {
// We implement these details which we implement in the shader // We implement these details which we implement in the shader
#define DETAIL_TYPE_ROUNDED_CORNERS 1 #define DETAIL_TYPE_ROUNDED_CORNERS 1
#define DETAIL_TYPE_OUTLINED 2 #define DETAIL_TYPE_OUTLINED 2
#define DETAIL_TYPE_OUTLINED_CIRCLE 3
// With custom shading we can extend the rendering library! // With custom shading we can extend the rendering library!
Draw_Quad *draw_rounded_rect(Vector2 p, Vector2 size, Vector4 color, float radius); Draw_Quad *draw_rounded_rect(Vector2 p, Vector2 size, Vector4 color, float radius);
Draw_Quad *draw_rounded_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float radius); Draw_Quad *draw_rounded_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float radius);
Draw_Quad *draw_outlined_rect(Vector2 p, Vector2 size, Vector4 color, float line_width); Draw_Quad *draw_outlined_rect(Vector2 p, Vector2 size, Vector4 color, float line_width_pixels);
Draw_Quad *draw_outlined_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width); Draw_Quad *draw_outlined_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width_pixels);
Draw_Quad *draw_outlined_circle(Vector2 p, Vector2 size, Vector4 color, float line_width_pixels);
Draw_Quad *draw_outlined_circle_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width_pixels);
int entry(int argc, char **argv) { int entry(int argc, char **argv) {
@ -64,7 +67,9 @@ int entry(int argc, char **argv) {
rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0)); rect_xform = m4_translate(rect_xform, v3(-.25f, -.25f, 0));
Draw_Quad *q = draw_rounded_rect_xform(rect_xform, v2(.5f, .5f), COLOR_GREEN, 0.1); Draw_Quad *q = draw_rounded_rect_xform(rect_xform, v2(.5f, .5f), COLOR_GREEN, 0.1);
draw_outlined_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED, 15); draw_outlined_rect(v2(sin(now), -.8), v2(.5, .25), COLOR_RED, 2);
draw_outlined_circle(v2(-sin(now), -.8), v2(.6, .6), COLOR_BLUE, 2);
// Shader hot reloading // Shader hot reloading
@ -82,6 +87,34 @@ int entry(int argc, char **argv) {
return 0; return 0;
} }
Vector2 world_to_screen(Vector2 p) {
Vector4 in_view_space = m4_transform(draw_frame.view, v4(p.x, p.y, 0.0, 1.0));
Vector4 in_clip_space = m4_transform(draw_frame.projection, in_view_space);
Vector4 ndc = {
.x = in_clip_space.x / in_clip_space.w,
.y = in_clip_space.y / in_clip_space.w,
.z = in_clip_space.z / in_clip_space.w,
.w = in_clip_space.w
};
return v2(
(ndc.x + 1.0f) * 0.5f * (f32)window.width,
(ndc.y + 1.0f) * 0.5f * (f32)window.height
);
}
Vector2 world_size_to_screen_size(Vector2 s) {
Vector2 origin = v2(0, 0);
Vector2 screen_origin = world_to_screen(origin);
Vector2 screen_size_point = world_to_screen(s);
return v2(
screen_size_point.x - screen_origin.x,
screen_size_point.y - screen_origin.y
);
}
Draw_Quad *draw_rounded_rect(Vector2 p, Vector2 size, Vector4 color, float radius) { Draw_Quad *draw_rounded_rect(Vector2 p, Vector2 size, Vector4 color, float radius) {
Draw_Quad *q = draw_rect(p, size, color); Draw_Quad *q = draw_rect(p, size, color);
// detail_type // detail_type
@ -98,19 +131,44 @@ Draw_Quad *draw_rounded_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, f
q->userdata[0].y = radius; q->userdata[0].y = radius;
return q; return q;
} }
Draw_Quad *draw_outlined_rect(Vector2 p, Vector2 size, Vector4 color, float line_width) { Draw_Quad *draw_outlined_rect(Vector2 p, Vector2 size, Vector4 color, float line_width_pixels) {
Draw_Quad *q = draw_rect(p, size, color); Draw_Quad *q = draw_rect(p, size, color);
// detail_type // detail_type
q->userdata[0].x = DETAIL_TYPE_OUTLINED; q->userdata[0].x = DETAIL_TYPE_OUTLINED;
// line_width // line_width_pixels
q->userdata[0].y = line_width; q->userdata[0].y = line_width_pixels;
// rect_size
q->userdata[0].zw = world_size_to_screen_size(size);
return q; return q;
} }
Draw_Quad *draw_outlined_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width) { Draw_Quad *draw_outlined_rect_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width_pixels) {
Draw_Quad *q = draw_rect_xform(xform, size, color); Draw_Quad *q = draw_rect_xform(xform, size, color);
// detail_type // detail_type
q->userdata[0].x = DETAIL_TYPE_OUTLINED; q->userdata[0].x = DETAIL_TYPE_OUTLINED;
// line_width // line_width_pixels
q->userdata[0].y = line_width; q->userdata[0].y = line_width_pixels;
// rect_size
q->userdata[0].zw = world_size_to_screen_size(size);
return q;
}
Draw_Quad *draw_outlined_circle(Vector2 p, Vector2 size, Vector4 color, float line_width_pixels) {
Draw_Quad *q = draw_rect(p, size, color);
// detail_type
q->userdata[0].x = DETAIL_TYPE_OUTLINED_CIRCLE;
// line_width_pixels
q->userdata[0].y = line_width_pixels;
// rect_size_pixels
q->userdata[0].zw = world_size_to_screen_size(size); // Transform world space to screen space
return q;
}
Draw_Quad *draw_outlined_circle_xform(Matrix4 xform, Vector2 size, Vector4 color, float line_width_pixels) {
Draw_Quad *q = draw_rect_xform(xform, size, color);
// detail_type
q->userdata[0].x = DETAIL_TYPE_OUTLINED_CIRCLE;
// line_width_pixels
q->userdata[0].y = line_width_pixels;
// rect_size_pixels
q->userdata[0].zw = world_size_to_screen_size(size); // Transform world space to screen space
return q; return q;
} }

View file

@ -10,6 +10,7 @@ cbuffer some_cbuffer : register(b0) {
#define DETAIL_TYPE_ROUNDED_CORNERS 1 #define DETAIL_TYPE_ROUNDED_CORNERS 1
#define DETAIL_TYPE_OUTLINED 2 #define DETAIL_TYPE_OUTLINED 2
#define DETAIL_TYPE_OUTLINED_CIRCLE 3
float4 get_light_contribution(PS_INPUT input) { float4 get_light_contribution(PS_INPUT input) {
@ -30,6 +31,9 @@ float4 get_light_contribution(PS_INPUT input) {
float4 pixel_shader_extension(PS_INPUT input, float4 color) { float4 pixel_shader_extension(PS_INPUT input, float4 color) {
float detail_type = input.userdata[0].x; float detail_type = input.userdata[0].x;
// Assumes rect with 90deg corners
float2 rect_size_pixels = input.userdata[0].zw;
if (detail_type == DETAIL_TYPE_ROUNDED_CORNERS) { if (detail_type == DETAIL_TYPE_ROUNDED_CORNERS) {
float corner_radius = input.userdata[0].y; float corner_radius = input.userdata[0].y;
@ -44,23 +48,45 @@ float4 pixel_shader_extension(PS_INPUT input, float4 color) {
color *= mask; color *= mask;
} else if (detail_type == DETAIL_TYPE_OUTLINED) { } else if (detail_type == DETAIL_TYPE_OUTLINED) {
float line_width = input.userdata[0].y; float line_width_pixels = input.userdata[0].y;
float2 pixel_pos = round(input.self_uv*window_size); float2 pixel_pos = round(input.self_uv*rect_size_pixels);
float xcenter = window_size.x/2; float xcenter = rect_size_pixels.x/2;
float ycenter = window_size.y/2; float ycenter = rect_size_pixels.y/2;
float xedge = pixel_pos.x < xcenter ? 0.0 : window_size.x; float xedge = pixel_pos.x < xcenter ? 0.0 : rect_size_pixels.x;
float yedge = pixel_pos.y < ycenter ? 0.0 : window_size.y; float yedge = pixel_pos.y < ycenter ? 0.0 : rect_size_pixels.y;
float xdist = abs(xedge-pixel_pos.x); float xdist = abs(xedge-pixel_pos.x);
float ydist = abs(yedge-pixel_pos.y); float ydist = abs(yedge-pixel_pos.y);
if (xdist >= line_width && ydist >= line_width) { if (xdist > line_width_pixels && ydist > line_width_pixels) {
discard; discard;
} }
} } else if (detail_type == DETAIL_TYPE_OUTLINED_CIRCLE) {
float line_width_pixels = input.userdata[0].y;
float2 rect_size_pixels = input.userdata[0].zw;
float line_width_uv = line_width_pixels / min(rect_size_pixels.x, rect_size_pixels.y);
// For some simple anti-aliasing, we add a little bit of padding around the outline
// and fade that padding outwards with a smooth curve towards 0.
// Very arbitrary smooth equation that I got from just testing different sizes of the circle.
// It's kinda meh.
float smooth = ((4.0/line_width_pixels)*6.0)/window_size.x;
float2 center = float2(0.5, 0.5);
float dist = length(input.self_uv - center);
float mask;
if (dist > 0.5-smooth) {
mask = 1.0-lerp(0, 1.0, max(dist-0.5+smooth, 0.0)/smooth);
} else if (dist < 0.5-line_width_uv+smooth) {
mask = smoothstep(0, 1.0, max(dist-0.5+line_width_uv+smooth, 0.0)/smooth);
}
if (mask <= 0) discard;
color *= mask;
}
float4 light = get_light_contribution(input); float4 light = get_light_contribution(input);

View file

@ -132,12 +132,13 @@ void d3d11_update_swapchain() {
DXGI_SWAP_CHAIN_DESC1 scd = ZERO(DXGI_SWAP_CHAIN_DESC1); DXGI_SWAP_CHAIN_DESC1 scd = ZERO(DXGI_SWAP_CHAIN_DESC1);
scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; scd.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING; scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
//scd.BufferDesc.RefreshRate.Numerator = 0; //scd.BufferDesc.RefreshRate.Numerator = 0;
//scd.BufferDesc.RefreshRate.Denominator = 1; //scd.BufferDesc.RefreshRate.Denominator = 1;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.SampleDesc.Count = 1; scd.SampleDesc.Count = 1;
scd.SampleDesc.Quality = 0; scd.SampleDesc.Quality = 0; // #Portability
if (d3d11_feature_level < D3D_FEATURE_LEVEL_11_0) { if (d3d11_feature_level < D3D_FEATURE_LEVEL_11_0) {
scd.Scaling = DXGI_SCALING_STRETCH; // for compatability with 7 scd.Scaling = DXGI_SCALING_STRETCH; // for compatability with 7
} }