| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- /******************************************************************************/
- #include "!Header.h"
- #include "Sky.h"
- #include "Volumetric.h"
- /******************************************************************************/
- struct VolCloudClass
- {
- Flt AC4_bottom,
- AC4_top ,
- A2_inv ,
- max_steps ;
- Vec2 pos ;
- Vec pixels ;
- };
- struct VolCloudMapClass
- {
- Flt curve, curve2, height, thickness, tex_scale, steps, shadow;
- Vec2 pos;
- Vec cam;
- };
- BUFFER(VolCloud)
- VolCloudClass Cloud;
- BUFFER_END
- BUFFER(VolCloudMap)
- VolCloudMapClass CloudMap;
- BUFFER_END
- /******************************************************************************/
- // CLOUDS
- /******************************************************************************
- clouds = -Cloud.curve*x*x + Cloud.height
- ray = m*x = dir.y/Length(dir.xz)*x
- m*x = -Cloud.curve*x*x + Cloud.height
- Cloud.curve*x*x + m*x - Cloud.height = 0
- A=Cloud.curve, B=m, C=-Cloud.height
- Delta=B*B - 4*A*C = m*m + 4*Cloud.curve*Cloud.height
- SqrtDelta=Sqrt(m*m + 4*Cloud.curve*Cloud.height)
- x0=(-m-SqrtDelta)/(2*Cloud.curve)
- x1=(-m+SqrtDelta)/(2*Cloud.curve)
- x1=(SqrtDelta-m)/(2*Cloud.curve)
- x1=(SqrtDelta-m)*A2_inv
- /******************************************************************************/
- void Clouds_VS(VtxInput vtx,
- out Vec dir :TEXCOORD,
- out Vec4 outVtx:POSITION)
- {
- dir=Transform3(Vec(ScreenToPosXY(vtx.tex()), 1), CamMatrix); // world-space position
- outVtx=Vec4(vtx.pos2(), !REVERSE_DEPTH, 1); AdjustPixelCenter(outVtx); // set Z to be at the end of the viewport, this enables optimizations by optional applying lighting only on solid pixels (no sky/background)
- }
- #if DX9
- Vec4
- #else
- Vec2
- #endif
- Clouds_PS(NOPERSP Vec dir:TEXCOORD):COLOR // 'dir'=world-space position
- {
- Flt a=Sat(dir.y*8); // alternatively, 'a' could be calculated as "a=Sat(max_from-from)"
- #if FLOW
- BRANCH if(a<=EPS_COL)return 0;
- #endif
- dir/=Length(dir.xz);
- Flt from=(Sqrt(dir.y*dir.y + Cloud.AC4_bottom)-dir.y)*Cloud.A2_inv,
- to =(Sqrt(dir.y*dir.y + Cloud.AC4_top )-dir.y)*Cloud.A2_inv, delta=to-from;
- Vec pos=Vec( 1, dir.x*from +Cloud.pos.x, dir.z*from +Cloud.pos.y); // correct way would be to start from "1-0.5f/Cloud.pixels.x", however it's really unnoticeable
- dir=Vec(-1, dir.x*delta , dir.z*delta );
- Flt pixels=Length(dir*Cloud.pixels);
- Int steps =Mid (pixels, 2, Cloud.max_steps);
- dir/=steps;
- Vec2 col=0;
- LOOP for(Int i=0; i<steps; i++)
- {
- #if MODEL>=SM_4
- Vec2 sample=Vol.SampleLevel(SamplerLinearCWW, pos, 0).rg;
- /* test code for adding detail if(Z)
- {
- Flt s=0.5f;
- Flt m;
- if(X>=2.5)m=2.0*(1-Sqr(1-sample.y))*s;else
- if(X>=1.5)m=1.1*Sqrt(sample.y)*s;else
- if(X)m=0.5*Sat(sample.y*10)*s;else
- m=3*sample.y*s;
- sample.y+=(Vol1.SampleLevel(SamplerLinearWrap, pos*S*Z , 0).r)*m;
- if(Y)sample.y+=(Vol1.SampleLevel(SamplerLinearWrap, pos*S*Z*2, 0).r)*m/2;
- sample.y=Sat(sample.y);
- }*/
- #elif !DX9
- Vec2 sample=Tex3DLod(Vol, pos).rg;
- #else
- Vec2 sample=Tex3DLod(Vol, pos).ra;
- #endif
- Flt alpha=sample.y*(1-col.y);
- col.x+=alpha*sample.x;
- col.y+=alpha;
- pos+=dir;
- }
- col.x/=col.y+EPS; // NaN
- col.y*=a;
- #if DX9
- return Vec4(col, 0, 0);
- #else
- return col;
- #endif
- }
- /******************************************************************************/
- // SHADOW MAP
- /******************************************************************************/
- void CloudsMap_VS(VtxInput vtx,
- out Vec outPos:TEXCOORD0,
- out Vec outDir:TEXCOORD1,
- out Vec4 outVtx:POSITION )
- {
- outPos=CloudMap.cam // this is CamMatrix.pos-ActiveCam.matrix.pos (light camera relative to main camera)
- +CamMatrix[0]*(vtx.pos2().x/ProjMatrix[0][0]) // ProjMatrix.x.x which is 1/fov.x
- +CamMatrix[1]*(vtx.pos2().y/ProjMatrix[1][1]); // ProjMatrix.y.y which is 1/fov.y
- outDir=CamMatrix[2];
- outVtx=vtx.pos4(); AdjustPixelCenter(outVtx);
- }
- #if DX9
- Vec4
- #else
- Flt
- #endif
- CloudsMap_PS(NOPERSP Vec pos:TEXCOORD0, // world-space position, relative to main camera
- NOPERSP Vec dir:TEXCOORD1 // world-space direction
- ):COLOR
- {
- /* clouds = -Cloud.curve*x*x + Cloud.height
- ray = pos + dir*t
- x = (pos + dir*t).xz.length() (this is the X as in, distance from cloud Y axis)
- x = (pos.xz + dir.xz*t).length()
- x*x = (pos.xz + dir.xz*t).length2()
- Length2(v) = Sqr(v.x) + Sqr(v.y)
- x*x = Sqr(pos.x + dir.x*t) + Sqr(pos.z + dir.z*t)
- clouds = -Cloud.curve*(Sqr(pos.x + dir.x*t) + Sqr(pos.z + dir.z*t)) + Cloud.height
- pos.y + dir.y*t = -Cloud.curve*(pos.x*pos.x + dir.x*dir.x*t*t + 2*pos.x*dir.x*t + pos.z*pos.z + dir.z*dir.z*t*t + 2*pos.z*dir.z*t) + Cloud.height
- pos.y + dir.y*t + Cloud.curve*(pos.x*pos.x + dir.x*dir.x*t*t + 2*pos.x*dir.x*t + pos.z*pos.z + dir.z*dir.z*t*t + 2*pos.z*dir.z*t) - Cloud.height = 0
- Cloud.curve*(dir.x*dir.x + dir.z*dir.z)*t*t + (dir.y+Cloud.curve*2*(pos.x*dir.x + pos.z*dir.z))*t + pos.y+Cloud.curve*(pos.x*pos.x + pos.z*pos.z)-Cloud.height
- Flt a = CloudMap.curve *(dir.x*dir.x + dir.z*dir.z),
- b =dir.y+CloudMap.curve*2*(pos.x*dir.x + pos.z*dir.z),
- c =pos.y+CloudMap.curve *(pos.x*pos.x + pos.z*pos.z)-CloudMap.height,
- d_u=b*b - 4*a*(c-CloudMap.thickness), // -thickness because 'c' is calculated with -CloudMap.height so we're subtracting
- d_l=b*b - 4*a* c ; */
- Flt a2 = CloudMap.curve2*(dir.x*dir.x + dir.z*dir.z), // this is a*2, which allows better performance
- b =dir.y+CloudMap.curve2*(pos.x*dir.x + pos.z*dir.z),
- c =pos.y+CloudMap.curve *(pos.x*pos.x + pos.z*pos.z)-CloudMap.height,
- d_u=b*b - 2*a2*(c-CloudMap.thickness), // here "4*a" was replaced with "2*a2", -thickness because 'c' is calculated with -CloudMap.height so we're subtracting
- d_l=b*b - 2*a2* c ; // here "4*a" was replaced with "2*a2"
- BRANCH if(d_u<=0 || d_l<=0)return 1; // 1=full light (zero shadow)
- Flt t_u=(-b - Sqrt(d_u))/a2, // here "(2*a)" was replaced with "a2"
- t_l=(-b - Sqrt(d_l))/a2, // here "(2*a)" was replaced with "a2"
- delta=(t_l-t_u)*CloudMap.tex_scale;
- pos=Vec( 0, (pos.x+dir.x*t_u)*CloudMap.tex_scale+CloudMap.pos.x, (pos.z+dir.z*t_u)*CloudMap.tex_scale+CloudMap.pos.y); // start from upper layer (above clouds)
- dir=Vec( 1, dir.x*delta , dir.z*delta ); // go down (below clouds)
- Int steps=CloudMap.steps;
- dir/=steps;
- Flt density=0;
- LOOP for(Int i=0; i<steps; i++)
- {
- #if MODEL>=SM_4
- Flt alpha=Vol.SampleLevel(SamplerLinearCWW, pos, 0).g;
- #elif !DX9
- Flt alpha=Tex3DLod(Vol, pos).g;
- #else
- Flt alpha=Tex3DLod(Vol, pos).a;
- #endif
- density+=alpha*(1-density);
- pos +=dir;
- }
- return 1-density*CloudMap.shadow; // Lerp(1, 1-density, CloudMap.shadow) = 1*(1-CloudMap.shadow) + (1-density)*CloudMap.shadow = 1-CloudMap.shadow+CloudMap.shadow - density*CloudMap.shadow
- }
- /******************************************************************************/
- // DRAW
- /******************************************************************************/
- void CloudsDraw_VS(VtxInput vtx,
- out Vec2 outTex:TEXCOORD0,
- out Vec outPos:TEXCOORD1,
- out Vec4 outVtx:POSITION )
- {
- outTex=vtx.tex();
- outPos=Vec(ScreenToPosXY(vtx.tex()), 1);
- outVtx=Vec4(vtx.pos2(), !REVERSE_DEPTH, 1); AdjustPixelCenter(outVtx); // set Z to be at the end of the viewport, this enables optimizations by optional applying lighting only on solid pixels (no sky/background)
- }
- Vec4 CloudsDraw_PS(NOPERSP Vec2 inTex:TEXCOORD0,
- NOPERSP Vec inPos:TEXCOORD1):COLOR
- {
- Vec2 clouds=TexLod(Col, inTex).xy; // can't use TexPoint because Col may be smaller
- #if 1
- clouds.y*=Sat(TexDepthPoint(inTex)*Length(inPos)*SkyFracMulAdd.x+SkyFracMulAdd.y);
- #else
- Vec pos=GetPosPoint(inTex, inPosXY); clouds.y*=Sat(Length(pos)*SkyFracMulAdd.x+SkyFracMulAdd.y);
- #endif
- return Vec4(Color[0].rgb*clouds.x, clouds.y);
- }
- /******************************************************************************/
- // TECHNIQUES
- /******************************************************************************/
- TECHNIQUE(Clouds , Clouds_VS (), Clouds_PS ());
- TECHNIQUE(CloudsMap , CloudsMap_VS (), CloudsMap_PS ());
- TECHNIQUE(CloudsDraw, CloudsDraw_VS(), CloudsDraw_PS());
- /******************************************************************************/
|