FreeWRL/FreeX3D  3.0.0
Component_Texturing3D.c
1 /*
2 
3 
4 X3D Texturing3D Component
5 
6 */
7 
8 
9 /****************************************************************************
10  This file is part of the FreeWRL/FreeX3D Distribution.
11 
12  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13 
14  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15  it under the terms of the GNU Lesser Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  GNU General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26 ****************************************************************************/
27 
28 
29 
30 #include <config.h>
31 #include <system.h>
32 #include <display.h>
33 #include <internal.h>
34 
35 #include <libFreeWRL.h>
36 
37 #include "../vrml_parser/Structs.h"
38 #include "../main/headers.h"
39 #include "../opengl/OpenGL_Utils.h"
40 #include "../opengl/Textures.h"
41 #include "../scenegraph/Component_Shape.h"
42 #include "../scenegraph/RenderFuncs.h"
43 
44 /*
45 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/texture3D.html
46 
47 Texturing3D > Volumetric Image Formats
48 http://www.volumesoffun.com/voldat-format/
49 https://graphics.stanford.edu/data/voldata/
50 http://paulbourke.net/dataformats/pvl/
51 http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2954506/#!po=59.5238
52 https://www.blender.org/manual/render/blender_render/textures/types/volume/voxel_data.html
53 
54 http://paulbourke.net/dataformats/volumetric/
55 -Simplest 3d texture file if you write your own images
56 http://www.web3d.org/x3d/content/examples/Basic/VolumeRendering/
57 - Volumetric Rendering Samples use nrrd format
58 - http://teem.sourceforge.net/index.html
59 - http://teem.sourceforge.net/nrrd/index.html
60 -- Nrrd lib LGPL
61 https://msdn.microsoft.com/en-us/library/windows/desktop/bb205579(v=vs.85).aspx
62 - DDS Volume Texture Example
63 
64 What is Texturing3D used for? a few links:
65 https://msdn.microsoft.com/en-us/library/windows/desktop/ff476906(v=vs.85).aspx
66 - difference between composed slices and volume image
67 http://docs.nvidia.com/gameworks/content/gameworkslibrary/graphicssamples/opengl_samples/texturearrayterrainsample.htm
68 - an application for rendering terrain
69 
70 
71 
72 Fuzzy Design:
73 - load various ways into a buffer representing contiguous voxels, with width, height, depth available
74 - somewhere in geometry rendering - polyrep stuff? - give it 3D or 4D-homogenous texture coordinates
75  instead of regular 2D. Hint: look at per-vertex RGBA floats in polyrep?
76 - somewhere in sending geom to shader, send the 3D/4D texture coords (and/or Matrix?)
77 - in shader, detect if its 3D texture, and use 3D texture lookup
78 
79 Q. is Texture3D available in GLES2?
80  https://www.khronos.org/opengles/sdk/docs/reference_cards/OpenGL-ES-2_0-Reference-card.pdf
81  - at bottom shows texture2D etc sampler functions
82  instead of vec3 texture2D(sampler2D,coord2D)
83  it would be vec4 texture3D(sampler3D sampler, vec3 coord) ?
84 
85 GLES2 texture3D: first edition doesn't have sampler3D/texture3D
86 https://www.khronos.org/registry/gles/extensions/OES/OES_texture_3D.txt
87 - there's a proposed extension
88 -Q.how to test for it at runtime?
89 -A. worst case: frag shader has a compile error:
90 -- if I put Texture3D uniform, and sampler3D(texture3d,vec3(coords2D,0.0)) then:
91  - desktop windows opengl frag shader compiles
92  x uwp windows (using angle over dx/hlsl) frag shader doesn't compile
93  x android frag shader doesn't compile
94 http://stackoverflow.com/questions/14150941/webgl-glsl-emulate-texture3d
95 http://stackoverflow.com/questions/16938422/3d-texture-emulation-in-shader-subpixel-related
96 - hackers emulating with texture2D tiles and lerps
97 https://android.googlesource.com/platform/external/chromium_org/third_party/angle/+/0027fa9%5E!/
98 - looks like chromium's ANGLE^ emulates cube as 6 2Ds as of 2014
99  ^(gles2 over DX/HLSL for webgl in windows chrome browser)
100 Michalis: "Note that Castle Game Engine does not support 3D textures in
101  OpenGLES now (so we don't use OES_texture_3D), but only on desktop
102  OpenGL now (available through EXT_texture3D, or in standard OpenGL >=
103  1.2). But that's simply due to my lack of time to patch necessary
104  things:) From the first glance, using OES_texture_3D to achieve the
105  same functionality on OpenGLES should be easy."
106  https://github.com/castle-engine/demo-models > texturing_advanced/tex3d_*
107 
108 Example use: if you have 3 images for terrain - white for mountain peaks, brown for mountain sides, green for valleys
109 - then combine them into a nxmx3 volume image?
110 - then you can use the terrain height to compute an R value ?
111 - cube sampler should in theory interpolate between the 3 layers?
112 
113 Design:
114 Texture coordinates:
115 I think the geometry vertices, scaled into the range 0-1 on each axis,
116 could/should serve as default 3D texture coordinates.
117 algorithm:
118 a) interpolate through varying the vertex xyz you want as usual
119 b) transform xyz into 0-1 range
120  -would need to know bounding box, or have pre-computed, or assume -1 to 1, or in textureTransform3D
121 Option: convert xyz vertex to 0-1 range in vertex shader,
122  and do varying interpolation in 0-1 range for varying textureCoords3D aka tc3d
123 c) sample the texture
124 A. if have texture3D/sampler3D/EXT_texture3D/OES_texture3D:
125  sample directly tc3d.xyz (0-1): frag = sampler3D(texture3D, vec3 tc3d.xyz)
126 B. else emulate texture3D/sampler3D with 2D tiled texture:
127  single texture2D: sample the texture at xy[z] on the 2D image plane, z rounded 'above' and 'below'
128  Q. how many z layers, and does it have to be same as rows & cols?
129  nx,ny,nz = size of image in pixels
130  nz == number of z levels
131  nzr = sqrt(nz) so if 256 z levels, it would be sqrt(256) = 16. 16x16 tiles in 2D plane
132  x,y,z - 0-1 range 3D image texture coords from tc3d.xyz
133  vec2 xyi = xy[i] = f(xyz) = [x/nzr + (i / nzr), y/nzr + (i % nzr)]
134  vec2 xyj = xy[j] ... "
135  where
136  i = floor(z*nz)
137  j = ceil(z*nz)
138  fxyi = sampler2D(texture2D,xyi)
139  fxyj = sampler2D(texture2D,xyj)
140  lerp between layers xy[i],xy[j]: frag = lerp(fxyi,fxyj,(z*nz-i)/(j-i))
141  Note: i,j don't need to be ints, nothing above needs to be int, can all be float
142  Option1: strip of tiles - instead of maintaining square 2D texture,
143  make strip texture nx x (ny * nz)
144  then no re-arranging needed when sending uniform (parsed into strip)
145  and xyi = [x, y + i*nz]
146  xyj = [x, y + j*nz]
147  hack test on windows, uwp, and androidndk/nexus: they can all handle the oblong texture
148  Option2: lerp vs floor effects:
149  lerp - smooth transition between layers, good for 3-layer valley, hillside, mountain peak
150  floor - (frag = fxyi): gives abrupt change between layers, good for brick effects
151  Option3: compute 2D-ized texture coordinates on CPU, and use ordinary texture2D sampling (no lerp)
152  problem: geometry node doesn't know if shape>appearance has texture3D, so would need to pre-compute like flat coords
153 
154 Sept 13, 2016
155  .web3dit image file format developeed which includes volume L,LA,RGB,RGBA and int/float, Up/Down options
156 
157 4 scenarios:
158  1. GL has texture3D/EXT_texture3D/OES_texture3D
159  2. GL no texture3D - emulate
160  A. 3D image: source imagery is i) 3D image or ii) composed image with image layers all same size
161  B. 2D layers: source imagery is composed image with z < 7 layers and layers can be different sizes
162  1 2
163  A vol texture3D tiled texture2D
164  B multi texure2D multi texture2D
165 
166 */
167 
168 int isTex3D(struct X3D_Node *node){
169  int ret = 0;
170  if(node)
171  switch(node->_nodeType){
172  case NODE_PixelTexture3D:
173  case NODE_ComposedTexture3D:
174  case NODE_ImageTexture3D:
175  ret = TRUE; break;
176  default:
177  ret = FALSE;break;
178  }
179  return ret;
180 }
181 
182 void render_PixelTexture3D (struct X3D_PixelTexture3D *node) {
183  loadTextureNode(X3D_NODE(node),NULL);
184  gglobal()->RenderFuncs.textureStackTop=1; /* not multitexture - should have saved to boundTextureStack[0] */
185 }
186 void move_texture_to_opengl(textureTableIndexStruct_s* me);
187 void render_ImageTexture3D (struct X3D_ImageTexture3D *node) {
188  /* printf ("render_ImageTexture, global Transparency %f\n",getAppearanceProperties()->transparency); */
189  loadTextureNode(X3D_NODE(node),NULL);
190  gglobal()->RenderFuncs.textureStackTop=1; /* not multitexture - should have saved to boundTextureStack[0] */
191 }
192 textureTableIndexStruct_s *getTableTableFromTextureNode(struct X3D_Node *textureNode);
193 void render_ComposedTexture3D (struct X3D_ComposedTexture3D *node) {
194  /* printf ("render_ComposedTexture, global Transparency %f\n",getAppearanceProperties()->transparency); */
195  if(node && node->_nodeType == NODE_ComposedTexture3D){
196  int i, allLoaded; //ntextures,
197  struct Multi_Node *tex = &node->texture;
198  //Sep 14, 2016 we assume all ComposedTexture3D are 'LAYERED' TEX3D_LAYER_SHADER / TEX3DLAY
199  if(0){
200  //could switch from layered to volume, if layers all same size?
201  //somewhere around here we could detect if all images are loaded,
202  // and if so, check/test:
203  // A. do they all have the same xy size? if same size,
204  // then they could be converted to single volume texture
205  // and i) texture3D or ii) tiled texture2D
206  // and set shader flag TEX3D_VOLUME_SHADER / TEX3D, TEX3DVOL
207  // B. if different sizes, and z < 7, then treat like multi-texture:
208  // ii) do sampler2D on either size of z
209  // and set shader flag TEX3D_LAYER_SHADER / TEX3D, TEX3DLAY
210  // either way if ii) we have 2 values in frag shader: take floor, ceil or lerp between
211  //
212  int nx, ny, nfound, nsamesize;
213  nfound = nsamesize = 0;
214  for(i=0;i<tex->n;i++){
215  if(tex->p[i] ){
217  tti = getTableTableFromTextureNode(tex->p[i]);
218  if(tti){
219  if(tti->status == TEX_LOADED){
220  nfound++;
221  if(nfound == 1){
222  nx = tti->x; ny = tti->y;
223  nsamesize = 1;
224  }else{
225  if(tti->x == nx && tti->y == ny) nsamesize++;
226  }
227  }
228  }
229  }
230  }
231  if(nsamesize == nfound && nfound == tex->n){
232  //all 2D textures are loadded and the same size
233  // -can combine into single volume texture
234  printf("ComposedTexture3D all same size textures n %d x %d y %d\n",tex->n,nx,ny);
235  //COMBINE?
236  //TEX3DVOL
237  }else{
238  //not all loaded (so can't trust all same size) or not all same size
239  //so we'll do up to 6 'layers' or texture2Ds, and lerp between floor/ceil in the shader
240  printf("ComposedTexture3D not all same size textures \n");
241  //TEX3DLAY
242  }
243  }
244  allLoaded = TRUE;
245  gglobal()->RenderFuncs.textureStackTop = 0;
246  for(i=0;i<min(tex->n,MAX_MULTITEXTURE);i++){
247  //doing layers, we can only handle up to MAX_MULTITEXTURE textures in the shader
248  //gglobal()->RenderFuncs.textureStackTop = ntextures; /* not multitexture - should have saved to boundTextureStack[0] */
249  loadTextureNode(X3D_NODE(tex->p[i]),NULL);
250  allLoaded = allLoaded && getTableTableFromTextureNode(X3D_NODE(tex->p[i]))->status >= TEX_LOADED;
251  gglobal()->RenderFuncs.textureStackTop++;
252  //loadMultiTexture(node);
253  }
254  //move_texture_to_opengl(getTableTableFromTextureNode(X3D_NODE(node))); //load composed texture properties
255 
256  if(allLoaded){
258  tti = getTableTableFromTextureNode(X3D_NODE(node));
259  tti->status = max(TEX_NEEDSBINDING, tti->status);
260  loadTextureNode(X3D_NODE(node),NULL);
261  }
262  }
263 }
264 
265 //void loadImageTexture3D(struct X3D_ImageTexture3D *node){
266 // //we don't seem to call or need this
267 //}