FreeWRL/FreeX3D  3.0.0
Component_EnvironEffects.c
1 
2 /****************************************************************************
3  This file is part of the FreeWRL/FreeX3D Distribution.
4 
5  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
6 
7  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
8  it under the terms of the GNU Lesser Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
19 ****************************************************************************/
20 
21 
22 /*******************************************************************
23 
24  X3D Environmental Effects Component
25 
26 *********************************************************************/
27 
28 /*
29 FOG - state as of July 2016:
30  - our conformance page says local_fog and fog_coordinates are unimplemented
31  - Bindable.c
32  - render_fog
33  - #ifndef GL_ES_VERSION_2_0 // this should be handled in material shader
34  Unclear if global Fog is working
35 
36  http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/lighting.html#LightingModel
37  - Use of fog and fog coords in lighting eqn.
38  http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/enveffects.html#FogSemantics
39  - meaning of fog nodes
40  - background nodes are not affected by fog
41 
42  VRML2 fog examples:
43  http://www.web3d.org/x3d-resources/content/examples/Vrml2.0Sourcebook/Chapter23-Fog/
44  http://www.web3d.org/x3d/content/examples/Vrml2.0Sourcebook/Chapter23-Fog/Figure23.3cExponentialFogVisibility20.x3d
45  - Octaga shows light fog increasing exponentially with distance (but shows ground white)
46  - InstantReality shows heavy fog increasing exponentially with distance (then bombs on exit)
47  - Vivaty - medium " works well
48  - freewrl desktop win32 - no fog effect
49  X3D fog in kelp forest example:
50  http://x3dgraphics.com/examples/X3dForWebAuthors/Chapter11-LightingEnvironmentalEffects/
51  http://x3dgraphics.com/examples/X3dForWebAuthors/Chapter11-LightingEnvironmentalEffects/Fog-KelpForestMain.x3d
52  - freewrl Aug 8, 2016
53  x no fog
54  - fog (and scene) looks great in Octaga, InstantReality, Vivaty (although Octaga crashes if left running 8min)
55 
56  Non-X3D links:
57  http://www.mbsoftworks.sk/index.php?page=tutorials&series=1&tutorial=15
58  - fog shader with linear and exponential
59  http://www.geeks3d.com/20100228/fog-in-glsl-webgl/
60  - frag shader, webgl
61  Fog Scale:
62  The fog distance is in the coordinate system of the Fog Node
63  - that means scale, relative to current shape/leaf/renderable node
64  When visiting Fog or LocalFog node in scenegraph:
65  1. transform a unit vector from Fog node to viewpoint/eye: vec3 = ModelViewMatrix x [0 0 1]
66  fogScale = 1.0/length(vec3) //so as to scale from eye/viewpoint to fognode scale
67  2. when at Shape node, send fogScale to shader
68  in shader, apply fogScale _after_ vertex/fogCoord is transformed by modelview into viewpoint/eyesapce
69  LocalFog vs Fog
70  LocalFog over-rides Fog, and its the most-local Fog that applies
71  - so there should be a stack of fogParameters
72  - LocalFog should push params and bitmask in prep_localFog and pop in fin_localFog
73  - render_hier at root level on VF_Blend/VF_Geom pass should see if there's a bound Fog enabled,
74  - if so push its parameters and bitmask
75  Fog - on bind_Fog it sets itself as the global fog node
76  bind: this means the node type has a 'singleton' effect on the scene ie only one can be active at a time
77 
78  Shader pseudo-algo 1:
79  dV = distance from point on geometry to viewer's position, in coordinate system (scale) of current fog node
80  if(usingFogCoords)
81  dv = fog_depth * fogScale; //fog_depth[i] is VBO of floats, one per vertex
82  else
83  dv = (modelviewMatrix * gl_position).z * fogScale;
84 
85  f0 = fog(useFog,fogType,fogVisibility,dv){
86  f0 = 1;
87  if(useFog){
88  f0 = 0;
89  if(fogType==LINEAR)
90  if(dv < fogVisibility)
91  f0 = (fogVisibility-dv)/fogVisibility;
92  else //EXPONENTIAL
93  if(dv < fogVisibility)
94  f0 = exp(-dv/(fogVisibillity -dv) );
95  }
96  return f0;
97  }
98  Pseudo-algo 2:
99  FOG VERTEX SNIPPET
100  vec4 eyeSpacePos = modelViewMatrix*vec4(inPosition, 1.0);
101  if(fogCoords) eyeSpacePos.z = fogCoord;
102  eyeSpacePos *= fogScale;
103 
104  FOG FRAGMENT SNIPPET
105  uniform struct fogParams
106  {
107  vec4 fogColor;
108  float visibilityRange;
109  int fogType; // 0 None, 1= FOGTYPE_LINEAR, 2 = FOGTYPE_EXPONENTIAL
110  } fogParams;
111 
112  float fogFactor(fogParams params, float fogDepth);
113  float fogDepth = abs(eyeSpacePos.z/eyeSpacePos.w);
114 
115  float fogFactor(fogParams params, float fogDepth)
116  {
117  float ff = 1.0;
118  if(params.fogType > 0){
119  ff = 0.0;
120  if(params.fogType==FOGTYPE_LINEAR)
121  if(dv < fogVisibility)
122  fF = (fogVisibility-dv)/fogVisibility;
123  else //FOGTYPE_EXPONENTIAL
124  if(dv < fogVisibility)
125  fF = exp(-dv/(fogVisibillity -dv) );
126  ff = clamp(ff, 0.0, 1.0);
127  }
128  return ff;
129  }
130 
131  Shader requirements signalling, for compiling fog capabilities into shader:
132  in render_hier, if VF_Blend || VF_Geom
133  set global shader requirements top of stack bitmask to 00000000
134  if bound global fog, set fog bit
135  in render_node, prep_localFog
136  if enableed,
137  copy top-of-stack bitmask
138  set local fog bit flag
139  push bitmask on bitmask stack
140  in render_node, fin_localFog
141  if enabled,
142  pop bitmask stack
143  in render_shape
144  //add any locallights, fog, clipplane bitmask to shape's shader requirements bitmask:
145  bitmask = node->_shadernode_requirements_bitmask
146  bitmask = bitmask |= bitmaskStackTop
147  request_shader(bitmask)
148  //send fog data to shader program:
149  if(fogset(bitmask))
150  copy fogTopOfStack to fogParams
151  if(have_fogCoords)
152  set haveFogCoords in fogParams
153  send_fogCoords
154  send fogParams
155 
156 
157 */
158 #include <config.h>
159 #include <system.h>
160 #include <display.h>
161 #include <internal.h>
162 
163 #include <libFreeWRL.h>
164 
165 #include "../vrml_parser/Structs.h"
166 #include "../main/headers.h"
167 #include "../vrml_parser/CParseGeneral.h"
168 #include "../scenegraph/Vector.h"
169 #include "../vrml_parser/CFieldDecls.h"
170 #include "../vrml_parser/CParseParser.h"
171 #include "../vrml_parser/CParseLexer.h"
172 #include "../vrml_parser/CRoutes.h"
173 #include "../opengl/OpenGL_Utils.h"
174 #include "../x3d_parser/Bindable.h"
175 #include "../scenegraph/quaternion.h"
176 #include "../scenegraph/Viewer.h"
177 #include "../scenegraph/Component_Geospatial.h"
178 #include "../scenegraph/RenderFuncs.h"
179 #include "../scenegraph/Component_ProgrammableShaders.h"
180 #include "../scenegraph/Component_Shape.h"
181 #include "../ui/common.h"
182 #include "../scenegraph/LinearAlgebra.h"
183 #define FOGTYPE_LINEAR 1
184 #define FOGTYPE_EXPONENTIAL 2
185 //unsigned int getShaderFlags();
186 shaderflagsstruct getShaderFlags();
187 //void pushShaderFlags(unsigned int flags);
188 void pushShaderFlags(shaderflagsstruct flags);
189 void popShaderFlags();
190 struct X3D_Node *getFogParams();
191 void pushFogParams(struct X3D_Node *fogparams);
192 void popFogParams();
193 struct X3D_Node *getFogParams(); //see renderfuncs.c
194 //in child_shape or in general in renderable-leaf-nodes,
195 // you would call getShaderFlags() and |= to node->_shaderIndex requirement bits before requesting a shader
196 // and check the fog bit
197 // if fogbit set, you would call getFogParams() and send them to the shader
198 
199 
200 //typedef struct fogParams {
201 // float color[3];
202 // float visibilityRange;
203 // float scale;
204 // int type; //0=NONE 1=LINEAR 2=EXPONENTIAL
205 //} fogParams;
206 double calculateFogScale(){
207  //call this when scenegraph render_hier() visiting a Fog or LocalFog node to update its fogScale
208  // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/enveffects.html#Fog
209  // "The distances are calculated in the coordinate space of the Fog node."
210  // H: that's mathemeatically/numerically equivalent to scaling visibilityRange into the viewpoint system
211  // via the transform stack or more precisely the scale effects of the transform stack at the Fog/LocalFog node
212  // in the scenegraph ie:
213  // Transform { scale 10 10 10 children [Fog { visibilityRange 2, then fogScale is 10, and viewspace visrange is 10*2 = 20
214  GLDOUBLE modelviewMatrix[16], fogLocal[3], eyeLocal[3], eyeLocalB[3], eyeDepth, fogScale;
215  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelviewMatrix);
216  fogLocal[0] = 0.0; fogLocal[1] = 0.0; fogLocal[2] = 0.0; //point in fog-local
217  transformAFFINEd(eyeLocal,fogLocal,modelviewMatrix);
218  fogLocal[2] = 1.0; //second point in fog local, just 1 unit away from first point
219  transformAFFINEd(eyeLocalB,fogLocal,modelviewMatrix);
220  vecdifd(eyeLocal,eyeLocal,eyeLocalB); //get transformed unit vector (how long a unit vector in Fog coords is in View system)
221  eyeDepth = veclengthd(eyeLocal);
222  if(eyeDepth != 0.0)
223  fogScale = eyeDepth; //in shader or before sending to shader, effectively multiplies visibility range by fogScale to get in view scale
224  else
225  fogScale = 1.0;
226  return fogScale;
227 }
228 void render_Fog(struct X3D_Fog *node) {
229  //this can be done on either a prep pass, or rendering pass in render_hier, or all passes
230  // - its just to get the fog scale
231  //if Fog DEF/USED (multiple scales possible) we use the last one calculated
232  int fogType = 0;
233  node->__fogScale = (float)calculateFogScale();
234  if(node->fogType->strptr){
235  if(!strcmp(node->fogType->strptr,"LINEAR")) fogType = FOGTYPE_LINEAR; //1
236  if(!strcmp(node->fogType->strptr,"EXPONENTIAL")) fogType = FOGTYPE_EXPONENTIAL; //2
237  }
238  node->__fogType = fogType;
239 }
240 
241 void prep_LocalFog(struct X3D_Node *node){
242  //LocalFog applies to siblings and descendents of parent Group
243  //Q. how do we handle sibling effects in freewrl?
244  struct X3D_LocalFog *fog = (struct X3D_LocalFog*)node;
245  if(fog->enabled && fog->visibilityRange > 0.0f){
246  //unsigned int shaderflags;
247  shaderflagsstruct shaderflags;
248  //compute fogScale
249  render_Fog((struct X3D_Fog*)node);
250  //push fog parameters on fogParams stack
251  //copy and push shader requirements stack with fog bit set
252  shaderflags = getShaderFlags();
253  shaderflags.base |= FOG_APPEARANCE_SHADER;
254  pushShaderFlags(shaderflags);
255  pushFogParams((struct X3D_Node*)fog);
256  }
257 }
258 void fin_LocalFog(struct X3D_Node *node){
259  struct X3D_LocalFog *fog = (struct X3D_LocalFog*)node;
260  if(fog->enabled && fog->visibilityRange > 0.0f){
261  popFogParams();
262  popShaderFlags();
263  }
264 }
265 void sib_prep_LocalFog(struct X3D_Node *parent, struct X3D_Node *node){
266  ttrenderstate rs = renderstate();
267  if(rs->render_blend || rs->render_geom){
268  prep_LocalFog(node);
269  }
270 }
271 void sib_fin_LocalFog(struct X3D_Node *parent, struct X3D_Node *node){
272  ttrenderstate rs = renderstate();
273  if(rs->render_blend || rs->render_geom){
274  fin_LocalFog(node);
275  }
276 }