Javascript 如何在three.js中正确实现Cook-Torrance着色?
我正在尝试在three.js中实现Cook-Torrance着色算法。我有一个基本可行的解决方案,但是它没有显示环境光的效果。未被灯光照亮的立方体侧面是完全黑色的。如果我去掉“贝克曼项”,那么我确实可以看到环境光效果: 同时,将Beckmann替换为始终返回Javascript 如何在three.js中正确实现Cook-Torrance着色?,javascript,three.js,fragment-shader,Javascript,Three.js,Fragment Shader,我正在尝试在three.js中实现Cook-Torrance着色算法。我有一个基本可行的解决方案,但是它没有显示环境光的效果。未被灯光照亮的立方体侧面是完全黑色的。如果我去掉“贝克曼项”,那么我确实可以看到环境光效果: 同时,将Beckmann替换为始终返回0.0的函数,我得到: 似乎错误行为的原因在于: vec3 Specular = (Beckmann(NdotH) * G(NdotH, NdotV, VdotH, NdotL) * R_F(VdotH)) / ( NdotL* Ndo
0.0
的函数,我得到:
似乎错误行为的原因在于:
vec3 Specular = (Beckmann(NdotH) * G(NdotH, NdotV, VdotH, NdotL) * R_F(VdotH)) / ( NdotL* NdotV);
如果我将NdotL*NdotV
修改为NdotV
,并将gl\u FragColor
的计算更改为:
gl_FragColor = vec4(beta * NdotL * (1.0-s)*Kd + beta * s*Specular + ambient*Kd, 1.0);
一切似乎都正常工作
我不明白的是:为什么?这个部门的问题在任何地方都没有提到,我也不能100%肯定,即使是剩下的部门在其他情况下也不会造成问题
以下是完整的MWE:
<html>
<head>
<title>Cook-Torrance BRDF computed by shader</title>
<style>
body {
font-family: Monospace;
background-color: #f0f0f0;
margin: 0px;
overflow: hidden;
}
canvas {
width: 100%;
height: 100%;
}
</style>
<script src="lib/three.min.js"></script>
<script src="lib/OrbitControls.js"></script>
</head>
<body>
<script type="text/x-glsl" id="vertex">
varying vec3 transformedNormal;
varying vec3 pointPosition;
varying vec3 lightVector;
uniform vec3 pointLightPosition;
void main()
{
transformedNormal = normalMatrix * normal;
pointPosition = (modelViewMatrix * vec4( position, 1.0 )).xyz;
vec4 lPosition = viewMatrix * vec4( pointLightPosition, 1.0 );
lightVector = lPosition.xyz - pointPosition;
gl_Position = projectionMatrix * vec4(pointPosition,1.0);
}
</script>
<script type="text/x-glsl" id="ct-fragment">
uniform vec3 lightPower;
uniform vec3 ambient;
uniform vec3 Kd; // surface diffuse color
uniform vec3 Ks; // surface specular color: equal to R_F(0)
uniform float m; // material roughness (average slope of microfacets)
uniform float s; // percentage of incoming light which is specularly reflected
varying vec3 transformedNormal;
varying vec3 pointPosition;
varying vec3 lightVector;
#define PI 3.14159265
float G(float NdotH, float NdotV, float VdotH, float NdotL)
{
float G1 = 2.0 * NdotH * NdotV / VdotH;
float G2 = 2.0 * NdotH * NdotL / VdotH;
return min( 1.0, min( G1, G2 ));
}
vec3 R_F(float VdotH) {
return Ks + (1.0 - Ks)*pow(1.0-VdotH, 5.0);
}
float Beckmann(float NdotH){
float A = 1.0 / (pow(m,2.0)+pow(NdotH,4.0)*PI);
float B = exp( - pow( tan(acos(NdotH)) , 2.0) / pow(m,2.0));
return A*B;
}
void main()
{
vec3 n = normalize( transformedNormal );
vec3 v = normalize( -pointPosition );
vec3 l = normalize( lightVector );
vec3 h = normalize( v+l );
float NdotH = max(0.0, dot( n, h ));
float VdotH = max(0.0, dot( v, h ));
float NdotV = max(0.0, dot( n, v ));
float NdotL = max(0.0, dot( n, l ));
// specular BRDF
vec3 Specular = (Beckmann(NdotH) * G(NdotH, NdotV, VdotH, NdotL) * R_F(VdotH)) / ( NdotL* NdotV);
vec3 beta = lightPower / ( 4.0 * PI * pow( length(lightVector),2.0) );
gl_FragColor = vec4(beta * NdotL * ((1.0-s)*Kd + s*Specular) + ambient*Kd, 1.0);
}
</script>
<script>
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position = new THREE.Vector3(0,0,5);
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xf0f0f0 );
document.body.appendChild( renderer.domElement );
controls = new THREE.OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
var uniforms = {
Ks: { type: "v3", value: new THREE.Vector3() },
Kd: { type: "v3", value: new THREE.Vector3() },
ambient: { type: "v3", value: new THREE.Vector3() },
pointLightPosition: { type: "v3", value: new THREE.Vector3() },
lightPower: { type: "v3", value: new THREE.Vector3() },
s: {type: "f", value: 0},
m: {type: "f", value: 0}
};
var vs = document.getElementById("vertex").textContent;
var fs = document.getElementById("ct-fragment").textContent;
var material = new THREE.ShaderMaterial({ uniforms: uniforms, vertexShader: vs, fragmentShader: fs });
var geometry = new THREE.CubeGeometry(1, 1, 1);
var mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
light = new THREE.Mesh( new THREE.SphereGeometry( 1, 16, 16), new THREE.MeshBasicMaterial ({color: 0xffff00, wireframe:true}));
light.position = new THREE.Vector3( 10.0, 10.0, 10.0 );
scene.add( light );
uniforms.Ks.value = new THREE.Vector3( 0.95, 0.93, 0.88 );
uniforms.Kd.value = (new THREE.Vector3( 0.50754, 0.50754, 0.50754 ));
uniforms.ambient.value = (new THREE.Vector3( 0.5, 0.5, 0.5 ));
uniforms.pointLightPosition.value = new THREE.Vector3(light.position.x, light.position.y, light.position.z);
uniforms.lightPower.value = new THREE.Vector3( 7000.0, 7000.0, 7000.0 );
uniforms.s.value = 0.5;
uniforms.m.value = 0.1;
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
controls.update();
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
由着色器计算的Cook-Torrance BRDF
身体{
字体系列:Monospace;
背景色:#f0;
边际:0px;
溢出:隐藏;
}
帆布{
宽度:100%;
身高:100%;
}
可变vec3转换正常;
改变vec3点位置;
可变vec3光矢量;
均匀vec3点光源位置;
void main()
{
transformedNormal=法线矩阵*法线;
pointPosition=(modelViewMatrix*vec4(位置,1.0)).xyz;
vec4 lPosition=viewMatrix*vec4(pointLightPosition,1.0);
lightVector=lPosition.xyz-pointPosition;
gl_位置=投影矩阵*vec4(点位置,1.0);
}
均匀vec3光功率;
均匀vec3环境;
均匀vec3 Kd;//表面漫反射颜色
均匀矢量3 Ks;//曲面镜面反射颜色:等于R_F(0)
均匀浮点数m;//材料粗糙度(微面平均坡度)
均匀浮点数s;//镜面反射的入射光百分比
可变vec3转换正常;
改变vec3点位置;
可变vec3光矢量;
#定义PI 3.14159265
浮点G(浮点NdotH、浮点NdotV、浮点VdotH、浮点NdotL)
{
浮点G1=2.0*NdotH*NdotV/VdotH;
浮点数G2=2.0*NdotH*NdotL/VdotH;
返回最小值(1.0,最小值(G1,G2));
}
vec3 R_F(浮动VdotH){
返回Ks+(1.0-Ks)*功率(1.0-VdotH,5.0);
}
浮点数贝克曼(浮点数){
浮点数A=1.0/(功率(m,2.0)+功率(NdotH,4.0)*PI;
浮动B=exp(-pow(tan(acos(NdotH)),2.0)/pow(m,2.0));
返回A*B;
}
void main()
{
vec3 n=正常化(转换正常);
vec3 v=标准化(-pointPosition);
vec3 l=标准化(光向量);
vec3 h=标准化(v+l);
float NdotH=最大值(0.0,点(n,h));
浮动VdotH=最大值(0.0,点(v,h));
浮点数NdotV=最大值(0.0,点(n,v));
float NdotL=最大值(0.0,点(n,l));
//镜面反射BRDF
vec3镜面反射=(贝克曼(NdotH)*G(NdotH,NdotV,VdotH,NdotL)*R_F(VdotH))/(NdotL*NdotV);
vec3β=光功率/(4.0*PI*pow(长度(光向量),2.0));
gl_FragColor=vec4(β*NdotL*((1.0-s)*Kd+s*镜面反射)+环境*Kd,1.0);
}
var scene=new THREE.scene();
var摄像机=新的三透视摄像机(75,window.innerWidth/window.innerHeight,0.11000);
camera.position=新的三个矢量3(0,0,5);
var renderer=new THREE.WebGLRenderer({antialas:true});
renderer.setSize(window.innerWidth、window.innerHeight);
renderer.setClearColor(0xF0);
document.body.appendChild(renderer.doElement);
控件=新的三个.轨道控件(摄影机、渲染器.doElement);
controls.target.set(0,0,0);
变量={
Ks:{type:“v3”,值:new THREE.Vector3()},
Kd:{type:“v3”,值:new THREE.Vector3()},
环境:{type:“v3”,值:new THREE.Vector3()},
pointLightPosition:{类型:“v3”,值:new THREE.Vector3()},
lightPower:{type:“v3”,值:new THREE.Vector3()},
s:{type:“f”,值:0},
m:{type:“f”,值:0}
};
var vs=document.getElementById(“顶点”).textContent;
var fs=document.getElementById(“ct片段”).textContent;
var material=new THREE.ShaderMaterial({uniforms:uniforms,vertexShader:vs,fragmentShader:fs});
var geometry=新的三立方测量法(1,1,1);
var mesh=新的三个网格(几何体、材质);
场景。添加(网格);
灯光=新的三点网格(新的三点球面测量法(1,16,16),新的三点网格基本材质({color:0xffff00,线框:true}));
light.position=新的三个矢量3(10.0,10.0,10.0);
场景。添加(灯光);
councies.Ks.value=新的三个向量3(0.95,0.93,0.88);
uniforms.Kd.value=(新的三个向量3(0.50754,0.50754,0.50754));
uniforms.ambient.value=(新的3.Vector3(0.5,0.5,0.5));
uniforms.pointLightPosition.value=新的3.Vector3(light.p
void main()
{
vec3 n = normalize( transformedNormal );
vec3 v = normalize( -pointPosition );
vec3 l = normalize( lightVector );
vec3 h = normalize( v+l );
vec3 specular = vec(0.0, 0.0, 0.0);
float NdotH = max(0.0, dot( n, h ));
float VdotH = max(0.0, dot( v, h ));
float NdotV = max(0.0, dot( n, v ));
float NdotL = max(0.0, dot( n, l ));
if (NdotL > 0 && NdotV > 0)
{
specular = (Beckmann(NdotH) * G(NdotH, NdotV, VdotH, NdotL) * R_F(VdotH)) / ( NdotL* NdotV);
}
vec3 beta = lightPower / ( 4.0 * PI * pow( length(lightVector),2.0) );
gl_FragColor = vec4(beta * NdotL * ((1.0-s)*Kd + s*specular) + ambient*Kd, 1.0);
}