当前位置: 首页 > news >正文

网站默认图片素材/电工培训技术学校

网站默认图片素材,电工培训技术学校,自己建设网站赚钱,微信端网站开发模板最近在写一个大型一点的Demo,就相当于毕业设计了吧,目前正在把以前学的东西逐个集成,昨天终于完成了大气渲染的这一部分,虽然以前也做个一个的,但是那只是一个实验性质的,不过还是相当有效,这次…

  最近在写一个大型一点的Demo,就相当于毕业设计了吧,目前正在把以前学的东西逐个集成,昨天终于完成了大气渲染的这一部分,虽然以前也做个一个的,但是那只是一个实验性质的,不过还是相当有效,这次很快就完成了,我想做个比较完善的天空,加入云,云也应该加入光照计算,夜晚星空这些我也正在考虑,我把目前大气渲染的一些细节写出来,方便大家以后如果要使用的话可以用作参考。

  先贴张效果图。

                        

  从视觉的角度来说应该是正确的,不过右图的太阳之中感觉太明亮了,这可能和Mie散射的参数设置有关,具体的参数设置,大家可以自己尝试。

技术细节:

  光学深度(Optical Depth): 描述了光强度通过某一种介质的衰减程度。

  描述方程:t(Pa, Pb, waveLength) = 4*PI*K(waveLength)[exp( -h/H0 )]在Pa到Pb间的积分(ps:公式不好输入,具体可以参考GPU Gems2或相关论文)

  方程解释:h 是一个相对高度, H0表示大气层中平均密度所在的考度(因为大气层越往上越稀薄)大气层中最高位置被压缩至1.一般我们大气层的平均密度所在高度为0.25, 也就是大气层厚度X0.25所在的高度。Pa, Pb表示大气层中任意两点,当然要是被光照的一面。

  

  其实呢,我们可以讲这个光学深度值预计算出来,想想地球,内层是地壳,外层是大气层,我们以高度h代表一张查找表的U值,以弧度theta代表V值(球体是圆的,我们也可以假设是太阳围绕地球旋转),具体如何计算大家画画图用初中的几何知识就可以得出结果了,这里要注意,我们的h的增量不是线性增长的,和星球半径和大气层厚度有关。(积分用数值逼近法计算,因为是预计算的,因此可以比较精确,一般采用100次分割就不错了)。

 

