FreeWRL / FreeX3D 4.3.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/*
29FOG - 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();
186shaderflagsstruct getShaderFlags();
187//void pushShaderFlags(unsigned int flags);
188void pushShaderFlags(shaderflagsstruct flags);
189void popShaderFlags();
190struct X3D_Node *getFogParams();
191void pushFogParams(struct X3D_Node *fogparams);
192void popFogParams();
193struct 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;
206double 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}
228void 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
241void 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}
258void 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}
265void 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}
271void 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}