glsl实现像素光照的方法

本文详细介绍了如何在OpenGL中实现逐像素方向光照明效果,包括顶点着色器和片段着色器的具体实现方法。文章通过实例展示了如何计算光照模型,并比较了逐顶点计算与逐像素计算在视觉效果上的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

GLSL Tutorial

Directional Light per Pixel

In this section we'll modify the previous shaders to compute the directional light per pixel. Basically we're going to split the work between the two shaders, so that some operations are done per pixel.

First lets take a look at the information we receive per vertex:
//我们可以从每个顶点接收三个数值

  • normal //顶点法向量
  • half vector //眼睛坐标和灯光的方向的和
  • light direction //灯光的方向
We have to transform the normal to eye space, and normalize it. We also have to normalize both the half vector and the light direction, both of which are already in eye space. These normalized vectors are to be interpolated and then sent to the fragment shader so we need to declare varying variables to hold the normalized vectors.

We can also perform some computations combining the lights settings with the materials in the vertex shader, hence helping to split the load between the vertex and fragment shader.

The vertex shader could be:


	varying vec4 diffuse,ambient;
	varying vec3 normal,lightDir,halfVector;
	
	void main()
	{	
		/* first transform the normal into eye space and 
		normalize the result */
		normal = normalize(gl_NormalMatrix * gl_Normal);
		
		/* now normalize the light's direction. Note that 
		according to the OpenGL specification, the light 
		is stored in eye space. Also since we're talking about 
		a directional light, the position field is actually direction */
		lightDir = normalize(vec3(gl_LightSource[0].position));
	        //gl_LightSource[0].position存储在眼坐标
		/* Normalize the halfVector to pass it to the fragment shader */
		halfVector = normalize(gl_LightSource[0].halfVector.xyz);
                //把halfVector传递给片元着色器
					
		/* Compute the diffuse, ambient and globalAmbient terms */
		diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
		ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
		ambient += gl_LightModel.ambient * gl_FrontMaterial.ambient;//全局环境光
	
		gl_Position = ftransform();
	} 

Now for the fragment shader. The same varying variables have to be declared. We have to normalize again the normal. Note that there is no need to normalize again the light direction. This last vector is common to all vertices since we're talking about a directional light. The interpolation between two equal vectors yields the same vector, so there is no need to normalize again. Then we compute the dot product between the interpolated normalized normal and the light direction.


	varying vec4 diffuse,ambient;
	varying vec3 normal,lightDir,halfVector;
	
	
	void main()
	{
		vec3 n,halfV;
		float NdotL,NdotHV;
		
		/* The ambient term will always be present */
		vec4 color = ambient;
		
		/* a fragment shader can't write a varying variable, hence we need
		a new variable to store the normalized interpolated normal */
		n = normalize(normal);
		
		/* compute the dot product between normal and ldir */
		NdotL = max(dot(n,lightDir),0.0);
	
		....
	}

If the dot product NdotL is greater than zero then we must compute the diffuse component, which is the diffuse setting we received from the vertex shader multiplied by the dot product. We must also compute the specular term. To compute the specular component we must first normalize the halfvector we received from the vertex shader, and also compute the dot product between the normalized halfvector and the normal.


		...
		if (NdotL > 0.0) {
			color += diffuse * NdotL;
			halfV = normalize(halfVector);
			NdotHV = max(dot(n,halfV),0.0);
			color += gl_FrontMaterial.specular * 
					gl_LightSource[0].specular * 
					pow(NdotHV, gl_FrontMaterial.shininess);
		}
	
		gl_FragColor = color;
}

The following images show the difference in terms of visual results between computing the lighting per vertex versus per pixel.

Per VertexPer Pixel

A Shader Designer project containing the shaders for the directional light per pixel can be found in here

转载于:https://www.cnblogs.com/lizhengjin/archive/2009/08/11/1544005.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值