如何在GLSL片段着色器中获得相对于法线的视角?

如何在GLSL片段着色器中获得相对于法线的视角?,glsl,shader,light,openframeworks,Glsl,Shader,Light,Openframeworks,我刚刚开始使用openframeworks中的着色器,并尝试编写一个片段着色器,该着色器根据片段从哪个角度观看来更改片段的颜色。例如,给定一个矩形,如果从正面观看(相机与法线平行),它将为红色,但如果从侧面观看,它将变为蓝色 类似地,对于球体,其外观中间应为红色(因为摄影机与这些面垂直),而外观边缘应为蓝色 我想我可以根据相对于法线的视角来设置片段颜色,但是,我很难找到任何GLSL输入变量来提供必要的信息gl_FragCoord似乎不起作用,因为它只给出相对于窗口的位置,gl_PointCoor

我刚刚开始使用openframeworks中的着色器,并尝试编写一个片段着色器,该着色器根据片段从哪个角度观看来更改片段的颜色。例如,给定一个矩形,如果从正面观看(相机与法线平行),它将为红色,但如果从侧面观看,它将变为蓝色

类似地,对于球体,其外观中间应为红色(因为摄影机与这些面垂直),而外观边缘应为蓝色

我想我可以根据相对于法线的视角来设置片段颜色,但是,我很难找到任何GLSL输入变量来提供必要的信息
gl_FragCoord
似乎不起作用,因为它只给出相对于窗口的位置,
gl_PointCoord
给出相对于模型本身的位置,而不是从其查看位置

获得视角/实现此效果的直接方法是什么

我正在使用GLSL版本1.2,并使用openframeworks 0.9.8加载着色器

类似地,对于球体,其外观中间应为红色(因为摄影机与这些面垂直),而外观边缘应为蓝色

为了达到你想要的效果,我建议计算一个完美灯光的强度,它从前面照亮场景。 在viewspace中进行此计算很容易

朗伯反射通常用作漫反射的模型。该技术使所有闭合多边形(例如三维网格中的三角形)在渲染时在所有方向上均匀反射灯光。从法向量和光向量之间的角度计算扩散系数

f_Lambertian = max( 0.0, dot( N, L ) )
其中,
N
是曲面的法向量,
L
是指向光源的向量。
有关详细信息,请参阅

在系统的视图空间中,Z轴指向视图外(注意,在右手系统中,Z轴是X轴和Y轴的叉积)

这意味着光强度可以通过视图空间中的法向量和视图空间中的“光”向量的点积来计算,即视图空间Z轴(0,0,1)

以下着色器将具有指向视图的法向量的片段着色为红色。法向量指向侧面的碎片呈淡蓝色:

顶点着色器:

in vec3 inPos;
in vec3 inNV;

out vec3 viewNV;

uniform mat4 u_projectionMat44;
uniform mat4 u_viewMat44;
uniform mat4 u_modelMat44;

void main()
{   
    viewNV      = mat3(u_viewMat44 * u_modelMat44) * inNV;

    vec4 pos    = u_viewMat44 * u_modelMat44 * vec4( inPos, 1.0 );
    gl_Position = u_projectionMat44 * pos;
}
片段着色器:

in vec3 viewNV;

void main()
{
    vec3  N      = normalize(viewNV);
    vec3  L      = vec3(0.0, 0.0, 1.0);
    float NdotL  = dot(N, L);

    vec3  color  = vec3(NdotL, 0.0, 1.0-NdotL);

    gl_FragColor = vec4( color.rgb, 1.0 );
} 
请参见WebGL示例,该示例演示了旋转立方体的效果:

(函数loadscene(){
var gl、progDraw、vp_尺寸;
var bufCube={};
函数渲染(delteMS){
Camera.create();
Camera.vp=vp_尺寸;
总图视口(0,0,vp_大小[0],vp_大小[1]);
总帐启用(总帐深度测试);
gl.clearColor(0.0,0.0,0.0,1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
//设置绘图着色器
着色器程序。使用(progDraw);
SetUniformM44(progDraw,“u_projectionMat44”,Camera.Perspective());
SetUniformM44(progDraw,“u_viewMat44”,Camera.LookAt());
var modelMat=IdentityMat44()
modelMat=旋转轴(modelMat,CalcAng(delteMS,13.0),0);
modelMat=旋转轴(modelMat,CalcAng(delteMS,17.0),1);
SetUniformM44(progDraw,“u_modelMat44”,modelMat);
//画场景
VertexBuffer.Draw(bufCube);
请求动画帧(渲染);
}
函数resize(){
//vp_大小=[gl.drawingBufferWidth,gl.drawingBufferHeight];
vp_size=[window.innerWidth,window.innerHeight]
canvas.width=vp_大小[0];
canvas.height=vp_大小[1];
}
函数initScene(){
canvas=document.getElementById(“canvas”);
gl=canvas.getContext(“实验性webgl”);
如果(!gl)
返回null;
progDraw=ShaderProgram.Create(
[{来源:“绘制着色器vs”,阶段:gl.VERTEX_shader},
{来源:“绘制着色器fs”,阶段:gl.FRAGMENT_shader}
] );
如果(!progDraw.progObj)
返回null;
progDraw.inPos=ShaderProgram.AttributeIndex(progDraw,“inPos”);
progDraw.inNV=着色器程序.AttributeIndex(progDraw,“inNV”);
//创建多维数据集
var cubePos=[
-1.0, -1.0,  1.0,  1.0, -1.0,  1.0,  1.0,  1.0,  1.0, -1.0,  1.0,  1.0,
-1.0, -1.0, -1.0,  1.0, -1.0, -1.0,  1.0,  1.0, -1.0, -1.0,  1.0, -1.0 ];
var cubeCol=[1.0,0.0,0.0,1.0,0.5,0.0,1.0,0.0,1.0,1.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0];
var cubeHlpInx=[0,1,2,3,1,5,6,2,5,4,7,6,4,0,3,7,3,2,6,7,1,0,4,5];
变量cubePosData=[];
对于(变量i=0;i