ExpandedBlockStart.gif代码
void CLUTs::CalculateOpticalDepth(int samples, float R, float r, float havg, float Kr, float Kg, float Kb, float M)
{
    
/**********************************
    原理:采用数值逼近法求的光学深度的积分值
    参数值: u 高度,压缩量(0,1)区间
             v cos角度, 通过0.5*(1-cos(theta)) 压缩至(0,1)
    *********************************
*/

    
float sARadius = R / (R - r); // Scale Atmosphere Radius
    float sPRadius = r / (R - r); // Scale Planet     Radius

    
for (int u=0; u<uSize; u++)
    {
        
for (int v=0; v<vSize; v++)
        {
            p[u][v].a 
= 0;
            
//高度
            float h = 1.0f / (uSize-1* u;
            
//方向角度(弧度制)
            float theta = 3.1415926535 / (vSize-1* v;

            
// 可以简化
            float A = sPRadius+h;
            
float L  = -A*cos(theta) + sqrt(sARadius*sARadius - A*A*sin(theta)*sin(theta));
            
float ds = L / samples; 

            
for (int i=0; i<samples; i++)
            {
                
float L  = ds*(i+0.5);
                
float hi = sqrt(A*+ L*+ 2*A*L*cos(theta)) - sPRadius;
                
if (hi < 0)
                {
                    
break;
                }
                p[u][v].a 
+= exp( -hi / havg);
            }

            p[u][v].a 
*= ds;

            
// Rayleigh散射
            p[u][v].a *= 0.012;
            p[u][v].r 
= p[u][v].a * 4 * 3.1415926535;// * Kr;
            p[u][v].g = p[u][v].a * 4 * 3.1415926535;// * Kg;
            p[u][v].b = p[u][v].a * 4 * 3.1415926535;// * Kb;

            
// Mie散射
            p[u][v].a *= 4 * 3.1415926535;

        }
    }
}

渲染图:

              大小是512x512的,这种图可以直接使用。

分析一下,相同高度下角度越大我们的像素越亮,基本到中央90度的位置是最亮的,随着高度的增加,我们的最亮的地方也逐渐向下移动,因为光学深度和光线在大气层中通过的距离有关,角度越大距离则越大(因为我们不是在球体的中心,而是非常靠近顶层,我们只是在球体表面,其实可以使用数学软件计算公式并画出曲线图,这对程序问题的发现有很重大的意义,也可以便于分析计算结果(可惜,以前貌似大一学过Mathmatics,不过全部忘完了)。

   RayLeigh散射和Mie散射:RayLeigh散射导致天空颜色的改变,Mie散射导致天空有时看上去朦朦胧胧的,RayLeigh散射和光线波长有关,和光线波长的四次方成反比,这也是出现大气颜色的一个关键,记住了,光学深度出来后不要忘记乘以1/pow(waveLength, 4);

 

  第二个方程就是外向散射方程(GPU Gems2中文版如是说)这个方程的推导过程可以看NishiTa的论文,有个假定条件:光线是平行的!!!这样就可以大大简化方程的复杂度。推导我不写了(在电脑上输入公式就是一种杯具...)具体在《Display of the Earth Taking into Account Atmosphereric Scattering》上。

 

 Shader代码

float4x4 matWorldViewProj;
float3 eyePos;

#define PI 3.1415926535858


float  Krr = 1.0f/pow(0.6254);
float  Krg = 1.0f/pow(0.5254);
float  Krb = 1.0f/pow(0.4704);

float  Km  = 1.0f;

float  Luminance;
float  OpticalScale;
float  RayLeighDensity;
float  MieDensity;

float3 lightDir 
= float3(0,0,1);

float  scale = 0.005;

float  Viewheight = 0.10;

float Exposure = 1.5;


#define SAMPLES 5

sampler s0 : register(s0);

float PhaseFunction(float g, float costheta)
{
    
return 1.5*(1-g*g)/(2+g*g) * (1 + costheta*costheta) / pow(1 + g*- 2*g*costheta, 1.5);
}


void vs_main(float4 inPos : POSITION,
             
out float4 outPos : POSITION,
             
out float4 outColor : TEXCOORD0,
             
out float3 eyeVec   : TEXCOORD1)
{
    float4 Pos 
= float4(inPos.xyz + eyePos, 1.0f);
    outPos 
= mul(Pos, matWorldViewProj);
    
    float3 rayVec 
= inPos / SAMPLES;
    
float rayVecLength = length(rayVec);
    
    float3 StartPos 
= eyePos;
    
float cosAngle = dot(normalize(rayVec), normalize(float3(inPos.x, 0, inPos.z)));
    
float sinAngle = sqrt(1 - sqrt(cosAngle*cosAngle));
    float4 OutScatter 
= 0;
    
    
float radEye = acos(dot(normalize(rayVec), float3(0,1,0)))  / PI;
    
float radSun = acos(dot(normalize(lightDir), float3(0,1,0)))/ PI;
    
for(int i=0; i<SAMPLES; i++)
    {
        float3 currentPos 
= StartPos + (i+0.5)*rayVec;
        
float currentPosHeight = (currentPos.y - eyePos.y)*scale;//(i+0.5)*rayVecLength*(sinAngle)*scale + Viewheight;
        float4 opticalDepthCP = tex2Dlod(s0, float4( currentPosHeight, radEye, 00) );
        
        float4 opticalDepthEP 
= tex2Dlod(s0, float4( Viewheight,       radEye, 00) );
        float4 opticalDepthCS 
= tex2Dlod(s0, float4( currentPosHeight, radSun, 00) );
        
        float4 opticalDepthCE 
= opticalDepthEP - opticalDepthCP;
        float4 Attenuation 
= exp( -(opticalDepthCE + opticalDepthCS) * OpticalScale * float4(Krr, Krg, Krb, 1.0f));

        OutScatter 
+= Attenuation * exp(-4*currentPosHeight) ;

    }
    OutScatter 
*= rayVecLength;
    
    
    outColor 
= OutScatter * Luminance * scale;
    eyeVec 
= normalize(rayVec);

}

void ps_main(float4 inColor : TEXCOORD0,
             float3 eyeVec  : TEXCOORD1, 
             
out float4 outColor : COLOR)
{

    
float costheta = dot(normalize(eyeVec), -normalize(lightDir)); 
    
float Fr = 0.75*(1 + costheta * costheta);
    
    
float Fm = PhaseFunction( -0.9922f, costheta);
    
    
    float4 RColor 
= inColor * float4(Krr, Krg, Krb, 1);
    float4 MColor 
= inColor.a * Km;
    
    float4 color 
= MColor*Fm*MieDensity + RColor*RayLeighDensity ;
    

     outColor 
= color;
}
Technique T0
{
    pass p0
    {
        VertexShader 
= compile vs_3_0 vs_main();
        PixelShader  
= compile ps_3_0 ps_main();

    }
}

这里用了顶点纹理,以前没用过,还不知道顶点纹理只能用tex2Dlod()。注意参数,Mie散射的phase Function的g值影响到了太阳光斑的大小(没说耀斑),也就是日晕的大小,我设置成-0.9922f的样子感觉还不错,最麻烦的其实还是如何调节参数,我整整调了两天才感觉比较合理,当然,还加入了HDR效果,不过是个简单的ToneMap。加了之后感觉颜色更加协调,如果只是一个简单的Explosure的话你会发现日落时黄色和红色不太分明。

 

天空模型的问题:不是严格意义上的半球,而只是一个半径是8000的球的最顶端的0.025的那一部分,就像碟状的那种,之所以选这种是因为我感觉更加合理,不过我想就算是个半球也没有什么问题。

  我把天空封装成一个完整的类就把代码发上来,希望这篇文章对大家有所帮助。

 

 

转载于:https://www.cnblogs.com/ttthink/archive/2010/02/06/1665002.html

http://www.lbrq.cn/news/744661.html

相关文章:

  • 怎么给网站做链接/互联网广告平台有哪些
  • 面试问你如何快速优化网站/财经新闻最新消息
  • 建设银行网站登录首页/本地免费发布信息网站
  • 网站推广 昆明/网站推广途径
  • 河南网站建设外贸/长春疫情最新情况
  • 做微信网站公司/长沙官网网站推广优化
  • 室内设计师简介/孝感seo
  • 专注网站建站/网络营销怎么做推广
  • 华为手机商城官网/seo技术教程
  • 深圳手机网站建设公司/广告推广免费平台
  • 申请网站平台怎么做/企业门户网站模板
  • 泰安网站制作推荐/今天今日头条新闻
  • 济南住房和房产信息网/seo中文含义
  • 石家庄工信部网站备案/经典软文案例标题加内容
  • 朋友要我帮忙做网站/武汉大学人民医院地址
  • 给周杰伦做网站/安卓aso优化排名
  • 黄色国内外网站/网络营销有哪些特点
  • asp.net做织梦网站/seo技术培训东莞
  • 能免费做微信群推广的网站/汕头网站设计
  • 网站怎么企业备案/搜索引擎优化与关键词的关系
  • 政府网站建设与管理官网/如何建立一个自己的网站啊
  • 教育培训官网/优化大师兑换码
  • 上海网站建设公司/seo网站营销公司哪家好
  • 西安 医疗网站建设/如何自制网站
  • 用明星名字做网站/seo属于运营还是技术
  • 跨境电子商务网站建设/网站制作公司官网
  • 做网站找哪个/廊坊百度推广电话
  • 网站后台文本编辑器/seo优化工具
  • 金启网站建设/找网络公司做推广费用
  • 网络在线培训网站建设方案/搜索引擎优化排名seo
  • Java多线程:线程创建、安全、同步与线程池
  • Vue 3中watch的返回值:解锁监听的隐藏技巧
  • 机器学习(决策树)
  • IC验证 AHB-RAM 项目(一)——项目理解
  • JVM常用工具:jstat、jmap、jstack
  • Docker+飞算JavaAI=未来:全流程容器化AI开发实战