@@ -25,61 +25,175 @@ inline static float expf_s(float arg)
25
25
return expf (clamp_tpl (arg, -80 .0f , 80 .0f ));
26
26
}
27
27
28
+ AABB UnprojectAABB2D (const AABB& aabb, const CCamera& camera)
29
+ {
30
+ Vec3 results[4 ];
31
+ camera.Unproject (Vec3 (aabb.min .x , aabb.min .y , 1 ), results[0 ]);
32
+ camera.Unproject (Vec3 (aabb.max .x , aabb.min .y , 1 ), results[1 ]);
33
+ camera.Unproject (Vec3 (aabb.max .x , aabb.max .y , 1 ), results[2 ]);
34
+ camera.Unproject (Vec3 (aabb.min .x , aabb.max .y , 1 ), results[3 ]);
35
+
36
+ AABB newAABB (AABB::RESET);
37
+ newAABB.Add (results[0 ]);
38
+ newAABB.Add (results[1 ]);
39
+ newAABB.Add (results[2 ]);
40
+ newAABB.Add (results[3 ]);
41
+ return newAABB;
42
+ }
43
+
44
+ AABB GetProjectedQuadFromAABB (const AABB& aabb, const CCamera& camera)
45
+ {
46
+ // Get all 8 points of the AABB
47
+
48
+ Vec3 aabbPoints[] =
49
+ {
50
+ Vec3 (aabb.max .x , aabb.max .y , aabb.max .z ),
51
+ Vec3 (aabb.max .x , aabb.min .y , aabb.max .z ),
52
+ Vec3 (aabb.min .x , aabb.min .y , aabb.max .z ),
53
+ Vec3 (aabb.min .x , aabb.max .y , aabb.max .z ),
54
+ Vec3 (aabb.max .x , aabb.max .y , aabb.min .z ),
55
+ Vec3 (aabb.max .x , aabb.min .y , aabb.min .z ),
56
+ Vec3 (aabb.min .x , aabb.min .y , aabb.min .z ),
57
+ Vec3 (aabb.min .x , aabb.max .y , aabb.min .z ),
58
+ };
59
+ const int numAABBPoints = AZ_ARRAY_SIZE (aabbPoints);
60
+
61
+ AZ_Assert (numAABBPoints==8 ," you should have 8 points in the aabb" );
62
+
63
+ // Project each AABB point and construct another AABB.
64
+ AABB quadResult (AABB::RESET);
65
+ for (int i = 0 ; i < numAABBPoints; ++i)
66
+ {
67
+ Vec3 projectedPoint;
68
+ camera.Project (aabbPoints[i], projectedPoint);
69
+ quadResult.Add (projectedPoint);
70
+ }
71
+ return quadResult;
72
+ }
73
+
74
+
75
+ // To know if aabb are aligned with camera, we test if projected quads overlap.
76
+ bool CFogVolumeRenderNode::OverlapProjectedAABB (const AABB& aabb0, const AABB& aabb1, const CCamera& camera)
77
+ {
78
+ // quads are AABB2D.
79
+ AABB quad0 = GetProjectedQuadFromAABB (aabb0, camera);
80
+ AABB quad1 = GetProjectedQuadFromAABB (aabb1, camera);
81
+ bool bOverlap = Overlap::AABB_AABB2D (quad0, quad1);
82
+ return bOverlap;
83
+ }
84
+
85
+ void AverageFogVolume (SFogVolumeData& fogVolData, const CFogVolumeRenderNode* pFogVol)
86
+ {
87
+ AABB& avgAABBoxOut = fogVolData.avgAABBox ;
88
+ avgAABBoxOut.Add (pFogVol->GetBBox ());
89
+
90
+ // ratio is used to approximate fog volumes contribution depending of the importance of their size.
91
+ float ratio = pFogVol->GetBBox ().GetRadius () / avgAABBoxOut.GetRadius ();
92
+ fogVolData.m_heightFallOffBasePoint = Lerp (fogVolData.m_heightFallOffBasePoint ,pFogVol->GetHeightFallOffBasePoint (), ratio);
93
+ fogVolData.m_heightFallOffDirScaled = Lerp (fogVolData.m_heightFallOffDirScaled ,pFogVol->GetHeightFallOffDirScaled (), ratio);
94
+ fogVolData.m_densityOffset = Lerp (fogVolData.m_densityOffset , pFogVol->GetDensityoffset (), ratio);
95
+ fogVolData.m_globalDensity = Lerp (fogVolData.m_globalDensity , pFogVol->GetGlobalDensity (), ratio);
96
+ fogVolData.m_volumeType |= pFogVol->GetVolumeType ();
97
+ }
28
98
29
99
// /////////////////////////////////////////////////////////////////////////////
100
+ // TraceFogVolumes :
101
+ // if object intersects/is aligned with fog volumes then register these fog volumes,
102
+ // check if object is in front of the fog volume and compute average color.
103
+ // if highVertexShadingQuality average fog volume box.
30
104
// /////////////////////////////////////////////////////////////////////////////
31
- void CFogVolumeRenderNode::TraceFogVolumes (const Vec3& worldPos, ColorF& fogColor, const SRenderingPassInfo& passInfo)
105
+ void CFogVolumeRenderNode::TraceFogVolumes (const Vec3& objPosition, const AABB& objAABB, SFogVolumeData& fogVolData, const SRenderingPassInfo& passInfo, bool fogVolumeShadingQuality )
32
106
{
33
107
FUNCTION_PROFILER_3DENGINE;
34
108
PrefetchLine (&s_tracableFogVolumeArea, 0 );
35
109
36
110
// init default result
37
111
ColorF localFogColor = ColorF (0 .0f , 0 .0f , 0 .0f , 0 .0f );
38
112
39
-
113
+ // We will "accumulate" fog volumes contribution the same way that fog color.
114
+
40
115
// trace is needed when volumetric fog is off.
41
116
if (GetCVars ()->e_Fog && GetCVars ()->e_FogVolumes && (GetCVars ()->e_VolumetricFog == 0 ))
42
117
{
118
+ const Vec3 worldPos = objPosition;
119
+
43
120
// init view ray
44
121
Vec3 camPos (s_tracableFogVolumeArea.GetCenter ());
45
- Lineseg lineseg (camPos, worldPos );
122
+ Lineseg lineseg (camPos, objPosition );
46
123
47
124
#ifdef _DEBUG
48
125
const SCachedFogVolume* prev (0 );
49
126
#endif
50
-
127
+
51
128
// loop over all traceable fog volumes
52
129
CachedFogVolumes::const_iterator itEnd (s_cachedFogVolumes.end ());
53
130
for (CachedFogVolumes::const_iterator it (s_cachedFogVolumes.begin ()); it != itEnd; ++it)
54
131
{
55
132
// get current fog volume
56
133
const CFogVolumeRenderNode* pFogVol ((*it).m_pFogVol );
57
-
134
+
135
+ bool isAligned = false ;
136
+ bool isFrontOfBoxCenter = false ;
58
137
// only trace visible fog volumes
59
138
if (!(pFogVol->GetRndFlags () & ERF_HIDDEN))
60
139
{
140
+ bool projectedAABBIntersect = false ;
141
+ bool isInside = Overlap::Point_AABB (objPosition, pFogVol->m_WSBBox );
142
+
143
+ if (fogVolumeShadingQuality)
144
+ {
145
+ projectedAABBIntersect = OverlapProjectedAABB (pFogVol->m_WSBBox , objAABB, passInfo.GetCamera ());
146
+ isInside = isInside || Overlap::AABB_AABB (objAABB, pFogVol->m_WSBBox );
147
+ }
148
+
61
149
// check if view ray intersects with bounding box of current fog volume
62
- if (Overlap::Lineseg_AABB (lineseg, pFogVol->m_WSBBox ))
150
+ isAligned = Overlap::Lineseg_AABB (lineseg, pFogVol->m_WSBBox );
151
+ if (projectedAABBIntersect || isAligned)
63
152
{
64
153
// compute contribution of current fog volume
65
- ColorF color;
66
- if (0 == pFogVol->m_volumeType )
154
+ ColorF color (0 ,0 ,0 );
155
+
156
+ // Get distance camera to fog volume.
157
+ const CCamera& cam (passInfo.GetCamera ());
158
+ Vec3 cameraToObject (objPosition - cam.GetPosition ());
159
+ Vec3 cameraToFogVolume (pFogVol->m_WSBBox .GetCenter () - cam.GetPosition ());
160
+ isFrontOfBoxCenter = (cameraToFogVolume.GetLengthSquared () > cameraToObject.GetLengthSquared ());
161
+ // if particle is in front of the box center and not inside the box, then do not accumulate fog color.
162
+ if (isFrontOfBoxCenter && !isInside)
163
+ {
164
+ continue ;
165
+ }
166
+
167
+ if (fogVolumeShadingQuality)
67
168
{
68
- pFogVol->GetVolumetricFogColorEllipsoid (worldPos, passInfo, color);
169
+ // Accumulate this fogVolData
170
+ AverageFogVolume (fogVolData, pFogVol);
171
+ color = pFogVol->GetFogColor ();
69
172
}
70
173
else
71
174
{
72
- pFogVol->GetVolumetricFogColorBox (worldPos, passInfo, color);
175
+ if (0 == pFogVol->m_volumeType )
176
+ {
177
+ pFogVol->GetVolumetricFogColorEllipsoid (worldPos, passInfo, color);
178
+ }
179
+ else
180
+ {
181
+ pFogVol->GetVolumetricFogColorBox (worldPos, passInfo, color);
182
+ }
183
+
184
+ color.a = 1 .0f - color.a ; // 0 = transparent, 1 = opaque
73
185
}
74
-
75
- color. a = 1 . 0f - color. a ; // 0 = transparent, 1 = opaque
76
-
186
+
187
+
188
+
77
189
// blend fog colors
78
190
localFogColor.r = Lerp (localFogColor.r , color.r , color.a );
79
191
localFogColor.g = Lerp (localFogColor.g , color.g , color.a );
80
192
localFogColor.b = Lerp (localFogColor.b , color.b , color.a );
81
193
localFogColor.a = Lerp (localFogColor.a , 1 .0f , color.a );
194
+
82
195
}
196
+
83
197
}
84
198
85
199
#ifdef _DEBUG
@@ -100,8 +214,7 @@ void CFogVolumeRenderNode::TraceFogVolumes(const Vec3& worldPos, ColorF& fogColo
100
214
}
101
215
102
216
localFogColor.a = 1 .0f - localFogColor.a ;
103
-
104
- fogColor = localFogColor;
217
+ fogVolData.fogColor = localFogColor;
105
218
}
106
219
107
220
// /////////////////////////////////////////////////////////////////////////////
0 commit comments