DEV Community

k7064569
k7064569

Posted on

Landing page with Three.js & Shader programming

Three.js is a good framework to make a landing page with 3D object & visual effecting.

This is a function to render 3D text with shader programming.

let AddText = (scene, font , fontsize, position, text) =>
{
let vTxShader=`
varying vec3 vWorldPosition;
varying vec4 fragCoord;
varying vec2 vUv;
uniform vec3 iResolution;
uniform float iTime;
varying vec4 fragColor;
uniform float iFontsize;
uniform vec3 iPosition;

#define PI 3.14159265358979
#define P2 6.28318530717959

float Pow5 (float x)
{
    return x*x * x*x * x;
}

float saturate(float x)
{
  return max(0., min(1., x));
}

vec3 F_Schlick1(float u, vec3 f0, float f90) {
  return f0 + (vec3(f90) - f0) * pow(1.0 - u, 5.0);
}

float F_Schlick2(float u, float f0) {
  float f = pow(1.0 - u, 5.0);
  return f + f0 * (1.0 - f);
}

vec3 F_Schlick(vec3 f0, float f90, float u) {
  return f0 + (f90 - f0) * exp2((-5.55473f * u - 6.98316f) * u);  //native_powr(1.f - u, 5.f);
}

float Fr_DisneyDiffuse(float NdotV, float NdotL, float LdotH, float linearRoughness) {
  float energyBias = mix(0., 0.5, linearRoughness);
  float energyFactor = mix(1.0, 1.0 / 1.51, linearRoughness);
  float fd90 = energyBias + 2.0 * LdotH*LdotH * linearRoughness;
  vec3 f0 = vec3(1.0f, 1.0f, 1.0f);
  float lightScatter = F_Schlick(f0, fd90, NdotL).r;
  float viewScatter = F_Schlick(f0, fd90, NdotV).r;

  return lightScatter * viewScatter * energyFactor;
}

float DisneyDiffuse(float NdotV, float NdotL, float LdotH, float perceptualRoughness)
{
    float fd90 = 0.5 + 2. * LdotH * LdotH * perceptualRoughness;
    // Two schlick fresnel term
    float lightScatter   = (1. + (fd90 - 1.) * Pow5(1. - NdotL));
    float viewScatter    = (1. + (fd90 - 1.) * Pow5(1. - NdotV));

    return lightScatter * viewScatter;
}


float ggxNormalDistribution( float NdotH, float roughness )
{
  float a2 = roughness * roughness;
  float d = ((NdotH * a2 - NdotH) * NdotH + 1.);
  return a2 / (d * d * PI);
}

float ggxSchlickMaskingTerm(float NdotL, float NdotV, float roughness)
{
  float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - roughness) + roughness);
  float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - roughness) + roughness);
  float G = 0.5/(GGXV + GGXL);
  return G;
}

vec3 schlickFresnel(vec3 f0, float lDotH)
{
  return f0 + (vec3(1.0f, 1.0f, 1.0f) - f0) * pow(1.0f - lDotH, 5.0f);
}

float D_GGX(float NoH, float roughness) {
  float a = NoH * roughness;
  float k = roughness / (1.0 - NoH * NoH + a * a);
  return k * k * (1.0 / PI);
}

float V_Kelemen(float LoH) {
  return 0.25 / (LoH * LoH);
}

float Fd_Lambert() {
  return 1.0 / PI;
}

float V_SmithGGXCorrelated(float NoV, float NoL, float roughness) {
  float a2 = roughness * roughness;
  float GGXV = NoL * sqrt(NoV * NoV * (1.0 - a2) + a2);
  float GGXL = NoV * sqrt(NoL * NoL * (1.0 - a2) + a2);
  return 0.5 / (GGXV + GGXL);
}


float roughnessValue = 1.1;
vec3 WorldSpaceCameraPos = vec3(0.1, 0.8, 0.8);
vec3 lightpos = vec3(0., 4., -8.);
vec3 baseColor = vec3(0.9, .45, .1);
float lightColor = 3.5;
float clearCoat = 0.5;
float transparent = .8;

void main() {
vUv = uv;
vec4 worldPosition = modelMatrix * vec4(position, 1.0);
vWorldPosition = vec3(-worldPosition.z, worldPosition.y, -worldPosition.x);
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);

vec3 origin = (vec4(iPosition,1.0) * modelMatrix).xyz + vec3(iFontsize/2.5, 5.0, 2.0);
WorldSpaceCameraPos += origin;
lightpos += origin;

float linearRoughness = roughnessValue * roughnessValue;
vec3 normalDirection = normalize(worldPosition.xyz);
vec3 viewDirection = normalize(WorldSpaceCameraPos-worldPosition.xyz);
vec3 lightDirection = normalize(lightpos-worldPosition.xyz);
vec3 halfDirection = normalize(lightDirection + viewDirection );


float NdotL = saturate(dot(normalDirection, lightDirection));
float NdotV = saturate(dot(normalDirection, viewDirection));
float VdotH = saturate(dot(viewDirection, halfDirection));
float NdotH = saturate(dot(normalDirection, halfDirection));
float LdotH = saturate(dot(lightDirection, halfDirection));

float diffuse = Fr_DisneyDiffuse(NdotV, NdotL, LdotH, linearRoughness);
vec3 diffuseColor = baseColor * diffuse/PI;

vec3 F = schlickFresnel(baseColor, LdotH);  
float  D = ggxNormalDistribution(NdotH, linearRoughness);
float  G = ggxSchlickMaskingTerm(NdotL, NdotV, linearRoughness);

vec3 specularReflection = lightColor * baseColor * (F * D * G);

float clearCoatPerceptualRoughness = clamp(roughnessValue, 0.089, 1.0);
float clearCoatRoughness = clearCoatPerceptualRoughness * clearCoatPerceptualRoughness;

float f0 = 0.04;
float  Dc = D_GGX(NdotH, clearCoatRoughness);
float  Vc = V_Kelemen(LdotH);
float  Fc = F_Schlick2(f0, LdotH) * clearCoat; // clear coat strength
float Frc = (Dc * Vc) * Fc;
vec3 Fd = diffuseColor * Fd_Lambert();
float V = V_SmithGGXCorrelated(NdotV, NdotL, clearCoatRoughness);
vec3 Fr = (Dc * V) * F;
vec3 CoatColor =  baseColor * ((Fd + Fr * (1.0 - Fc)) * (1.0 - Fc) + Frc);

float alpha = transparent;//baseColor.a;
vec3 specularColor = specularReflection;    
vec4 glassColor =  vec4(diffuseColor + specularColor, alpha);


fragColor = vec4(diffuseColor, 1.0);
fragColor = vec4(specularReflection, 1.0);
fragColor = glassColor;

fragCoord = gl_Position;
}
`;
let fTxShader=`
varying vec4 fragColor;

void main(void)
{
  gl_FragColor = fragColor;
}
`;

txtMaterial.push(new THREE.ShaderMaterial({
  side: THREE.DoubleSide,
  uniforms: {
    iResolution: {
      value: new THREE.Vector3(window.innerWidth , window.innerHeight, 1)
    },
    iTime: {
      value: time
    },
    iFontsize: {
      value: fontsize
    },
    iPosition: {
      value: position
    }
  },
  vertexShader: vTxShader,
  fragmentShader: fTxShader
})
);


const textGeometry = new TextGeometry( text, {
  font: font,
  size: fontsize,
  height: fontsize,
  curveSegments: 20,
  bevelEnabled: true,
  bevelThickness: fontsize*.5,
  bevelSize: fontsize/10.0,
  bevelOffset: 0.0,
  bevelSegments: 20
} );

var textmesh = new THREE.Mesh( textGeometry, [txtMaterial[txtMaterial.length-1],txtMaterial[txtMaterial.length-1]]);
textmesh.position.set(position.x, position.y, position.z);
scene.add( textmesh );

textTitle.push(textmesh);
return textmesh;
Enter fullscreen mode Exit fullscreen mode

}

Top comments (0)