public void Setup(int cx, int cy) { this._cx = cx; this._cy = cy; // Version strings _version.Retrieve(); // Get OpenGL extensions _extensions.Retrieve(); // Debug callback _debug_callback.Init(); // to do mesh buffer creator form multi indices mesh // use in-source wave font file? float[] attributes = { // left -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // right 1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 2.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 2.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2.0f, 0.0f, 1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 2.0f, 0.0f, // front -1.0f, -1.0f, -1.0f, 0.0f, 0.0f, 3.0f, 0.0f, 1.0f, -1.0f, -1.0f, 0.0f, 1.0f, 3.0f, 0.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f, -1.0f, -1.0f, 1.0f, 1.0f, 0.0f, 3.0f, 0.0f, // back 1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 4.0f, 0.0f, -1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 4.0f, 0.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 4.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 4.0f, 0.0f, // bottom -1.0f, 1.0f, -1.0f, 0.0f, 0.0f, 5.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 5.0f, 0.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 5.0f, 0.0f, -1.0f, -1.0f, -1.0f, 1.0f, 0.0f, 5.0f, 0.0f, // top -1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 6.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 1.0f, 6.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 6.0f, 0.0f, -1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 6.0f, 0.0f }; uint[] indices = { 0, 1, 2, 0, 2, 3, // front 4, 5, 6, 4, 6, 7, // back 8, 9, 10, 8, 10, 11, // left 12, 13, 14, 12, 14, 15, // right 16, 17, 18, 16, 18, 19, // bottom 20, 21, 22, 20, 22, 23 // top }; // create Vertex Array Object, Array Buffer Object and Element Array Buffer Object TVertexFormat[] format = { new TVertexFormat(0, 0, 3, 0, false), new TVertexFormat(0, 1, 4, 3, false), }; _vao = openGLFactory.NewVertexArrayObject(); _vao.AppendVertexBuffer(0, 7, attributes); _vao.Create(format, indices); _vao.Bind(); // Create shader program string vert_shader = @" #version 460 core layout (location = 0) in vec3 inPos; layout (location = 1) in vec4 inAttr; out vec3 vertPos; out vec4 vertTex; out float highlight; layout (std430, binding = 1) buffer UB_MVP { mat4 u_projection; mat4 u_view; mat4 u_model; }; layout (std430, binding = 2) buffer UB_RUBIKS { mat4 u_rubiks_model[27]; int u_cube_hit; int u_side_hit; }; void main() { vec4 tex = inAttr; int cube_i = gl_InstanceID; int color_i = int(tex.z + 0.5); int x_i = cube_i % 3; int y_i = (cube_i % 9) / 3; int z_i = cube_i / 9; if ( color_i == 1 ) tex.z = x_i == 0 ? tex.z : 0.0; else if ( color_i == 2 ) tex.z = x_i == 2 ? tex.z : 0.0; else if ( color_i == 3 ) tex.z = y_i == 0 ? tex.z : 0.0; else if ( color_i == 4 ) tex.z = y_i == 2 ? tex.z : 0.0; else if ( color_i == 5 ) tex.z = z_i == 0 ? tex.z : 0.0; else if ( color_i == 6 ) tex.z = z_i == 2 ? tex.z : 0.0; mat4 model_view = u_view * u_model * u_rubiks_model[cube_i]; vec4 vertex_pos = model_view * vec4(inPos, 1.0); vertPos = vertex_pos.xyz; vertTex = tex; //highlight = tex.z > 0.5 && cube_i == u_cube_hit ? 1.0 : 0.0; //highlight = tex.z > 0.5 && color_i == u_side_hit ? 1.0 : 0.0; highlight = tex.z > 0.5 && cube_i == u_cube_hit && color_i == u_side_hit ? 1.0 : 0.0; gl_Position = u_projection * vertex_pos; }"; string frag_shader = @" #version 460 core in vec3 vertPos; in vec4 vertTex; in float highlight; out vec4 fragColor; vec4 color_table[7] = vec4[7]( vec4(0.5, 0.5, 0.5, 1.0), vec4(1.0, 0.0, 0.0, 1.0), vec4(0.0, 1.0, 0.0, 1.0), vec4(0.0, 0.0, 1.0, 1.0), vec4(1.0, 0.5, 0.0, 1.0), vec4(1.0, 1.0, 0.0, 1.0), vec4(1.0, 0.0, 1.0, 1.0) ); void main() { int color_i = int(vertTex.z + 0.5); vec4 color = color_table[color_i]; color.rgb *= max(0.5, highlight); fragColor = color; }"; this._prog = openGLFactory.VertexAndFragmentShaderProgram(vert_shader, frag_shader); this._prog.Generate(); // matrices this._view = Matrix4.LookAt(0.0f, -4.0f, 0.0f, 0, 0, 0, 0, 0, 1); float angle = 70.0f * (float)Math.PI / 180.0f; float aspect = (float)this._cx / (float)this._cy; this._projection = Matrix4.CreatePerspectiveFieldOfView(angle, aspect, 0.1f, 100.0f); // Model view projection shader storage block objects and buffers this._mvp_data = new TMVP(Matrix4.Identity, this._view, this._projection); this._mvp_ssbo = openGLFactory.NewStorageBuffer(); this._mvp_ssbo.Create(ref this._mvp_data); this._mvp_ssbo.Bind(1); T_RUBIKS_DATA rubiks_data = rubiks_data = new T_RUBIKS_DATA(); this._rubiks_ssbo = openGLFactory.NewStorageBuffer(); this._rubiks_ssbo.Create(ref rubiks_data); this._rubiks_ssbo.Bind(2); TLightSource light_source = new TLightSource(new Vector4(-1.0f, -0.5f, -2.0f, 0.0f), 0.2f, 0.8f, 0.8f, 10.0f); this._light_ssbo = openGLFactory.NewStorageBuffer(); this._light_ssbo.Create(ref light_source); this._light_ssbo.Bind(3); this._depth_pack_buffer = openGLFactory.NewPixelPackBuffer(); this._depth_pack_buffer.Create <float>(); // states GL.Viewport(0, 0, this._cx, this._cy); //GL.ClearColor(System.Drawing.Color.Beige); GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.CullFace); GL.FrontFace(FrontFaceDirection.Ccw); GL.CullFace(CullFaceMode.Back); // controller var spin = new ModelSpinningControls( () => { return(this._period); }, () => { return(new float[] { 0, 0, (float)this._cx, (float)this._cy }); }, () => { return(this._view); } ); spin.SetAttenuation(1.0f, 0.05f, 0.0f); _controls = new RubiksMouseControlsProxy(spin); float offset = 2.0f * 1.1f; float scale = 1.0f / 3.0f; this._rubiks_cube = new RubiksControls( () => { return(this._period); }, offset, scale ); int shuffles = 11; this._rubiks_cube.Shuffle(shuffles); double time_s = 1.0; _rubiks_cube.AnimationTime = time_s; }
public void Setup(int cx, int cy) { this._cx = cx; this._cy = cy; // Version strings _version.Retrieve(); // Get OpenGL extensions _extensions.Retrieve(); // Debug callback _debug_callback.Init(); // create Vertex Array Object, Array Buffer Object and Element Array Buffer Object (float[] attributes, uint[] indices) = new Cube().Create(); TVertexFormat[] format = { new TVertexFormat(0, 0, 3, 0, false), new TVertexFormat(0, 1, 3, 3, false), new TVertexFormat(0, 2, 2, 6, false), //new TVertexFormat(0, 2, 4, 8, false), }; _cube_vao = openGLFactory.NewVertexArrayObject(); _cube_vao.AppendVertexBuffer(0, 12, attributes); _cube_vao.Create(format, indices); _cube_vao.Bind(); // Create textures objects _tbos = new List <ITexture>(); _tbos.Add(openGLFactory.NewTexture()); _tbos[0].Create2D(_image_cx, _image_cy, ITexture.Format.RGBA_8); _tbos.Add(openGLFactory.NewTexture()); _tbos[1].Create2D(_image_cx, _image_cy, ITexture.Format.RGBA_F32); _tbos.Add(openGLFactory.NewTexture()); _tbos[2].Create2D(_image_cx, _image_cy, ITexture.Format.RGBA_F32); GL.TextureParameter(_tbos[2].Object, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TextureParameter(_tbos[2].Object, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); // Create generators this._generators = new List <TextureGenerator>(); this._generators.Add(new TextureGenerator(openGLFactory, TextureGenerator.TType.texture_test1, new ITexture[] { _tbos[0] })); this._generators.Add(new TextureGenerator(openGLFactory, TextureGenerator.TType.heightmap_test1, new ITexture[] { _tbos[1] })); this._generators.Add(new TextureGenerator(openGLFactory, TextureGenerator.TType.cone_step_map, new ITexture[] { _tbos[2] }, new ITexture[] { _tbos[1] })); // Create textures foreach (var generator in this._generators) { generator.Generate(); } // Create shader program string vert_shader = @"#version 460 core layout (location = 0) in vec3 inPos; layout (location = 1) in vec3 inNV; layout (location = 2) in vec2 inUV; out TVertexData { vec3 pos; vec3 nv; vec2 uv; float clip; } out_data; layout(std430, binding = 1) buffer MVP { mat4 proj; mat4 view; mat4 model; } mvp; layout(location=1) uniform vec4 u_clipPlane; void main() { vec3 modelNV = mat3( mvp.model ) * normalize( inNV ); out_data.nv = mat3( mvp.view ) * modelNV; out_data.uv = inUV; vec4 worldPos = mvp.model * vec4( inPos, 1.0 ); vec4 viewPos = mvp.view * worldPos; out_data.pos = viewPos.xyz / viewPos.w; gl_Position = mvp.proj * viewPos; vec4 clipPlane = vec4(normalize(u_clipPlane.xyz), u_clipPlane.w); out_data.clip = dot(worldPos, clipPlane); }"; string frag_shader = @"#version 460 core //#define NORMAL_MAP_TEXTURE #define NORMAL_MAP_QUALITY 1 in TVertexData { vec3 pos; vec3 nv; vec2 uv; float clip; } in_data; out vec4 fragColor; layout(std430, binding = 1) buffer MVP { mat4 proj; mat4 view; mat4 model; } mvp; layout(location=1) uniform vec4 u_clipPlane; layout(std430, binding = 2) buffer TLight { vec4 u_lightDir; float u_ambient; float u_diffuse; float u_specular; float u_shininess; } light_data; layout(binding=1) uniform sampler2D u_texture; layout(binding=2) uniform sampler2D u_displacement_map; layout(location=2) uniform float u_displacement_scale; layout(location=3) uniform vec2 u_parallax_quality; #if defined(NORMAL_MAP_TEXTURE) uniform sampler2D u_normal_map; #endif vec2 GetHeightAndCone( in vec2 texCoords ) { vec2 h_and_c = texture( u_displacement_map, texCoords ).rg; return clamp( h_and_c, 0.0, 1.0 ); } vec4 CalculateNormal( in vec2 texCoords ) { #if defined(NORMAL_MAP_TEXTURE) float height = GetHeight( texCoords ); vec3 tempNV = texture( u_normal_map, texCoords ).xyz * 2.0 / 1.0; return vec4( normalize( tempNV ), height ); #else vec2 texOffs = 1.0 / textureSize( u_displacement_map, 0 ).xy; vec2 scale = 1.0 / texOffs; #if NORMAL_MAP_QUALITY > 1 float hx[9]; hx[0] = texture( u_displacement_map, texCoords.st + texOffs * vec2(-1.0, -1.0) ).r; hx[1] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 0.0, -1.0) ).r; hx[2] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 1.0, -1.0) ).r; hx[3] = texture( u_displacement_map, texCoords.st + texOffs * vec2(-1.0, 0.0) ).r; hx[4] = texture( u_displacement_map, texCoords.st ).r; hx[5] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 1.0, 0.0) ).r; hx[6] = texture( u_displacement_map, texCoords.st + texOffs * vec2(-1.0, 1.0) ).r; hx[7] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 0.0, 1.0) ).r; hx[8] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 1.0, 1.0) ).r; vec2 deltaH = vec2(hx[0]-hx[2] + 2.0*(hx[3]-hx[5]) + hx[6]-hx[8], hx[0]-hx[6] + 2.0*(hx[1]-hx[7]) + hx[2]-hx[8]); float h_mid = hx[4]; #elif NORMAL_MAP_QUALITY > 0 float h_mid = texture( u_displacement_map, texCoords.st ).r; float h_xa = texture( u_displacement_map, texCoords.st + texOffs * vec2(-1.0, 0.0) ).r; float h_xb = texture( u_displacement_map, texCoords.st + texOffs * vec2( 1.0, 0.0) ).r; float h_ya = texture( u_displacement_map, texCoords.st + texOffs * vec2( 0.0, -1.0) ).r; float h_yb = texture( u_displacement_map, texCoords.st + texOffs * vec2( 0.0, 1.0) ).r; vec2 deltaH = vec2(h_xa-h_xb, h_ya-h_yb); #else vec4 heights = textureGather( u_displacement_map, texCoords, 0 ); vec2 deltaH = vec2(dot(heights, vec4(1.0, -1.0, -1.0, 1.0)), dot(heights, vec4(-1.0, -1.0, 1.0, 1.0))); float h_mid = heights.w; #endif return vec4( normalize( vec3( deltaH * scale, 1.0 ) ), h_mid ); #endif } // the super fast version // (change number of iterations at run time) float intersect_cone_fixed(in vec2 dp, in vec3 ds) { // the 'not Z' component of the direction vector // (requires that the vector ds was normalized!) float iz = sqrt(1.0 - ds.z * ds.z); // my starting location (is at z=1, // and moving down so I don't have // to invert height maps) // texture lookup (and initialized to starting location) vec4 t; // scaling distance along vector ds float sc; // the ds.z component is positive! // (headed the wrong way, since // I'm using heightmaps) // find the initial location and height t = texture(u_displacement_map, dp); // right, I need to take one step. // I use the current height above the texture, // and the information about the cone-ratio // to size a single step. So it is fast and // precise! (like a coneified version of // 'space leaping', but adapted from voxels) sc = (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); // and repeat a few (4x) times t = texture(u_displacement_map, dp + ds.xy * sc); sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); t = texture(u_displacement_map, dp + ds.xy * sc); sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); t = texture(u_displacement_map, dp + ds.xy * sc); sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); t = texture(u_displacement_map, dp + ds.xy * sc); sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); // and another five! t = texture(u_displacement_map, dp + ds.xy * sc); sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); t = texture(u_displacement_map, dp + ds.xy * sc); sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); t = texture(u_displacement_map, dp + ds.xy * sc); sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); t = texture(u_displacement_map, dp + ds.xy * sc); sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); t = texture(u_displacement_map, dp + ds.xy * sc); sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); // return the vector length needed to hit the height-map return (sc); } // (and you can do LOD by changing 'conesteps' based on size/distance, etc.) float intersect_cone_loop(in vec2 dp, in vec3 ds) { float maxBumpHeight = u_displacement_scale; const int conesteps = 10; // ??? // the 'not Z' component of the direction vector // (requires that the vector ds was normalized!) float iz = sqrt(1.0 - ds.z * ds.z); // my starting location (is at z=1, // and moving down so I don't have // to invert height maps) // texture lookup (and initialized to starting location) vec4 t; // scaling distance along vector ds float sc = 0.0; //t=texture2D(stepmap,dp); //return (max(0.0,-(t.b-0.5)*ds.x-(t.a-0.5)*ds.y)); // the ds.z component is positive! // (headed the wrong way, since // I'm using heightmaps) // adaptive (same speed as it averages the same # steps) //for (int i = int(float(conesteps)*(0.5+iz)); i > 0; --i) // fixed for (int i = conesteps; i > 0; --i) { // find the new location and height t = texture(u_displacement_map, dp + ds.xy * sc); t.r = t.r * maxBumpHeight; t.g = t.g / maxBumpHeight; // right, I need to take one step. // I use the current height above the texture, // and the information about the cone-ratio // to size a single step. So it is fast and // precise! (like a coneified version of // 'space leaping', but adapted from voxels) sc += (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); } // return the vector length needed to hit the height-map return (sc); } // slowest, but best quality float intersect_cone_exact(in vec2 dp, in vec3 ds) { vec2 texsize = textureSize(u_displacement_map, 0); // minimum feature size parameter float w = 1.0 / max(texsize.x, texsize.y); // the 'not Z' component of the direction vector // (requires that the vector ds was normalized!) float iz = sqrt(1.0 - ds.z * ds.z); // my starting location (is at z=1, // and moving down so I don't have // to invert height maps) // texture lookup vec4 t; // scaling distance along vector ds float sc = 0.0; // the ds.z component is positive! // (headed the wrong way, since // I'm using heightmaps) // find the starting location and height t = texture(u_displacement_map, dp); while (1.0 - ds.z * sc > t.r) { // right, I need to take one step. // I use the current height above the texture, // and the information about the cone-ratio // to size a single step. So it is fast and // precise! (like a coneified version of // 'space leaping', but adapted from voxels) sc += w + (1.0 - ds.z * sc - t.r) / (ds.z + iz / (t.g * t.g)); // find the new location and height t = texture(u_displacement_map, dp + ds.xy * sc); } // back off one step sc -= w; // return the vector length needed to hit the height-map return (sc); } // Parallax Occlusion Mapping in GLSL [http://sunandblackcat.com/tipFullView.php?topicid=28] vec3 ConeStep(in float frontFace, in vec3 texDir3D, in vec2 texCoord) { float maxBumpHeight = 1.0; vec2 quality_range = u_parallax_quality; // [Determinante](https://de.wikipedia.org/wiki/Determinante) // A x B = A.x * B.y - A.y * B.x = dot(A, vec2(B.y,-B.x)) = det(mat2(A,B)) // [How do you detect where two line segments intersect?](https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect) vec2 R = normalize(vec2(length(texDir3D.xy), texDir3D.z)); vec2 P = R * maxBumpHeight / texDir3D.z; vec2 tex_size = textureSize(u_displacement_map, 0).xy; vec2 min_tex_step = normalize(texDir3D.xy) / tex_size; float min_step = length(min_tex_step) * 1.0 / R.x; float t = 0.0; const int max_no_of_steps = int(5.0 + quality_range * 45.0); for (int i = 0; i < max_no_of_steps; ++i) { vec3 sample_pt = vec3(texCoord.xy, maxBumpHeight) + texDir3D * t; vec2 h_and_c = GetHeightAndCone(sample_pt.xy); float h = h_and_c.x * maxBumpHeight; float c = h_and_c.y * h_and_c.y / maxBumpHeight; vec2 C = P + R * t; if (C.y <= h) break; vec2 Q = vec2(C.x, h); vec2 S = normalize(vec2(c, 1.0)); float new_t = dot(Q - P, vec2(S.y, -S.x)) / dot(R, vec2(S.y, -S.x)); t = max(t + min_step, new_t); } vec2 texC = texCoord.xy + texDir3D.xy * t; float mapHeight = GetHeightAndCone(texC.xy).x - step(frontFace, 0.0); return vec3(texC.xy, mapHeight); } void main() { vec3 objPosEs = in_data.pos; vec3 objNormalEs = in_data.nv; vec2 texCoords = in_data.uv.st; float frontFace = gl_FrontFacing ? 1.0 : -1.0; // TODO $$$ sign(dot(N,objPosEs)); //vec3 normalEs = frontFace * normalize( objNormalEs ); // orthonormal tangent space matrix //vec3 p_dx = dFdx( objPosEs ); //vec3 p_dy = dFdy( objPosEs ); //vec2 tc_dx = dFdx( texCoords ); //vec2 tc_dy = dFdy( texCoords ); //float texDet = determinant( mat2( tc_dx, tc_dy ) ); //vec3 tangentVec = ( tc_dy.y * p_dx - tc_dx.y * p_dy ) / abs( texDet ); //vec3 tangentEs = normalize( tangentVec - normalEs * dot(tangentVec, normalEs ) ); //mat3 tbnMat = mat3( sign( texDet ) * tangentEs, cross( normalEs, tangentEs ), normalEs ); // Followup: Normal Mapping Without Precomputed Tangents [http://www.thetenthplanet.de/archives/1180] vec3 N = frontFace * normalize(objNormalEs); vec3 dp1 = dFdx(objPosEs); vec3 dp2 = dFdy(objPosEs); vec2 duv1 = dFdx(texCoords); vec2 duv2 = dFdy(texCoords); vec3 dp2perp = cross(dp2, N); vec3 dp1perp = cross(N, dp1); vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; float invmax = inversesqrt(max(dot(T, T), dot(B, B))); mat3 tbnMat = mat3(T * invmax, B * invmax, N * u_displacement_scale); mat3 inv_tbnMat = inverse(tbnMat); vec3 texDir3D = normalize(inv_tbnMat * objPosEs); vec3 newTexCoords = abs(u_displacement_scale) < 0.001 ? vec3(texCoords.st, 0.0) : ConeStep(frontFace, texDir3D, texCoords.st); //float depth_displ = length(tbnMat * (newTexCoords.z * texDir3D.xyz / abs(texDir3D.z))); //vec3 view_pos_displ = objPosEs - depth_displ * normalize(objPosEs); vec3 displ_vec = tbnMat * (newTexCoords.z * texDir3D.xyz / abs(texDir3D.z)); vec3 view_pos_displ = objPosEs - displ_vec; vec4 modelPos = inverse(mvp.view) * vec4(view_pos_displ, 1.0); vec4 clipPlane = vec4(normalize(u_clipPlane.xyz), u_clipPlane.w); float clip_dist = dot(modelPos, clipPlane); //float clip_dist = in_data.clip; if (clip_dist < 0.0) discard; texCoords.st = newTexCoords.xy; vec4 normalVec = CalculateNormal(texCoords); //vec3 nvMappedEs = normalize( tbnMat * normalVec.xyz ); vec3 nvMappedEs = u_displacement_scale < 0.001 ? normalize(objNormalEs) : (normalize(transpose(inv_tbnMat) * normalVec.xyz)); //vec3 color = in_data.col; vec3 color = texture(u_texture, texCoords.st).rgb; // ambient part vec3 lightCol = light_data.u_ambient * color; // diffuse part vec3 normalV = normalize(nvMappedEs); vec3 lightV = -normalize(mat3(mvp.view) * light_data.u_lightDir.xyz); float NdotL = max(0.0, dot(normalV, lightV)); lightCol += NdotL * light_data.u_diffuse * color; // specular part vec3 eyeV = normalize(-objPosEs); vec3 halfV = normalize(eyeV + lightV); float NdotH = max(0.0, dot(normalV, halfV)); float kSpecular = (light_data.u_shininess + 2.0) * pow(NdotH, light_data.u_shininess) / (2.0 * 3.14159265); lightCol += kSpecular * light_data.u_specular * color; fragColor = vec4(lightCol.rgb, 1.0); vec4 proj_pos_displ = mvp.proj * vec4(view_pos_displ.xyz, 1.0); float depth = 0.5 + 0.5 * proj_pos_displ.z / proj_pos_displ.w; gl_FragDepth = u_displacement_scale < 0.001 ? gl_FragCoord.z : depth; //fragColor = vec4( vec3(1.0-depth), 1.0 ); }"; this._parallax_prog = openGLFactory.VertexAndFragmentShaderProgram(vert_shader, frag_shader); this._parallax_prog.Generate(); // Model view projection shader storage block objects and buffers TMVP mvp = new TMVP(Matrix4.Identity, Matrix4.Identity, Matrix4.Identity); this._mvp_ssbo = openGLFactory.NewStorageBuffer(); this._mvp_ssbo.Create(ref mvp); this._mvp_ssbo.Bind(1); TLightSource light_source = new TLightSource(new Vector4(-1.0f, -0.5f, -2.0f, 0.0f), 0.2f, 0.8f, 0.8f, 10.0f); this._light_ssbo = openGLFactory.NewStorageBuffer(); this._light_ssbo.Create(ref light_source); this._light_ssbo.Bind(2); // states GL.Viewport(0, 0, this._cx, this._cy); //GL.ClearColor(System.Drawing.Color.Beige); GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); GL.Enable(EnableCap.DepthTest); // no face culling, because of clipping //GL.Enable(EnableCap.CullFace); GL.FrontFace(FrontFaceDirection.Ccw); GL.CullFace(CullFaceMode.Back); // matrices and controller this._view = Matrix4.LookAt(0.0f, 0.0f, 2.5f, 0, 0, 0, 0, 1, 0); float angle = 90.0f * (float)Math.PI / 180.0f; float aspect = (float)this._cx / (float)this._cy; this._projection = Matrix4.CreatePerspectiveFieldOfView(angle, aspect, 0.1f, 100.0f); this._spin = new ModelSpinningControls( () => { return(this._period); }, () => { return(new float[] { 0, 0, (float)this._cx, (float)this._cy }); }, () => { return(this._view); } ); this._spin.SetAttenuation(1.0f, 0.05f, 0.0f); // properties ViewModel.HeightScale = 50; ViewModel.QualityScale = 50; ViewModel.ClipScale = 50; }
public void Setup(int cx, int cy) { this._cx = cx; this._cy = cy; // Version strings _version.Retrieve(); // Get OpenGL extensions _extensions.Retrieve(); // Debug callback _debug_callback.Init(); // create Vertex Array Object, Array Buffer Object and Element Array Buffer Object (float[] attributes, uint[] indices) = new Cube().Create(); TVertexFormat[] format = { new TVertexFormat(0, 0, 3, 0, false), new TVertexFormat(0, 1, 3, 3, false), //new TVertexFormat(0, ?, 2, 6, false), new TVertexFormat(0, 2, 4, 8, false), }; _test_vao = openGLFactory.NewVertexArrayObject(); _test_vao.AppendVertexBuffer(0, 12, attributes); _test_vao.Create(format, indices); _test_vao.Bind(); // Create shader program string vert_shader = @"#version 460 core layout (location = 0) in vec4 a_pos; layout (location = 1) in vec3 a_nv; layout (location = 2) in vec4 a_color; layout (location = 0) out TVertexData { vec3 pos; vec3 nv; vec4 col; } outData; layout(std430, binding = 1) buffer MVP { mat4 proj; mat4 view; mat4 model; } mvp; void main() { mat4 mv_mat = mvp.view * mvp.model; mat3 normal_mat = inverse(transpose(mat3(mv_mat))); outData.nv = normalize(normal_mat * a_nv); outData.col = a_color; vec4 viewPos = mv_mat * a_pos; outData.pos = viewPos.xyz / viewPos.w; gl_Position = mvp.proj * viewPos; }"; string frag_shader = @"#version 460 core out vec4 frag_color; layout (location = 0) in TVertexData { vec3 pos; vec3 nv; vec4 col; } inData; layout(std430, binding = 2) buffer TLight { vec4 u_lightDir; float u_ambient; float u_diffuse; float u_specular; float u_shininess; } light_data; void main() { vec3 color = inData.col.rgb; // ambient part vec3 lightCol = light_data.u_ambient * color; vec3 normalV = normalize( inData.nv ); vec3 eyeV = normalize( -inData.pos ); vec3 lightV = normalize( -light_data.u_lightDir.xyz ); // diffuse part float NdotL = max( 0.0, dot( normalV, lightV ) ); lightCol += NdotL * light_data.u_diffuse * color; // specular part vec3 halfV = normalize( eyeV + lightV ); float NdotH = max( 0.0, dot( normalV, halfV ) ); float kSpecular = ( light_data.u_shininess + 2.0 ) * pow( NdotH, light_data.u_shininess ) / ( 2.0 * 3.14159265 ); lightCol += kSpecular * light_data.u_specular * color; frag_color = vec4( lightCol.rgb, inData.col.a ); }"; this._test_prog = openGLFactory.VertexAndFragmentShaderProgram(vert_shader, frag_shader); this._test_prog.Generate(); // Model view projection shader storage block objects and buffers TMVP mvp = new TMVP(Matrix4.Identity, Matrix4.Identity, Matrix4.Identity); this._mvp_ssbo = openGLFactory.NewStorageBuffer(); this._mvp_ssbo.Create(ref mvp); this._mvp_ssbo.Bind(1); TLightSource light_source = new TLightSource(new Vector4(-1.0f, -0.5f, -2.0f, 0.0f), 0.2f, 0.8f, 0.8f, 10.0f); this._light_ssbo = openGLFactory.NewStorageBuffer(); this._light_ssbo.Create(ref light_source); this._light_ssbo.Bind(2); this._depth_pack_buffer = openGLFactory.NewPixelPackBuffer(); this._depth_pack_buffer.Create <float>(); // states GL.Viewport(0, 0, this._cx, this._cy); //GL.ClearColor(System.Drawing.Color.Beige); GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.CullFace); GL.FrontFace(FrontFaceDirection.Ccw); GL.CullFace(CullFaceMode.Back); // matrices and controller this._view = Matrix4.LookAt(0.0f, -4.0f, 0.0f, 0, 0, 0, 0, 0, 1); float angle = 90.0f * (float)Math.PI / 180.0f; float aspect = (float)this._cx / (float)this._cy; this._projection = Matrix4.CreatePerspectiveFieldOfView(angle, aspect, 0.1f, 100.0f); _controls = new NavigationControls( () => { return(new float[] { 0, 0, (float)this._cx, (float)this._cy }); }, () => { return(this._view); }, () => { return(this._projection); }, this.GetDepth, (cursor_pos) => { return(new Vector3(0, 0, 0)); }, (Matrix4 view) => { this._view = view; } ); }
public void Setup(int cx, int cy) { this._cx = cx; this._cy = cy; // Version strings _version.Retrieve(); // Get OpenGL extensions _extensions.Retrieve(); // Debug callback _debug_callback.Init(); // create Vertex Array Object, Array Buffer Object and Element Array Buffer Object (float[] attributes, uint[] indices) = new Cube().Create(); TVertexFormat[] format = { new TVertexFormat(0, 0, 3, 0, false), new TVertexFormat(0, 1, 3, 3, false), new TVertexFormat(0, 2, 2, 6, false), //new TVertexFormat(0, 2, 4, 8, false), }; _cube_vao = openGLFactory.NewVertexArrayObject(); _cube_vao.AppendVertexBuffer(0, 12, attributes); _cube_vao.Create(format, indices); _cube_vao.Bind(); // Create textures Assembly assembly = Assembly.GetExecutingAssembly(); //string[] names = assembly.GetManifestResourceNames(); Stream textue_stream = assembly.GetManifestResourceStream("OpenTK_parallax_relief_mapping.Resource.woodtiles.jpg"); Stream normalmap_stream = assembly.GetManifestResourceStream("OpenTK_parallax_relief_mapping.Resource.toy_box_normal.png"); Stream displacementmap_stream = assembly.GetManifestResourceStream("OpenTK_parallax_relief_mapping.Resource.toy_box_disp.png"); _texture = openGLFactory.NewTexture(); _texture.Create2D(new Bitmap(textue_stream)); _normalmap = openGLFactory.NewTexture(); _normalmap.Create2D(new Bitmap(normalmap_stream)); _displacementmap = openGLFactory.NewTexture(); _displacementmap.Create2D(new Bitmap(displacementmap_stream)); // Create shader program string vert_shader = @"#version 460 core layout (location = 0) in vec4 a_pos; layout (location = 1) in vec3 a_nv; layout (location = 2) in vec2 a_uv; layout (location = 0) out TVertexData { vec3 w_pos; vec3 w_nv; vec2 uv; vec3 eye_pos; } outData; layout(std430, binding = 1) buffer MVP { mat4 proj; mat4 view; mat4 model; } mvp; void main() { mat3 normal_mat = inverse(transpose(mat3(mvp.model))); outData.w_nv = normalize(normal_mat * a_nv); outData.uv = a_uv; vec4 worldPos = mvp.model * a_pos; outData.w_pos = worldPos.xyz / worldPos.w; outData.eye_pos = inverse(mvp.view)[3].xyz; gl_Position = mvp.proj * mvp.view * mvp.model * a_pos; }"; string frag_shader = @"#version 460 core out vec4 frag_color; layout (location = 0) in TVertexData { vec3 w_pos; vec3 w_nv; vec2 uv; vec3 eye_pos; } inData; layout(std430, binding = 2) buffer TLight { vec4 u_lightDir; float u_ambient; float u_diffuse; float u_specular; float u_shininess; } light_data; layout(binding=1) uniform sampler2D u_diffuse; layout(binding=2) uniform sampler2D u_normal_map; layout(binding=3) uniform sampler2D u_displacement_map; layout(location=1) uniform float u_height_scale; vec2 ParallaxMapping (vec2 texCoord, vec3 viewDir) { float numLayers = 32.0 - 31.0 * abs(dot(vec3(0.0, 0.0, 1.0), viewDir)); float layerDepth = 1.0 / numLayers; vec2 P = viewDir.xy / viewDir.z * u_height_scale; vec2 deltaTexCoords = P / numLayers; vec2 currentTexCoords = texCoord; float currentLayerDepth = 0.0; float currentDepthMapValue = texture2D(u_displacement_map, currentTexCoords).r; for (int i=0; i<32; ++ i) { if (currentLayerDepth >= currentDepthMapValue) break; currentTexCoords -= deltaTexCoords; currentDepthMapValue = texture2D(u_displacement_map, currentTexCoords).r; currentLayerDepth += layerDepth; } vec2 prevTexCoords = currentTexCoords + deltaTexCoords; float afterDepth = currentDepthMapValue - currentLayerDepth; float beforeDepth = texture2D(u_displacement_map, prevTexCoords).r - currentLayerDepth + layerDepth; float weight = afterDepth / (afterDepth - beforeDepth); return prevTexCoords * weight + currentTexCoords * (1.0 - weight); } void main() { vec3 N = normalize(inData.w_nv); vec3 dp1 = dFdx( inData.w_pos ); vec3 dp2 = dFdy( inData.w_pos ); vec2 duv1 = dFdx( inData.uv ); vec2 duv2 = dFdy( inData.uv ); vec3 dp2perp = cross(dp2, N); vec3 dp1perp = cross(N, dp1); vec3 T = dp2perp * duv1.x + dp1perp * duv2.x; vec3 B = dp2perp * duv1.y + dp1perp * duv2.y; float invmax = inversesqrt(max(dot(T, T), dot(B, B))); mat3 tm = mat3(T * invmax, B * invmax, N); mat3 tbn_inv = mat3(vec3(tm[0].x, tm[1].x, tm[2].x), vec3(tm[0].y, tm[1].y, tm[2].y), vec3(tm[0].z, tm[1].z, tm[2].z)); vec3 view_dir = tbn_inv * normalize(inData.w_pos - inData.eye_pos); vec2 uv = ParallaxMapping(inData.uv, view_dir); if (uv.x > 1.0 || uv.y > 1.0 || uv.x < 0.0 || uv.y < 0.0) discard; vec4 color = texture(u_diffuse, uv.xy); vec3 normalV = texture2D(u_normal_map, uv.st).xyz * 2.0 - 1.0; normalV = normalize(vec3(normalV.xy, normalV.z / max(0.001, 10.0 * u_height_scale))); // ambient part vec3 lightCol = light_data.u_ambient * color.rgb; vec3 eyeV = normalize(inData.eye_pos - inData.w_pos); vec3 lightV = tbn_inv * normalize( -light_data.u_lightDir.xyz ); // diffuse part float NdotL = max( 0.0, dot( normalV, lightV ) ); lightCol += NdotL * light_data.u_diffuse * color.rgb; // specular part vec3 halfV = normalize( eyeV + lightV ); float NdotH = max( 0.0, dot( normalV, halfV ) ); float kSpecular = ( light_data.u_shininess + 2.0 ) * pow( NdotH, light_data.u_shininess ) / ( 2.0 * 3.14159265 ); lightCol += kSpecular * light_data.u_specular * color.rgb; frag_color = vec4( lightCol.rgb, color.a ); }"; this._parallax_prog = openGLFactory.VertexAndFragmentShaderProgram(vert_shader, frag_shader); this._parallax_prog.Generate(); // Model view projection shader storage block objects and buffers TMVP mvp = new TMVP(Matrix4.Identity, Matrix4.Identity, Matrix4.Identity); this._mvp_ssbo = openGLFactory.NewStorageBuffer(); this._mvp_ssbo.Create(ref mvp); this._mvp_ssbo.Bind(1); TLightSource light_source = new TLightSource(new Vector4(-1.0f, -0.5f, -2.0f, 0.0f), 0.2f, 0.8f, 0.8f, 10.0f); this._light_ssbo = openGLFactory.NewStorageBuffer(); this._light_ssbo.Create(ref light_source); this._light_ssbo.Bind(2); // states GL.Viewport(0, 0, this._cx, this._cy); //GL.ClearColor(System.Drawing.Color.Beige); GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.CullFace); GL.FrontFace(FrontFaceDirection.Ccw); GL.CullFace(CullFaceMode.Back); // matrices and controller this._view = Matrix4.LookAt(0.0f, 0.0f, 3.0f, 0, 0, 0, 0, 1, 0); float angle = 90.0f * (float)Math.PI / 180.0f; float aspect = (float)this._cx / (float)this._cy; this._projection = Matrix4.CreatePerspectiveFieldOfView(angle, aspect, 0.1f, 100.0f); this._spin = new ModelSpinningControls( () => { return(this._period); }, () => { return(new float[] { 0, 0, (float)this._cx, (float)this._cy }); }, () => { return(this._view); } ); this._spin.SetAttenuation(1.0f, 0.05f, 0.0f); // properties ViewModel.HeightScale = 100; }
//! On load window (once) protected override void OnLoad() { _version = openGLFactory.NewVersionInformation(Console.WriteLine); _extensions = openGLFactory.NewExtensionInformation(); _debug_callback = openGLFactory.NewDebugCallback(Console.WriteLine); // Version strings _version.Retrieve(); // Get OpenGL extensions _extensions.Retrieve(); // Debug callback _debug_callback.Init(); // create Vertex Array Object, Array Buffer Object and Element Array Buffer Object float[] vquad = { // x y z r g b a -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f }; uint [] iquad = { 0, 1, 2, 0, 2, 3 }; TVertexFormat[] format = { new TVertexFormat(0, 0, 3, 0, false), new TVertexFormat(0, 1, 4, 3, false), }; _test_vao = openGLFactory.NewVertexArrayObject(); _test_vao.AppendVertexBuffer(0, 7, vquad); _test_vao.Create(format, iquad); // Create shader program string vert_shader = @"#version 460 core layout (location = 0) in vec4 a_pos; layout (location = 1) in vec4 a_color; out vec4 v_color; uniform mat4 u_transform; void main() { v_color = a_color; gl_Position = u_transform * a_pos; }"; string frag_shader = @"#version 460 core out vec4 frag_color; in vec4 v_color; void main() { frag_color = v_color; }"; this._test_prog = openGLFactory.VertexAndFragmentShaderProgram(vert_shader, frag_shader); this._test_prog.Generate(); this._test_prog.Use(); // states GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); base.OnLoad(); }
//! On load window (once) protected override void OnLoad() { _version = openGLFactory.NewVersionInformation(Console.WriteLine); _extensions = openGLFactory.NewExtensionInformation(); _debug_callback = openGLFactory.NewDebugCallback(Console.WriteLine); // Version strings _version.Retrieve(); // Get OpenGL extensions _extensions.Retrieve(); // Debug callback _debug_callback.Init(); // create Vertex Array Object, Array Buffer Object and Element Array Buffer Object (float[] attributes, uint[] indices) = new TrefoilKnot(256, 16).Create(); TVertexFormat[] format = { new TVertexFormat(0, 0, 3, 0, false), new TVertexFormat(0, 1, 3, 3, false), //new TVertexFormat(0, ?, 2, 6, false), new TVertexFormat(0, 2, 4, 8, false), }; _test_vao = openGLFactory.NewVertexArrayObject(); _test_vao.AppendVertexBuffer(0, 12, attributes); _test_vao.Create(format, indices); _test_vao.Bind(); // Create shader program string vert_shader = @"#version 460 core layout (location = 0) in vec4 a_pos; layout (location = 1) in vec3 a_nv; layout (location = 2) in vec4 a_color; layout (location = 0) out TVertexData { vec3 pos; vec3 nv; vec4 col; } outData; layout(std430, binding = 1) buffer MVP { mat4 proj; mat4 view; mat4 model; } mvp; void main() { mat4 mv_mat = mvp.view * mvp.model; mat3 normal_mat = inverse(transpose(mat3(mv_mat))); outData.nv = normalize(normal_mat * a_nv); outData.col = a_color; vec4 viewPos = mv_mat * a_pos; outData.pos = viewPos.xyz / viewPos.w; gl_Position = mvp.proj * viewPos; }"; string frag_shader = @"#version 460 core out vec4 frag_color; layout (location = 0) in TVertexData { vec3 pos; vec3 nv; vec4 col; } inData; layout(std430, binding = 2) buffer TLight { vec4 u_lightDir; float u_ambient; float u_diffuse; float u_specular; float u_shininess; } light_data; void main() { vec3 color = inData.col.rgb; // ambient part vec3 lightCol = light_data.u_ambient * color; vec3 normalV = normalize( inData.nv ); vec3 eyeV = normalize( -inData.pos ); vec3 lightV = normalize( -light_data.u_lightDir.xyz ); // diffuse part float NdotL = max( 0.0, dot( normalV, lightV ) ); lightCol += NdotL * light_data.u_diffuse * color; // specular part vec3 halfV = normalize( eyeV + lightV ); float NdotH = max( 0.0, dot( normalV, halfV ) ); float kSpecular = ( light_data.u_shininess + 2.0 ) * pow( NdotH, light_data.u_shininess ) / ( 2.0 * 3.14159265 ); lightCol += kSpecular * light_data.u_specular * color; frag_color = vec4( lightCol.rgb, inData.col.a ); }"; this._test_prog = openGLFactory.VertexAndFragmentShaderProgram(vert_shader, frag_shader); this._test_prog.Generate(); // Model view projection shader storage block objects and buffers TMVP mvp = new TMVP(Matrix4.Identity, Matrix4.Identity, Matrix4.Identity); this._mvp_ssbo = openGLFactory.NewStorageBuffer(); this._mvp_ssbo.Create(ref mvp); this._mvp_ssbo.Bind(1); TLightSource light_source = new TLightSource(new Vector4(-1.0f, -0.5f, -2.0f, 0.0f), 0.2f, 0.8f, 0.8f, 10.0f); this._light_ssbo = openGLFactory.NewStorageBuffer(); this._light_ssbo.Create(ref light_source); this._light_ssbo.Bind(2); // states GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.CullFace); GL.FrontFace(FrontFaceDirection.Ccw); GL.CullFace(CullFaceMode.Back); // matrices and controller this._view = Matrix4.LookAt(0.0f, 0.0f, 1.5f, 0, 0, 0, 0, 1, 0); var spin = new ModelSpinningControls( () => { return(this._period); }, () => { return(new float[] { 0, 0, (float)this.Size.X, (float)this.Size.Y }); }, () => { return(this._view); } ); spin.SetAttenuation(1.0f, 0.05f, 0.0f); this._controls = spin; base.OnLoad(); }
//! On load window (once) protected override void OnLoad() { _version = openGLFactory.NewVersionInformation(Console.WriteLine); _extensions = openGLFactory.NewExtensionInformation(); _debug_callback = openGLFactory.NewDebugCallback(Console.WriteLine); // Version strings _version.Retrieve(); // Get OpenGL extensions _extensions.Retrieve(); // Debug callback _debug_callback.Init(); // create Vertex Array Object, Array Buffer Object and Element Array Buffer Object float[] vquad = { // x y z u v -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, -0.5f, 0.5f, 0.0f, 0.0f, 0.0f }; uint[] iquad = { 0, 1, 2, 0, 2, 3 }; TVertexFormat[] format = { new TVertexFormat(0, 0, 3, 0, false), new TVertexFormat(0, 1, 2, 3, false), }; _test_vao = openGLFactory.NewVertexArrayObject(); _test_vao.AppendVertexBuffer(0, 5, vquad); _test_vao.Create(format, iquad); // Create texture Assembly assembly = Assembly.GetExecutingAssembly(); string[] names = assembly.GetManifestResourceNames(); Stream resource_stream = assembly.GetManifestResourceStream("OpenTK_example_3.Resource.background.jpg"); _test_texture = openGLFactory.NewTexture(); _test_texture.Create2D(new Bitmap(resource_stream)); // Create shader program string vert_shader = @"#version 460 core layout (location = 0) in vec4 a_pos; layout (location = 1) in vec2 a_uv; out vec2 v_uv; void main() { v_uv = a_uv; gl_Position = a_pos; }"; string frag_shader = @"#version 460 core out vec4 frag_color; in vec2 v_uv; layout(binding = 7) uniform sampler2D u_texture; void main() { frag_color = texture(u_texture, v_uv).rgba; }"; this._test_prog = openGLFactory.VertexAndFragmentShaderProgram(vert_shader, frag_shader); this._test_prog.Generate(); this._test_prog.Use(); // states GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); base.OnLoad(); }
public void Setup(int cx, int cy) { this._cx = cx; this._cy = cy; // Version strings _version.Retrieve(); // Get OpenGL extensions _extensions.Retrieve(); // Debug callback _debug_callback.Init(); // create Vertex Array Object, Array Buffer Object and Element Array Buffer Object (float[] attributes, uint[] indices) = new Cube().Create(); TVertexFormat[] format = { new TVertexFormat(0, 0, 3, 0, false), new TVertexFormat(0, 1, 3, 3, false), new TVertexFormat(0, 2, 2, 6, false), //new TVertexFormat(0, 2, 4, 8, false), }; _cube_vao = openGLFactory.NewVertexArrayObject(); _cube_vao.AppendVertexBuffer(0, 12, attributes); _cube_vao.Create(format, indices); _cube_vao.Bind(); // Create textures objects _tbos = new List <ITexture>(); _tbos.Add(openGLFactory.NewTexture()); _tbos[0].Create2D(_image_cx, _image_cy, ITexture.Format.RGBA_8); _tbos.Add(openGLFactory.NewTexture()); _tbos[1].Create2D(_image_cx, _image_cy, ITexture.Format.RGBA_F32); _tbos.Add(openGLFactory.NewTexture()); _tbos[2].Create2D(_image_cx, _image_cy, ITexture.Format.RGBA_F32); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); // Create generators this._generators = new List <TextureGenerator>(); this._generators.Add(new TextureGenerator(openGLFactory, TextureGenerator.TType.texture_test1, new ITexture[] { _tbos[0] })); this._generators.Add(new TextureGenerator(openGLFactory, TextureGenerator.TType.heightmap_test1, new ITexture[] { _tbos[1] })); this._generators.Add(new TextureGenerator(openGLFactory, TextureGenerator.TType.cone_step_map, new ITexture[] { _tbos[2] }, new ITexture[] { _tbos[1] })); // Create textures foreach (var generator in this._generators) { generator.Generate(); } // Create shader program string vert_shader = @"#version 460 core layout (location = 0) in vec3 inPos; layout (location = 1) in vec3 inNV; layout (location = 2) in vec2 inUV; out TVertexData { vec3 world_pos; vec3 world_nv; vec2 uv; } out_data; layout(std430, binding = 1) buffer MVP { mat4 proj; mat4 view; mat4 model; } mvp; void main() { vec4 worldPos = mvp.model * vec4(inPos, 1.0); out_data.world_pos = worldPos.xyz / worldPos.w; out_data.world_nv = normalize( mat3(mvp.model) * inNV ); out_data.uv = inUV; }"; string geo_shader = @"#version 460 core layout( triangles ) in; layout( triangle_strip, max_vertices = 15 ) out; in TVertexData { vec3 world_pos; vec3 world_nv; vec2 uv; } inData[]; out TGeometryData { vec3 pos; vec3 nv; vec3 tv; vec3 bv; vec3 uvh; vec4 d; float clip; } outData; layout(std430, binding = 1) buffer MVP { mat4 proj; mat4 view; mat4 model; } mvp; layout(location=1) uniform vec4 u_clipPlane; layout(location=2) uniform float u_displacement_scale; void main() { // tangent space //vec3 p_dA = vsPos[1].xyz - vsPos[0].xyz; //vec3 p_dB = vsPos[2].xyz - vsPos[0].xyz; //vec2 tc_dA = inData[1].uv - inData[0].uv; //vec2 tc_dB = inData[2].uv - inData[0].uv; //float texDet = determinant( mat2( tc_dA, tc_dB ) ); //outData.vsTV = ( tc_dB.y * p_dA - tc_dA.y * p_dB ) / texDet; //outData.vsBVsign = sign(texDet); vec3 world_pos_up[3]; for (int i = 0; i < 3; ++ i) world_pos_up[i] = inData[i].world_pos + inData[i].world_nv * u_displacement_scale; vec3 view_nv[3]; vec3 view_pos[3]; vec3 view_pos_up[3]; for (int i = 0; i < 3; ++ i) { vec4 viewPos = mvp.view * vec4(inData[i].world_pos, 1.0); view_nv[i] = normalize(mat3(mvp.view) * inData[i].world_nv); view_pos[i] = viewPos.xyz; view_pos_up[i] = view_pos[i] + view_nv[i] * u_displacement_scale; //view_pos_up[i] = (mvp.view * vec4(world_pos_up[i], 1.0)).xyz; } // tangent space // Followup: Normal Mapping Without Precomputed Tangents [http://www.thetenthplanet.de/archives/1180] vec3 dp1 = view_pos[1].xyz - view_pos[0].xyz; vec3 dp2 = view_pos[2].xyz - view_pos[0].xyz; vec2 duv1 = inData[1].uv.xy - inData[0].uv.xy; vec2 duv2 = inData[2].uv.xy - inData[0].uv.xy; vec3 nv[3]; vec3 tv[3]; vec3 bv[3]; for ( int i=0; i < 3; ++i ) { vec3 dp2perp = cross(dp2, view_nv[i]); vec3 dp1perp = cross(view_nv[i], dp1); nv[i] = view_nv[i] * u_displacement_scale; tv[i] = dp2perp * duv1.x + dp1perp * duv2.x; bv[i] = dp2perp * duv1.y + dp1perp * duv2.y; } // distance to opposite planes float d[3]; float d_up[3]; float d_opp[3]; float d_opp_up[3]; float d_top[3]; for ( int i0=0; i0 < 3; ++i0 ) { d[i0] = length(view_pos[i0].xyz); d_up[i0] = length(view_pos_up[i0].xyz); int i1 = (i0+1) % 3; int i2 = (i0+2) % 3; vec3 edge = view_pos[i2].xyz - view_pos[i1].xyz; vec3 edge_up = view_pos_up[i2].xyz - view_pos_up[i1].xyz; vec3 up = view_nv[i1].xyz + view_nv[i2].xyz; // intersect the view ray trough a corner point of the prism (with triangular base) // with the opposite side face of the prism // // d = dot(P0 - R0, N) / dot(D, N) // // R0 : point on the ray // D : direction of the ray // P0 : point on the plane // N : norma vector of the plane // d :: distance from R0 to the intersection with the plane along D //vec3 R0 = vec3(view_pos[i0].xy, 0.0); // for orthographic projection //vec3 D = vec3(0.0, 0.0, -1.0); // for orthographic projection vec3 R0 = vec3(0.0); // for persepctive projection vec3 D = normalize(view_pos[i0].xyz); // for persepctive projection vec3 N = normalize(cross(edge, up)); vec3 P0 = (view_pos[i1].xyz+view_pos[i2].xyz)/2.0; d_opp[i0] = dot(P0 - R0, N) / dot(D, N); //vec3 R0_up = vec2(view_pos_up[i0].xyz, 0.0); // for orthographic projection //vec3 D_up = vec3(0.0, 0.0, -1.0); // for orthographic projection vec3 R0_up = vec3(0.0); // for persepctive projection vec3 D_up = normalize(view_pos_up[i0].xyz); // for persepctive projection vec3 N_up = normalize(cross(edge_up, up)); vec3 P0_up = (view_pos_up[i1].xyz+view_pos_up[i2].xyz)/2.0; d_opp_up[i0] = dot(P0_up - R0_up, N_up) / dot(D_up, N_up); //vec3 N_top = view_nv[i0]; vec3 N_top = normalize(view_nv[0]+view_nv[1]+view_nv[2]); vec3 P0_top = (view_pos_up[0].xyz + view_pos_up[1].xyz + view_pos_up[2].xyz)/3.0; d_top[i0] = dot(P0_top - R0, N_top) / dot(D, N_top); } vec4 clipPlane = vec4(normalize(u_clipPlane.xyz), u_clipPlane.w); for ( int i=0; i < 3; ++i ) { outData.nv = nv[i]; outData.tv = tv[i]; outData.bv = bv[i]; outData.pos = view_pos[i]; outData.uvh = vec3(inData[i].uv, 0.0); outData.d = vec4( i==0 ? d_opp[i] : d[i], i==1 ? d_opp[i] : d[i], i==2 ? d_opp[i] : d[i], d_top[i] ); outData.clip = dot(vec4(inData[i].world_pos, 1.0), clipPlane); gl_Position = mvp.proj * vec4( outData.pos, 1.0 ); EmitVertex(); } EndPrimitive(); vec3 cpt_tri = (view_pos[0] + view_pos[1] + view_pos[2]) / 3.0; for ( int i0=0; i0 < 3; ++i0 ) { int i1 = (i0+1) % 3; int i2 = (i0+2) % 3; vec3 cpt_edge = (view_pos[i0] + view_pos[i1]) / 2.0; vec3 dir_to_edge = cpt_edge - cpt_tri; // direction from thge center of the triangle to the edge vec3 edge = view_pos[i1] - view_pos[i0]; vec3 nv_edge = nv[i0] + nv[i1]; vec3 nv_side = cross(edge, nv_edge); // normal vector of a side of the prism nv_side *= sign(dot(nv_side, dir_to_edge)); // orentate the normal vector out of the center of the triangle // a front face is a side of the prism, where the normal vector is directed against the view vector float frontface = sign(dot(cpt_edge, -nv_side)); float d_opp0, d_opp1, d_opp_up0, d_opp_up1; if ( frontface > 0.0 ) { d_opp0 = max(d[i0], d_opp[i0]); d_opp1 = max(d[i1], d_opp[i1]); d_opp_up0 = max(d_up[i0], d_opp_up[i0]); d_opp_up1 = max(d_up[i1], d_opp_up[i1]); } else { d_opp0 = min(d[i0], d_opp[i0]); d_opp1 = min(d[i1], d_opp[i1]); d_opp_up0 = min(d_up[i0], d_opp_up[i0]); d_opp_up1 = min(d_up[i1], d_opp_up[i1]); } outData.nv = nv[i0]; outData.tv = tv[i0]; outData.bv = bv[i0]; outData.pos = view_pos[i0]; outData.uvh = vec3(inData[i0].uv, 0.0); outData.d = vec4(d_opp0, d[i0], frontface, d_top[i0]); outData.clip = dot(vec4(inData[i0].world_pos, 1.0), clipPlane); gl_Position = mvp.proj * vec4( outData.pos, 1.0 ); EmitVertex(); outData.nv = nv[i1]; outData.tv = tv[i1]; outData.bv = bv[i1]; outData.pos = view_pos[i1]; outData.uvh = vec3(inData[i1].uv, 0.0); outData.d = vec4(d[i1], d_opp1, frontface, d_top[i1]); outData.clip = dot(vec4(inData[i1].world_pos, 1.0), clipPlane); gl_Position = mvp.proj * vec4( outData.pos, 1.0 ); EmitVertex(); outData.nv = nv[i0]; outData.tv = tv[i0]; outData.bv = bv[i0]; outData.pos = view_pos_up[i0]; outData.uvh = vec3(inData[i0].uv, 1.0); outData.d = vec4(d_opp_up0, d_up[i0], frontface, 0.0); outData.clip = dot(vec4(world_pos_up[i0], 1.0), clipPlane); gl_Position = mvp.proj * vec4( outData.pos, 1.0 ); EmitVertex(); outData.nv = nv[i1]; outData.tv = tv[i1]; outData.bv = bv[i1]; outData.pos = view_pos_up[i1]; outData.uvh = vec3(inData[i1].uv, 1.0); outData.d = vec4(d_up[i1], d_opp_up1, frontface, 0.0); outData.clip = dot(vec4(world_pos_up[i1], 1.0), clipPlane); gl_Position = mvp.proj * vec4( outData.pos, 1.0 ); EmitVertex(); EndPrimitive(); } }"; string frag_shader = @"#version 460 core //#define NORMAL_MAP_TEXTURE #define NORMAL_MAP_QUALITY 1 in TGeometryData { vec3 pos; vec3 nv; vec3 tv; vec3 bv; vec3 uvh; vec4 d; float clip; } in_data; out vec4 fragColor; layout(std430, binding = 2) buffer TLight { vec4 u_lightDir; float u_ambient; float u_diffuse; float u_specular; float u_shininess; } light_data; layout(binding=1) uniform sampler2D u_texture; layout(binding=2) uniform sampler2D u_displacement_map; layout(location=2) uniform float u_displacement_scale; layout(location=3) uniform vec2 u_parallax_quality; layout(std430, binding = 1) buffer MVP { mat4 proj; mat4 view; mat4 model; } mvp; layout(location=1) uniform vec4 u_clipPlane; #if defined(NORMAL_MAP_TEXTURE) uniform sampler2D u_normal_map; #endif float CalculateHeight( in vec2 texCoords ) { float height = texture( u_displacement_map, texCoords ).x; return clamp( height, 0.0, 1.0 ); } vec2 GetHeightAndCone( in vec2 texCoords ) { vec2 h_and_c = texture( u_displacement_map, texCoords ).rg; return clamp( h_and_c, 0.0, 1.0 ); } vec4 CalculateNormal( in vec2 texCoords ) { #if defined(NORMAL_MAP_TEXTURE) float height = CalculateHeight( texCoords ); vec3 tempNV = texture( u_normal_map, texCoords ).xyz * 2.0 / 1.0; return vec4( normalize( tempNV ), height ); #else vec2 texOffs = 1.0 / vec2(textureSize( u_displacement_map, 0 ).xy); vec2 scale = 1.0 / texOffs; #if NORMAL_MAP_QUALITY > 1 float hx[9]; hx[0] = texture( u_displacement_map, texCoords.st + texOffs * vec2(-1.0, -1.0) ).r; hx[1] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 0.0, -1.0) ).r; hx[2] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 1.0, -1.0) ).r; hx[3] = texture( u_displacement_map, texCoords.st + texOffs * vec2(-1.0, 0.0) ).r; hx[4] = texture( u_displacement_map, texCoords.st ).r; hx[5] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 1.0, 0.0) ).r; hx[6] = texture( u_displacement_map, texCoords.st + texOffs * vec2(-1.0, 1.0) ).r; hx[7] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 0.0, 1.0) ).r; hx[8] = texture( u_displacement_map, texCoords.st + texOffs * vec2( 1.0, 1.0) ).r; vec2 deltaH = vec2(hx[0]-hx[2] + 2.0*(hx[3]-hx[5]) + hx[6]-hx[8], hx[0]-hx[6] + 2.0*(hx[1]-hx[7]) + hx[2]-hx[8]); float h_mid = hx[4]; #elif NORMAL_MAP_QUALITY > 0 float h_mid = texture( u_displacement_map, texCoords.st ).r; float h_xa = texture( u_displacement_map, texCoords.st + texOffs * vec2(-1.0, 0.0) ).r; float h_xb = texture( u_displacement_map, texCoords.st + texOffs * vec2( 1.0, 0.0) ).r; float h_ya = texture( u_displacement_map, texCoords.st + texOffs * vec2( 0.0, -1.0) ).r; float h_yb = texture( u_displacement_map, texCoords.st + texOffs * vec2( 0.0, 1.0) ).r; vec2 deltaH = vec2(h_xa-h_xb, h_ya-h_yb); #else vec4 heights = textureGather( u_displacement_map, texCoords, 0 ); vec2 deltaH = vec2(dot(heights, vec4(1.0, -1.0, -1.0, 1.0)), dot(heights, vec4(-1.0, -1.0, 1.0, 1.0))); float h_mid = heights.w; #endif return vec4( normalize( vec3( deltaH * scale, 1.0 ) ), h_mid ); #endif } vec3 Parallax( in float frontFace, in vec3 texCoord, in vec3 tbnP0, in vec3 tbnP1, in vec3 tbnStep ) { // inverse height map: -1 for inverse height map or 1 if not inverse // height maps of back faces base triangles are inverted float back_face = step(0.0, -frontFace); vec3 texC0 = texCoord.xyz + tbnP0 + back_face * vec3(tbnStep.xy, 0.0); vec3 texC1 = texCoord.xyz + tbnP1 + back_face * vec3(tbnStep.xy, 0.0); // sample steps and quality vec2 quality_range = u_parallax_quality; float quality = mix( quality_range.x, quality_range.y, 1.0 - abs(normalize(tbnStep).z) ); float numSteps = clamp( quality * 50.0, 1.0, 50.0 ); int numBinarySteps = int( clamp( quality * 10.0, 1.0, 10.0 ) ); // change of the height per step float bumpHeightStep = (texC0.z-texC1.z) / (numSteps-1.0); float bestBumpHeight = texC1.z; float mapHeight = 1.0; for ( int i = 0; i < int( numSteps ); ++ i ) { mapHeight = back_face + frontFace * CalculateHeight( mix(texC0.xy, texC1.xy, (bestBumpHeight-texC0.z)/(texC1.z-texC0.z)) ); if ( mapHeight >= bestBumpHeight || bestBumpHeight > 1.0 ) break; bestBumpHeight += bumpHeightStep; } if ( texCoord.z < 0.0001 || bestBumpHeight >= 0.0 ) // if not a silhouett { // binary steps, starting at the previous sample point bestBumpHeight -= bumpHeightStep; for ( int i = 0; i < numBinarySteps; ++ i ) { bumpHeightStep *= 0.5; bestBumpHeight += bumpHeightStep; mapHeight = back_face + frontFace * CalculateHeight( mix(texC0.xy, texC1.xy, (bestBumpHeight-texC0.z)/(texC1.z-texC0.z)) ); bestBumpHeight -= ( bestBumpHeight < mapHeight ) ? bumpHeightStep : 0.0; } // final linear interpolation between the last to heights bestBumpHeight += bumpHeightStep * clamp( ( bestBumpHeight - mapHeight ) / abs(bumpHeightStep), 0.0, 1.0 ); } // set displaced texture coordiante and intersection height vec2 texC = mix(texC0.xy, texC1.xy, (bestBumpHeight-texC0.z)/(texC1.z-texC0.z)); mapHeight = bestBumpHeight; return vec3(texC.xy, mapHeight); } void main() { vec3 objPosEs = in_data.pos; vec3 objNormalEs = in_data.nv; vec3 texCoords = in_data.uvh.stp; float frontFace = (texCoords.p > 0.0) ? 1.0 : (gl_FrontFacing ? 1.0 : -1.0); // TODO $$$ sign(dot(N,objPosEs)); //vec3 tangentEs = normalize( tangentVec - normalEs * dot(tangentVec, normalEs ) ); //mat3 tbnMat = mat3( tangentEs, binormalSign * cross( normalEs, tangentEs ), normalEs ); // tangent space // Followup: Normal Mapping Without Precomputed Tangents [http://www.thetenthplanet.de/archives/1180] // If backface, then the normal vector is downwards the (co-)tangent space. // In this case the normal has to be mirrored to make the parallax algorithm prpper work. vec3 N = frontFace * objNormalEs; vec3 T = in_data.tv; vec3 B = in_data.bv; float invmax = inversesqrt(max(dot(T, T), dot(B, B))); mat3 tbnMat = mat3(T * invmax, B * invmax, N * invmax); mat3 inv_tbnMat = inverse( tbnMat ); // distances to the sides of the prism bool is_silhouette = texCoords.p > 0.0001; bool silhouette_front = in_data.d.z > 0.0; float df = length( objPosEs ); float d0; float d1; if ( is_silhouette == false ) { if ( frontFace > 0.0 ) { d1 = 0.0; d0 = min(min(in_data.d.x, in_data.d.y), in_data.d.z) - df; // TODO $$$ * 0.9 } else { d0 = 0.0; d1 = max(max(in_data.d.x, in_data.d.y), in_data.d.z) - df; } } else { d1 = min(in_data.d.x, in_data.d.y) - df; d0 = max(in_data.d.x, in_data.d.y) - df; } // intersection points vec3 V = objPosEs / df; vec3 P0 = V * d0; vec3 P1 = V * d1; vec3 tbnP0 = inv_tbnMat * P0; vec3 tbnP1 = inv_tbnMat * P1; vec3 tbnDir = normalize(inv_tbnMat * objPosEs); vec3 tbnTopMax = tbnDir / tbnDir.z; // geometry situation float base_height = texCoords.p; // intersection level (height) on the silhouette (side of prism geometry) bool is_up_isect = is_silhouette && tbnDir.z > 0.0; // upwards intersection on potential silhouette (side of prism geometry) // sample start and end height (level) float delta_height0 = is_up_isect ? 1.05*(1.0-base_height) : base_height; // TODO $$$ 1.05 ??? float delta_height1 = is_up_isect ? 0.0 : (base_height - 1.0); // sample distance //vec3 texDist = tbnDir / abs(tbnDir.z); // (z is negative) the direction vector points downwards int tangent-space vec3 texDist = is_silhouette == false ? tbnDir / abs(tbnDir.z) : tbnDir / max(abs(tbnDir.z), 0.5*length(tbnDir.xy)); vec3 tbnStep = vec3(texDist.xy, sign(tbnDir.z)); // start and end of samples tbnP0 = delta_height0 * tbnStep; // sample end - bottom of prism tbnP1 = delta_height1 * tbnStep; // sample start - top of prism if ( is_silhouette ) { if ( silhouette_front ) { tbnP1 = vec3(0.0); } else { tbnP0 = vec3(0.0); } } vec3 newTexCoords = abs(u_displacement_scale) < 0.001 ? vec3(texCoords.st, 0.0) : Parallax( frontFace, texCoords.stp, tbnP0, tbnP1, tbnStep ); vec3 tex_offst = newTexCoords.stp-texCoords.stp; // slihouett discard (clipping) if ( is_silhouette ) { if ( newTexCoords.z > 1.000001 || // clip at top plane of the prism newTexCoords.z < 0.0 || // clip at bottom plane of the prism dot(tex_offst, tbnDir)*in_data.d.z < 0.0 ) // clip back side faces at the back and clip front side faces at the front discard; if ( silhouette_front == false && is_up_isect ) discard; } vec3 displ_vec = tbnMat * tex_offst/invmax; vec3 view_pos_displ = objPosEs + displ_vec; texCoords.st = newTexCoords.xy; #define DEBUG_CLIP #define DEBUG_CLIP_DISPLACED #if defined (DEBUG_CLIP) vec4 modelPos = inverse(mvp.view) * vec4(view_pos_displ, 1.0); vec4 clipPlane = vec4(normalize(u_clipPlane.xyz), u_clipPlane.w); #if defined (DEBUG_CLIP_DISPLACED) float clip_dist = dot(modelPos, clipPlane); #else float clip_dist = in_data.clip; #endif if ( clip_dist < 0.0 ) discard; #endif vec4 normalVec = CalculateNormal( texCoords.st ); // If back face, then the height map has been inverted (except cone step map). This causes that the normalvector has to be adapted. normalVec.xy *= frontFace; //vec3 nvMappedEs = normalize( tbnMat * normalVec.xyz ); vec3 nvMappedEs = normalize( transpose(inv_tbnMat) * normalVec.xyz ); // TODO $$$ evaluate `invmax`? vec3 color = texture( u_texture, texCoords.st ).rgb; // ambient part vec3 lightCol = light_data.u_ambient * color; // diffuse part vec3 normalV = normalize( nvMappedEs ); vec3 lightV = -normalize(mat3(mvp.view) * light_data.u_lightDir.xyz); float NdotL = max( 0.0, dot( normalV, lightV ) ); lightCol += NdotL * light_data.u_diffuse * color; // specular part vec3 eyeV = normalize( -objPosEs ); vec3 halfV = normalize( eyeV + lightV ); float NdotH = max( 0.0, dot( normalV, halfV ) ); float kSpecular = ( light_data.u_shininess + 2.0 ) * pow( NdotH, light_data.u_shininess ) / ( 2.0 * 3.14159265 ); lightCol += kSpecular * light_data.u_specular * color; fragColor = vec4( lightCol.rgb, 1.0 ); vec4 proj_pos_displ = mvp.proj * vec4(view_pos_displ.xyz, 1.0); float depth = 0.5 + 0.5 * proj_pos_displ.z / proj_pos_displ.w; gl_FragDepth = depth; //#define DEBUG_FRONT_SILHOUETTES //#define DEBUG_BACK_SILHOUETTES //#define DEBUG_DEPTH #if defined(DEBUG_FRONT_SILHOUETTES) if ( texCoords.p < 0.0001 ) discard; if ( in_data.d.z < 0.0 ) discard; fragColor = vec4(vec2(in_data.d.xy-df), in_data.d.z, 1.0); //fragColor = vec4(vec2(d1), in_data.d.z, 1.0); #endif #if defined(DEBUG_BACK_SILHOUETTES) if ( texCoords.p < 0.0001 ) discard; if ( in_data.d.z > 0.0 ) discard; fragColor = vec4(vec2(df-in_data.d.xy), -in_data.d.z, 1.0); //fragColor = vec4(vec2(-d0), -in_data.d.z, 1.0); #endif #if defined(DEBUG_DEPTH) fragColor = vec4( vec3(1.0-depth), 1.0 ); #endif }"; this._parallax_prog = openGLFactory.VertexGeometryFragmentShaderProgram(vert_shader, geo_shader, frag_shader); this._parallax_prog.Generate(); // Model view projection shader storage block objects and buffers TMVP mvp = new TMVP(Matrix4.Identity, Matrix4.Identity, Matrix4.Identity); this._mvp_ssbo = openGLFactory.NewStorageBuffer(); this._mvp_ssbo.Create(ref mvp); this._mvp_ssbo.Bind(1); TLightSource light_source = new TLightSource(new Vector4(-1.0f, -0.5f, -2.0f, 0.0f), 0.2f, 0.8f, 0.8f, 10.0f); this._light_ssbo = openGLFactory.NewStorageBuffer(); this._light_ssbo.Create(ref light_source); this._light_ssbo.Bind(2); // states GL.Viewport(0, 0, this._cx, this._cy); //GL.ClearColor(System.Drawing.Color.Beige); GL.ClearColor(0.2f, 0.3f, 0.3f, 1.0f); GL.Enable(EnableCap.DepthTest); // no face culling, because of clipping //GL.Enable(EnableCap.CullFace); GL.FrontFace(FrontFaceDirection.Ccw); GL.CullFace(CullFaceMode.Back); // matrices and controller this._view = Matrix4.LookAt(0.0f, 0.0f, 2.5f, 0, 0, 0, 0, 1, 0); float angle = 90.0f * (float)Math.PI / 180.0f; float aspect = (float)this._cx / (float)this._cy; this._projection = Matrix4.CreatePerspectiveFieldOfView(angle, aspect, 0.1f, 100.0f); this._spin = new ModelSpinningControls( () => { return(this._period); }, () => { return(new float[] { 0, 0, (float)this._cx, (float)this._cy }); }, () => { return(this._view); } ); this._spin.SetAttenuation(1.0f, 0.05f, 0.0f); // properties ViewModel.HeightScale = 50; ViewModel.QualityScale = 50; ViewModel.ClipScale = 50; }