iconSUPERMATRIX STUDIO
HomeProjectsAboutBlogNewsLatest Project
  1. Home
  2. Blog
  3. Creating a stylized 3D cel shader in godot 4 from scratch
Creating a Stylized 3D Cel Shader in Godot 4 from Scratch

Creating a Stylized 3D Cel Shader in Godot 4 from Scratch

By cyberdevz on September 28, 2025

Tags:#Godot 4#Shaders#Game Dev#3D Art#Cel Shading#Tutorial

Table of Contents#

  • Introduction: The Art of Non-Photorealistic Rendering
  • Step 1: Preparing Your 3D Test Scene
  • Step 2: Creating Your First Visual Shader
  • Step 3: Calculating Light for Hard Shadows
  • Step 4: The Magic of the step() Function
  • Step 5: Adding the Classic Ink Outline
  • Conclusion: A New Stylistic Tool in Your Arsenal

Introduction: The Art of Non-Photorealistic Rendering #

Photorealism is impressive, but some of the most visually stunning games embrace a stylized, artistic look. Cel shading (also known as toon shading) is a non-photorealistic rendering technique that makes 3D models look like they were hand-drawn in a 2D cartoon or anime. It's characterized by flat lighting, hard-edged shadows, and crisp outlines.

In this guide, we'll build a simple but effective 3D cel shader from scratch using the node-based Visual Shader editor, using the correct shader graphs for each operation.


Step 1: Preparing Your 3D Test Scene #

First, we need a simple scene to test our shader.

  1. Create a new 3D Scene.
  2. Add a MeshInstance3D node (e.g., with a SphereMesh).
  3. Add a DirectionalLight3D to cast light.
  4. Add a WorldEnvironment node for basic lighting.
  5. Add and position a Camera3D.

Step 2: Creating the Visual Shader #

Now, let's create the shader resource.

  1. Select the MeshInstance3D node.
  2. In the Inspector, go to Geometry > Material Override and select New ShaderMaterial.
  3. Click the new material, and for its Shader property, select New VisualShader.
  4. Click the VisualShader resource to open the editor.

In the Fragment Graph, which is shown by default, we will only set the base color.

  1. Right-click and add a VectorConstant. This will be your object's color (e.g., a nice orange).
  2. Connect its output to the Albedo input on the Output node.

Step 3: Creating Custom Logic in the Light Graph #

To create the hard-edged shadow, we need to tell the renderer how to calculate light hitting our object. This logic belongs in the Light graph.

  1. At the top of the Visual Shader Editor, click the Light button to switch to the Light graph.
  2. In this graph, add an Input node for Normal and another for LightVector.
  3. Add a DotProduct node and connect Normal and LightVector to its inputs.

Step 4: The Magic of the step() Function #

Now we'll turn the smooth light gradient from the dot product into a sharp line.

  1. Add a Step node and connect the DotProduct output to its sample input.
  2. Add a ScalarConstant (e.g., value 0.5) and connect it to the edge input of the Step node.
  3. Add a Mix node. Connect the Step output to its weight input.
  4. For the first Mix input, use a black VectorConstant for the shadow.
  5. For the second Mix input, add an Input node for Light to get the light's actual color.
  6. Connect the final Mix output to the Diffuse input on the main Output node.

Step 5: Adding the Classic Ink Outline #

The final touch is the outline, which uses the inverted hull method. This requires manipulating the model's vertices, so it is done in the Vertex graph.

  1. Select your main ShaderMaterial in the Inspector. Find the Next Pass property and assign a New ShaderMaterial to it.
  2. Create a New VisualShader for this "Next Pass" material.
  3. Open this new outline shader and click the Vertex button at the top to switch to its Vertex graph.
  4. In the shader's settings (click an empty space in the graph), go to Render Mode and set cull to front. This makes the "inside" of the enlarged mesh visible, which creates the outline.

Now, let's build the vertex offset logic with explicit steps:

  1. Get Vertex Normal: Add an Input node. By default, its type is Normal, which is what we need. This tells us the direction to push the vertex.
  2. Define Outline Thickness: Add a ScalarConstant (e.g., 0.02).
  3. Calculate Offset: Add a VectorOperators > Multiply node. Connect the Normal input and the ScalarConstant to it. The result is our offset vector.
  4. Get Original Vertex Position: Add another Input node. With this node selected, go to the Inspector panel. Click the dropdown for the Input property and change it from Normal to Vertex. This is the crucial step. You now have access to the model's original vertex positions.
  5. Combine and Output: Add a VectorOperators > Add node. Connect the output of your Vertex input node and your offset (from the Multiply node) into it.
  6. Connect the final result from the Add node to the Vertex input on the main Output node.

Finally, click the Fragment button for this outline shader. Since the outline should just be a solid color, add a black VectorConstant and connect it to the Albedo output.


Conclusion: A New Stylistic Tool in Your Arsenal #

By correctly placing logic in the Light graph for custom lighting and the Vertex graph for model manipulation, you have now created a complete, stylized cel shader. Understanding which graph to use—and how to access the correct inputs like Vertex—is key to unlocking the power of Godot's shader system.

Supermatrix Studio

Building immersive, neon-drenched worlds.

Social
TwitterInstagramYouTubeLinkedIn
© 2025 Supermatrix Studio. All rights reserved.