GEMINIGHT 警告:您的浏览器不支持JavaScript将无法正常浏览!
Warning: Your browser does not support JavaScript!
注册(Register) | 登录(Login)
看随机帖

主站(Home) »  论坛(Forum)  » 程序编写(Program)
GEMINIGHT

自称:发贴器2号
等级:发贴器
帖子数:4891
积分:9161
阅读权限:99
[转]卡通渲染演示(OGL+CG) 1樓
Tags引力关联贴

作者: Admin

\N

实现卡通渲染关键是要写自己的光照函数, 通过将光照程序计算出来的片段颜色,来查找一个1D的纹理,来将整个色域分解成少数几种离散的颜色, 最终将颜色输出, 呈现卡通渲染.

在这个程序中, 我没有使用1D纹理, 原因有几个, 首先1D数据不好获得, 不知道用什么编辑器去编辑一个阶梯的变化序列, 其次就是1D纹理不直观,无法直接观察效果, 所以我选用了2D纹理, 这下好了, 可以用PS等工具去直接创造个阶梯函数, 另外使用2D纹理还有一个好处, 这个在后文讲解.

当然使用了2D纹理, 就不能再用1D纹理的查找函数了, 需要用2D纹理的查找函数. 其实这个变换很简单.
原来查询1D纹理,是这样的:

\N
diffuseLighting = tex1D( diffuseRamp, diffuseLighting).x;
\N

diffuseRamp是个1D的纹理, diffuseLighting就是通过光照程序计算出来的diffuse值, 是一个float值.
因为diffuseLight是个float值, 最后我们就取x分量了.
下面我们把他改成查询2D纹理的.

\N
diffuseLighting = tex2D( diffuseRamp, float2(diffuseLight, 0.5)).x;
\N

这样就用2D查询代替了1D查询, 虽然在数据上废点硬盘空间,但这是值得的.

下面来简单说下如何用PS建立个拥有阶梯函数的2D纹理.
看下图,我们建立个256X16的纹理, 理论上256X1,16X1,4X1都可以, 如果你的眼睛能看的清楚也无所谓, 我眼睛差,太小了,看不清楚,所以我选择256X16的大小.

\N
\N


左边黑右边白,这就是个阶梯函数, 你可以调整分界点的位置, 来控制颜色过滤的严格程度, 自己调调看看效果就明白了.
使用这个纹理来查询来控制颜色有个缺点,漫反射,镜面反射和边界测试太严格了:当物体移动的时候, 他们的结果趋向于相当明显的起伏. 解决这个问题, 我们可以用一个平滑的过度了来代替, 如下图:

\N
\N



我将卡通渲染的vertex program 和 fragment program 贴出来

\N
//vertex program
// This binding semantic requires CG_PROFILE_ARBVP1 or higher.
uniform float4x4 modelViewProj : state.matrix.mvp;

void main( float4 position : POSITION,
float3 normal : NORMAL,

out float4 oPosition : POSITION,
out float diffuseLight: TEXCOORD0,
out float specularLight: TEXCOORD1,
out float edge : TEXCOORD2,

uniform float3 lightPosition,
uniform float3 eyePosition,
uniform float shininess)
{
oPosition = mul(modelViewProj, position);

// Calculate diffuse lighting
float3 N = normalize(normal);
float3 L = normalize(lightPosition - position.xyz);
diffuseLight = max(dot(N, L), 0);

// Calculate specular lighting
float3 V = normalize(eyePosition - position.xyz);
float3 H = normalize(L + V);
specularLight = pow(max(dot(N, H), 0), shininess);
if (diffuseLight <= 0) specularLight =0;

//Perform edge detection
edge = max(dot(N, V), 0);
}

//fragment program
void main(float diffuseLight : TEXCOORD0,
float specularLight : TEXCOORD1,
float edge : TEXCOORD2,

out float4 color : COLOR,

uniform float4 Kd,
uniform float4 Ks,
uniform sampler2D diffuseRamp,
uniform sampler2D specularRamp,
uniform sampler2D edgeRamp)
{
//Apply step functions
diffuseLight = tex2D(diffuseRamp, float2(diffuseLight, 0.5)).x;
specularLight = tex2D(specularRamp, float2(specularLight, 0.5)).x;
edge = tex2D(edgeRamp, float2(edge, 0.5)).x;

// Compute the final color
color = edge * (Kd * diffuseLight + Ks * specularLight);
}
\N


演示的源代码和执行程序下载:
点击下载

CG库下载,如果没有请下载拷贝的SYSTEM32目录下,否则无法运行
点击下载

演示截图:

\N
\N



\N
\N



www.azure.com.cn

发表于:2005-8-27 07:33(约18年前)  访问量:678

标题(Title):
关键字标签(Tags):
路人:回贴可以不必登录