threejs, webGL Custom Shader 01
I've worked on quite a few WebGL projects and always encountered some challenging aspects.
One question I often pondered was how to create and apply shaders more easily according to my preferences.
This led me to start with the simplest shaders, and I feel like I've gained considerable control over many aspects.
My goal wasn't to create realistic PBR shaders, but rather NPBR shaders.
Realistic shaders have already been extensively developed by others, with ample reference materials available (like those in Three.js).
So, I began to wonder how many attractive shaders suited to diverse tastes I could create with NPBR.
From here on, I'll share my journey.
To freely craft NPBR shaders, I started by implementing my own lighting.
This post assumes a basic understanding of programming (WebGL), so please excuse any omissions of fundamental concepts.
First, to create my own shaders, I didn’t use the materials provided by Three.js. Instead, I started with ShaderMaterial.
In the vertexShader, I employed a simple technique as it doesn’t calculate what's visible:
----- vertexShader ------
varying vec3 vNormal;
varying vec3 vViewDir;
void main() {
vec4 modelPosition = modelMatrix * vec4(position, 1.0);
vec4 viewPosition = viewMatrix * modelPosition;
vec4 clipPosition = projectionMatrix * viewPosition;
vNormal = normalize(normalMatrix * normal);
vViewDir = normalize(-viewPosition.xyz);
gl_Position = clipPosition;
}
In the fragmentShader, I only calculated vNormal for normal calculations and vViewDir for specular calculations:
-----fragmentShader ------
#include <common>
#include <lights_pars_begin>
uniform vec3 uColor;
uniform float uGlossiness;
varying vec3 vNormal;
varying vec3 vViewDir;
void main() {
float NdotL = dot(vNormal, directionalLights[0].direction);
float lightIntensity = NdotL;
vec3 directionalLight = directionalLights[0].color * lightIntensity;
vec3 halfVector = normalize(directionalLights[0].direction + vViewDir);
float NdotH = clamp(dot(vNormal, halfVector),0.0,1.0);
float specularIntensity = pow(NdotH * lightIntensity, 50.0 / uGlossiness);
float specularIntensitySmooth = smoothstep(0.05, 0.1, specularIntensity);
vec3 specular = specularIntensity * vec3(1.0,1.0,1.0);
gl_FragColor = vec4(uColor * (directionalLight + ambientLightColor + specular), 1.0);
}
I'm planning to start an English blog to document this journey, so stay tuned for more updates!