diff --git a/examples/amr_spherical_volume_rendering.py b/examples/amr_spherical_volume_rendering.py index e847b11..7a90b4a 100644 --- a/examples/amr_spherical_volume_rendering.py +++ b/examples/amr_spherical_volume_rendering.py @@ -1,4 +1,4 @@ -import sys +import argparse import numpy as np import yt @@ -7,45 +7,109 @@ # yt reminder: phi is the polar angle (0 to 2pi) # theta is the angle from north (0 to pi) - - # coord ordering here will be r, phi, theta - bbox_options = { "partial": np.array([[0.5, 1.0], [0.0, np.pi / 3], [np.pi / 4, np.pi / 2]]), - "whole": np.array([[0., 1.0], [0.0, 2 * np.pi], [0, np.pi]]), + "whole": np.array([[0.0, 1.0], [0.0, 2 * np.pi], [0, np.pi]]), + "shell": np.array([[0.7, 1.0], [0.0, 2 * np.pi], [0, np.pi]]), "north_hemi": np.array([[0.1, 1.0], [0.0, 2 * np.pi], [0, 0.5 * np.pi]]), + "north_shell": np.array([[0.8, 1.0], [0.0, 2 * np.pi], [0, 0.5 * np.pi]]), "south_hemi": np.array([[0.1, 1.0], [0.0, 2 * np.pi], [0.5 * np.pi, np.pi]]), "ew_hemi": np.array([[0.1, 1.0], [0.0, np.pi], [0.0, np.pi]]), } - - sz = (256, 256, 256) fake_data = {"density": np.random.random(sz)} if __name__ == "__main__": - if len(sys.argv) > 1: - bbox_type = sys.argv[1] + + parser = argparse.ArgumentParser( + prog="amr_spherical_volume_rendering", + description="Loads an example spherical dataset in yt_idv", + ) + + msg = f"The geometry subset to generate: one of {list(bbox_options.keys())}" + parser.add_argument("-d", "--domain", default="partial", help=msg) + msg = ( + "The field to plot. Provide a comma-separated string with field_type,field " + "e.g., to plot the field tuple ('index', 'phi'): \n " + " $ python amr_spherical_volume_rendering.py -f index,x " + "\nIf a single string is provided, a field type of gas is assumed." + ) + parser.add_argument("-f", "--field", default="index,phi", help=msg) + + args = parser.parse_args() + + field = str(args.field).split(",") + if len(field) == 1: + field = ("gas", str(field).strip()) + elif len(field) == 2: + field = (field[0].strip(), field[1].strip()) else: - bbox_type = "partial" + raise RuntimeError( + "Unexpected field formatting. Provide a single string" + " to provide just a field (will assume field type " + " of 'gas', or a comma separated string to provide a " + "field type and a field" + ) - bbox = bbox_options[bbox_type] + if args.domain not in bbox_options: + raise RuntimeError( + f"domain must be one of {list(bbox_options.keys())}, found {args.domain}" + ) + bbox = bbox_options[args.domain] ds = yt.load_uniform_grid( fake_data, sz, bbox=bbox, - nprocs=64, - geometry=("spherical", ("r", "phi", "theta")), - length_unit="m", + nprocs=128, + geometry="spherical", + axis_order=("r", "phi", "theta"), + length_unit=1, + ) + + phi_c = ds.quan(ds.domain_center[ds.coordinates.axis_id["phi"]].d, "") + theta_c = ds.quan(ds.domain_center[ds.coordinates.axis_id["theta"]].d, "") + rmax = ds.domain_right_edge[ds.coordinates.axis_id["r"]] + phi_f = ds.quan(15.0 * np.pi / 180.0, "") + theta_f = ds.quan(15.0 * np.pi / 180.0, "") + min_val = ds.quan(0.1, "") + + def _tube(field, data): + phi = data["index", "phi"] + theta = data["index", "theta"] + tube = (1 - min_val) * np.exp(-(((theta - theta_c) / theta_f) ** 2)) + tube = tube * np.exp(-(((phi - phi_c) / phi_f) ** 2)) + return tube + min_val + + ds.add_field( + name=("stream", "tube"), + function=_tube, + sampling_type="local", ) + def _r_rev(field, data): + r = data["index", "r"] + return rmax - r + + ds.add_field( + name=("stream", "r_rev"), + function=_r_rev, + sampling_type="local", + ) + + if field not in ds.field_list + ds.derived_field_list: + spaces = " " * 8 + fld_list_str = f"\n{spaces}".join(str(fld) for fld in ds.field_list) + drv_fld_list_str = f"\n{spaces}".join(str(fld) for fld in ds.derived_field_list) + raise RuntimeError( + f"field {field} not in field_list or derived_field_list:\n" + f"\n ds.field_list:\n{spaces}{fld_list_str}" + f"\n ds.derived_field_list:\n{spaces}{drv_fld_list_str}" + ) + rc = yt_idv.render_context(height=800, width=800, gui=True) - dd = ds.all_data() - dd.max_level = 1 - # sg = rc.add_scene(ds, ("index", "r"), no_ghost=True) - # sg = rc.add_scene(ds, ("index", "theta"), no_ghost=True) - sg = rc.add_scene(ds, ("index", "phi"), no_ghost=True) - # sg = rc.add_scene(ds, ("stream", "density"), no_ghost=True) - sg.camera.focus = [0.0, 0.0, 0.0] + sg = rc.add_scene(ds, field, no_ghost=True) + rc.scene.components[0].sample_factor = 20.0 + rc.run() diff --git a/examples/spherical_subset_volume_rendering.py b/examples/spherical_subset_volume_rendering.py deleted file mode 100644 index 682bf72..0000000 --- a/examples/spherical_subset_volume_rendering.py +++ /dev/null @@ -1,33 +0,0 @@ -import numpy as np -import yt - -import yt_idv - -# Spherical Test (to line 20) - -NDIM = 32 - -bbox = np.array( - [[0.0, 0.5], [np.pi / 8, 2 * np.pi / 8], [2 * np.pi / 8, 3 * np.pi / 8]] -) - -fake_data = {"density": np.random.random((NDIM, NDIM, NDIM))} -ds = yt.load_uniform_grid( - fake_data, - [NDIM, NDIM, NDIM], - bbox=bbox, - geometry="spherical", -) - -rc = yt_idv.render_context(height=800, width=800, gui=True) -dd = ds.all_data() -dd.max_level = 1 -sg = rc.add_scene(ds, ("index", "r"), no_ghost=True) -sg.camera.focus = [0.0, 0.0, 0.0] -rc.run() - -# Cartesian Test (to line 25) -# ds = yt.load_sample("IsolatedGalaxy") -# rc = yt_idv.render_context(height=800, width=800, gui=True) -# sg = rc.add_scene(ds, "density", no_ghost=True) -# rc.run() diff --git a/yt_idv/coordinate_utilities.pyx b/yt_idv/coordinate_utilities.pyx index dc6dd61..fe2cc6a 100644 --- a/yt_idv/coordinate_utilities.pyx +++ b/yt_idv/coordinate_utilities.pyx @@ -301,42 +301,3 @@ def cartesian_bboxes(MixedCoordBBox bbox_handler, dx[i] = dxyz_i[0] dy[i] = dxyz_i[1] dz[i] = dxyz_i[2] - - -@cython.cdivision(True) -@cython.boundscheck(False) -@cython.wraparound(False) -def one_cartesian_bbox(MixedCoordBBox bbox_handler, - np.float64_t pos0, - np.float64_t pos1, - np.float64_t pos2, - np.float64_t dpos0, - np.float64_t dpos1, - np.float64_t dpos2, - ): - # calculates the cartesian bounding boxes around non-cartesian - # volume elements - # - # bbox_handler : a MixedCoordBBox child instance - # pos0, pos1, pos2: native coordinates of element centers - # dpos0, dpos1, dpos2: element widths in native coordinates - # x, y, z: cartesian centers of bounding boxes, modified in place - # dx, dy, dz : full-widths of the cartesian bounding boxes, modified in place - - cdef int i - cdef np.float64_t xyz_i[3] - cdef np.float64_t dxyz_i[3] - - with nogil: - - bbox_handler.get_cartesian_bbox(pos0, - pos1, - pos2, - dpos0, - dpos1, - dpos2, - xyz_i, - dxyz_i) - - - return xyz_i, dxyz_i diff --git a/yt_idv/scene_components/blocks.py b/yt_idv/scene_components/blocks.py index 9ee0fd6..84b1cdb 100644 --- a/yt_idv/scene_components/blocks.py +++ b/yt_idv/scene_components/blocks.py @@ -140,9 +140,9 @@ def draw(self, scene, program): def _set_uniforms(self, scene, shader_program): shader_program._set_uniform( - "is_spherical", self.data.data_source.ds.geometry == "spherical" + "is_spherical", self.data._yt_geom_str == "spherical" ) - if self.data.data_source.ds.geometry == "spherical": + if self.data._yt_geom_str == "spherical": axis_id = self.data.data_source.ds.coordinates.axis_id shader_program._set_uniform("id_theta", axis_id["theta"]) shader_program._set_uniform("id_r", axis_id["r"]) diff --git a/yt_idv/scene_data/block_collection.py b/yt_idv/scene_data/block_collection.py index 26b9b42..1e175c9 100644 --- a/yt_idv/scene_data/block_collection.py +++ b/yt_idv/scene_data/block_collection.py @@ -76,21 +76,21 @@ def add_data(self, field, no_ghost=False): if hasattr(self.max_val, "in_units"): self.max_val = self.max_val.d - LE = np.array([b.LeftEdge for i, b in self.blocks.values()]).min(axis=0) - RE = np.array([b.RightEdge for i, b in self.blocks.values()]).max(axis=0) - self.diagonal = np.sqrt(((RE - LE) ** 2).sum()) - # Now we set up our buffer vert = np.array(vert, dtype="f4") dx = np.array(dx, dtype="f4") - le = np.array(le, dtype="f4") - re = np.array(re, dtype="f4") + le = np.array(le) + re = np.array(re) if self._yt_geom_str == "cartesian": units = self.data_source.ds.units ratio = (units.code_length / units.unitary).base_value dx = dx * ratio le = le * ratio re = re * ratio + LE = np.array([b.LeftEdge for i, b in self.blocks.values()]).min(axis=0) + RE = np.array([b.RightEdge for i, b in self.blocks.values()]).max(axis=0) + self.diagonal = np.sqrt(((RE - LE) ** 2).sum()) + self._set_geometry_attributes(le, re) self.vertex_array.attributes.append( VertexAttribute(name="model_vertex", data=vert) @@ -133,8 +133,8 @@ def _set_geometry_attributes(self, le, re): self.vertex_array.attributes.append( VertexAttribute(name="phi_plane_re", data=phi_plane_re) ) - # cartesian bbox: very ugly, just testing... - print("calculating cartesian bounding boxes.") + # cartesian bbox calcualtions + # TODO: clean this up by rewriting the cython a bit... widths = re - le centers = (le + re) / 2.0 bbox_handler = SphericalMixedCoordBBox() @@ -156,7 +156,7 @@ def _set_geometry_attributes(self, le, re): le_cart = np.column_stack([x - dx / 2.0, y - dy / 2.0, z - dz / 2.0]) re_cart = np.column_stack([x + dx / 2.0, y + dy / 2.0, z + dz / 2.0]) - # normalize to viewport in (0, 1), preserving ratio of the bounding box + # cartesian le, re, width of whole domain domain_le = [] domain_re = [] domain_wid = [] @@ -165,6 +165,7 @@ def _set_geometry_attributes(self, le, re): domain_re.append(re_cart[:, idim].max()) domain_wid.append(domain_re[idim] - domain_le[idim]) + # normalize to viewport in (0, 1), preserving ratio of the bounding box max_wid = np.max(domain_wid) for idim in range(3): le_cart[:, idim] = (le_cart[:, idim] - domain_le[idim]) / max_wid @@ -172,6 +173,10 @@ def _set_geometry_attributes(self, le, re): le_cart = np.asarray(le_cart) re_cart = np.asarray(re_cart) + + # these will get passed down as uniforms to go from screen coords of + # 0,1 to cartesian coords of domain_le to domain_re from which full + # spherical coords can be calculated. self.cart_bbox_max_width = max_wid self.cart_bbox_le = np.array(domain_le).astype("f4") @@ -182,6 +187,9 @@ def _set_geometry_attributes(self, le, re): VertexAttribute(name="re_cart", data=re_cart.astype("f4")) ) + # does not seem that diagonal is used anywhere, but recalculating to + # be safe... + self.diagonal = np.sqrt(((re_cart - le_cart) ** 2).sum()) else: raise NotImplementedError( f"{self.name} does not implement {self._yt_geom_str} geometries." diff --git a/yt_idv/scene_graph.py b/yt_idv/scene_graph.py index a78d7dc..c7b1f18 100644 --- a/yt_idv/scene_graph.py +++ b/yt_idv/scene_graph.py @@ -260,13 +260,7 @@ def from_ds(ds, field, no_ghost=True): else: ds, data_source = ds.ds, ds - if str(ds.geometry) == "cartesian": - center = ds.domain_center - pos = center + 1.5 * ds.domain_width.in_units("unitary") - near_plane = 3.0 * ds.index.get_smallest_dx().min().in_units("unitary").d - near_plane = max(near_plane, 1e-5) - else: - center, pos, near_plane = _get_camera_for_geometry(data_source, ds) + center, pos, near_plane = _get_camera_for_geometry(data_source, ds) c = TrackballCamera(position=pos, focus=center, near_plane=near_plane) c.update_orientation(0, 0, 0, 0) @@ -285,14 +279,17 @@ def _get_camera_for_geometry(data_source, ds): # spherical coordinates center = np.array([0.5, 0.5, 0.5]) wid = np.array([1.0, 1.0, 1.0]) - pos = center + 1.5 * wid - dx_aprox = wid[0] / np.max(ds.domain_dimensions) near_plane = 3.0 * dx_aprox near_plane = max(near_plane, 1e-5) - return center, pos, near_plane + elif str(ds.geometry) == "cartesian": + center = ds.domain_center + pos = center + 1.5 * ds.domain_width.in_units("unitary") + near_plane = 3.0 * ds.index.get_smallest_dx().min().in_units("unitary").d + near_plane = max(near_plane, 1e-5) else: raise NotImplementedError( "Only cartesian and spherical geometries are supported at present." ) + return center, pos, near_plane diff --git a/yt_idv/shaders/grid_expand.geom.glsl b/yt_idv/shaders/grid_expand.geom.glsl index 02aee55..4d09ea8 100644 --- a/yt_idv/shaders/grid_expand.geom.glsl +++ b/yt_idv/shaders/grid_expand.geom.glsl @@ -1,8 +1,6 @@ layout ( points ) in; layout ( triangle_strip, max_vertices = 14 ) out; -// note: all in/out variables below are always in native coordinates (e.g., -// spherical or cartesian) except when noted. flat in vec3 vdx[]; flat in vec3 vleft_edge[]; flat in vec3 vright_edge[]; @@ -16,14 +14,14 @@ flat out vec3 left_edge; flat out vec3 right_edge; flat out vec3 left_edge_cart; flat out vec3 right_edge_cart; -flat out mat4 inverse_proj; // always cartesian -flat out mat4 inverse_mvm; // always cartesian -flat out mat4 inverse_pmvm; // always cartesian +flat out mat4 inverse_proj; +flat out mat4 inverse_mvm; +flat out mat4 inverse_pmvm; out vec4 v_model; -flat in mat4 vinverse_proj[]; // always cartesian -flat in mat4 vinverse_mvm[]; // always cartesian -flat in mat4 vinverse_pmvm[]; // always cartesian +flat in mat4 vinverse_proj[]; +flat in mat4 vinverse_mvm[]; +flat in mat4 vinverse_pmvm[]; flat in vec4 vv_model[]; flat out ivec3 texture_offset; @@ -50,10 +48,10 @@ uniform int aindex[14] = int[](6, 7, 4, 5, 1, 7, 3, 6, 2, 4, 0, 1, 2, 3); void main() { - vec4 center = gl_in[0].gl_Position; // always cartesian + vec4 center = gl_in[0].gl_Position; + vec3 width, le; + vec4 newPos; - vec3 width; - vec3 le; if (is_spherical){ width = vright_edge_cart[0] - vleft_edge_cart[0]; le = vleft_edge_cart[0]; @@ -62,18 +60,13 @@ void main() { le = vleft_edge[0]; } - vec4 newPos; - vec3 current_pos; - for (int i = 0; i < 14; i++) { // walks through each vertex of the triangle strip, emit it. need to - // emit gl_Position in cartesian, but pass native coords out in v_model + // emit gl_Position in cartesian, pass along other attributes in native + // coordinates - // hm, this seems wrong. maybe should use the cartesian bounding box - // nodes for building the triangle strip primitive? - current_pos = vec3(le + width * arrangement[aindex[i]]); - newPos = vec4(current_pos, 1.0); // cartesian - gl_Position = projection * modelview * newPos; // cartesian + newPos = vec4(le + width * arrangement[aindex[i]], 1.0); + gl_Position = projection * modelview * newPos; left_edge = vleft_edge[0]; right_edge = vright_edge[0]; inverse_pmvm = vinverse_pmvm[0]; @@ -84,10 +77,9 @@ void main() { left_edge_cart = vleft_edge_cart[0]; right_edge_cart = vright_edge_cart[0]; dx = vdx[0]; - v_model = vec4(current_pos, 1.0); + v_model = newPos; texture_offset = ivec3(0); - EmitVertgex(); + EmitVertex(); } - // why no endprimitive? } diff --git a/yt_idv/shaders/grid_position.vert.glsl b/yt_idv/shaders/grid_position.vert.glsl index 9e30d34..1b0f2a5 100644 --- a/yt_idv/shaders/grid_position.vert.glsl +++ b/yt_idv/shaders/grid_position.vert.glsl @@ -14,9 +14,9 @@ in vec3 le_cart; in vec3 re_cart; flat out vec4 vv_model; -flat out mat4 vinverse_proj; // always cartesian -flat out mat4 vinverse_mvm; // always cartesian -flat out mat4 vinverse_pmvm; // always cartesian +flat out mat4 vinverse_proj; +flat out mat4 vinverse_mvm; +flat out mat4 vinverse_pmvm; flat out vec3 vdx; flat out vec3 vleft_edge; flat out vec3 vright_edge; @@ -29,15 +29,14 @@ flat out vec3 vright_edge_cart; void main() { - // camera uniforms: - // projection, modelview + // camera uniforms: projection, modelview vv_model = model_vertex; vinverse_proj = inverse(projection); // inverse model-view-matrix vinverse_mvm = inverse(modelview); vinverse_pmvm = inverse(projection * modelview); - gl_Position = projection * modelview * vv_model; //transform_vec4(model_vertex); + gl_Position = projection * modelview * model_vertex; // native coordinates vdx = vec3(in_dx); diff --git a/yt_idv/shaders/known_uniforms.inc.glsl b/yt_idv/shaders/known_uniforms.inc.glsl index 96c0219..a5085b6 100644 --- a/yt_idv/shaders/known_uniforms.inc.glsl +++ b/yt_idv/shaders/known_uniforms.inc.glsl @@ -71,8 +71,5 @@ uniform bool is_spherical; uniform int id_theta; // azimuthal angle (0 to pi) index in the yt dataset uniform int id_r; // radial index in the yt dataset uniform int id_phi; // polar angle (0 to 2pi) indexi n the yt dataset -//uniform float x0; -//uniform float y0; -//uniform float z0; uniform vec3 cart_bbox_le; uniform float cart_bbox_max_width; diff --git a/yt_idv/shaders/ray_tracing.frag.glsl b/yt_idv/shaders/ray_tracing.frag.glsl index 0b6cf99..77aeb07 100644 --- a/yt_idv/shaders/ray_tracing.frag.glsl +++ b/yt_idv/shaders/ray_tracing.frag.glsl @@ -2,25 +2,17 @@ in vec4 v_model; flat in vec3 dx; flat in vec3 left_edge; flat in vec3 right_edge; +flat in mat4 inverse_proj; +flat in mat4 inverse_mvm; +flat in mat4 inverse_pmvm; flat in vec3 left_edge_cart; flat in vec3 right_edge_cart; -flat in mat4 inverse_proj; // always cartesian -flat in mat4 inverse_mvm; // always cartesian -flat in mat4 inverse_pmvm; // always cartesian -flat in ivec3 texture_offset; -out vec4 output_color; - flat in vec4 phi_plane_le; flat in vec4 phi_plane_re; +flat in ivec3 texture_offset; +out vec4 output_color; bool within_bb(vec3 pos) -{ - bvec3 left = greaterThanEqual(pos, left_edge_cart); - bvec3 right = lessThanEqual(pos, right_edge_cart); - return all(left) && all(right); -} - -bool within_bb_sp(vec3 pos) { bvec3 left = greaterThanEqual(pos, left_edge); bvec3 right = lessThanEqual(pos, right_edge); @@ -61,17 +53,17 @@ bool sample_texture(vec3 tex_curr_pos, inout vec4 curr_color, float tdelta, float t, vec3 dir); vec4 cleanup_phase(in vec4 curr_color, in vec3 dir, in float t0, in float t1); +// This main() function will call a function called sample_texture at every +// step along the ray. sample_texture must be of the form +// void (vec3 tex_curr_pos, inout vec4 curr_color, float tdelta, float t, +// vec3 direction); void main() { - // Draws the block outline - // output_color = vec4(1.0); - // return; // Obtain screen coordinates // https://www.opengl.org/wiki/Compute_eye_space_from_window_space#From_gl_FragCoord - vec3 ray_position = v_model.xyz; - vec3 ray_position_sp = cart_to_sphere_vec3(ray_position); + vec3 ray_position_native; output_color = vec4(0.); @@ -92,7 +84,7 @@ void main() } else { tl = (left_edge - camera_pos)*idir; tr = (right_edge - camera_pos)*idir; - dx_cart = right_edge - left_edge; + dx_cart = dx; } vec3 step_size = dx_cart/ sample_factor; @@ -109,7 +101,7 @@ void main() temp_t = min(tmax.xx, tmax.yz); float t1 = min(temp_t.x, temp_t.y); t0 = max(t0, 0.0); - // if (t1 <= t0) discard; + if (t1 <= t0) discard; // Some more discussion of this here: // http://prideout.net/blog/?p=64 @@ -131,10 +123,10 @@ void main() vec3 tex_curr_pos = vec3(0.0); vec3 tex_min = vec3(0.0 + 1. * dx/2.0); vec3 tex_max = vec3(1.0 - 1. * dx/2.0); - bool within_el = true; bool sampled; bool ever_sampled = false; + bool within_el = true; vec4 v_clip_coord; float f_ndc_depth; @@ -146,20 +138,17 @@ void main() // texture position if (is_spherical) { - ray_position_sp = cart_to_sphere_vec3(ray_position); - within_el = within_bb_sp(ray_position_sp); + ray_position_native = cart_to_sphere_vec3(ray_position); + within_el = within_bb(ray_position_native); } else { - ray_position_sp = ray_position; - within_el = true; + ray_position_native = ray_position; } if (within_el) { - tex_curr_pos = (ray_position_sp - left_edge) / range; // Scale from 0 .. 1 + tex_curr_pos = (ray_position_native - left_edge) / range; // Scale from 0 .. 1 // But, we actually need it to be 0 + normalized dx/2 to 1 - normalized dx/2 tex_curr_pos = (tex_curr_pos * (1.0 - ndx)) + ndx/2.0; sampled = sample_texture(tex_curr_pos, curr_color, tdelta, t, dir); - // sampled = true; - // curr_color = vec4(1., 0., 0., 1.); } if (sampled) { diff --git a/yt_idv/shaders/spherical_grid_position.vert.glsl b/yt_idv/shaders/spherical_grid_position.vert.glsl deleted file mode 100644 index b297dfc..0000000 --- a/yt_idv/shaders/spherical_grid_position.vert.glsl +++ /dev/null @@ -1,45 +0,0 @@ -in vec4 model_vertex; // The location of the vertex in model space -in vec3 in_dx; -in vec3 in_left_edge; -in vec3 in_right_edge; -flat out vec4 vv_model; -flat out mat4 vinverse_proj; -flat out mat4 vinverse_mvm; -flat out mat4 vinverse_pmvm; -flat out vec3 vdx; -flat out vec3 vleft_edge; -flat out vec3 vright_edge; - -vec4 spherical_to_cartesian4(vec4 v) { - int theta = 2; - int phi = 1; - return vec4( - v[0] * sin(v[phi]) * cos(v[theta]), - v[0] * sin(v[phi]) * sin(v[theta]), - v[0] * cos(v[phi]), - v[3] - ); -} - -vec3 spherical_to_cartesian3(vec3 v) { - int theta = 2; - int phi = 1; - return vec3( - v[0] * sin(v[phi]) * cos(v[theta]), - v[0] * sin(v[phi]) * sin(v[theta]), - v[0] * cos(v[phi]) - ); -} - -void main() -{ - vv_model = spherical_to_cartesian4(model_vertex); - vinverse_proj = inverse(projection); - // inverse model-view-matrix - vinverse_mvm = inverse(modelview); - vinverse_pmvm = inverse(projection * modelview); - gl_Position = projection * modelview * vv_model; - vdx = in_dx; - vleft_edge = spherical_to_cartesian3(in_left_edge); - vright_edge = spherical_to_cartesian3(in_right_edge); -}