GtePlanarReflectionEffect.cpp
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #include <GTEnginePCH.h>
10 #include <LowLevel/GteLogger.h>
11 using namespace gte;
12 
13 PlanarReflectionEffect::PlanarReflectionEffect(std::vector<std::shared_ptr<Visual>> const& planes,
14  std::vector<float> const& reflectances)
15  :
16  mPlanes(planes),
17  mReflectances(reflectances),
18  mPlaneOrigins(planes.size()),
19  mPlaneNormals(planes.size())
20 {
21  unsigned int const numPlanes = static_cast<unsigned int>(mPlanes.size());
22  for (unsigned int i = 0; i < numPlanes; ++i)
23  {
24  std::shared_ptr<Visual> plane = mPlanes[i];
25 
26  // The culling flag is set to "always" because this effect is responsible
27  // for drawing the triangle mesh. This prevents drawing attempts by another
28  // scene graph for which 'plane' is a leaf node.
29  plane->culling = CULL_ALWAYS;
30 
31  // Compute the model-space origin and normal for the plane.
32 
33  // Get the position data.
34  std::shared_ptr<VertexBuffer> vbuffer = plane->GetVertexBuffer();
35  unsigned int vstride = vbuffer->GetElementSize();
36  std::set<DFType> required;
37  required.insert(DF_R32G32B32_FLOAT);
38  required.insert(DF_R32G32B32A32_FLOAT);
39  char const* positions = vbuffer->GetChannel(VA_POSITION, 0, required);
40  if (!positions)
41  {
42  LogError("Expecting 3D positions.");
45  continue;
46  }
47 
48  // Verify the plane topology involves triangles.
49  std::shared_ptr<IndexBuffer> ibuffer = plane->GetIndexBuffer();
50  IPType primitiveType = ibuffer->GetPrimitiveType();
51  if (!(primitiveType & IP_HAS_TRIANGLES))
52  {
53  LogError("Expecting triangle topology.");
56  continue;
57  }
58 
59  // Get the vertex indices for the first triangle defining the plane.
60  unsigned int v[3];
61  if (ibuffer->IsIndexed())
62  {
63  ibuffer->GetTriangle(i, v[0], v[1], v[2]);
64  }
65  else if (primitiveType == IP_TRIMESH)
66  {
67  v[0] = 3 * i;
68  v[1] = v[0] + 1;
69  v[2] = v[0] + 2;
70  }
71  else // primitiveType == IP_TRISTRIP
72  {
73  int offset = (i & 1);
74  v[0] = i + offset;
75  v[1] = i + 1 + offset;
76  v[2] = i + 2 - offset;
77  }
78 
79  // Get the model-space positions of the triangle vertices.
80  Vector4<float> p[3];
81  for (int j = 0; j < 3; ++j)
82  {
83  Vector3<float> temp = *reinterpret_cast<Vector3<float> const*>(positions + v[j] * vstride);
84  p[j] = HLift<3, float>(temp, 1.0f);
85  }
86 
87  mPlaneOrigins[i] = p[0];
88  mPlaneNormals[i] = UnitCross(p[2] - p[0], p[1] - p[0]);
89  }
90 
91  // Turn off color writes.
92  mNoColorWrites = std::make_shared<BlendState>();
93  mNoColorWrites->target[0].mask = 0;
94  mNoColorWrites->target[0].enable = true;
95 
96  // Blend with a constant alpha. The blend color is set for each
97  // reflecting plane.
98  mReflectanceBlend = std::make_shared<BlendState>();
99  mReflectanceBlend->target[0].enable = true;
100  mReflectanceBlend->target[0].srcColor = BlendState::BM_INV_FACTOR;
101  mReflectanceBlend->target[0].dstColor = BlendState::BM_FACTOR;
102  mReflectanceBlend->target[0].srcAlpha = BlendState::BM_INV_FACTOR;
103  mReflectanceBlend->target[0].dstAlpha = BlendState::BM_FACTOR;
104 
105  // For toggling the current cull mode to the opposite of what is active.
106  mCullReverse = std::make_shared<RasterizerState>();
107 
108  // The depth-stencil passes. The reference values are set for each
109  // reflecting plane.
110  mDSPass0 = std::make_shared<DepthStencilState>();
111  mDSPass0->depthEnable = true;
112  mDSPass0->writeMask = DepthStencilState::MASK_ZERO;
113  mDSPass0->comparison = DepthStencilState::LESS_EQUAL;
114  mDSPass0->stencilEnable = true;
115  mDSPass0->frontFace.fail = DepthStencilState::OP_KEEP;
116  mDSPass0->frontFace.depthFail = DepthStencilState::OP_KEEP;
117  mDSPass0->frontFace.pass = DepthStencilState::OP_REPLACE;
118  mDSPass0->frontFace.comparison = DepthStencilState::ALWAYS;
119 
120  mDSPass1 = std::make_shared<DepthStencilState>();
121  mDSPass1->depthEnable = true;
122  mDSPass1->writeMask = DepthStencilState::MASK_ALL;
123  mDSPass1->comparison = DepthStencilState::ALWAYS;
124  mDSPass1->stencilEnable = true;
125  mDSPass1->frontFace.fail = DepthStencilState::OP_KEEP;
126  mDSPass1->frontFace.depthFail = DepthStencilState::OP_KEEP;
127  mDSPass1->frontFace.pass = DepthStencilState::OP_KEEP;
128  mDSPass1->frontFace.comparison = DepthStencilState::EQUAL;
129 
130  mDSPass2 = std::make_shared<DepthStencilState>();
131  mDSPass2->depthEnable = true;
132  mDSPass2->writeMask = DepthStencilState::MASK_ALL;
134  mDSPass2->stencilEnable = true;
135  mDSPass2->frontFace.fail = DepthStencilState::OP_KEEP;
136  mDSPass2->frontFace.depthFail = DepthStencilState::OP_KEEP;
137  mDSPass2->frontFace.pass = DepthStencilState::OP_ZERO;
138  mDSPass2->frontFace.comparison = DepthStencilState::EQUAL;
139 }
140 
141 void PlanarReflectionEffect::Draw(std::shared_ptr<GraphicsEngine> const& engine,
142  VisibleSet const& visibleSet, PVWUpdater& pvwMatrices)
143 {
144  // Save the global state, to be restored later.
145  std::shared_ptr<BlendState> saveBState = engine->GetBlendState();
146  std::shared_ptr<DepthStencilState> saveDSState = engine->GetDepthStencilState();
147  std::shared_ptr<RasterizerState> saveRState = engine->GetRasterizerState();
148 
149  // The depth range will be modified during drawing, so save the current
150  // depth range for restoration later.
151  float minDepth, maxDepth;
152  engine->GetDepthRange(minDepth, maxDepth);
153 
154  // Get the camera to store post-world transformations.
155  std::shared_ptr<Camera> camera = pvwMatrices.GetCamera();
156 
157  // Get the current cull mode and reverse it. Allow for models that are not
158  // necessarily set up with front or back face culling.
159  if (saveRState->cullMode == RasterizerState::CULL_BACK)
160  {
162  }
163  else if (saveRState->cullMode == RasterizerState::CULL_FRONT)
164  {
165  mCullReverse->cullMode = RasterizerState::CULL_BACK;
166  }
167  else
168  {
170  }
171  engine->Bind(mCullReverse);
172 
173  unsigned int const numPlanes = static_cast<unsigned int>(mPlanes.size());
174  for (unsigned int i = 0, reference = 1; i < numPlanes; ++i, ++reference)
175  {
176  std::shared_ptr<Visual> plane = mPlanes[i];
177 
178  // Render the plane to the stencil buffer only; that is, there are no
179  // color writes or depth writes. The depth buffer is read so that
180  // plane pixels occluded by other already drawn geometry are not drawn.
181  // The stencil buffer value for pixels from plane i is (i+1). The
182  // stencil buffer is updated at a pixel only when the depth test passes
183  // at that pixel (the plane pixel is visible):
184  // frontFace.fail is always false, so value KEEP is irrelevant
185  // frontFace.depthFail = true, KEEP current stencil value
186  // frontFace.pass = false, REPLACE current stencil value with (i+1)
187  mDSPass0->reference = reference;
188  engine->SetDepthStencilState(mDSPass0);
189  engine->SetBlendState(mNoColorWrites);
190  engine->Draw(plane);
191 
192  // Render the plane again. The stencil buffer comparison is EQUAL,
193  // so the color and depth are updated only at pixels generated by the
194  // plane; the stencil values for such pixels is necessarily (i+1).
195  // The depth buffer comparison is ALWAYS and the depth range settings
196  // cause the depth to be updated to maximum depth at all pixels
197  // where the stencil values are (i+1). This allows us to draw the
198  // reflected object on the plane. Color writes are enabled, because
199  // the portion of the plane not covered by the reflected object must
200  // be drawn because it is visible.
201  mDSPass1->reference = reference;
202  engine->SetDepthStencilState(mDSPass1);
203  engine->SetDefaultBlendState();
204  engine->SetDepthRange(maxDepth, maxDepth);
205  engine->Draw(plane);
206  engine->SetDepthRange(minDepth, maxDepth);
207 
208  // Render the reflected object only at pixels corresponding to those
209  // drawn for the current plane; that is, where the stencil buffer
210  // value is (i+1). The reflection matrix is constructed from the
211  // plane in world coordinates and must be applied in the transformation
212  // pipeline before the world-to-view matrix is applied; thus, we
213  // insert the reflection matrix into the pipeline via SetPreViewMatrix.
214  // Because the pvw-matrices are dependent on this, each time the
215  // full transformation is computed we must update the pvw matrices in
216  // the constant buffers for the shaders. NOTE: The reflected objects
217  // will generate pixels whose depth is larger than that for the
218  // reflecting plane. This is not a problem, because we will later
219  // draw the plane again and blend its pixels with the reflected object
220  // pixels, after which the depth buffer values are updated to the plane
221  // pixel depths.
222 #if defined(GTE_USE_MAT_VEC)
223  Vector4<float> origin = plane->worldTransform * mPlaneOrigins[i];
224  Vector4<float> normal = plane->worldTransform * mPlaneNormals[i];
225 #else
226  Vector4<float> origin = mPlaneOrigins[i] * plane->worldTransform;
227  Vector4<float> normal = mPlaneNormals[i] * plane->worldTransform;
228 #endif
229  Normalize(normal);
230  camera->SetPreViewMatrix(MakeReflection(origin, normal));
231  pvwMatrices.Update();
232  engine->SetDefaultDepthStencilState();
233  engine->SetRasterizerState(mCullReverse);
234  for (auto const& visual : visibleSet)
235  {
236  engine->Draw(visual);
237  }
238  engine->SetRasterizerState(saveRState);
239  camera->SetPreViewMatrix(Matrix4x4<float>::Identity());
240  pvwMatrices.Update();
241 
242  // Render the plane a third time and blend its colors with the
243  // colors of the reflect objects. The blending occurs only at the
244  // pixels corresponding to the current plane; that is, where the
245  // stencil values are (i+1). The stencil values are cleared (set to
246  // zero) at pixels where the depth test passes. The blending uses
247  // the reflectance value for the plane,
248  // (1 - reflectance) * plane.rgba + reflectance * backbuffer.rgba
249  mDSPass2->reference = reference;
250  mReflectanceBlend->blendColor = { mReflectances[i], mReflectances[i], mReflectances[i], mReflectances[i] };
251  engine->SetDepthStencilState(mDSPass2);
252  engine->SetBlendState(mReflectanceBlend);
253  engine->Draw(plane);
254  }
255 
256  // Restore the global state that existed before this function call.
257  engine->SetBlendState(saveBState);
258  engine->SetDepthStencilState(saveDSState);
259  engine->SetRasterizerState(saveRState);
260 
261  // Render the objects using a normal drawing pass.
262  for (auto const& visual : visibleSet)
263  {
264  engine->Draw(visual);
265  }
266 }
267 
268 std::pair<Vector4<float>, Vector4<float>> PlanarReflectionEffect::GetPlane(int i) const
269 {
270  if (0 <= i && i < GetNumPlanes())
271  {
272  return std::make_pair(mPlaneOrigins[i], mPlaneNormals[i]);
273  }
274  else
275  {
276  return std::make_pair(Vector4<float>::Zero(), Vector4<float>::Zero());
277  }
278 }
279 
280 std::shared_ptr<Visual> PlanarReflectionEffect::GetPlaneVisual(int i) const
281 {
282  if (0 <= i && i < GetNumPlanes())
283  {
284  return mPlanes[i];
285  }
286  else
287  {
288  return nullptr;
289  }
290 }
291 
292 void PlanarReflectionEffect::SetReflectance(int i, float reflectance)
293 {
294  if (0 <= i && i < GetNumPlanes())
295  {
296  mReflectances[i] = reflectance;
297  }
298 }
299 
301 {
302  if (0 <= i && i < GetNumPlanes())
303  {
304  return mReflectances[i];
305  }
306  else
307  {
308  return 0.0f;
309  }
310 }
BM_FACTOR
Definition: GteBlendState.h:21
CULL_ALWAYS
Definition: GteCuller.h:34
GLint reference
Definition: glext.h:9678
void SetReflectance(int i, float reflectance)
IP_TRIMESH
BM_INV_FACTOR
Definition: GteBlendState.h:21
std::vector< Visual * > VisibleSet
Definition: GteCuller.h:47
std::pair< Vector4< float >, Vector4< float > > GetPlane(int i) const
Vector< N, Real > UnitCross(Vector< N, Real > const &v0, Vector< N, Real > const &v1, bool robust=false)
Definition: GteVector3.h:130
std::shared_ptr< DepthStencilState > mDSPass0
GLsizeiptr size
Definition: glcorearb.h:659
std::shared_ptr< Visual > GetPlaneVisual(int i) const
std::vector< Vector4< float > > mPlaneOrigins
std::vector< Vector4< float > > mPlaneNormals
virtual void Draw(std::shared_ptr< GraphicsEngine > const &engine, VisibleSet const &visibleSet, PVWUpdater &pvwMatrices)
VA_POSITION
GLfixed GLfixed GLint GLint GLfixed GLfixed GLint vstride
Definition: glext.h:4928
#define LogError(message)
Definition: GteLogger.h:92
std::shared_ptr< DepthStencilState > mDSPass2
std::shared_ptr< DepthStencilState > mDSPass1
static Vector Zero()
DF_R32G32B32A32_FLOAT
Definition: GteDataFormat.h:20
std::shared_ptr< Camera > const & GetCamera() const
Definition: GtePVWUpdater.h:66
Matrix4x4< Real > MakeReflection(Vector4< Real > const &origin, Vector4< Real > const &normal)
Definition: GteMatrix4x4.h:301
std::vector< std::shared_ptr< Visual > > mPlanes
CULL_FRONT
Real Normalize(GVector< Real > &v, bool robust=false)
Definition: GteGVector.h:454
std::shared_ptr< BlendState > mNoColorWrites
const GLdouble * v
Definition: glcorearb.h:832
IP_HAS_TRIANGLES
std::shared_ptr< BlendState > mReflectanceBlend
std::shared_ptr< RasterizerState > mCullReverse
GLintptr offset
Definition: glcorearb.h:660
DF_R32G32B32_FLOAT
Definition: GteDataFormat.h:20
GLfloat GLfloat p
Definition: glext.h:11668
PlanarReflectionEffect(std::vector< std::shared_ptr< Visual >> const &planes, std::vector< float > const &reflectances)


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 04:00:01