游戏开发论坛

 找回密码
 立即注册
搜索
查看: 2230|回复: 3

试了一下用PS3.0渲染Mandelbrot集。为什么循环不能超过15次?

[复制链接]

10

主题

62

帖子

68

积分

注册会员

Rank: 2

积分
68
发表于 2010-5-24 22:11:00 | 显示全部楼层 |阅读模式
试了一下用PS3.0渲染Mandelbrot集。为什么循环不能超过15次?

刚学HLSL。听说 Pixel Shader 3.0支持循环,于是试了一下用 PS3.0 渲染Mandelbrot集(一个著名的复数分形集)。
但测试后发现,循环次数在1~15次时渲染结果是正确的,但达到16次或更高时渲染结果不对。见下图——

(上为循环15次,下为循环16次)

按道理M集的中间部分是不会发散的,应该总是黑色。而现在渲染成了绿色,似乎循环提前结束了。
试了一下切换到参考设备,效果不变。
怀疑M集的实现代码有问题,但我检查了几次都没看出问题。


PS代码如下——

  1. sampler2D Texture0;

  2. float4 ps_main( float2 texCoord:TEXCOORD0 ) : COLOR
  3. {
  4.    float4 crR = float4(0,1,0,1);
  5.    float4 cr = float4(1,1,1,1);
  6.    float2 fPos = float2(0,0);
  7.    float fScale = 4.0f;
  8.    int nmax = 15;
  9.    int ncur = 0;
  10.    float x0 = (texCoord.x-0.5f)*fScale + fPos.x;
  11.    float y0 = (texCoord.y-0.5f)*fScale + fPos.y;
  12.    float fx = x0;
  13.    float fy = y0;
  14.    float ty;
  15.    while ((fx*fx+fy*fy) <= 4.0f)   // |z| <= 2
  16.    {
  17.       // z = z^2 + z0
  18.       ty = fy;
  19.       fy = 2*fx*fy + y0;
  20.       fx = fx*fx - ty*ty + x0;
  21.       ncur = ncur + 1;
  22.       if (ncur > nmax)
  23.       {
  24.          cr.rgb = 0;
  25.          return cr;
  26.       }
  27.    }
  28.    cr = lerp(cr, crR, saturate((float)ncur / nmax));
  29.    return cr;
  30. }

复制代码

227

主题

1794

帖子

1866

积分

金牌会员

Rank: 6Rank: 6

积分
1866
发表于 2010-5-25 18:00:00 | 显示全部楼层

Re:试了一下用PS3.0渲染Mandelbrot集。为什么循环不能超过15

啥显卡

10

主题

62

帖子

68

积分

注册会员

Rank: 2

积分
68
 楼主| 发表于 2010-5-25 20:12:00 | 显示全部楼层

Re: 试了一下用PS3.0渲染Mandelbrot集。为什么循环不能超过15

nVidia 6150,支持PS3.0的

10

主题

62

帖子

68

积分

注册会员

Rank: 2

积分
68
 楼主| 发表于 2011-5-3 00:04:00 | 显示全部楼层

Re:试了一下用PS3.0渲染Mandelbrot集。为什么循环不能超过15

没想到过了这么久,这个帖子还在。

这个问题我后来解决了,其实故障原因很简单——
1.int类型并不是真正的整数类型,GPU会将其当做浮点数进行运算。而浮点数运算是不准确的,在进行浮点比较时需要引入误差项。
2.当循环小于等于15次时,编译器会自动展开循环,避开了浮点误差问题。

修改后的代码为——

  1. sampler2D Texture0;

  2. float4 ps_main( float2 texCoord:TEXCOORD0 ) : COLOR
  3. {
  4.    float4 crR = float4(0,1,0,1);
  5.    float4 cr = float4(1,1,1,1);
  6.    float2 fPos = float2(0,0);
  7.    float fScale = 4.0f;
  8.    float nmax = 16;
  9.    float ncur = 0;
  10.    float x0 = (texCoord.x-0.5f)*fScale + fPos.x;
  11.    float y0 = (texCoord.y-0.5f)*fScale + fPos.y;
  12.    float fx = x0;
  13.    float fy = y0;
  14.    float ty;
  15.    while ((fx*fx+fy*fy) <= 4.0f)   // |z| <= 2
  16.    {
  17.       // z = z^2 + z0
  18.       ty = fy;
  19.       fy = 2*fx*fy + y0;
  20.       fx = fx*fx - ty*ty + x0;
  21.       ncur = ncur + 1;
  22.       if (ncur+0.001 > nmax)   // 浮点误差
  23.       {
  24.          cr.rgb = 0;
  25.          return cr;
  26.       }
  27.    }
  28.    cr = lerp(cr, crR, saturate((float)ncur / nmax));
  29.    return cr;
  30. }
复制代码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-8 06:03

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表