{"id":19817153,"url":"https://github.com/nvpro-samples/vk_toon_shader","last_synced_at":"2025-09-05T17:31:29.393Z","repository":{"id":86083494,"uuid":"274906330","full_name":"nvpro-samples/vk_toon_shader","owner":"nvpro-samples","description":"Silhouette and toon shading post-processing with Vulkan","archived":false,"fork":false,"pushed_at":"2024-06-28T09:56:16.000Z","size":16275,"stargazers_count":81,"open_issues_count":0,"forks_count":7,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-12-25T03:07:46.098Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nvpro-samples.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-06-25T12:06:57.000Z","updated_at":"2024-10-11T20:12:14.000Z","dependencies_parsed_at":"2024-06-28T11:21:11.914Z","dependency_job_id":null,"html_url":"https://github.com/nvpro-samples/vk_toon_shader","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvpro-samples%2Fvk_toon_shader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvpro-samples%2Fvk_toon_shader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvpro-samples%2Fvk_toon_shader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nvpro-samples%2Fvk_toon_shader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nvpro-samples","download_url":"https://codeload.github.com/nvpro-samples/vk_toon_shader/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232049596,"owners_count":18465275,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T10:11:51.080Z","updated_at":"2025-01-01T05:15:04.476Z","avatar_url":"https://github.com/nvpro-samples.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Silhouette and toon shading\n\nThis sample is loading a glTF scene and extracting lines for object contours and details, like when there is a sharp curvature on the object.\n\nThis is only post-processing, no line/edge drawing.\n\n![](doc/vk_toon_shader.png)\n\n\n## Line extractions\n\nEither we are using the raster or the ray tracer, the renderer must provide 3 data information: normal, depth, object id. \n\n![normal](doc/normal.png)\n![depth](doc/depth.png)\n![objectID](doc/object_id.png)\n\nIn the fragment shader, or in the closest hit shader, these data will be stored in a single RGBA32F buffer, where the first XY will have the normal data encoded, Z, the depth and W the object ID, an integer we cast to float.\n\n## Contour Extraction\n\nTo extract the contour, we are using a post-processing pipeline, mainly using a fragment shader. There is a case where we are using a compute shader to find the min and max value of the depth buffer.\n\nThe extraction of the object contour is done by comparing the actual pixel with the neighbors. We compare each immediate neighbor if the value is greather, smaller or different from the current one. This has for effect to create a line on the current object, outside of it or both, which makes a thicker line.\n\n~~~~\n     +---+---+---+\n     | A | B | C |\n     +---+---+---+\n     | D | X | E |\n     +---+---+---+\n     | F | G | H |\n     +---+---+---+\n~~~~\n\nComparing X against any A-H, if one value is (\u003c , \u003e, !=) then we set 1 to the result.\n\nThe GLSL shader is a fragment shader, but to use the `unsigned int` from Iray, we cast the image pixels data to a single `GL_R32F` and in the fragment shader, we reinteprete the \nvalue as an integer using `floatBitsToInt`.\n\nThis will result to something like this\n\n![obj](doc/obj_contour.png)\n\n### FXAA\n\nThe result is jaggy and one method to remove this, is to apply a FXAA pass on the image, which is resulting to smoother lines.\n\n![obj](doc/obj_contour_fxaa.png)\n\n\n## Normal and depth\n\n In some cases, the contour of individual object is not enough as we might want to see details that are part of the same object, like crease and valleys.\n\nThis is without\n\n![Without](doc/nrm_depth_without.png)\n\n\nWith depth and normal extraction\n\n![With](doc/nrm_depth.png)\n\n### Normal extraction\n\nTo extract the normal gradient to create and create additional contour, we are using the\nfollowing function. See above for the position of the surrounding pixels.\n\n`N = (|X-B|∙|X-B|) + (|X-G|∙|X-G|) + (|X-E|∙|X-E|) + (|X-D|∙|X-D|)`\n\n### Depth extraction\n\nFor depth extraction, we are normalizing the depth value by finding the nearest depth \nposition (d1) and the farthest value (d2).\n\nSince we want to clearly emphasis the elements closer to the camera to avoid too many \ncontour created in the background, we will give more priority to the closest elements as you can see with the blue line.\n\n \u003ciframe src=\"https://www.desmos.com/calculator/quc4zl5xf8?embed\" width=\"500px\" height=\"300px\" style=\"border: 1px solid #ccc\" frameborder=0\u003e\u003c/iframe\u003e\n\n\nThe extraction of the depth contour is done using Sobel eqn. [linear1] for the first order of differential and eqn. [linear2]\nSee: [Comprehensible Rendering of 3-D Shapes](https://www.cs.princeton.edu/courses/archive/fall00/cs597b/papers/saito90.pdf)\n\nlinear1: `g = (|A +2B +C -F-2G-H| + C|C+2E+H-A-2D-F|)/8`\n\nlinear2: `l = (8X -A-B-C-D-E-F-G-H)/3`\n\n## References\n\n* https://graphics.pixar.com/library/ToonRendering/paper.pdf\n* https://en.wikipedia.org/wiki/Cel_shading\n* https://gfx.cs.princeton.edu/gfx/pubs/DeCarlo_2003_SCF/DeCarlo2003.pdf\n* http://www.markmark.net/npar/npar2000_lake_et_al.pdf\n* https://hpi.de/fileadmin/user_upload/hpi/navigation/10_forschung/30_publikationen/15_dissertationen/Diss_Nienhaus.pdf\n* https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter15.html\n* https://www.ijstr.org/final-print/apr2018/Edge-Detection-In-Images-Using-Haar-Wavelets-Sobel-Gabor-And-Laplacian-Filters.pdf\n* https://en.wikipedia.org/wiki/Canny_edge_detector\n* https://www.cs.princeton.edu/courses/archive/fall00/cs597b/papers/saito90.pdf\n* https://adempsey.github.io/edgey/\n\n \n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvpro-samples%2Fvk_toon_shader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnvpro-samples%2Fvk_toon_shader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnvpro-samples%2Fvk_toon_shader/lists"}