From e644ab3be72d6904f5810a1ebcd8b63d7378a94d Mon Sep 17 00:00:00 2001 From: Chris Rorden Date: Wed, 21 Mar 2018 10:07:16 -0400 Subject: [PATCH] Curvature based gaps --- .DS_Store | Bin 32772 -> 32772 bytes colorTable.pas | 44 ++- curv.pas | 30 +- mainunit.pas | 2 +- mesh.pas | 46 ++- meshify_marchingcubes.pas | 7 - mz3/README.md | 3 +- prefs.pas | 4 +- shaderu.pas | 2 - .../Contents/Resources/shaders/HideCurves.txt | 119 ++++++ surfice.lps | 356 +++++++++++------- 11 files changed, 417 insertions(+), 196 deletions(-) create mode 100755 surfice.app/Contents/Resources/shaders/HideCurves.txt diff --git a/.DS_Store b/.DS_Store index 2d213248071b1bad96b6bf7c5e821ab38942e889..ed3edf4a2d4ce026a1a25de2508e8f97e2578f1b 100755 GIT binary patch delta 69 zcmZo^U}|Y#+OXYX@-Cz4QsULsrUp6+Mn<(d3e|=N<|aA{=B6gKwE}A=zi}|1Jm2yc X6XWmAz8e?Gh&dQJoV% diff --git a/colorTable.pas b/colorTable.pas index e31c9d0..346319d 100755 --- a/colorTable.pas +++ b/colorTable.pas @@ -261,31 +261,33 @@ function makeLUT(var lIndex: integer): TLUTnodes; setNode(255,192,0,52,192, 5, result); setNode(255,3,0,80,255, 6, result); end; - 15: begin //FreeSurferCurve - center dark + 15: begin //FreeSurferCurve - valleys dark result.isFreeSurfer:= true; - setNode(0,0,0,0,0, 0, result); - setNode(0,0,0,128,40,1, result); - setNode(0,0,0,128,215,2, result); - setNode(0,0,0,0,255, 3, result); + setNode(0,0,0,0,0, 0, result); + setNode(0,0,0,0,156, 1, result); + setNode(0,0,0,255,255, 2, result); + end; - 16: begin //FreeSurferCurve - center transparent + 16: begin //FreeSurferCurve - curves (valleys and ridges) dark result.isFreeSurfer:= true; - setNode(0,0,0,128,0, 0, result); - setNode(0,0,0,0, 40,1, result); - setNode(0,0,0,0, 215,2, result); - setNode(0,0,0,128,255, 3, result); + setNode(0,0,0,255,0, 0, result); + setNode(0,0,0,0,100, 1, result); + setNode(0,0,0,0,156, 2, result); + setNode(0,0,0,255,255, 3, result); end; - 17: begin //FreeSurferCurve - center dark + 17: begin //FreeSurferCurve - flat surfaces darkened result.isFreeSurfer:= true; setNode(0,0,0,0,0, 0, result); - setNode(0,0,0,148,128,1, result); - setNode(0,0,0,0,255, 2, result); + setNode(0,0,0,0,100, 1, result); + setNode(0,0,0,255,128, 2, result); + setNode(0,0,0,0,156, 3, result); + setNode(0,0,0,0,255, 4, result); end; - 18: begin //FreeSurferCurve - center transparent + 18: begin //FreeSurferCurve - ridges dark result.isFreeSurfer:= true; - setNode(0,0,0,148,0, 0, result); - setNode(0,0,0,0,128,1, result); - setNode(0,0,0,148,255, 2, result); + setNode(0,0,0,255,0, 0, result); + setNode(0,0,0,0,100,1, result); + setNode(0,0,0,0,255, 2, result); end; else begin result := loadCustomLUT(lIndex); //index unknown!!! @@ -332,7 +334,13 @@ function UpdateTransferFunction (var lIndex: integer; isInvert: boolean): TLUT;/ result[0].A := rev[0].A; result[255].A := rev[255].A; end; - if lLUTNodes.isFreeSurfer then exit; //not for freesurfer + if lLUTNodes.isFreeSurfer then begin + //result[255].R := 0; + //result[255].G := 0; + //result[255].B := 0; + //result[255].A := 255;//result[254].A; + exit; //not for freesurfer + end; //result[0].A := 0; //see LUT[0].A <> 0 for lInc := 1 to 255 do result[lInc].A := 255; diff --git a/curv.pas b/curv.pas index 9b27dce..ce2a78f 100644 --- a/curv.pas +++ b/curv.pas @@ -3,7 +3,7 @@ interface uses define_types, matmath, sysutils, Dialogs; -procedure GenerateCurv(fnm: string; var faces: TFaces; vertices: TVertices); +procedure GenerateCurv(fnm: string; var faces: TFaces; vertices: TVertices; isSmooth: boolean); implementation @@ -71,41 +71,42 @@ procedure SaveCurv(fnm: string; k: TFloats; num_f: integer); end; end; -(*procedure SmoothK (var vK : TFloats; var faces: TFaces); +procedure SmoothK (var vK : TFloats; var faces: TFaces); //smooth curvature across neighbors //vK : one curvature value k for each vertex, faces: triangle face indices var - tK: TFloats; + inK: TFloats; nK : array of integer; i, num_v, x, y, z: integer; begin num_v := length(vK); - setlength(tK, num_v); + setlength(inK, num_v); setlength(nK, num_v); - tK := Copy(vK, Low(vK), num_v); + //tK := Copy(vK, Low(vK), num_v); for i := 0 to (num_v-1) do begin + inK[i] := vK[i]; vK[i] := 0; nK[i] := 0; end; for i := 0 to (length(faces)-1) do begin //compute the normal for each face X := faces[i].X; - Y := faces[i].X; - Z := faces[i].X; + Y := faces[i].Y; + Z := faces[i].Z; nK[X] := nK[X] + 1; nK[Y] := nK[Y] + 1; nK[Z] := nK[Z] + 1; - vK[X] := vK[X] + tK[X]; - vK[Y] := vK[Y] + tK[Y]; - vK[Z] := vK[Z] + tK[Z]; + vK[X] := vK[X] + inK[X]; + vK[Y] := vK[Y] + inK[Y]; + vK[Z] := vK[Z] + inK[Z]; end; - setlength(tK, 0); + setlength(inK, 0); for i := 0 to (num_v-1) do if nK[i] > 1 then vK[i] := vK[i] / nK[i]; setlength(nK, 0); -end; *) +end; -procedure GenerateCurv(fnm: string; var faces: TFaces; vertices: TVertices); +procedure GenerateCurv(fnm: string; var faces: TFaces; vertices: TVertices; isSmooth: boolean); var vNorm : array of TPoint3f; vK : TFloats; @@ -162,7 +163,8 @@ procedure GenerateCurv(fnm: string; var faces: TFaces; vertices: TVertices); vK[i] := vK[i]/vnK[i]; end; //optional: smooth curves - //SmoothK (vK, faces); + if (isSmooth) then + SmoothK (vK, faces); //normalize curvature from mx := vK[0]; for i := 0 to (length(vertices)-1) do diff --git a/mainunit.pas b/mainunit.pas index 4a1e57e..dc54c05 100755 --- a/mainunit.pas +++ b/mainunit.pas @@ -2936,7 +2936,7 @@ procedure TGLForm1.CurvMenuClick(Sender: TObject); showmessage('File already exists '+fnm); exit; end; - GenerateCurv(fnm, gMesh.faces, gMesh.vertices); + GenerateCurv(fnm, gMesh.faces, gMesh.vertices, gPrefs.GenerateSmoothCurves); OpenOverlay(fnm); if isTemp then deletefile(fnm); diff --git a/mesh.pas b/mesh.pas index 00bb8dd..b9bf1a6 100755 --- a/mesh.pas +++ b/mesh.pas @@ -159,7 +159,7 @@ implementation mainunit, meshify_simplify,shaderu, {$IFDEF COREGL} gl_core_3d {$ELSE} gl_legacy_3d {$ENDIF}; -{$IFDEF COREGL} +//{$IFDEF COREGL} function mixRGBA(c1, c2: TRGBA; frac2: single): TRGBA; var frac1: single; @@ -170,7 +170,7 @@ function mixRGBA(c1, c2: TRGBA; frac2: single): TRGBA; result.G := round(c1.G*frac1 + c2.G*frac2); result.B := round(c1.B*frac1 + c2.B*frac2); end; -{$ENDIF} +//{$ENDIF} procedure AddPt4f(var v: TPoint4f; c1,c2,c3: TRGBA); //create float vector begin @@ -247,6 +247,7 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v for i := 0 to (length(v)-1) do vRGBA[i] := blendRGBA(vRGBA[i],vRGBAmx[i]); end else begin + //GLForm1.caption := 'xxxxx'+(inttostr(vRGBA[i].A)); for c := OpenOverlays downto 1 do begin if (overlay[c].LUTvisible <> kLUTinvisible) and (length(overlay[c].intensity) = length(v)) then begin if overlay[c].LUTvisible <> kLUTopaque then @@ -321,17 +322,33 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v for i := 0 to (length(v)-1) do vRGBA[i] := mixRGBA( Clr, vRGBA[i], mx); {$ELSE} //with old GLSL we mix in the shader - if (OverlayTransparency > 0 ) and (OverlayTransparency <= 100) then - for i := 0 to (length(v)-1) do + if (OverlayTransparency > 0 ) and (OverlayTransparency <= 100) then begin + for i := 0 to (length(v)-1) do vRGBA[i].a := round( vRGBA[i].a * (1 - (OverlayTransparency /100)) ); + end; {$ENDIF} end; // if OpenOverlays > 0 {$IFDEF COREGL} + //the purpose of the next loop is to allow us to hide curvature + for c := OpenOverlays downto 1 do begin + if isFreeSurferLUT(overlay[c].LUTindex) then begin + for i := 0 to (length(v)-1) do begin + mn := ((overlay[c].intensity[i] + 1.0) * 0.5); //convert curvature to range 0..1 + if (mn < 0) then mn := 0; + if (mn > 1) then mn := 1; + mn := mn * 255.0; + vRGBA[i].A := round(mn); + end; + end; + end; //for c + {$ENDIF} + {$IFDEF COREGL} BuildDisplayList(f, v, vRGBA, vao, vbo, Clr); {$ELSE} displayList:= BuildDisplayList(f, v, vRGBA); {$ENDIF} end else begin + Clr.A := 128; //just a bit less than 50% - only for hiding curvature setLength(vRGBA,0); {$IFDEF COREGL} BuildDisplayList(f, v, vRGBA,vao, vbo, Clr); @@ -5636,6 +5653,7 @@ procedure TMesh.LoadCurv(const FileName: string; lOverlayIndex: integer); var f: File; i, sz: integer; + mn,mx: single; num_v, num_f, ValsPerVertex : LongWord; sig : array [1..3] of byte; begin @@ -5672,6 +5690,17 @@ procedure TMesh.LoadCurv(const FileName: string; lOverlayIndex: integer); SwapSingle(overlay[lOverlayIndex].intensity[i]); //Curv files are ALWAYS big endian {$ENDIF} CloseFile(f); + //normalize intensity + mn := overlay[lOverlayIndex].intensity[0]; + mx := mn; + for i := 0 to (num_v-1) do begin + if (overlay[lOverlayIndex].intensity[i] > mx) then mx := overlay[lOverlayIndex].intensity[i]; + if (overlay[lOverlayIndex].intensity[i] < mn) then mn := overlay[lOverlayIndex].intensity[i]; + end; + if (mn = mx) or (mx < 0) or (mn > 0) then exit; + if abs(mn) > mx then mx := abs(mn); + for i := 0 to (num_v-1) do + overlay[lOverlayIndex].intensity[i] := overlay[lOverlayIndex].intensity[i] / mx; end; // LoadCurv() function fread3 (var f: File): LongWord; @@ -6039,12 +6068,10 @@ function TMesh.LoadOverlay(const FileName: string; lLoadSmooth: boolean): boolea end; end else nOverlays := 1; - if (length(overlay[OpenOverlays].faces) < 1 ) and (length(overlay[OpenOverlays].intensity) < 1 ) then begin //unable to open as an overlay - perhaps vertex colors? OpenOverlays := OpenOverlays - 1; exit; end; - end; if not isCiftiNii then begin {$IFDEF FOREIGNVOL} @@ -6063,14 +6090,15 @@ function TMesh.LoadOverlay(const FileName: string; lLoadSmooth: boolean): boolea if (length(overlay[OpenOverlays].intensity) > 0 ) then Overlay[OpenOverlays].LUTindex := 15;//CURV file end; - if (length(overlay[OpenOverlays].intensity) < 1 ) then begin LoadMeshAsOverlay(FileName, OpenOverlays); end else SetOverlayDescriptives(OpenOverlays); if isFreeSurferLUT(Overlay[OpenOverlays].LUTindex) then begin //CURV file - Overlay[OpenOverlays].windowScaledMin:= 0.0;//-0.1; - Overlay[OpenOverlays].windowScaledMax := 0.8; + Overlay[OpenOverlays].windowScaledMin := -0.6; + Overlay[OpenOverlays].windowScaledMax := 0.6; + //Overlay[OpenOverlays].windowScaledMin:= 0.0;//-0.1; + //Overlay[OpenOverlays].windowScaledMax := 1.0;//0.8; end; Overlay[OpenOverlays].LUT := UpdateTransferFunction (Overlay[OpenOverlays].LUTindex, Overlay[OpenOverlays].LUTinvert); //set color scheme isRebuildList := true; diff --git a/meshify_marchingcubes.pas b/meshify_marchingcubes.pas index b771f0b..ba4382f 100755 --- a/meshify_marchingcubes.pas +++ b/meshify_marchingcubes.pas @@ -1,4 +1,3 @@ - // // This unit is part of the GLScene Project, http://glscene.org // {: GLIsosurface

