Note: This series blog was translated from Nathan Vaughn's Shaders Language Tutorial and has been authorized by the author. If reprinted or reposted, please be sure to mark the original link and description in the key position of the article after obtaining the author’s consent as well as the translator's. If the article is helpful to you, click this Donation link to buy the author a cup of coffee.

### 冯式反射模型

float k_a = 0.6; // 0到1之间的任意值
vec3 i_a = vec3(0.7, 0.7, 0); // 颜色值

vec3 ambient = k_a * i_a;



k_a值是一个环境光照的固定值。环境光对于屏幕上出现的每一个点来说，都是一样的。i_a值表示环境光的颜色，有时它表示所有光源照射的集合。

  vec3 p = ro + rd * d; // point on surface found by ray marching
vec3 N = calcNormal(p); // 表面法线 surface normal
vec3 lightPosition = vec3(1, 1, 1);
vec3 L = normalize(lightPosition - p);

float k_d = 0.5; // a value of our choice, typically between zero and one
vec3 dotLN = dot(L, N);
vec3 i_d = vec3(0.7, 0.5, 0); // a color of our choice

vec3 diffuse = k_d * dotLN * i_d;



k_d是漫反射的常量，漫放射的反射率来自Lambertian reflectancedotLNg则是我们之前教程中使用的漫反射——朗伯反射。i_d，表示场景中的光照强度，它由一个颜色值所定义。

  vec3 p = ro + rd * d; // point on surface found by ray marching
vec3 N = calcNormal(p); // surface normal
vec3 lightPosition = vec3(1, 1, 1);
vec3 L = normalize(lightPosition - p);

float k_s = 0.6; // a value of our choice, typically between zero and one

vec3 R = reflect(L, N);
vec3 V = -rd; //  direction pointing toward viewer (V) is just the negative of the ray direction

vec3 dotRV = dot(R, V);
vec3 i_s = vec3(1, 1, 1); // a color of our choice
float alpha = 10.;

vec3 specular = k_s * pow(dotRV, alpha) * i_s;



k_s表示镜面反射常量，即入射光线的反射率。向量R，是一束光线被放射后的方向：

### 把所有的都放到一起

  const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float PRECISION = 0.001;

float sdSphere(vec3 p, float r )
{
return length(p) - r;
}

float sdScene(vec3 p) {
return sdSphere(p, 1.);
}

float rayMarch(vec3 ro, vec3 rd) {
float depth = MIN_DIST;

for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
vec3 p = ro + depth * rd;
float d = sdScene(p);
depth += d;
if (d < PRECISION || depth > MAX_DIST) break;
}

return depth;
}

vec3 calcNormal(vec3 p) {
vec2 e = vec2(1.0, -1.0) * 0.0005;
return normalize(
e.xyy * sdScene(p + e.xyy) +
e.yyx * sdScene(p + e.yyx) +
e.yxy * sdScene(p + e.yxy) +
e.xxx * sdScene(p + e.xxx));
}

mat3 camera(vec3 cameraPos, vec3 lookAtPoint) {
vec3 cd = normalize(lookAtPoint - cameraPos); // camera direction
vec3 cr = normalize(cross(vec3(0, 1, 0), cd)); // camera right
vec3 cu = normalize(cross(cd, cr)); // camera up

return mat3(-cr, cu, -cd);
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y;
vec3 backgroundColor = vec3(0.835, 1, 1);
vec3 col = vec3(0);

vec3 lp = vec3(0); // lookat point (aka camera target)
vec3 ro = vec3(0, 0, 3);

vec3 rd = camera(ro, lp) * normalize(vec3(uv, -1)); // ray direction

float d = rayMarch(ro, rd);

if (d > MAX_DIST) {
col = backgroundColor;
} else {
vec3 p = ro + rd * d;
vec3 normal = calcNormal(p);
vec3 lightPosition = vec3(2, 2, 7);
vec3 lightDirection = normalize(lightPosition - p);

float diffuse = clamp(dot(lightDirection, normal), 0., 1.);

col = diffuse * vec3(0.7, 0.5, 0);
}

fragColor = vec4(col, 1.0);
}



void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y;
vec3 backgroundColor = vec3(0.835, 1, 1);
vec3 col = vec3(0);

vec3 lp = vec3(0); // lookat point (aka camera target)
vec3 ro = vec3(0, 0, 3);

vec3 rd = camera(ro, lp) * normalize(vec3(uv, -1)); // ray direction

float d = rayMarch(ro, rd);

if (d > MAX_DIST) {
col = backgroundColor;
} else {
vec3 p = ro + rd * d; // point on surface found by ray marching
vec3 normal = calcNormal(p); // surface normal

// light
vec3 lightPosition = vec3(-8, -6, -5);
vec3 lightDirection = normalize(lightPosition - p);

// ambient
float k_a = 0.6;
vec3 i_a = vec3(0.7, 0.7, 0);
vec3 ambient = k_a * i_a;

// diffuse
float k_d = 0.5;
float dotLN = clamp(dot(lightDirection, normal), 0., 1.);
vec3 i_d = vec3(0.7, 0.5, 0);
vec3 diffuse = k_d * dotLN * i_d;

// specular
float k_s = 0.6;
float dotRV = clamp(dot(reflect(lightDirection, normal), -rd), 0., 1.);
vec3 i_s = vec3(1, 1, 1);
float alpha = 10.;
vec3 specular = k_s * pow(dotRV, alpha) * i_s;

// final sphere color
col = ambient + diffuse + specular;
}

fragColor = vec4(col, 1.0);
}



### 多束光线

const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float PRECISION = 0.001;

float sdSphere(vec3 p, float r )
{
return length(p) - r;
}

float sdScene(vec3 p) {
return sdSphere(p, 1.);
}

float rayMarch(vec3 ro, vec3 rd) {
float depth = MIN_DIST;

for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
vec3 p = ro + depth * rd;
float d = sdScene(p);
depth += d;
if (d < PRECISION || depth > MAX_DIST) break;
}

return depth;
}

vec3 calcNormal(vec3 p) {
vec2 e = vec2(1.0, -1.0) * 0.0005;
return normalize(
e.xyy * sdScene(p + e.xyy) +
e.yyx * sdScene(p + e.yyx) +
e.yxy * sdScene(p + e.yxy) +
e.xxx * sdScene(p + e.xxx));
}

mat3 camera(vec3 cameraPos, vec3 lookAtPoint) {
vec3 cd = normalize(lookAtPoint - cameraPos); // camera direction
vec3 cr = normalize(cross(vec3(0, 1, 0), cd)); // camera right
vec3 cu = normalize(cross(cd, cr)); // camera up

return mat3(-cr, cu, -cd);
}

vec3 phong(vec3 lightDir, vec3 normal, vec3 rd) {
// ambient
float k_a = 0.6;
vec3 i_a = vec3(0.7, 0.7, 0);
vec3 ambient = k_a * i_a;

// diffuse
float k_d = 0.5;
float dotLN = clamp(dot(lightDir, normal), 0., 1.);
vec3 i_d = vec3(0.7, 0.5, 0);
vec3 diffuse = k_d * dotLN * i_d;

// specular
float k_s = 0.6;
float dotRV = clamp(dot(reflect(lightDir, normal), -rd), 0., 1.);
vec3 i_s = vec3(1, 1, 1);
float alpha = 10.;
vec3 specular = k_s * pow(dotRV, alpha) * i_s;

return ambient + diffuse + specular;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y;
vec3 backgroundColor = vec3(0.835, 1, 1);
vec3 col = vec3(0);

vec3 lp = vec3(0); // lookat point (aka camera target)
vec3 ro = vec3(0, 0, 3);

vec3 rd = camera(ro, lp) * normalize(vec3(uv, -1)); // ray direction

float d = rayMarch(ro, rd);

if (d > MAX_DIST) {
col = backgroundColor;
} else {
vec3 p = ro + rd * d; // point on surface found by ray marching
vec3 normal = calcNormal(p); // surface normal

// light #1
vec3 lightPosition1 = vec3(-8, -6, -5);
vec3 lightDirection1 = normalize(lightPosition1 - p);
float lightIntensity1 = 0.6;

// light #2
vec3 lightPosition2 = vec3(1, 1, 1);
vec3 lightDirection2 = normalize(lightPosition2 - p);
float lightIntensity2 = 0.7;

// final sphere color
col = lightIntensity1 * phong(lightDirection1, normal, rd);
col += lightIntensity2 * phong(lightDirection2, normal , rd);
}

fragColor = vec4(col, 1.0);
}


### 为多个物体上色

phong函数中，给所有的反射都加上统一的系数和强度看起来世不太现实。很多时候我们的场景中会有多个物体，他们的材质却并不统一。有些物体看起来会非常光滑，而有些物体则是完全不会有镜面反射光线。因此有必要创建一个能够应用到一个或者多个物体上的材质。每个材质都会有自己的环境反射、漫反射以及镜面反射系数。我们可以创建一个struct来为材质保存所有的冯氏反射模型的信息。

  struct Material {
vec3 ambientColor; // k_a * i_a
vec3 diffuseColor; // k_d * i_d
vec3 specularColor; // k_s * i_s
float alpha; // shininess
};



  struct Surface {
int id; // id of object
float sd; // signed distance value from SDF
Material mat; // material of object
}



Material gold() {
vec3 aCol = 0.5 * vec3(0.7, 0.5, 0);
vec3 dCol = 0.6 * vec3(0.7, 0.7, 0);
vec3 sCol = 0.6 * vec3(1, 1, 1);
float a = 5.;

return Material(aCol, dCol, sCol, a);
}

Material silver() {
vec3 aCol = 0.4 * vec3(0.8);
vec3 dCol = 0.5 * vec3(0.7);
vec3 sCol = 0.6 * vec3(1, 1, 1);
float a = 5.;

return Material(aCol, dCol, sCol, a);
}

Material checkerboard(vec3 p) {
vec3 aCol = vec3(1. + 0.7*mod(floor(p.x) + floor(p.z), 2.0)) * 0.3;
vec3 dCol = vec3(0.3);
vec3 sCol = vec3(0);
float a = 1.;

return Material(aCol, dCol, sCol, a);
}



Surface opUnion(Surface obj1, Surface obj2) {
if (obj2.sd < obj1.sd) return obj2;
return obj1;
}



  Surface scene(vec3 p) {
Surface sFloor = Surface(1, p.y + 1., checkerboard(p));
Surface sSphereGold = Surface(2, sdSphere(p - vec3(-2, 0, 0), 1.), gold());
Surface sSphereSilver = Surface(3, sdSphere(p - vec3(2, 0, 0), 1.), silver());

Surface co = opUnion(sFloor, sSphereGold);
co = opUnion(co, sSphereSilver);
return co;
}



  vec3 phong(vec3 lightDir, vec3 normal, vec3 rd, Material mat) {
// ambient
vec3 ambient = mat.ambientColor;

// diffuse
float dotLN = clamp(dot(lightDir, normal), 0., 1.);
vec3 diffuse = mat.diffuseColor * dotLN;

// specular
float dotRV = clamp(dot(reflect(lightDir, normal), -rd), 0., 1.);
vec3 specular = mat.specularColor * pow(dotRV, mat.alpha);

return ambient + diffuse + specular;
}



mainImage函数里面，我们可以传递最近物体的材质给到phong函数：

col = lightIntensity1 * phong(lightDirection1, normal, rd, co.mat);
col += lightIntensity2 * phong(lightDirection2, normal , rd, co.mat);



  const int MAX_MARCHING_STEPS = 255;
const float MIN_DIST = 0.0;
const float MAX_DIST = 100.0;
const float PRECISION = 0.001;

float sdSphere(vec3 p, float r )
{
return length(p) - r;
}

struct Material {
vec3 ambientColor; // k_a * i_a
vec3 diffuseColor; // k_d * i_d
vec3 specularColor; // k_s * i_s
float alpha; // shininess
};

struct Surface {
int id; // id of object
float sd; // signed distance
Material mat;
};

Material gold() {
vec3 aCol = 0.5 * vec3(0.7, 0.5, 0);
vec3 dCol = 0.6 * vec3(0.7, 0.7, 0);
vec3 sCol = 0.6 * vec3(1, 1, 1);
float a = 5.;

return Material(aCol, dCol, sCol, a);
}

Material silver() {
vec3 aCol = 0.4 * vec3(0.8);
vec3 dCol = 0.5 * vec3(0.7);
vec3 sCol = 0.6 * vec3(1, 1, 1);
float a = 5.;

return Material(aCol, dCol, sCol, a);
}

Material checkerboard(vec3 p) {
vec3 aCol = vec3(1. + 0.7*mod(floor(p.x) + floor(p.z), 2.0)) * 0.3;
vec3 dCol = vec3(0.3);
vec3 sCol = vec3(0);
float a = 1.;

return Material(aCol, dCol, sCol, a);
}

Surface opUnion(Surface obj1, Surface obj2) {
if (obj2.sd < obj1.sd) return obj2;
return obj1;
}

Surface scene(vec3 p) {
Surface sFloor = Surface(1, p.y + 1., checkerboard(p));
Surface sSphereGold = Surface(2, sdSphere(p - vec3(-2, 0, 0), 1.), gold());
Surface sSphereSilver = Surface(3, sdSphere(p - vec3(2, 0, 0), 1.), silver());

Surface co = opUnion(sFloor, sSphereGold); // closest object
co = opUnion(co, sSphereSilver);
return co;
}

Surface rayMarch(vec3 ro, vec3 rd) {
float depth = MIN_DIST;
Surface co;

for (int i = 0; i < MAX_MARCHING_STEPS; i++) {
vec3 p = ro + depth * rd;
co = scene(p);
depth += co.sd;
if (co.sd < PRECISION || depth > MAX_DIST) break;
}

co.sd = depth;

return co;
}

vec3 calcNormal(vec3 p) {
vec2 e = vec2(1.0, -1.0) * 0.0005;
return normalize(
e.xyy * scene(p + e.xyy).sd +
e.yyx * scene(p + e.yyx).sd +
e.yxy * scene(p + e.yxy).sd +
e.xxx * scene(p + e.xxx).sd);
}

mat3 camera(vec3 cameraPos, vec3 lookAtPoint) {
vec3 cd = normalize(lookAtPoint - cameraPos); // camera direction
vec3 cr = normalize(cross(vec3(0, 1, 0), cd)); // camera right
vec3 cu = normalize(cross(cd, cr)); // camera up

return mat3(-cr, cu, -cd);
}

vec3 phong(vec3 lightDir, vec3 normal, vec3 rd, Material mat) {
// ambient
vec3 ambient = mat.ambientColor;

// diffuse
float dotLN = clamp(dot(lightDir, normal), 0., 1.);
vec3 diffuse = mat.diffuseColor * dotLN;

// specular
float dotRV = clamp(dot(reflect(lightDir, normal), -rd), 0., 1.);
vec3 specular = mat.specularColor * pow(dotRV, mat.alpha);

return ambient + diffuse + specular;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = (fragCoord-.5*iResolution.xy)/iResolution.y;
vec3 backgroundColor = mix(vec3(1, .341, .2), vec3(0, 1, 1), uv.y) * 1.6;
vec3 col = vec3(0);

vec3 lp = vec3(0); // lookat point (aka camera target)
vec3 ro = vec3(0, 0, 5);

vec3 rd = camera(ro, lp) * normalize(vec3(uv, -1)); // ray direction

Surface co = rayMarch(ro, rd); // closest object

if (co.sd > MAX_DIST) {
col = backgroundColor;
} else {
vec3 p = ro + rd * co.sd; // point on surface found by ray marching
vec3 normal = calcNormal(p); // surface normal

// light #1
vec3 lightPosition1 = vec3(-8, -6, -5);
vec3 lightDirection1 = normalize(lightPosition1 - p);
float lightIntensity1 = 0.9;

// light #2
vec3 lightPosition2 = vec3(1, 1, 1);
vec3 lightDirection2 = normalize(lightPosition2 - p);
float lightIntensity2 = 0.5;

// final color of object
col = lightIntensity1 * phong(lightDirection1, normal, rd, co.mat);
col += lightIntensity2 * phong(lightDirection2, normal , rd, co.mat);
}

fragColor = vec4(col, 1.0);
}



### 参考资源

posted on 2021-12-20 09:45  chen·yan  阅读(74)  评论(0编辑  收藏  举报