Graphics APIs and Shading Languages
Rendering APIs like OpenGL and DirectX provide the necessary interface for rendering 2D and 3D graphics. GLSL is the shading language tailored for OpenGL, boasting excellent cross-platform compatibility across Windows, Linux, macOS, and mobile platforms. Conversely, HLSL is heavily tied to Microsoft's ecosystem, primarily functioning on Windows and Xbox, lacking compilers for other environments. Cg, developed by Nvidia, bridges this divide by functioning as a truly cross-platform shading language.
GPU Rendering Pipeline Stages
1. Vertex Processing
As the initial pipeline stage, the vertex shader receives input directly from the CPU. It operates on a per-vertex basis, executing once for every vertex provided. Its core responsibilities include coordinate transformations and per-vertex lighting calculations. It can also output custom data required by subsequent stages. The minimal requirement for this stage is transforming vertex coordinates from local model space into homogeneous clip space.
2. Primitive Clipping
Since camera frustums cannot always encompass an entire massive scene, geometry outside the view volume is discarded to save resources. A primitive's relationship to the camera falls into three categories: entirely inside, partially inside, or entirely outside. Primitives partially inside require clipping; for instance, if a line segment has one vertex inside and one outside, the external vertex is replaced by a new vertex generated at the intersection of the line and the frustum boundary.
3. Screen Space Mapping
At this point, coordinates remain in 3D. Screen mapping converts the x and y components of primitives into a 2D screen coordinate system tied to the display resolution. These screen coordinates dictate which specific pixel a vertex corresponds to and its relative depth. Note that OpenGL anchors the screen origin at the bottom-left, whereas DirectX places it at the top-left—a discrepancy that often causes flipped renders if overlooked.
4. Triangle Setup and Traversal
These stages mark the beginning of rasterization. The setup phase computes the necessary boundary equations for a triangle based on vertex endpoints. The traversal phase, sometimes called scan conversion, scans these boundaries to determine which pixels fall inside the triangle. Covered pixels generate fragments, and the data from the three triangle vertices is interpolated across these fragments.
5. Fragment Processing
This programmable stage consumes the interpolated data produced by rasterization. Its primary output is one or more color values. A fundamental technique executed here is texture sampling; UV coordinates passed from the vertex shader are interpolated across the primitive, allowing the fragment shader to map texture pixels to fragments accurately.
6. Fragment Tests and Blending
Referred to as the Output Merger stage in DirectX, this phase dictates final visibility via depth and stencil tests. If a fragment passes all evaluations, its resulting color is blended with the existing color residing in the framebuffer.
Unity Shader Paradigms
- Surface Shaders: A higher-level abstraction encapsulating Vertex/Fragment logic for simplified lighting interactions.
- Vertex/Fragment Shaders: Granular control over the rendering pipeline.
- Fixed Function Shaders: Deprecated legacy syntax used for outdated hardware limitations.
Unity Shader Architecture
Shader "Custom/IntroShader"
{
Properties { /* Material inputs defined here */ }
SubShader
{
// Multiple SubShaders can exist; Unity evaluates them top-down
// based on hardware capability.
Pass
{
// Rendering logic implemented using HLSL/CG
CGPROGRAM
// Shader code...
ENDCG
}
}
Fallback "Diffuse" // Default fallback if SubShaders fail
}Properties and Variable Mapping
Declaration Block
_BaseTint("Main Color", Color) = (1,1,1,1)
_CustomDir("Direction Vector", Vector) = (1,2,3,4)
_SampleInt("Integer Value", Int) = 2
_SampleFloat("Float Value", Float) = 12.3
_SampleRange("Clamped Value", Range(0.0, 10.0)) = 1.0
_MainTex("Albedo Map", 2D) = "white" {}
_EnvCube("Skybox Cube", Cube) = "red" {}
_VolTex("Volume Data", 3D) = "black" {}Variable Implementation
float4 _BaseTint;
float4 _CustomDir;
float _SampleInt;
float _SampleRange;
sampler2D _MainTex;
samplerCUBE _EnvCube;
sampler3D _VolTex;Precision Qualifiers
- float: 32-bit precision, standard for complex calculations.
- half: 16-bit precision, range of roughly -60,000 to 60,000.
- fixed: 11-bit precision, ideal for simple color operations on mobile.
Vertex and Fragment Functions
Vertex Program
#pragma vertex VertMain
float4 VertMain(float4 localPos : POSITION) : SV_POSITION
{
// Transform local model space to homogeneous clip space
return UnityObjectToClipPos(localPos);
}Fragment Program
#pragma fragment FragMain
fixed4 FragMain() : SV_Target
{
// Output a solid white pixel
return fixed4(1, 1, 1, 1);
}Data Structures and Inter-Stage Communication
Structs streamline parameter passing between stages. Certain attributes like normals are strictly accessible in the vertex stage; utilizing structs ensures this data propagates correctly to the fragment stage.
Shader "Custom/StructPipelineShader"
{
SubShader
{
Pass
{
CGPROGRAM
#pragma vertex VertMain
#pragma fragment FragMain
struct AppData
{
float4 pos : POSITION;
float3 norm : NORMAL;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 clipPos : SV_POSITION;
float3 interpolatedNorm : COLOR0;
};
Varyings VertMain(AppData input)
{
Varyings output;
output.clipPos = UnityObjectToClipPos(input.pos);
output.interpolatedNorm = input.norm;
return output;
}
fixed4 FragMain(Varyings input) : SV_Target
{
// Visualize the interpolated normal direction as a color
return fixed4(input.interpolatedNorm, 1.0);
}
ENDCG
}
}
Fallback "VertexLit"
}Fragment computations yield superior visual fidelity compared to vertex computations because fragments are evaluated per-pixel, producing finer detail despite higher performance overhead.
Common Semantic Keywords
Application to Vertex (AppData)
- POSITION: Local model space vertex coordinates.
- NORMAL: Local model space normal direction.
- TANGENT: Local model space tangent vector.
- TEXCOORD0: Primary UV mapping coordinates.
- COLOR: Per-vertex color attribute.
Vertex to Fragment (Varyings)
- SV_POSITION: Clip space coordinates (consumed internally for rasterization).
- COLOR0 / COLOR1: Custom interpolated float4 data sets.
- TEXCOORD0~7: Interpolated UV or general data channels.
Fragment to Framebuffer
- SV_Target: Final pixel color destination for the render target.