@@ -82,13 +81,7 @@ TIsoSurfaceExtractor = class(TObject) out Triangles: TFaces); end; -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- implementation -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- -//------------------------------------------------------------------------- const diff --git a/mz3/README.md b/mz3/README.md index bcf9c22..1133f64 100755 --- a/mz3/README.md +++ b/mz3/README.md @@ -19,7 +19,8 @@ The MZ3 format is the internal file format for Surfice. The goals are to be simp - If BOTH isSCALAR and isRGBA: both values are stored in the file. However, in this case the mesh is assumed to be a template. The RGBA colors refer to the color of the region, and the scalar intensity value refers to the region number. In this case, one expects the scalar values can be losslessly converted to integers. In other words, one expects the template to have regions `17` and `18`, but one does not expect a region `17.2`. - Files can store isSCALAR without having any other data. Since these files do not report vertex position or face indexing, they must be viewed with a corresponding mesh that includes these values. An example includes a [Gaussian curvature](https://en.wikipedia.org/wiki/Gaussian_curvature) measurement. Further, statistics might produce separate isSCALAR files for every contrast: for example consider a brain activation study where we produce statistical maps for both left hand movements relative to rest and right hand movements relative to rest. This would produce two statistical maps that are likely to contain some overlap (e.g. some brain regions are only used by one task, but others are involved with moving either hand). - The format does not store vertex normals. It is typically straightforward to compute these based on the mesh (though see next bullet point for potential issues with per-face colors). - - The format only allows per-vertex colors. This is typical for shader-based per-pixel interpolation. However, if per-face colors are desired one will have to create replicated vertices. For example, a cube with per-vertex colors can be saved as 8 vertices. However, if one wants each face of the cube to have a single unique color, one must save 24 faces (four for each of the six faces). Be aware that using per-face colors may influence the surface normal estimation, depending on the visualization software. If the software does not remove the duplicated vertices when computing normals you will get [jagged per-facet normals rather than smooth per pixel normals](https://www.scratchapixel.com/lessons/3d-basic-rendering/introduction-to-shading/shading-normals). For an example of per-face colors see the mesh 7ColoredMeshPerFace.mz3 described below. + - The format only allows per-vertex colors. This is typical for shader-based per-pixel interpolation. However, if per-face colors are desired one will have to create replicated vertices. For example, a cube with per-vertex colors can be saved as 8 vertices. However, if one wants each face of the cube to have a single unique color, one must save 24 faces (four for each of the six faces). Be aware that using per-face colors may influence the surface normal estimation, depending on the visualization software. If the software does not remove the duplicated vertices when computing normals you will get [jagged per-facet normals rather than smooth per pixel normals](https://www.scratchapixel.com/lessons/3d-basic-rendering/introduction-to-shading/shading-normals). For an example of per-face colors see the mesh 7ColoredMeshPerFace.mz3 described below (and created by the included Matlab software). + - The format requires all faces to be triangles: quads and ngons are not allowed. First, the creation of MRI based meshes traditionally creates triangulated meshes (e.g. marching cubes and marching tetrahedra). Further, Any triangle formed from three non-colinear points necessarily define one plane, wheres the four points that form a quad are not necessarily coplanar. As an analogy: a stool with four legs can rock if one leg is short, whereas a stool with three legs will not. For this reason, quads and ngons are not natively supported by modern graphics cards (they are simulated using triangles). While triangles are the required format for native display, storing quad information can be useful: for example subdivision in Blender can be nicer if applied to quad meshes. The mz3 format is ideal for getting data from MRI algorithms and final optimized display. However, it may be useful to convert triangles to quads while editing the meshes with Blender. Future versions of the mz3 format could handle quads by having a face repeat the same index three times - this would indicate that the vertex forms a quad when combined with the three vertices of the previous face. - File consistency checks. The following rules help identify invalid mz3 files: - isFACE and isTRUE always have the same value. If both are true, the file contains mesh geometry (the vertices and face indices). If both are false, the file only contains vertex scalars/colors (e.g. it is a statistical map or curvature file designed to be overlayed on top of a mesh). In theory, one could store a point cloud in an mz3 file by storing vertices without any faces. However, in practice mz3 files are assumed to store triangular meshes. - If isFACE is true, then NFACE must be at least 1. The minimum mesh has one triangle. diff --git a/prefs.pas b/prefs.pas index 82b5c2b..7521a76 100755 --- a/prefs.pas +++ b/prefs.pas @@ -22,7 +22,7 @@ TPrefs = record SmoothVoxelwiseData, OverlayClip, StartupScript, SupportBetterRenderQuality, AdditiveOverlay,Perspective, OrientCube, MultiSample, Colorbar,TracksAreTubes, ScreenCaptureTransparentBackground,LoadTrackOnLaunch,ColorBarPrecedenceTracksNotOverlays, - ZDimIsUp, ShaderForBackgroundOnly, CoreTrackDisableDepth, SkipPrefWriting, isFlipMeshOverlay, RetinaDisplay : boolean; + ZDimIsUp, ShaderForBackgroundOnly, CoreTrackDisableDepth, SkipPrefWriting, isFlipMeshOverlay, RetinaDisplay, GenerateSmoothCurves : boolean; TrackTubeSlices, ScreenCaptureZoom,ColorbarColor,ColorBarPosition, window_width, window_height, RenderQuality, SaveAsFormat,SaveAsFormatTrack, OcclusionAmount: integer; ObjColor,BackColor: TColor; @@ -322,6 +322,7 @@ procedure SetDefaultPrefs (var lPrefs: TPrefs; lEverything, askUserIfMissing: b ColorbarColor := 4; ColorBarPosition := 3; ZDimIsUp := true; + GenerateSmoothCurves := true; ShaderForBackgroundOnly := false; CoreTrackDisableDepth := false; LoadTrackOnLaunch := false; @@ -605,6 +606,7 @@ function IniFile(lRead: boolean; lFilename: string; var lPrefs: TPrefs): boolean //IniBool(lRead,lIniFile, 'SaveAsObj',lPrefs.SaveAsObj); IniBool(lRead,lIniFile, 'TracksAreTubes',lPrefs.TracksAreTubes); IniBool(lRead,lIniFile, 'ZDimIsUp',lPrefs.ZDimIsUp); + IniBool(lRead,lIniFile,'GenerateSmoothCurves',lPrefs.GenerateSmoothCurves); //IniBool(lRead,lIniFile, 'ShaderForBackgroundOnly',lPrefs.ShaderForBackgroundOnly); IniBool(lRead,lIniFile, 'CoreTrackDisableDepth',lPrefs.CoreTrackDisableDepth); IniBool(lRead,lIniFile, 'LoadTrackOnLaunch',lPrefs.LoadTrackOnLaunch); diff --git a/shaderu.pas b/shaderu.pas index 91b1a97..967efb4 100755 --- a/shaderu.pas +++ b/shaderu.pas @@ -1125,8 +1125,6 @@ function LoadShader(lFilename: string; var Shader: TShader): boolean; kFragBOM = kBOM + kFragStr; kGeomStr = '//geom'; kGeomBOM = kBOM + kGeomStr; - //kAOStr = '//AOradius'; - //kAOBOM = kBOM + kAOStr; var mode: integer; F : TextFile; diff --git a/surfice.app/Contents/Resources/shaders/HideCurves.txt b/surfice.app/Contents/Resources/shaders/HideCurves.txt new file mode 100755 index 0000000..ecb5346 --- /dev/null +++ b/surfice.app/Contents/Resources/shaders/HideCurves.txt @@ -0,0 +1,119 @@ +//pref +Ambient|float|0.0|0|1 +Diffuse|float|0.0|1|2 +Specular|float|0.0|0.25|1 +SpecularRough|float|0.01|0.05|1 +Edge|float|0|0.05|1.0 +CurvThreshLo|float|0.0|0.0|1.0 +CurvThreshHi|float|0.0|0.51|1.0 +Use Advanced/ComputeCurvature and then adjust the CurvThresh.|note +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec3 Norm; +layout(location = 6) in vec4 Clr; +out vec3 vN, vL, vV; +out vec4 vClr, vP; +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ModelViewMatrix; +uniform mat3 NormalMatrix; +uniform vec3 LightPos = vec3(0.0, 20.0, 30.0); //LR, -DU+, -FN+ +void main() { + vN = normalize((NormalMatrix * Norm)); + vP = vec4(Vert, 1.0); + gl_Position = ModelViewProjectionMatrix * vec4(Vert, 1.0); + vL = normalize(LightPos); + vV = -vec3(ModelViewMatrix*vec4(Vert,1.0)); + vClr = Clr; +} +//frag +#version 330 +in vec4 vClr, vP; +in vec3 vN, vL, vV; +out vec4 color; +uniform float Ambient = 0.5; +uniform float Diffuse = 0.7; +uniform float Specular = 0.2; +uniform float SpecularRough = 0.05; +uniform float Edge = 0.05; +uniform float CurvThreshLo = 0.0; +uniform float CurvThreshHi = 0.51; +uniform vec4 ClipPlane = vec4(2.0, 0.0, 0.0, 0.0); + +//Spherical harmonics constants +const float C1 = 0.429043; +const float C2 = 0.511664; +const float C3 = 0.743125; +const float C4 = 0.886227; +const float C5 = 0.247708; + +//Spherical harmonics coefficients +// Ramamoorthi, R., and P. Hanrahan. 2001b. "An Efficient Representation for Irradiance Environment Maps." In Proceedings of SIGGRAPH 2001, pp. 497–500. +// https://github.com/eskimoblood/processingSketches/blob/master/data/shader/shinyvert.glsl +// https://github.com/eskimoblood/processingSketches/blob/master/data/shader/shinyvert.glsl +// See table on page 397 of OpenGL programming Guide, 8th Edition Shreiner et al. + +// Constants for Old Town Square lighting +const vec3 L00 = vec3( 0.871297, 0.875222, 0.864470); +const vec3 L1m1 = vec3( 0.175058, 0.245335, 0.312891); +const vec3 L10 = vec3( 0.034675, 0.036107, 0.037362); +const vec3 L11 = vec3(-0.004629, -0.029448, -0.048028); +const vec3 L2m2 = vec3(-0.120535, -0.121160, -0.117507); +const vec3 L2m1 = vec3( 0.003242, 0.003624, 0.007511); +const vec3 L20 = vec3(-0.028667, -0.024926, -0.020998); +const vec3 L21 = vec3(-0.077539, -0.086325, -0.091591); +const vec3 L22 = vec3(-0.161784, -0.191783, -0.219152); + +// Constants for Eucalyptus Grove lighting +/*const vec3 L00 = vec3( 0.3783264, 0.4260425, 0.4504587); +const vec3 L1m1 = vec3( 0.2887813, 0.3586803, 0.4147053); +const vec3 L10 = vec3( 0.0379030, 0.0295216, 0.0098567); +const vec3 L11 = vec3(-0.1033028, -0.1031690, -0.0884924); +const vec3 L2m2 = vec3(-0.0621750, -0.0554432, -0.0396779); +const vec3 L2m1 = vec3( 0.0077820, -0.0148312, -0.0471301); +const vec3 L20 = vec3(-0.0935561, -0.1254260, -0.1525629); +const vec3 L21 = vec3(-0.0572703, -0.0502192, -0.0363410); +const vec3 L22 = vec3( 0.0203348, -0.0044201, -0.0452180);*/ + +vec3 SH(vec3 vNormal) +{ + vNormal = vec3(vNormal.x,vNormal.z,-vNormal.y); + vec3 diffuseColor = C1 * L22 * (vNormal.x * vNormal.x - vNormal.y * vNormal.y) + + C3 * L20 * vNormal.z * vNormal.z + + C4 * L00 - + C5 * L20 + + 2.0 * C1 * L2m2 * vNormal.x * vNormal.y + + 2.0 * C1 * L21 * vNormal.x * vNormal.z + + 2.0 * C1 * L2m1 * vNormal.y * vNormal.z + + 2.0 * C2 * L11 * vNormal.x + + 2.0 * C2 * L1m1 * vNormal.y + + 2.0 * C2 * L10 * vNormal.z; + return diffuseColor; +} + +vec3 desaturate(vec3 color, float amount) { + vec3 gray = vec3(dot(vec3(0.2126,0.7152,0.0722), color)); + return vec3(mix(color, gray, amount)); +} + +void main() { + if ((ClipPlane[0] < 1.5) && (dot( ClipPlane, vP) > 0.0)) discard; + if ((vClr.a < CurvThreshLo) || (vClr.a > CurvThreshHi)) discard; + vec3 l = normalize(vL); + vec3 n = normalize(vN); + vec3 v = normalize(vV); + vec3 h = normalize(l+v); + vec3 a = vClr.rgb; + vec3 d = a * Diffuse; + a *= Ambient; + vec3 backcolor = desaturate(0.75 * a + 0.75 * d * abs(dot(n,l)), 0.5); + d *= SH(-reflect(n, l) ); + float specular = max(0.0,dot(n,h)); + specular = pow(specular, 1.0/(SpecularRough * SpecularRough)); + color = vec4(a + d + specular* Specular, 1.0); + float edge =((max(dot(n,normalize(vV)), 0.0) - 0.5) * Edge) + 1.0; + edge = min(1.0, edge); + color.rgb *= edge; + float backface = step(0.0, n.z); + color = vec4(mix(backcolor.rgb, color.rgb, backface), 1.0); +} \ No newline at end of file diff --git a/surfice.lps b/surfice.lps index 1bef203..70f54d8 100644 --- a/surfice.lps +++ b/surfice.lps @@ -3,7 +3,7 @@ - + @@ -17,8 +17,8 @@ - - + + @@ -36,105 +36,109 @@ - - - - + + + + - + - - - + + + + - + - + - + - + - + - + - + - - - - + + + + + + - + - - - - + + + + + - + - + @@ -145,236 +149,302 @@ - + - + - + - - - - - - - - - - + + + - - + + - - + + + - - - + + + - + + + + + + + + + - - - - - - - - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - + - - - + + + - - - + + + - - - - - - - - - - - - - + + + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + - + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +