diff --git a/colorTable.pas b/colorTable.pas index 7626ea2..ff061da 100755 --- a/colorTable.pas +++ b/colorTable.pas @@ -8,6 +8,11 @@ interface const //maximum number of control points for color schemes... maxNodes = 32; + kPaintHideDefaultBehavior = -1; + kPaintHideDarkHideBright = 0; + kPaintHideDarkShowBright = 1; + kPaintShowDarkHideBright = 2; + kPaintShowDarkShowBright = 3; type @@ -22,7 +27,9 @@ function UpdateTransferFunction (var lIndex: integer; isInvert: boolean): TLUT;/ function CLUTDir: string; function blendRGBA(c1, c2: TRGBA ): TRGBA; function maxRGBA(c1, c2: TRGBA ): TRGBA; -function inten2rgb(intensity, mn, mx: single; lut: TLUT): TRGBA; +//function inten2rgb(intensity, mn, mx: single; lut: TLUT): TRGBA; +function inten2rgb(intensity, mn, mx: single; lut: TLUT; mode: integer): TRGBA; overload; +//function inten2rgb(intensity, mn, mx: single; lut: TLUT): TRGBA; overload; function inten2rgb1(intensity, mn, mx: single; lut: TLUT): TRGBA; //use 1st not 0th LUT color (0 is transparent) function desaturateRGBA ( rgba: TRGBA; frac: single; alpha: byte): TRGBA; function isFreeSurferLUT(lIndex: integer): boolean; @@ -69,7 +76,44 @@ function maxRGBA(c1, c2: TRGBA ): TRGBA; result.A := c2.A; end; -function inten2rgb(intensity, mn, mx: single; lut: TLUT): TRGBA; + + +function inten2rgb(intensity, mn, mx: single; lut: TLUT; mode: integer): TRGBA; overload; +var + i: byte; + isInvert : boolean; +begin + if (mn < 0) and (mx < 0) and (mode = kPaintHideDefaultBehavior) then begin + if intensity >= mx then + exit( lut[0]) + else if intensity <= mn then + exit( lut[255]) + else + exit( lut[round(255* (1.0- (intensity-mn)/(mx-mn)))]); + end; + if intensity > mx then begin + i := 255; + if (mode = kPaintHideDarkHideBright) or (mode = kPaintShowDarkHideBright) then //hide bright + i := 0; + end else if intensity < mn then begin + i := 0; + if (mode = kPaintShowDarkHideBright) or (mode = kPaintShowDarkShowBright) then //hide dark + i := 1; + end else begin + i := round(255*(intensity-mn)/(mx-mn)); + if (i = 0) and ((mode = kPaintHideDefaultBehavior) or (mode = kPaintShowDarkHideBright) or (mode = kPaintShowDarkShowBright)) then //hide dark + i := 1; + end; + result := lut[i]; +end; + +function inten2rgb(intensity, mn, mx: single; lut: TLUT): TRGBA; overload; +begin + //result := inten2rgb(intensity, mn, mx, lut, kPaintHideDefaultBehavior); + result := inten2rgb(intensity, mn, mx, lut,kPaintHideDarkHideBright); +end; + +(*function inten2rgb(intensity, mn, mx: single; lut: TLUT): TRGBA; begin if (mn < 0) and (mx < 0) then begin if intensity >= mx then begin @@ -91,7 +135,7 @@ function inten2rgb(intensity, mn, mx: single; lut: TLUT): TRGBA; else result := lut[round(255*(intensity-mn)/(mx-mn))]; end; -end; +end; *) function inten2rgb1(intensity, mn, mx: single; lut: TLUT): TRGBA; //use 1st not 0th LUT color (0 is transparent) var i :integer; diff --git a/define_types.pas b/define_types.pas index ced7158..bc3581d 100755 --- a/define_types.pas +++ b/define_types.pas @@ -7,7 +7,7 @@ interface {$endif} const - kVers = 'v1.0.20190518'; + kVers = 'v1.0.20190707'; NaN : double = 1/0; kTab = chr(9); kCR = chr (13); diff --git a/glclrbar.pas b/glclrbar.pas index ea6e103..2ee7505 100644 --- a/glclrbar.pas +++ b/glclrbar.pas @@ -6,6 +6,7 @@ interface uses + {$IFNDEF OLD}graphTicks, {$ENDIF} {$IFDEF COREGL}shaderu,glcorearb, gl_core_matrix, {$ELSE}gl, glext, {$ENDIF} glmtext,Classes, SysUtils, Graphics, OpenGLContext, math, dialogs, define_types,colorTable; @@ -322,6 +323,7 @@ function fRemainder(const a,b:double):double; end; +{$IFDEF OLD} type TTicks = record stepSize, remainder: single; @@ -374,12 +376,18 @@ function setStepSizeForce(lRange: double; lDesiredSteps: integer): TTicks; if result.remainder < (0.001* result.stepSize) then result.remainder := 0; end; +{$ENDIF} procedure TGLClrbar.CreateTicksText(mn,mx: single; BarLength, BarTop, BarThick, fntScale: single); var lStep,lRange, t, MarkerSzX,MarkerSzY, lPosX, lPosY, StWid: double; isInvert: boolean; + {$IFDEF OLD} tic, ticAlt: TTicks; + {$ELSE} + stepSize: double; + ticDecimals: integer; + {$ENDIF} St: string; begin if (mx = mn) or (BarThick = 0) or (BarLength = 0) then exit; @@ -404,6 +412,7 @@ procedure TGLClrbar.CreateTicksText(mn,mx: single; BarLength, BarTop, BarThick, lRange := max(abs(mn),mx);// + (0.5 * min(abs(mn),mx)); if lRange < 0.000001 then exit; //glform1.caption := inttostr(random(888))+' '+floattostr(min(abs(mn),mx) / lRange); + {$IFDEF OLD} if ((mn < 0) and (mx > 0)) and ((min(abs(mn),mx)/lRange) > 0.65) then begin tic := setStepSize(lRange, 2); //now try forcing other values @@ -435,6 +444,10 @@ procedure TGLClrbar.CreateTicksText(mn,mx: single; BarLength, BarTop, BarThick, //if (rem < (lStepSize * 0.001)) then //e.g. 0.2..3.0 can be evenly spanned // lStep := mn; if (lStep < (mn)) and ((mn -lStep) > (lStep * 0.001) ) then lStep := lStep+tic.stepSize; + {$ELSE} + SelectTicks(mn, mx, lStep, stepSize, ticDecimals); + {$ENDIF} + lRange := abs(mx - mn); //full range, in case mn < 0 and mx > 0 nglColor4ub (FontClr.r,FontClr.g,FontClr.b,255);//outline repeat @@ -459,15 +472,25 @@ procedure TGLClrbar.CreateTicksText(mn,mx: single; BarLength, BarTop, BarThick, nglVertex2fr(lPosX+MarkerSzX,lPosY+MarkerSzY); nglEnd; if fntScale > 0 then begin + {$IFDEF OLD} St := FloatToStrF(lStep, ffFixed,7,tic.decimals); + {$ELSE} + St := FloatToStrF(lStep, ffFixed,7,ticDecimals); + {$ENDIF} StWid := Txt.TextWidth(fntScale, St); if not fisVertical then Txt.TextOut(lPosX-(StWid*0.5),BarTop-(BarThick*0.88),fntScale, St) else Txt.TextOut(lPosX+(BarThick*0.88),lPosY-(StWid*0.5),fntScale,90, St) end; - lStep := lStep + tic.stepSize; + {$IFDEF OLD} + lStep := lStep + tic.stepSize; until lStep > (mx+(tic.stepSize*0.01)); + {$ELSE} + lStep := lStep + stepSize; + until lStep > (mx+(stepSize*0.01)); + {$ENDIF} + end; //CreateTicksText() procedure TGLClrbar.CreateClrbar; diff --git a/graphticks.pas b/graphticks.pas new file mode 100644 index 0000000..f90b666 --- /dev/null +++ b/graphticks.pas @@ -0,0 +1,175 @@ +unit graphTicks; + +{$mode objfpc}{$H+} + +interface + +procedure SelectTicks(mn, mx: double; out ticMin, ticStep: double; out ticDecimals: integer); + +implementation + +uses + //Dialogs, SysUtils, + Math; + +function tickSpacing(tickCount: integer; mn, mx: double; out ticMin: double): double; +//https://stackoverflow.com/questions/326679/choosing-an-attractive-linear-scale-for-a-graphs-y-axis +var + pow10x, x, range, unroundedTickSize: double; +begin + ticMin := mn; + range := abs(mx-mn); + if range = 0.0 then exit(0); + unroundedTickSize := range/(tickCount-1); + x := ceil(log10(unroundedTickSize)-1); + pow10x := power(10, x); + result := ceil(unroundedTickSize / pow10x) * pow10x; + //if mn < 0 then + // ticMin := ceil((mn+result) / result) * result + //else + if frac(mn / result) = 0.0 then exit; + ticMin := floor((mn+result) / result) * result; +end; + +procedure SelectTicks(mn, mx: double; out ticMin, ticStep: double; out ticDecimals: integer); +var + imx, imn, range: double; +begin + imn := min(mx,mn); + imx := max(mx,mn); + range := mx - mn; + ticStep := tickSpacing(5, imn, imx, ticMin); + if frac(range / ticStep) <> 0.0 then begin + ticStep := tickSpacing(6, imn, imx, ticMin); + if frac(range / ticStep) <> 0.0 then begin + ticStep := tickSpacing(7, imn, imx, ticMin); + if frac(range / ticStep) <> 0.0 then begin + ticStep := tickSpacing(6, imn, imx, ticMin); + //if (range / ticStep) <> 0.0 then begin + // ticStep := tickSpacing(5, imn, imx, ticMin); + //end; + end; + end; + end; + ticDecimals := 0; + if ticStep > 1 then exit; + ticDecimals := abs(floor(log10(ticStep))); +end; + +(*type + TTicks = record + stepSize, remainder: single; + decimals: integer; + end; + + function decimals(v: double): integer; + var + f: double; + begin + result := 0; + f := frac(v); + while (f > 0.001) and (f < 0.999) do begin + v := v * 10; + result := result + 1; + f := frac(v); + end; + end; + + function fRemainder(const a,b:double):double; + begin + result := a-b * Int(a/b); + if (result > (0.5 * b)) then result := b - result; + end; + +function setStepSize(lRange: double; lDesiredSteps: integer): TTicks; +var + lPower: integer; +begin + result.stepSize := lRange / lDesiredSteps; + //{$DEFINE OLD} + {$IFDEF OLD} + lPower := 0; + while result.stepSize >= 10 do begin + result.stepSize := result.stepSize/10; + inc(lPower); + end; + while result.stepSize < 1 do begin + result.stepSize := result.stepSize * 10; + dec(lPower); + end; + {$ELSE} + lPower := floor(log10(result.stepSize)); + result.stepSize := result.stepSize/power(10, lPower); + {$ENDIF} + if lPower < 0 then + result.decimals := abs(lPower) + else + result.decimals := 0; + result.stepSize := round(result.stepSize) * Power(10,lPower); + result.remainder := fRemainder(lRange, result.stepSize); + if result.remainder < (0.001* result.stepSize) then + result.remainder := 0; +end; + +function setStepSizeForce(lRange: double; lDesiredSteps: integer): TTicks; +begin + result.stepSize := lRange / lDesiredSteps; + result.decimals := decimals(result.stepSize); + result.remainder := fRemainder(lRange, result.stepSize); + if result.remainder < (0.001* result.stepSize) then + result.remainder := 0; +end; + +procedure SelectTicks(mn, mx: double; out ticMin, ticStep: double; out ticDecimals: integer); +var + lStep,lRange: double; + tic, ticAlt: TTicks; +begin + ticMin := 0; + ticStep := 1; + ticDecimals := 0; + lRange := abs(mx - mn); + if (mn < 0) and (mx > 0) then + lRange := max(abs(mn),mx);// + (0.5 * min(abs(mn),mx)); + if lRange < 0.000001 then exit; + if ((mn < 0) and (mx > 0)) and ((min(abs(mn),mx)/lRange) > 0.65) then begin + tic := setStepSize(lRange, 2); + //now try forcing other values + ticAlt := setStepSizeForce(lRange, 3); + if (ticAlt.remainder < tic.remainder) and (ticAlt.decimals <= tic.decimals) then + tic := ticAlt; + ticAlt := setStepSizeForce(lRange, 4); + if (ticAlt.remainder < tic.remainder) and (ticAlt.decimals <= tic.decimals) then + tic := ticAlt; + end else begin + tic := setStepSize(lRange, 3); + //now try forcing other values + ticAlt := setStepSizeForce(lRange, 2); + if (ticAlt.remainder < tic.remainder) and (ticAlt.decimals <= tic.decimals) then + tic := ticAlt; + ticAlt := setStepSizeForce(lRange, 4); + if (ticAlt.remainder < tic.remainder) and (ticAlt.decimals <= tic.decimals) then + tic := ticAlt; + ticAlt := setStepSizeForce(lRange, 1); + if (ticAlt.remainder < tic.remainder) and (ticAlt.decimals < tic.decimals) then + tic := ticAlt; + end; + if (mn > 0) and (decimals(mn) <= tic.decimals) then + lStep := mn + else + lStep := trunc((mn) / tic.stepSize)*tic.stepSize; + if (lStep < (mn)) and ((mn -lStep) > (lStep * 0.001) ) then lStep := lStep+tic.stepSize; + + lStep := 400; + //showmessage(format('%g %g', [lStep, mn])); + //lRange := abs(mx - mn); //full range, in case mn < 0 and mx > 0 + ticMin := lStep; + ticStep := tic.stepSize; + ticDecimals := tic.decimals; + //result := format('stepSize %g 1stTick %g decimals %d', [tic.stepSize, lStep, tic.decimals]); + +end; *) + + +end. + diff --git a/mainunit.lfm b/mainunit.lfm index ab1c6ef..a68f328 100755 --- a/mainunit.lfm +++ b/mainunit.lfm @@ -1,12 +1,12 @@ object GLForm1: TGLForm1 - Left = 233 - Height = 684 - Top = 41 - Width = 1047 + Left = 553 + Height = 514 + Top = 103 + Width = 691 AllowDropFiles = True Caption = 'Surf Ice' - ClientHeight = 684 - ClientWidth = 1047 + ClientHeight = 514 + ClientWidth = 691 Menu = MainMenu1 OnChangeBounds = FormChangeBounds OnClose = FormClose @@ -18,15 +18,15 @@ object GLForm1: TGLForm1 LCLVersion = '2.1.0.0' object ToolPanel: TScrollBox Left = 0 - Height = 684 + Height = 514 Top = 0 Width = 261 HorzScrollBar.Page = 1 HorzScrollBar.Visible = False - VertScrollBar.Page = 684 + VertScrollBar.Page = 514 Align = alLeft BorderStyle = bsNone - ClientHeight = 684 + ClientHeight = 514 ClientWidth = 246 Constraints.MaxWidth = 272 Constraints.MinWidth = 4 @@ -161,8 +161,8 @@ object GLForm1: TGLForm1 Height = 25 Top = 144 Width = 116 - Max = 2 - Position = 2 + Max = 100 + Position = 100 TickStyle = tsNone BorderSpacing.Left = 122 BorderSpacing.Top = 2 @@ -1531,7 +1531,7 @@ object GLForm1: TGLForm1 end object LeftSplitter: TSplitter Left = 261 - Height = 684 + Height = 514 Top = 0 Width = 6 OnCanOffset = LeftSplitterCanOffset @@ -1541,9 +1541,9 @@ object GLForm1: TGLForm1 end object CenterPanel: TPanel Left = 267 - Height = 684 + Height = 514 Top = 0 - Width = 766 + Width = 410 Align = alClient Constraints.MinHeight = 32 Constraints.MinWidth = 32 @@ -1552,21 +1552,21 @@ object GLForm1: TGLForm1 OnClick = CenterPanelClick end object RightSplitter: TSplitter - Left = 1033 - Height = 684 + Left = 677 + Height = 514 Top = 0 Width = 6 Align = alRight ResizeAnchor = akRight end object ScriptPanel: TPanel - Left = 1039 - Height = 684 + Left = 683 + Height = 514 Top = 0 Width = 8 Align = alRight BevelOuter = bvNone - ClientHeight = 684 + ClientHeight = 514 ClientWidth = 8 Constraints.MinWidth = 2 ParentFont = False @@ -1574,19 +1574,19 @@ object GLForm1: TGLForm1 OnDblClick = ScriptPanelDblClick object ScriptBox: TGroupBox Left = 0 - Height = 684 + Height = 514 Top = 0 Width = 8 Align = alClient Caption = 'Scripting' - ClientHeight = 666 + ClientHeight = 496 ClientWidth = 0 ParentFont = False TabOrder = 0 OnDblClick = ScriptPanelDblClick object ScriptMemo: TMemo Left = 0 - Height = 460 + Height = 290 Top = 0 Width = 0 Align = alClient @@ -1608,7 +1608,7 @@ object GLForm1: TGLForm1 object ScriptOutputMemo: TMemo Left = 0 Height = 200 - Top = 466 + Top = 296 Width = 0 Align = alBottom BorderStyle = bsNone @@ -1625,7 +1625,7 @@ object GLForm1: TGLForm1 Cursor = crVSplit Left = 0 Height = 6 - Top = 460 + Top = 290 Width = 0 Align = alBottom ResizeAnchor = akBottom @@ -1648,6 +1648,49 @@ object GLForm1: TGLForm1 Caption = 'Show Header' OnClick = LayerShowHeaderMenuClick end + object LayerPainHideMenu: TMenuItem + Caption = 'Extreme Values' + object PaintModeAutomatic: TMenuItem + Tag = -1 + AutoCheck = True + Caption = 'Automatic' + Checked = True + GroupIndex = 197 + RadioItem = True + OnClick = PaintModeAutomaticMenu + end + object PaintModeHideBrightHideDarkMenu: TMenuItem + AutoCheck = True + Caption = 'Hide Dark and Bright' + GroupIndex = 197 + RadioItem = True + OnClick = PaintModeAutomaticMenu + end + object PaintModeHideDarkShowBrightMenu: TMenuItem + Tag = 1 + AutoCheck = True + Caption = 'Hide Dark, Show Bright' + GroupIndex = 197 + RadioItem = True + OnClick = PaintModeAutomaticMenu + end + object PaintModeShowDarkHideBrightMenu: TMenuItem + Tag = 2 + AutoCheck = True + Caption = 'Show Dark, Hide Bright' + GroupIndex = 197 + RadioItem = True + OnClick = PaintModeAutomaticMenu + end + object PaintModeShowBirghtShowDark: TMenuItem + Tag = 3 + AutoCheck = True + Caption = 'Show Dark and Bright' + GroupIndex = 197 + RadioItem = True + OnClick = PaintModeAutomaticMenu + end + end end object ColorDialog1: TColorDialog Color = 15119026 @@ -2025,7 +2068,6 @@ object GLForm1: TGLForm1 end object SwapYZMenu: TMenuItem Caption = 'Rotate mesh' - ShortCut = 16472 OnClick = SwapYZMenuClick end object CenterMeshMenu: TMenuItem diff --git a/mainunit.pas b/mainunit.pas index 6e13572..c0d2773 100755 --- a/mainunit.pas +++ b/mainunit.pas @@ -32,6 +32,12 @@ TGLForm1 = class(TForm) LeftSplitter: TSplitter; CenterPanel: TPanel; LayerAOMapMenu: TMenuItem; + LayerPainHideMenu: TMenuItem; + PaintModeAutomatic: TMenuItem; + PaintModeHideBrightHideDarkMenu: TMenuItem; + PaintModeHideDarkShowBrightMenu: TMenuItem; + PaintModeShowDarkHideBrightMenu: TMenuItem; + PaintModeShowBirghtShowDark: TMenuItem; shadermatcap1: TMenuItem; NextOverlayMenu: TMenuItem; PrevOverlayMenu: TMenuItem; @@ -326,6 +332,8 @@ procedure LayerAlphaTrackMouseUp(Sender: TObject; Button: TMouseButton; Shift: T procedure LeftSplitterMoved(Sender: TObject); procedure LayerAOMapMenuClick(Sender: TObject); procedure MatCapDropChange(Sender: TObject); + procedure PaintModeAutomaticMenu(Sender: TObject); + procedure PaintModeMenuClick(Sender: TObject); procedure PrevOverlayMenuClick(Sender: TObject); procedure Shaders1Click(Sender: TObject); procedure UpdateLayerBox(NewLayers: boolean); @@ -1948,7 +1956,17 @@ procedure TGLForm1.LayerPopupPopup(Sender: TObject); if (i < 1) or (i > gMesh.OpenOverlays) then exit; LayerInvertColorsMenu.Checked := gMesh.Overlay[i].LUTinvert; LayerAOMapMenu.Checked := gMesh.Overlay[i].aoMap; + LayerPainHideMenu.Enabled := (not gMesh.Overlay[i].aoMap) and (length(gMesh.Overlay[i].intensity) > 0); + if not LayerPainHideMenu.Enabled then exit; + case gMesh.Overlay[i].PaintMode of + //kPaintHideDefaultBehavior = -1; + kPaintHideDarkHideBright: PaintModeHideBrightHideDarkMenu.Checked := true; + kPaintHideDarkShowBright: PaintModeHideDarkShowBrightMenu.Checked := true; + kPaintShowDarkHideBright: PaintModeShowDarkHideBrightMenu.Checked := true; + kPaintShowDarkShowBright: PaintModeShowBirghtShowDark.Checked := true; + else PaintModeAutomatic.Checked := true; + end; end; procedure TGLForm1.LayerListClickCheck(Sender: TObject); @@ -1990,7 +2008,7 @@ procedure TGLForm1.LayerWidgetChange(Sender: TObject); if (i < 1) or (i > gMesh.OpenOverlays) then exit; gMesh.Overlay[i].WindowScaledMin := strtofloatdef(LayerDarkEdit.Caption, gMesh.Overlay[i].WindowScaledMin); gMesh.Overlay[i].WindowScaledMax := strtofloatdef(LayerBrightEdit.Caption, gMesh.Overlay[i].WindowScaledMax); - gMesh.Overlay[i].LUTvisible := LayerAlphaTrack.position; + gMesh.Overlay[i].OpacityPercent := LayerAlphaTrack.position; PrevOverlayMenu.Enabled := (gMesh.Overlay[i].volumes > 1); NextOverlayMenu.Enabled := (gMesh.Overlay[i].volumes > 1); if (gMesh.Overlay[i].LUTindex <> LayerColorDrop.ItemIndex) then begin @@ -2084,6 +2102,15 @@ procedure TGLForm1.Shaders1Click(Sender: TObject); end; +function DefuzzX(const x: single): single; +//instead of "5.9e-6" write "0.0" +const + fuzz = 1.0E-5; +begin + if ABS(x) < fuzz then exit(0.0); + exit(x); +end {Defuzz}; + procedure TGLForm1.LayerAlphaTrackMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin //caption := format('%d %d', [ViewGPU1.width, ViewGPU1.clientWidth]); @@ -2105,7 +2132,7 @@ procedure TGLForm1.UpdateLayerBox(NewLayers: boolean); LayerList.Items.add(format('%d/%d: %s',[gMesh.Overlay[i].CurrentVolume, gMesh.Overlay[i].volumes, s])) else LayerList.Items.add(s); - LayerList.Checked[i-1] := gMesh.Overlay[i].LUTvisible <> kLUTinvisible;//true; + LayerList.Checked[i-1] := gMesh.Overlay[i].OpacityPercent <> kLUTinvisible;//true; end; LayerList.ItemIndex := gMesh.OpenOverlays - 1; end; @@ -2122,8 +2149,9 @@ procedure TGLForm1.UpdateLayerBox(NewLayers: boolean); LayerColorDrop.Enabled := not isAtlas; LayerDarkEdit.Text := format('%.6g', [gMesh.Overlay[i].WindowScaledMin]); LayerBrightEdit.Text := format('%.6g', [gMesh.Overlay[i].WindowScaledMax]); + OverlayBox.Hint := format('image intensity range %g..%g',[DefuzzX(gMesh.Overlay[i].minIntensity), DefuzzX(gMesh.Overlay[i].maxIntensity)]); LayerColorDrop.ItemIndex := gMesh.Overlay[i].LUTindex; - LayerAlphaTrack.Position := gMesh.Overlay[i].LUTvisible; + LayerAlphaTrack.Position := gMesh.Overlay[i].OpacityPercent; end; {$IFDEF LCLCocoa} @@ -2536,6 +2564,7 @@ function TGLForm1.OpenTrack(FilenameIN: string): boolean; var Filename: string; i: integer; + isMultiProperties: boolean = false; begin result := false; Filename := FindFile(FilenameIN); @@ -2562,12 +2591,24 @@ function TGLForm1.OpenTrack(FilenameIN: string): boolean; TrackScalarLUTdrop.ItemIndex := 1; TrackScalarLUTdrop.Enabled := false; TrackScalarRangeBtn.Enabled := false; - end else - {$IFDEF LCLcocoa} - TrackBox.Height := 105; - {$ELSE} - TrackBox.ClientHeight := TrackDitherTrack.Top + TrackDitherTrack.Height; - {$ENDIF} + isMultiProperties := true; + end else begin + TrackScalarNameDrop.Items.Clear; + TrackScalarNameDrop.Items.Add('Direction'); + TrackScalarNameDrop.ItemIndex := 0; + TrackScalarLUTdrop.Enabled := false; + TrackScalarRangeBtn.Enabled := false; + isMultiProperties := false; + + end; + TrackScalarNameDrop.Visible := isMultiProperties; + TrackScalarLUTdrop.Visible := isMultiProperties; + TrackScalarRangeBtn.Visible := isMultiProperties; + //{$IFDEF LCLcocoa} + //TrackBox.Height := 105; + //{$ELSE} + //TrackBox.ClientHeight := TrackDitherTrack.Top + TrackDitherTrack.Height; + //{$ENDIF} UpdateToolbar; GLBoxRequestUpdate(nil); end; @@ -2904,7 +2945,6 @@ procedure TGLForm1.ShaderDropChange(Sender: TObject); GLBoxRequestUpdate(Sender); end; - procedure TGLForm1.MatCapDropChange(Sender: TObject); begin {$IFDEF MATCAP} @@ -2918,6 +2958,22 @@ procedure TGLForm1.MatCapDropChange(Sender: TObject); {$ENDIF} end; +procedure TGLForm1.PaintModeAutomaticMenu(Sender: TObject); +var + i: integer; +begin + i := LayerList.ItemIndex+ 1; + if (i < 1) or (i > gMesh.OpenOverlays) then exit; + gMesh.Overlay[i].PaintMode := (Sender as TMenuItem).Tag; + caption := format('%d -> %d', [i, gMesh.Overlay[i].PaintMode]); + LayerWidgetChange(sender); +end; + +procedure TGLForm1.PaintModeMenuClick(Sender: TObject); +begin + +end; + procedure TGLForm1.GLboxMouseMove(Sender: TObject; Shift: TShiftState; lX, lY: Integer); var X,Y:integer; @@ -3393,26 +3449,24 @@ procedure TGLForm1.ScalarDropChange(Sender: TObject); result := PrefForm.ModalResult = mrOK; FreeAndNil(PrefForm); end;*) -function ScalarPref(var min, max: single; var ColorBarPrecedenceTracksNotOverlays: boolean): boolean; +function ScalarPref(var min, max, viewMin, viewmax: single; var ColorBarPrecedenceTracksNotOverlays, HideDark, HideBright: boolean; isScalarPerFiberColor: boolean): boolean; var PrefForm: TForm; OkBtn: TButton; minLabel, maxLabel: TLabel; minEdit, maxEdit: TEdit; - ColorBarCheck: TCheckBox; + DarkCheck, BrightCheck, ColorBarCheck: TCheckBox; begin PrefForm:=TForm.Create(nil); //PrefForm.SetBounds(100, 100, 520, 142); PrefForm.AutoSize := True; PrefForm.BorderWidth := 8; - PrefForm.Caption:='Track simplification preferences'; + PrefForm.Caption:=format('Track preferences (%g..%g)', [min, max]); PrefForm.Position := poScreenCenter; PrefForm.BorderStyle := bsDialog; - //Tolerance + //minEdit minLabel:=TLabel.create(PrefForm); minLabel.Caption:= 'Minimum intensity'; - //minLabel.Left := 8; - //minLabel.Top := 12; minLabel.AutoSize := true; minLabel.AnchorSide[akTop].Side := asrTop; minLabel.AnchorSide[akTop].Control := PrefForm; @@ -3422,9 +3476,7 @@ function ScalarPref(var min, max: single; var ColorBarPrecedenceTracksNotOverla minLabel.BorderSpacing.Left := 6; minLabel.Parent:=PrefForm; minEdit:=TEdit.create(PrefForm); - minEdit.Caption := FloatToStrF(min, ffGeneral, 8, 4); - //minEdit.Top := 12; - //minEdit.Width := 92; + minEdit.Caption := FloatToStrF(viewMin, ffGeneral, 8, 4); minEdit.Constraints.MinWidth:= 128; minEdit.AutoSize := true; minEdit.AnchorSide[akTop].Side := asrTop; @@ -3435,48 +3487,69 @@ function ScalarPref(var min, max: single; var ColorBarPrecedenceTracksNotOverla minEdit.BorderSpacing.Left := 6; minEdit.Left := PrefForm.Width - minEdit.Width - 8; minEdit.Parent:=PrefForm; - //minLength + //DarkCheck + DarkCheck:=TCheckBox.create(PrefForm); + DarkCheck.Checked := HideDark; + DarkCheck.Caption:='Hide tracks darker than minimum'; + DarkCheck.AutoSize := true; + DarkCheck.AnchorSide[akTop].Side := asrBottom; + DarkCheck.AnchorSide[akTop].Control := minEdit; + DarkCheck.BorderSpacing.Top := 6; + DarkCheck.AnchorSide[akLeft].Side := asrLeft; + DarkCheck.AnchorSide[akLeft].Control := PrefForm; + DarkCheck.BorderSpacing.Left := 6; + DarkCheck.enabled := isScalarPerFiberColor; + if not isScalarPerFiberColor then + DarkCheck.Checked := false; + DarkCheck.Parent:=PrefForm; + //maxEdit maxLabel:=TLabel.create(PrefForm); maxLabel.Caption:= 'Maximum intensity'; - //maxLabel.Left := 8; - //maxLabel.Top := 42; maxLabel.AutoSize := true; maxLabel.AnchorSide[akTop].Side := asrBottom; - maxLabel.AnchorSide[akTop].Control := minEdit; + maxLabel.AnchorSide[akTop].Control := DarkCheck; maxLabel.BorderSpacing.Top := 6; maxLabel.AnchorSide[akLeft].Side := asrLeft; maxLabel.AnchorSide[akLeft].Control := PrefForm; maxLabel.BorderSpacing.Left := 6; - maxLabel.Parent:=PrefForm; maxEdit:=TEdit.create(PrefForm); - maxEdit.Caption := FloatToStrF(max, ffGeneral, 8, 4); - //maxEdit.Top := 42; - //maxEdit.Width := 92; - //maxEdit.Left := PrefForm.Width - maxEdit.Width - 8; + maxEdit.Caption := FloatToStrF(viewMax, ffGeneral, 8, 4); maxEdit.Constraints.MinWidth:= 128; maxEdit.AutoSize := true; maxEdit.AnchorSide[akTop].Side := asrBottom; - maxEdit.AnchorSide[akTop].Control := minEdit; + maxEdit.AnchorSide[akTop].Control := DarkCheck; maxEdit.BorderSpacing.Top := 4; maxEdit.AnchorSide[akLeft].Side := asrRight; maxEdit.AnchorSide[akLeft].Control := maxLabel; maxEdit.BorderSpacing.Left := 6; maxEdit.Parent:=PrefForm; - //Precedence ColorBarPrecedenceTracksNotOverlays + //BrightCheck + BrightCheck:=TCheckBox.create(PrefForm); + BrightCheck.Checked := HideBright; + BrightCheck.Caption:='Hide tracks brighter than maximum'; + BrightCheck.AutoSize := true; + BrightCheck.AnchorSide[akTop].Side := asrBottom; + BrightCheck.AnchorSide[akTop].Control := maxEdit; + BrightCheck.BorderSpacing.Top := 6; + BrightCheck.AnchorSide[akLeft].Side := asrLeft; + BrightCheck.AnchorSide[akLeft].Control := PrefForm; + BrightCheck.BorderSpacing.Left := 6; + BrightCheck.Enabled := isScalarPerFiberColor; + if not isScalarPerFiberColor then + BrightCheck.Checked := false; + BrightCheck.Parent:=PrefForm; + //ColorBarCheck ColorBarCheck:=TCheckBox.create(PrefForm); ColorBarCheck.Checked := ColorBarPrecedenceTracksNotOverlays; ColorBarCheck.Caption:='Colorbar for tracks, even if overlay loaded'; - //ColorBarCheck.Left := 8; - //ColorBarCheck.Top := 72; ColorBarCheck.AutoSize := true; ColorBarCheck.AnchorSide[akTop].Side := asrBottom; - ColorBarCheck.AnchorSide[akTop].Control := maxEdit; + ColorBarCheck.AnchorSide[akTop].Control := BrightCheck; ColorBarCheck.BorderSpacing.Top := 6; ColorBarCheck.AnchorSide[akLeft].Side := asrLeft; ColorBarCheck.AnchorSide[akLeft].Control := PrefForm; ColorBarCheck.BorderSpacing.Left := 6; - ColorBarCheck.Parent:=PrefForm; //OK button OkBtn:=TButton.create(PrefForm); @@ -3491,15 +3564,16 @@ function ScalarPref(var min, max: single; var ColorBarPrecedenceTracksNotOverla OkBtn.AnchorSide[akLeft].Side := asrCenter; OkBtn.AnchorSide[akLeft].Control := PrefForm; OkBtn.Constraints.MinWidth:= 64; - OkBtn.Parent:=PrefForm; OkBtn.ModalResult:= mrOK; {$IFDEF LCLCocoa} if gPrefs.DarkMode then SetFormDarkMode(PrefForm); {$ENDIF} PrefForm.ShowModal; - min := StrToFloatDef(minEdit.Caption, min); - max := StrToFloatDef(maxEdit.Caption, max); + viewMin := StrToFloatDef(minEdit.Caption, viewMin); + HideBright := BrightCheck.Checked; + HideDark := DarkCheck.Checked; + viewMax := StrToFloatDef(maxEdit.Caption, viewMax); ColorBarPrecedenceTracksNotOverlays := ColorBarCheck.Checked; result := PrefForm.ModalResult = mrOK; FreeAndNil(PrefForm); @@ -3509,7 +3583,7 @@ function ScalarPref(var min, max: single; var ColorBarPrecedenceTracksNotOverla procedure TGLForm1.TrackScalarRangeBtnClick(Sender: TObject); begin if (gTrack.scalarSelected < 0) or (gTrack.scalarSelected >= length(gTrack.scalars)) then exit; - ScalarPref(gTrack.scalars[gTrack.scalarSelected].mnView, gTrack.scalars[gTrack.scalarSelected].mxView, gPrefs.ColorBarPrecedenceTracksNotOverlays); + ScalarPref(gTrack.scalars[gTrack.scalarSelected].mn, gTrack.scalars[gTrack.scalarSelected].mx, gTrack.scalars[gTrack.scalarSelected].mnView, gTrack.scalars[gTrack.scalarSelected].mxView, gPrefs.ColorBarPrecedenceTracksNotOverlays, gPrefs.HideDarkTracks, gPrefs.HideBrightTracks,gTrack.HasScalarPerFiberColor); gTrack.isRebuildList:= true; gnLUT := -1; //refresh colorbar GLBoxRequestUpdate(Sender); @@ -3557,10 +3631,11 @@ procedure TGLForm1.OverlayVisible(lOverlay: integer; lVisible: integer); if (lOverlay > gMesh.OpenOverlays) or (lOverlay < 1) then exit; if (lVisible < kLUTinvisible) or (lVisible > kLUTopaque) then - gMesh.Overlay[lOverlay].LUTvisible := kLUTopaque + gMesh.Overlay[lOverlay].OpacityPercent := kLUTopaque else - gMesh.Overlay[lOverlay].LUTvisible := lVisible; + gMesh.Overlay[lOverlay].OpacityPercent := lVisible; UpdateLayerBox(false); + OverlayTimerStart; end; procedure TGLForm1.OverlayInvert(lOverlay: integer; lInvert: boolean); @@ -4096,8 +4171,17 @@ procedure TGLForm1.ResetMenuClick(Sender: TObject); MeshBlendTrack.Position:= 0; LightElevTrack.Position:= 25; LightAziTrack.Position := 0; - ShaderDrop.ItemIndex:= 0; - ShaderDropChange(Sender); + if (ShaderDrop.ItemIndex <> 0) then begin + ShaderDrop.ItemIndex:= 0; + ShaderDropChange(Sender); + end; + {$IFDEF MATCAP} + if (MatCapDrop.Items.Count > 1) and (MatCapDrop.ItemIndex <> 0) then begin + MatCapDrop.ItemIndex := 0; + MatCapDropChange(Sender); + + end; + {$ENDIF} end; procedure TGLForm1.RestrictEdgeMenuClick(Sender: TObject); @@ -4379,11 +4463,11 @@ function TGLForm1.UpdateClrBar: integer; if (gMesh.OpenOverlays > 0) then for lI := 1 to gMesh.OpenOverlays do //https://www.nitrc.org/forum/forum.php?thread_id=10001&forum_id=6713 - if (length(gMesh.overlay[lI].intensity) > 0) and (not gMesh.overlay[lI].aoMap) and (gMesh.overlay[lI].LUTvisible <> kLUTinvisible) and (not isFreeSurferLUT(gMesh.overlay[lI].LUTindex)) then begin + if (length(gMesh.overlay[lI].intensity) > 0) and (not gMesh.overlay[lI].aoMap) and (gMesh.overlay[lI].OpacityPercent <> kLUTinvisible) and (not isFreeSurferLUT(gMesh.overlay[lI].LUTindex)) then begin isDuplicate := false; lJ := 1; while (lJ < lI) do begin - if (gMesh.overlay[lI].LUTindex = gMesh.overlay[lJ].LUTindex) and(gMesh.overlay[lJ].LUTvisible <> kLUTinvisible) + if (gMesh.overlay[lI].LUTindex = gMesh.overlay[lJ].LUTindex) and(gMesh.overlay[lJ].OpacityPercent <> kLUTinvisible) and (gMesh.overlay[lI].windowScaledMin = gMesh.overlay[lJ].windowScaledMin) and (gMesh.overlay[lI].windowScaledMax = gMesh.overlay[lJ].windowScaledMax) then isDuplicate := true; @@ -5332,10 +5416,7 @@ procedure TGLForm1.CopyMenuClick(Sender: TObject); procedure TGLForm1.DepthLabelClick(Sender: TObject); begin - if ClipTrack.Position > 900 then - ClipTrack.Position := 0 - else - ClipTrack.Position := 100 * ((ClipTrack.Position +100) div 100); + IncTrackBar(ClipTrack, true); end; procedure TGLForm1.DisplayMenuClick(Sender: TObject); @@ -6094,6 +6175,7 @@ procedure TGLForm1.FormDropFiles(Sender: TObject; const FileNames: array of String); begin OpenMesh(Filenames[0]); + //caption := 'abba'+inttostr(random(888)); end; procedure TGLForm1.GLBoxClick(Sender: TObject); diff --git a/mesh.pas b/mesh.pas index 493aaa2..06554e7 100755 --- a/mesh.pas +++ b/mesh.pas @@ -16,8 +16,8 @@ interface kMinOverlayIndex = 1; kMaxOverlays = 256; kLUTinvisible = 0; - kLUTtranslucent = 1; - kLUTopaque = 2; + kLUTtranslucent = 50; + kLUTopaque = 100; type TSphere = packed record X: single; @@ -29,7 +29,9 @@ interface TOverlay = record LUTinvert, AOmap: boolean; - LUTvisible: integer; //0=invisible, 1=translucent, 2=opaque + PaintMode: integer; + OpacityPercent: integer; + //LUTvisible: integer; //0=invisible, 1=translucent, 2=opaque LUTindex,atlasMaxIndex, volumes, CurrentVolume : integer; LUT: TLUT; minIntensity, maxIntensity, windowScaledMin, windowScaledMax: single; @@ -295,8 +297,8 @@ procedure darken(var c: TRGBA; v, mn,mx: single); procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var vtxRGBA: TVertexRGBA; vRemap: TInts = nil; isWriteToGPU: boolean = true); var - i,volInc, c, translucent: integer; - mn, mx: single; + i,volInc, c: integer; + mn, mx, frac: single; rgb, rgb0: TRGBA; vRGBA, vRGBAmx :TVertexRGBA; vNumNeighbor: array of integer; @@ -309,7 +311,7 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v isOverlayPainting := false; if (OpenOverlays > 0) then //ignore overlays if they are all meshes rather than vertex colors for c := OpenOverlays downto 1 do - if (overlay[c].LUTvisible <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then + if (overlay[c].OpacityPercent <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then isOverlayPainting := true; if (isOverlayPainting) or (length(vtxRGBA) = length(v)) then begin rgb := RGBA(Clr.R, Clr.G, Clr.B, 0); @@ -318,7 +320,10 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v c := round(vertexRgbaAlpha * 255); if vertexRgbaSaturation >= 1 then begin for i := 0 to (length(v)-1) do begin - vRGBA[i].r := vtxRGBA[i].r; vRGBA[i].g := vtxRGBA[i].g; vRGBA[i].b := vtxRGBA[i].b; vRGBA[i].a := c; + vRGBA[i].r := vtxRGBA[i].r; + vRGBA[i].g := vtxRGBA[i].g; + vRGBA[i].b := vtxRGBA[i].b; + vRGBA[i].a := c; end; end else begin for i := 0 to (length(v)-1) do @@ -344,11 +349,9 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v for c := OpenOverlays downto 1 do begin if isFreeSurferLUT(overlay[c].LUTindex) then continue; //curve files ALWAYs darken volInc := length(v) * (overlay[c].currentVolume - 1); - if (not overlay[c].aoMap) and (overlay[c].LUTvisible <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then begin - if overlay[c].LUTvisible <> kLUTopaque then - translucent := 2 //if translucent, halve alpha - else - translucent := 1; + if (not overlay[c].aoMap) and (overlay[c].OpacityPercent <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then begin + frac := overlay[c].OpacityPercent/100; + if (frac > 1) or (frac < 0) then frac := 1; if overlay[c].windowScaledMax > overlay[c].windowScaledMin then begin mn := overlay[c].windowScaledMin; mx := overlay[c].windowScaledMax; @@ -358,14 +361,14 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v end; if vRemap <> nil then begin //filtered atlas: vertices have been decimated for i := 0 to (length(v)-1) do begin - rgb := inten2rgb(overlay[c].intensity[vRemap[i]+volInc], mn, mx, overlay[c].LUT); - rgb.A := rgb.A div translucent; + rgb := inten2rgb(overlay[c].intensity[vRemap[i]+volInc], mn, mx, overlay[c].LUT, overlay[c].PaintMode); + rgb.A := round(rgb.A * frac); vRGBAmx[i] := maxRGBA(vRGBAmx[i], rgb); end; //for i end else begin for i := 0 to (length(v)-1) do begin - rgb := inten2rgb(overlay[c].intensity[i+volInc], mn, mx, overlay[c].LUT); - rgb.A := rgb.A div translucent; + rgb := inten2rgb(overlay[c].intensity[i+volInc], mn, mx, overlay[c].LUT, overlay[c].PaintMode); + rgb.A := round(rgb.A * frac); vRGBAmx[i] := maxRGBA(vRGBAmx[i], rgb); end; //for i end; @@ -375,11 +378,9 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v //next curve files for c := OpenOverlays downto 1 do begin if not isFreeSurferLUT(overlay[c].LUTindex) then continue; //only curve files - if (not overlay[c].aoMap) and (overlay[c].LUTvisible <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then begin - if overlay[c].LUTvisible <> kLUTopaque then - translucent := 2 //if translucent, halve alpha - else - translucent := 1; + if (not overlay[c].aoMap) and (overlay[c].OpacityPercent <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then begin + frac := overlay[c].OpacityPercent / 100; + if (frac < 0) or (frac > 1) then frac := 1; if overlay[c].windowScaledMax > overlay[c].windowScaledMin then begin mn := overlay[c].windowScaledMin; mx := overlay[c].windowScaledMax; @@ -390,14 +391,14 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v volInc := length(v) * (overlay[c].currentVolume - 1); if vRemap <> nil then begin //filtered atlas: vertices have been decimated for i := 0 to (length(v)-1) do begin - rgb := inten2rgb(overlay[c].intensity[vRemap[i]+volInc], mn, mx, overlay[c].LUT); - rgb.A := rgb.A div translucent; + rgb := inten2rgb(overlay[c].intensity[vRemap[i]+volInc], mn, mx, overlay[c].LUT, overlay[c].PaintMode); + rgb.A := round(rgb.A * frac); vRGBA[i] := blendRGBA(vRGBA[i], rgb); end; //for i end else begin for i := 0 to (length(v)-1) do begin - rgb := inten2rgb(overlay[c].intensity[i+volInc], mn, mx, overlay[c].LUT); - rgb.A := rgb.A div translucent; + rgb := inten2rgb(overlay[c].intensity[i+volInc], mn, mx, overlay[c].LUT, overlay[c].PaintMode); + rgb.A := round(rgb.A * frac); vRGBA[i] := blendRGBA(vRGBA[i], rgb); end; //for i end; @@ -408,11 +409,8 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v vRGBA[i] := blendRGBA(vRGBA[i],vRGBAmx[i]); end else begin //not additive: mix overlays for c := OpenOverlays downto 1 do begin - if (not overlay[c].aoMap) and (overlay[c].LUTvisible <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then begin - if overlay[c].LUTvisible <> kLUTopaque then - translucent := 2 //if translucent, halve alpha - else - translucent := 1; + if (not overlay[c].aoMap) and (overlay[c].OpacityPercent <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then begin + frac := overlay[c].OpacityPercent / 100; if overlay[c].windowScaledMax > overlay[c].windowScaledMin then begin mn := overlay[c].windowScaledMin; mx := overlay[c].windowScaledMax; @@ -423,14 +421,14 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v volInc := length(v) * (overlay[c].currentVolume - 1); if vRemap <> nil then begin //filtered atlas: vertices have been decimated for i := 0 to (length(v)-1) do begin - rgb := inten2rgb(overlay[c].intensity[vRemap[i]+volInc], mn, mx, overlay[c].LUT); - rgb.A := rgb.A div translucent; + rgb := inten2rgb(overlay[c].intensity[vRemap[i]+volInc], mn, mx, overlay[c].LUT, overlay[c].PaintMode); + rgb.A := round(rgb.A * frac); vRGBA[i] := blendRGBA(vRGBA[i], rgb); end; //for i end else begin for i := 0 to (length(v)-1) do begin - rgb := inten2rgb(overlay[c].intensity[i+volInc], mn, mx, overlay[c].LUT); - rgb.A := rgb.A div translucent; + rgb := inten2rgb(overlay[c].intensity[i+volInc], mn, mx, overlay[c].LUT, overlay[c].PaintMode); + rgb.A := round(rgb.A * frac); vRGBA[i] := blendRGBA(vRGBA[i], rgb); end; //for i end; @@ -518,7 +516,7 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v //for i := 0 to (length(v)-1) do // vRGBA[i].R := 0; for c := OpenOverlays downto 1 do begin - if (overlay[c].aoMap) and (overlay[c].LUTvisible <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then begin + if (overlay[c].aoMap) and (overlay[c].OpacityPercent <> kLUTinvisible) and (length(overlay[c].intensity) >= length(v)) then begin if overlay[c].windowScaledMax > overlay[c].windowScaledMin then begin mn := overlay[c].windowScaledMin; mx := overlay[c].windowScaledMax; @@ -527,8 +525,8 @@ procedure TMesh.BuildListCore(Clr: TRGBA; var f: TFaces; var v: TVertices; var v mn := overlay[c].windowScaledMax; end; volInc := length(v) * (overlay[c].currentVolume - 1); - if overlay[c].LUTvisible = kLUTtranslucent then - mx := ((mx - mn) * 0.5) + mn; + if (overlay[c].OpacityPercent < 100) then + mx := ((mx - mn) * (overlay[c].OpacityPercent/100)) + mn; if (overlay[c].LUTinvert) then begin if vRemap <> nil then begin //filtered atlas: vertices have been decimated for i := 0 to (length(v)-1) do @@ -715,7 +713,7 @@ procedure TMesh.FilterOverlay(c: integer; var f: TFaces; var v: TVertices; var v setlength(f,0); nVert := length(overlay[c].vertices); nFace := length(overlay[c].faces); - if (overlay[c].atlasMaxIndex > 0) or (overlay[c].LUTvisible = kLUTinvisible) or (nVert < 3) or (nFace < 1) then exit; + if (overlay[c].atlasMaxIndex > 0) or (overlay[c].OpacityPercent = kLUTinvisible) or (nVert < 3) or (nFace < 1) then exit; //if length(overlay[c].intensity) <> nVert then exit; //requires intensity values if length(overlay[c].intensity) < nVert then exit; //requires intensity values 2019 if overlay[c].windowScaledMax > overlay[c].windowScaledMin then begin @@ -756,7 +754,7 @@ procedure TMesh.FilterOverlay(c: integer; var f: TFaces; var v: TVertices; var v setlength(vRGBA, nvOK); rgba192 := overlay[c].LUT[192]; for i := 0 to (nvOK -1) do begin - rgb := inten2rgb(overlay[c].intensity[i], mn, mx, overlay[c].LUT); + rgb := inten2rgb(overlay[c].intensity[i], mn, mx, overlay[c].LUT, overlay[c].PaintMode); vRGBA[i].r := rgb.r; vRGBA[i].g := rgb.g; vRGBA[i].b := rgb.b; @@ -794,7 +792,7 @@ procedure TMesh.FilterOverlay(c: integer; var f: TFaces; var v: TVertices; var v j := 0; for i := 0 to (nVert -1) do begin if vOK[i] >= 0 then begin - rgb := inten2rgb(overlay[c].intensity[i], mn, mx, overlay[c].LUT); + rgb := inten2rgb(overlay[c].intensity[i], mn, mx, overlay[c].LUT, overlay[c].PaintMode); vRGBA[j].r := rgb.r; vRGBA[j].g := rgb.g; vRGBA[j].b := rgb.b; @@ -822,7 +820,7 @@ procedure TMesh.BuildListOverlay(Clr: TRGBA); exit; nMeshOverlay := 0; for c := 1 to OpenOverlays do - if (overlay[c].LUTvisible <> kLUTinvisible) and (length(overlay[c].vertices) > 2) then + if (overlay[c].OpacityPercent <> kLUTinvisible) and (length(overlay[c].vertices) > 2) then nMeshOverlay := nMeshOverlay + 1; if nMeshOverlay < 1 then exit; nMeshOverlay := 0; @@ -831,7 +829,7 @@ procedure TMesh.BuildListOverlay(Clr: TRGBA); for c := 1 to OpenOverlays do begin nVert := length(overlay[c].vertices); nFace := length(overlay[c].faces); - if (overlay[c].LUTvisible = kLUTinvisible) or (nVert < 3) or (nFace < 1) then continue; + if (overlay[c].OpacityPercent = kLUTinvisible) or (nVert < 3) or (nFace < 1) then continue; //isIntensityColored := length(overlay[c].intensity) = nVert; isIntensityColored := length(overlay[c].intensity) >= nVert; //2019 if (not isIntensityColored) then begin @@ -2592,12 +2590,14 @@ procedure TMesh.LoadObj(const FileName: string); faces[num_f].X := strtointDef(strlst[1], 1); faces[num_f].Y := strtointDef(strlst[j+1], 1); faces[num_f].Z := strtointDef(strlst[j+2], 1); - if faces[num_f].X < 0 then - faces[num_f].X := 1 + num_v - faces[num_f].X; + //showmessage(format('%d:%d= %d %d %d', [num_v, num_f, faces[num_f].x, faces[num_f].y, faces[num_f].z])); + //20:6 -4 -3 -2 + if faces[num_f].X < 0 then + faces[num_f].X := 1 + num_v + faces[num_f].X; if faces[num_f].Y < 0 then - faces[num_f].Y := 1 + num_v - faces[num_f].Y; + faces[num_f].Y := 1 + num_v + faces[num_f].Y; if faces[num_f].Z < 0 then - faces[num_f].Z := 1 + num_v - faces[num_f].Z; + faces[num_f].Z := 1 + num_v + faces[num_f].Z; faces[num_f] := vectorAdd(faces[num_f],-1);//-1 since "A valid vertex index starts from 1" inc(num_f); end; @@ -4708,7 +4708,7 @@ function TMesh.LoadMz3(const FileName: string; lOverlayIndex : integer): boolean Overlay[OpenOverlays].filename := ExtractFilename(FileName); Overlay[OpenOverlays].volumes := length(floats) div length(Vertices); Overlay[OpenOverlays].CurrentVolume := 1; - Overlay[OpenOverlays].LUTvisible:= kLUTopaque; + Overlay[OpenOverlays].OpacityPercent:= kLUTopaque; SetOverlayDescriptives(OpenOverlays); Overlay[OpenOverlays].aoMap := isAOMap; if isAOMap then Overlay[OpenOverlays].LUTindex := 0; @@ -7977,6 +7977,7 @@ procedure TMesh.SetOverlayDescriptives(lOverlayIndex: integer); begin overlay[lOverlayIndex].LUTinvert := false; overlay[lOverlayIndex].aoMap := false; + overlay[lOverlayIndex].PaintMode := kPaintHideDefaultBehavior; num_v := length(overlay[lOverlayIndex].intensity); if (num_v < 3) then exit; mn := overlay[lOverlayIndex].intensity[0]; @@ -7996,8 +7997,8 @@ procedure TMesh.SetOverlayDescriptives(lOverlayIndex: integer); if mnNot0 < mx then mn := mnNot0; end; - overlay[lOverlayIndex].minIntensity := mn; - overlay[lOverlayIndex].maxIntensity := mx; + overlay[lOverlayIndex].minIntensity := (mn); + overlay[lOverlayIndex].maxIntensity := (mx); lLog10 := trunc(log10( mx-mn))-1; if (mx > 4) and (mn < -1) then begin overlay[lOverlayIndex].windowScaledMin:= 2; @@ -8159,6 +8160,7 @@ procedure TMesh.SaveMesh(const FileName: string; MeshColor: TColor = clWhite); vRGBA := nil; if (length(vertexRGBA) > 0) and (x = '.MZ3') and (PosEx('AOMap',Filename) > 0) then begin //save RGB as ambient occlusion map + //showmessage('xx'); setlength(intensities, length(Vertices)); for i := 0 to (length(Vertices)-1) do intensities[i] := vertexRGBA[i].G / 255.0; @@ -8190,7 +8192,7 @@ procedure TMesh.SaveMesh(const FileName: string; MeshColor: TColor = clWhite); exit; end; for i := OpenOverlays downto 1 do - if (overlay[i].LUTvisible <> kLUTinvisible) and (length(overlay[i].intensity) >= length(Vertices)) then + if (overlay[i].OpacityPercent <> kLUTinvisible) and (length(overlay[i].intensity) >= length(Vertices)) then isOverlayPainting := true; if (not isOverlayPainting) then begin SaveMeshCore(Filename, Faces,Vertices, vertexRGBA); @@ -8244,7 +8246,7 @@ function TMesh.LoadOverlay(const FileName: string; lLoadSmooth: boolean): boolea Overlay[OpenOverlays].volumes := 1; Overlay[OpenOverlays].CurrentVolume := 1; setlength(Overlay[OpenOverlays].intensity,0); - Overlay[OpenOverlays].LUTvisible:= kLUTopaque; + Overlay[OpenOverlays].OpacityPercent:= kLUTopaque; Overlay[OpenOverlays].filename := ExtractFilename(FileName); Overlay[OpenOverlays].LUTindex := SetLutIndex(OpenOverlays); Overlay[OpenOverlays].LUT := UpdateTransferFunction (Overlay[OpenOverlays].LUTindex, Overlay[OpenOverlays].LUTinvert); @@ -8283,7 +8285,7 @@ function TMesh.LoadOverlay(const FileName: string; lLoadSmooth: boolean): boolea LoadCol(FileName, OpenOverlays, i); Overlay[OpenOverlays].filename := ExtractFilename(FileName)+':'+inttostr(i); Overlay[OpenOverlays].LUTindex := SetLutIndex(OpenOverlays); - Overlay[OpenOverlays].LUTvisible := kLUTinvisible; + Overlay[OpenOverlays].OpacityPercent := kLUTinvisible; Overlay[OpenOverlays].LUT := UpdateTransferFunction (Overlay[OpenOverlays].LUTindex, Overlay[OpenOverlays].LUTinvert); end; end; @@ -8323,9 +8325,9 @@ function TMesh.LoadOverlay(const FileName: string; lLoadSmooth: boolean): boolea OpenOverlays := OpenOverlays + 1; setlength(Overlay[OpenOverlays].intensity,0); if isCiftiNii then - Overlay[OpenOverlays].LUTvisible := kLUTinvisible + Overlay[OpenOverlays].OpacityPercent := kLUTinvisible else - Overlay[OpenOverlays].LUTvisible := kLUTopaque; + Overlay[OpenOverlays].OpacityPercent := kLUTopaque; Overlay[OpenOverlays].filename := ExtractFilename(FileName); if isCiftiNii then nOverlays := loadCifti(FileName, OpenOverlays, i, (origin.X < 0)) diff --git a/prefs.pas b/prefs.pas index 8e21084..7396e11 100755 --- a/prefs.pas +++ b/prefs.pas @@ -21,7 +21,7 @@ interface TPrefs = record //ObjectBasedClipPlane, SmoothVoxelwiseData, OverlayClip, StartupScript, SupportBetterRenderQuality, AdditiveOverlay,Perspective, OrientCube, MultiSample, BlackDefaultBackground, - Colorbar,TracksAreTubes, ScreenCaptureTransparentBackground,LoadTrackOnLaunch,ColorBarPrecedenceTracksNotOverlays, + Colorbar,TracksAreTubes, ScreenCaptureTransparentBackground,LoadTrackOnLaunch,ColorBarPrecedenceTracksNotOverlays,HideDarkTracks, HideBrightTracks, ZDimIsUp, ShaderForBackgroundOnly, CoreTrackDisableDepth, SkipPrefWriting, isFlipMeshOverlay, DarkMode, RetinaDisplay, GenerateSmoothCurves : boolean; TrackTubeSlices, ScreenCaptureZoom,ColorbarColor,ColorBarPosition, window_width, window_height, RenderQuality, SaveAsFormat,SaveAsFormatTrack, OcclusionAmount: integer; @@ -318,6 +318,8 @@ procedure SetDefaultPrefs (var lPrefs: TPrefs; lEverything, askUserIfMissing: b with lPrefs do begin RenderQuality := kRenderBetter; ColorBarPrecedenceTracksNotOverlays := false; + HideDarkTracks := false; + HideBrightTracks := false; SupportBetterRenderQuality := false; Colorbar := true; ColorbarColor := 4; diff --git a/shaderu.pas b/shaderu.pas index 8fbd29e..7ed976a 100755 --- a/shaderu.pas +++ b/shaderu.pas @@ -247,7 +247,7 @@ implementation +#10'bool noise = true; //use noise instead of pattern for sample dithering' +#10'float noiseamount = 0.0002; //dithering amount' +#10'float diffarea = 0.5; //self-shadowing reduction' -+#10'float gdisplace = 0.4; //gauss bell center' ++#10'float gdisplace = 0.35; //gauss bell center' +#10'vec2 rand(vec2 coord) {' +#10' float noiseX = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.25)+(fract(coord.t*(texture_size.y/2.0))*0.75))*2.0-1.0;' +#10' float noiseY = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.75)+(fract(coord.t*(texture_size.y/2.0))*0.25))*2.0-1.0;' @@ -1343,9 +1343,12 @@ procedure RunAoGLSL (var f1, f2: TFrameBuffer; zoom : integer; alpha1, blend1, f end; //GLForm1.ShaderBox.Caption := inttostr(round(mxXY)); if gShader.AOradiusU > 0 then begin - uniform1fx(gShader.programAoID, 'aoRadius', aoScale * gShader.Uniform[gShader.AOradiusU].DefaultV); + //uniform1fx(gShader.programAoID, 'aoRadius', aoScale * gShader.Uniform[gShader.AOradiusU].DefaultV); + uniform1fx(gShader.programAoID, 'aoRadius', aoScale * gShader.Uniform[gShader.AOradiusU].DefaultV / distance ); if gShader.Uniform[gShader.AOradiusU].DefaultV <= 0 then uniform1fx(gShader.programAoID, 'fracAO', 0.0); + uniform1fx(gShader.programAoID, 'aoRadiusPx', gShader.Uniform[gShader.AOradiusU].DefaultV); + uniform1fx(gShader.programAoID, 'aoRadiusDx', distance); end else begin uniform1fx(gShader.programAoID, 'aoRadius', aoScale * 16.0 / distance); end; diff --git a/surfice.app/Contents/Resources/ao3 copy 2.glsl b/surfice.app/Contents/Resources/ao3 copy 2.glsl new file mode 100755 index 0000000..a78faba --- /dev/null +++ b/surfice.app/Contents/Resources/ao3 copy 2.glsl @@ -0,0 +1,54 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +#define RADIUS 4 +smooth in vec2 texCoord; +out vec4 color; +// True if we're blurring vertically, false if horizontally since we +// do the blurring in two passes, once for horizontal and once for vertical +//uniform ivec2 axis; + + +void main(void){ + ivec2 axis = ivec2(0, 1); + //ivec2 px = ivec2(texCoord.xy); //ivec2(gl_FragCoord.xy); + //ivec2 px = ivec2(gl_FragCoord.xy); + // Gaussian filter values from the author's blurring shader + //const float gaussian[RADIUS + 1] = float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); + //vec4 t1 = texture(tex1, texCoord); + //vec3 val = texture(tex1, px).xyz; + vec2 px = texCoord; + vec3 val = texture(tex1, px).rgb; + const float gaussian[RADIUS + 1] = float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); + float weight = gaussian[0]; + vec3 sum = weight * val; + for (int i = -RADIUS; i <= RADIUS; ++i){ + // We handle the center pixel above so skip that case + if (i == 0) continue; + // Filter scale effects how many pixels the kernel actually covers + vec2 p = px + axis * i * aoRadius; + //vec3 val = texelFetch(ao_in, p, 0).xyz; + vec3 val = texture(tex1, p).xyz; + //float z = val.y; + float w = 0.3 + gaussian[abs(i)]; + // Decrease weight as depth difference increases. This prevents us from + // blurring across depth discontinuities + //w *= max(0.f, 1.f - (ao_params.edge_sharpness * 400.f) * abs(z_pos - z)); + sum += val * w; + weight += w; + } + color = vec4(sum / (weight + 0.0001), 1.0); +} diff --git a/surfice.app/Contents/Resources/ao3 copy 3.glsl b/surfice.app/Contents/Resources/ao3 copy 3.glsl new file mode 100755 index 0000000..90f2b21 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3 copy 3.glsl @@ -0,0 +1,57 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +#define RADIUS 4 +smooth in vec2 texCoord; +out vec4 color; +// True if we're blurring vertically, false if horizontally since we +// do the blurring in two passes, once for horizontal and once for vertical +//uniform ivec2 axis; + + +void main(void){ + ivec2 axis = ivec2(0, 1); + //ivec2 px = ivec2(texCoord.xy); //ivec2(gl_FragCoord.xy); + //ivec2 px = ivec2(gl_FragCoord.xy); + // Gaussian filter values from the author's blurring shader + //const float gaussian[RADIUS + 1] = float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); + //vec4 t1 = texture(tex1, texCoord); + //vec3 val = texture(tex1, px).xyz; + ivec2 px = ivec2(gl_FragCoord.xy); + vec3 val = texelFetch(tex1, px, 0).xyz; + + const float gaussian[RADIUS + 1] = float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); + float weight = gaussian[0]; + vec3 sum = weight * val; + for (int i = -RADIUS; i <= RADIUS; ++i){ + // We handle the center pixel above so skip that case + if (i == 0) continue; + // Filter scale effects how many pixels the kernel actually covers + //vec2 p = px + axis * i * aoRadius; + //ivec2 p = px + axis * i * int(aoRadius); + ivec2 p = px + axis * i; + + vec3 val = texelFetch(tex1, p, 0).xyz; + //float z = val.y; + float w = 0.3 + gaussian[abs(i)]; + // Decrease weight as depth difference increases. This prevents us from + // blurring across depth discontinuities + //w *= max(0.f, 1.f - (ao_params.edge_sharpness * 400.f) * abs(z_pos - z)); + sum += val * w; + weight += w; + } + color = vec4(sum / (weight + 0.0001), 1.0); +} diff --git a/surfice.app/Contents/Resources/ao3-itWorks.glsl b/surfice.app/Contents/Resources/ao3-itWorks.glsl new file mode 100755 index 0000000..556ad0e --- /dev/null +++ b/surfice.app/Contents/Resources/ao3-itWorks.glsl @@ -0,0 +1,224 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +#define M_PI 3.14159265 +smooth in vec2 texCoord; +out vec4 color; +//general stuff +int samples = 32; //ao sample count +float aoclamp = 0.25; //depth clamp - reduces haloing at screen edges +bool noise = true; //use noise instead of pattern for sample dithering +float noiseamount = 0.0002; //dithering amount +float diffarea = 0.1; //self-shadowing reduction +float gdisplace = 0.4; //gauss bell center +vec2 pixFrac = 1.0/texture_size; //texture spacing for one pixel + +vec2 rand(vec2 coord) { + float noiseX = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.25)+(fract(coord.t*(texture_size.y/2.0))*0.75))*2.0-1.0; + float noiseY = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.75)+(fract(coord.t*(texture_size.y/2.0))*0.25))*2.0-1.0; + if (noise) { + noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0; + noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0; + } + return vec2(noiseX,noiseY)*noiseamount; +} +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} +float compareDepths(in float depth1, in float depth2,inout int far) { + float garea = 2.0; //gauss bell width + float diff = (depth1 - depth2)*100.0; //depth difference (0-100) + if (diff 0) { + float temp2 = compareDepths(readDepth(texCoord-coordwh),depth,far); + temp += (1.0-temp)*temp2; + } + return temp; +} +float getAOorig(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + ao = smoothstep(0.0, 1.0, ao); + ao = (1.0 - ao) * fracAO; + return ao; +} + +float getAO(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += readDepth(vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + //ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + return depth; + //if (ao < depth) + // ao = 0.5; + //else + // ao = 0.0; + //ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + //ao = smoothstep(0.0, 1.0, ao); + //ao = (1.0 - ao) * fracAO; + return ao; +} + +vec3 worldFromScreen(vec2 tx) { //texture positon 0..1, 0..1, + return vec3(tx, readDepth(tx)); +} + +vec3 getNormal(vec2 tx) { //compute normal given texture coordinate "tx" + vec3 p = worldFromScreen(tx); //center + vec3 p1 = worldFromScreen(tx+ vec2(0.0, pixFrac.y)); //up + vec3 p2 = worldFromScreen(tx+ vec2(pixFrac.x, 0.0));//right + vec3 normal = cross(p2-p, p1-p); + return normalize(normal); +} + + +float random(vec3 scale) { + return fract(sin(dot(gl_FragCoord.xyz, scale)) * 43758.5453); +} + + vec3 getOffsetPositionVS(vec2 screenOrigin, vec2 unitOffset, float screenSpaceRadius) { + // Offset by screenSpaceRadius pixels in the direction of unitOffset + vec2 screenOffset = screenOrigin + + screenSpaceRadius * unitOffset * pixFrac; + + // Get the world coordinate from the offset screen space coordinate + return worldFromScreen(screenOffset); + } + +void main(void) { + + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + //texture_size + vec3 normal = getNormal(texCoord); + vec3 pos = worldFromScreen(texCoord); + color.rgb = normal; + + const int NUM_SAMPLES = 32; + const int NUM_SPIRAL_TURNS = 7; + const float EPSILON = 0.1; + const float BIAS = 0.5; + + vec3 randomScale = vec3(12.9898, 78.233, 151.7182); + float sampleNoise = random(randomScale); + float initialAngle = 2.0 * M_PI * sampleNoise; + float WORLD_SPACE_RADIUS = 0.2; // radius of influence in world space + // radius of influence in screen space + float screenSpaceSampleRadius = aoRadius; //<-xxxx + float occlusion = 0.0; + float ao_value = 0.0; + for (int sampleNumber = 0; sampleNumber < NUM_SAMPLES; sampleNumber++) { + // Step 1: + // Looking at the 2D image of the scene, sample the points surrounding the current one + // in a spiral pattern + + float sampleProgress = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); + float angle = sampleProgress * (float(NUM_SPIRAL_TURNS) * 2.0 * M_PI) + initialAngle; + float sampleDistance = sampleProgress * screenSpaceSampleRadius; + vec2 angleUnitVector = vec2(cos(angle), sin(angle)); + float beta = 0.0005; + // Step 2: + // Get the 3d coordinate corresponding to the sample on the spiral + vec3 q = getOffsetPositionVS(texCoord, angleUnitVector, sampleDistance); + vec3 v = q - pos; + // The original estimator in the paper, from Alchemy AO + // I tried getting their new recommended estimator running but couldn't get it to look nice, + // from taking a look at their AO shader it also looks like we compute this value quite differently + ao_value += max(0, dot(v, normal + pos.z * beta)) / (dot(v, v) + 0.01); + + + } + float kappa = 0.8; + float sigma = 3.8; + // The original method in paper, from Alchemy AO + ao_value = max(0, 1.f - 2.f * sigma / NUM_SAMPLES * ao_value); + ao_value = pow(ao_value, kappa); + + //if (occlusion > 0.0) + // occlusion = 1.0; + /* + 0 int use_rendered_normals; + 27 int n_samples; + 16 int turns; + 3.5 float ball_radius; + 3.8 float sigma; + 0.8 float kappa; + 0.0005 float beta; + // Parameters for the blurring pass + 2 int filter_scale; + 0.8 float edge_sharpness; +*/ + color.rgb = vec3(ao_value, ao_value, ao_value); + return; + occlusion = 1.0 - occlusion / (4.0 * float(NUM_SAMPLES)); + //color.rgb = vec3(ao, ao, ao); + float INTENSITY = 200.0; + occlusion = clamp(pow(occlusion, 1.0 + INTENSITY), 0.0, 1.0); + color.rgb = vec3(occlusion,occlusion,occlusion); + + //return; + //vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + //t1.r = getAO(); + //t1.g = t1.r; + //t1.b = t1.r; + //color = t1; + //return; + //if (fracAO > 0.0) + // t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + //t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + //float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + //depth = clamp(depth, 0.0, 1.0); + //color = mix(t1, t2, blend1 * depth); +} \ No newline at end of file diff --git a/surfice.app/Contents/Resources/ao3.glsl b/surfice.app/Contents/Resources/ao3.glsl new file mode 100755 index 0000000..9af0a02 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3.glsl @@ -0,0 +1,249 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 +// https://github.com/Twinklebear/ssao +// https://codepen.io/davepvm/details/zWdepm +uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform float aoRadiusPx, aoRadiusDx; +uniform vec2 texture_size; +smooth in vec2 texCoord; +out vec4 color; +vec2 pixFrac = 1.0/texture_size; //texture spacing for one pixel + +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} + +vec3 worldFromScreen(vec2 tx) { //texture positon 0..1, 0..1, + return vec3(tx, readDepth(tx)); +} + +float random() { + vec3 scale = vec3(12.9898, 78.233, 151.7182); + return fract(sin(dot(gl_FragCoord.xyz, scale)) * 43758.5453); +} + +vec3 getOffsetPositionVS(vec2 screenOrigin, vec2 unitOffset, float screenSpaceRadius) { + // Offset by screenSpaceRadius pixels in the direction of unitOffset + vec2 screenOffset = screenOrigin + screenSpaceRadius * unitOffset * pixFrac; + //vec2 pixFrac2 = vec2(1.0, 1.0); + //vec2 screenOffset = screenOrigin + screenSpaceRadius * unitOffset * pixFrac2; + // Get the world coordinate from the offset screen space coordinate + return worldFromScreen(screenOffset); +} + +void main(void) { + float kappa = 0.8; //contrast + float beta = 0.0005; + float sigma = 3.8; + #define M_PI 3.14159265 + const int NUM_SAMPLES = 27; + const int NUM_SPIRAL_TURNS = 16; + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + //texture_size + vec3 pos = worldFromScreen(texCoord); + vec3 normal = normalize(cross(dFdx(pos), dFdy(pos))); + //color.rgb = normal; return; + float sampleNoise = random(); + float initialAngle = 2.0 * M_PI * sampleNoise; + float screenSpaceSampleRadius = aoRadiusPx;//aoRadius; + //float screenSpaceSampleRadius = 16.0 * pixFrac.x * fracAO; + float ao_value = 0.0; + for (int sampleNumber = 0; sampleNumber < NUM_SAMPLES; sampleNumber++) { + // Step 1: + // sample the points surrounding the central pixel one in a spiral pattern + float sampleProgress = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); + float angle = sampleProgress * (float(NUM_SPIRAL_TURNS) * 2.0 * M_PI) + initialAngle; + float sampleDistance = sampleProgress * screenSpaceSampleRadius; + vec2 angleUnitVector = vec2(cos(angle), sin(angle)); + // Step 2: + // Get the 3d coordinate corresponding to the sample on the spiral + vec3 q = getOffsetPositionVS(texCoord, angleUnitVector, sampleDistance); + vec3 v = q - pos; + // The original estimator in the paper, from Alchemy AO + // I tried getting their new recommended estimator running but couldn't get it to look nice, + // from taking a look at their AO shader it also looks like we compute this value quite differently + ao_value += max(0, dot(v, normal + pos.z * beta)) / (dot(v, v) + 0.01); + } + ao_value *= fracAO; + // The original method in paper, from Alchemy AO + ao_value = max(0, 1.f - 2.f * sigma / NUM_SAMPLES * ao_value); + ao_value = pow(ao_value, kappa); + + //float ao_valuer = 0.0; + //if (abs(dFdx(pos.z)) > 0.005) { + // ao_valuer = 1.0;// -= dFdx(ao_value) ; + //} + //if (abs(dFdy(pos.z)) > 0.005) { + // ao_valuer = 1.0;// -= dFdx(ao_value) ;//-= dFdy(ao_value) ; + //} + + color.rgb = vec3(ao_value, ao_value, ao_value); + /* + occlusion = 1.0 - occlusion / (4.0 * float(NUM_SAMPLES)); + //color.rgb = vec3(ao, ao, ao); + float INTENSITY = 200.0; + occlusion = pow(occlusion, 1.0 + INTENSITY); + occlusion = clamp(occlusion, 0.0, 1.0); + color.rgb = vec3(occlusion,occlusion,occlusion); + + //return; + //vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + //t1.r = getAO(); + //t1.g = t1.r; + //t1.b = t1.r; + //color = t1; + //return; + //if (fracAO > 0.0) + // t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + //t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + //float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + //depth = clamp(depth, 0.0, 1.0); + //color = mix(t1, t2, blend1 * depth); + */ +} + +/* + const fragmentShaderSourceAO = ` + #extension GL_OES_standard_derivatives : enable + precision highp float; + + uniform sampler2D diffuseBuf; + uniform sampler2D normalBuf; + uniform sampler2D positionBuf; + uniform sampler2D depthBuf; + + uniform vec2 screenSize; + + const int NUM_SAMPLES = 11; + const int NUM_SPIRAL_TURNS = 7; + const float EPSILON = 0.1; + const float BIAS = 0.5; + const float WORLD_SPACE_RADIUS = 30.0; // radius of influence in world space + const float INTENSITY = 200.0; + + const float M_PI = 3.1415926535897932384626433832795; + + int AND(int n1, int n2){ + float v1 = float(n1); + float v2 = float(n2); + + int byteVal = 1; + int result = 0; + + for(int i = 0; i < 32; i++){ + bool keepGoing = v1>0.0 || v2 > 0.0; + if(keepGoing){ + + bool addOn = mod(v1, 2.0) > 0.0 && mod(v2, 2.0) > 0.0; + + if(addOn){ + result += byteVal; + } + + v1 = floor(v1 / 2.0); + v2 = floor(v2 / 2.0); + byteVal *= 2; + } else { + return result; + } + } + return result; + } + + float random(vec3 scale, float seed) { + return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed); + } + + vec3 worldFromScreen(const vec2 screen) { + return texture2D(positionBuf, screen).xyz; + } + + vec3 getOffsetPositionVS(vec2 screenOrigin, vec2 unitOffset, float screenSpaceRadius) { + // Offset by screenSpaceRadius pixels in the direction of unitOffset + vec2 screenOffset = screenOrigin + + screenSpaceRadius * unitOffset * vec2(1.0 / screenSize.x, 1.0 / screenSize.y); + + // Get the world coordinate from the offset screen space coordinate + return worldFromScreen(screenOffset); + } + + void main() { + vec2 screenSpaceOrigin = gl_FragCoord.xy * vec2(1.0/screenSize.x, 1.0/screenSize.y); + ivec2 pixel = ivec2(gl_FragCoord.xy); + + vec3 worldSpaceOrigin = worldFromScreen(screenSpaceOrigin); + vec3 normalAtOrigin = normalize(texture2D(normalBuf, screenSpaceOrigin).xyz); + vec3 colorAtOrigin = texture2D(diffuseBuf, screenSpaceOrigin).xyz; + + vec3 randomScale = vec3(12.9898, 78.233, 151.7182); + vec3 sampleNoise = vec3( + random(randomScale, 0.0), + random(randomScale, 1.0), + random(randomScale, 2.0)); + + float initialAngle = 2.0 * M_PI * sampleNoise.x; + + // radius of influence in screen space + float screenSpaceSampleRadius = 100.0 * WORLD_SPACE_RADIUS / worldSpaceOrigin.y; + + float occlusion = 0.0; + for (int sampleNumber = 0; sampleNumber < NUM_SAMPLES; sampleNumber++) { + // Step 1: + // Looking at the 2D image of the scene, sample the points surrounding the current one + // in a spiral pattern + + float sampleProgress = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); + float angle = sampleProgress * (float(NUM_SPIRAL_TURNS) * 2.0 * M_PI) + initialAngle; + + float sampleDistance = sampleProgress * screenSpaceSampleRadius; + vec2 angleUnitVector = vec2(cos(angle), sin(angle)); + + // Step 2: + // Get the 3d coordinate corresponding to the sample on the spiral + vec3 worldSpaceSample = + getOffsetPositionVS(screenSpaceOrigin, angleUnitVector, sampleDistance); + + // Step 3: + // Approximate occlusion from this sample + vec3 originToSample = worldSpaceSample - worldSpaceOrigin; + float squaredDistanceToSample = dot(originToSample, originToSample); + + // vn is proportional to how close the sample point is to the origin point along + // the normal at the origin + float vn = dot(originToSample, normalAtOrigin) - BIAS; + + // f is proportional to how close the sample point is to the origin point in the + // sphere of influence in world space + float radiusSquared = WORLD_SPACE_RADIUS * WORLD_SPACE_RADIUS; + float f = max(radiusSquared - squaredDistanceToSample, 0.0) / radiusSquared; + float sampleOcclusion = f * f * f * max(vn / (EPSILON + squaredDistanceToSample), 0.0); + + // Accumulate occlusion + occlusion += sampleOcclusion; + } + + occlusion = 1.0 - occlusion / (4.0 * float(NUM_SAMPLES)); + + occlusion = clamp(pow(occlusion, 1.0 + INTENSITY), 0.0, 1.0); + if (abs(dFdx(worldSpaceOrigin.z)) < 0.5) { + occlusion -= dFdx(occlusion) * (float(AND(pixel.x, 1)) - 0.5); + } + if (abs(dFdy(worldSpaceOrigin.z)) < 0.5) { + occlusion -= dFdy(occlusion) * (float(AND(pixel.y, 1)) - 0.5); + } + + gl_FragData[0] = vec4(occlusion, occlusion, occlusion, 1.0); + } +*/ \ No newline at end of file diff --git a/surfice.app/Contents/Resources/ao3_4.glsl b/surfice.app/Contents/Resources/ao3_4.glsl new file mode 100755 index 0000000..90f2b21 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3_4.glsl @@ -0,0 +1,57 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +#define RADIUS 4 +smooth in vec2 texCoord; +out vec4 color; +// True if we're blurring vertically, false if horizontally since we +// do the blurring in two passes, once for horizontal and once for vertical +//uniform ivec2 axis; + + +void main(void){ + ivec2 axis = ivec2(0, 1); + //ivec2 px = ivec2(texCoord.xy); //ivec2(gl_FragCoord.xy); + //ivec2 px = ivec2(gl_FragCoord.xy); + // Gaussian filter values from the author's blurring shader + //const float gaussian[RADIUS + 1] = float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); + //vec4 t1 = texture(tex1, texCoord); + //vec3 val = texture(tex1, px).xyz; + ivec2 px = ivec2(gl_FragCoord.xy); + vec3 val = texelFetch(tex1, px, 0).xyz; + + const float gaussian[RADIUS + 1] = float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); + float weight = gaussian[0]; + vec3 sum = weight * val; + for (int i = -RADIUS; i <= RADIUS; ++i){ + // We handle the center pixel above so skip that case + if (i == 0) continue; + // Filter scale effects how many pixels the kernel actually covers + //vec2 p = px + axis * i * aoRadius; + //ivec2 p = px + axis * i * int(aoRadius); + ivec2 p = px + axis * i; + + vec3 val = texelFetch(tex1, p, 0).xyz; + //float z = val.y; + float w = 0.3 + gaussian[abs(i)]; + // Decrease weight as depth difference increases. This prevents us from + // blurring across depth discontinuities + //w *= max(0.f, 1.f - (ao_params.edge_sharpness * 400.f) * abs(z_pos - z)); + sum += val * w; + weight += w; + } + color = vec4(sum / (weight + 0.0001), 1.0); +} diff --git a/surfice.app/Contents/Resources/ao3_blur.glsl b/surfice.app/Contents/Resources/ao3_blur.glsl new file mode 100755 index 0000000..436ae78 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3_blur.glsl @@ -0,0 +1,53 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +#define RADIUS 4 +smooth in vec2 texCoord; +out vec4 color; +// True if we're blurring vertically, false if horizontally since we +// do the blurring in two passes, once for horizontal and once for vertical +//uniform ivec2 axis; + + +void main(void){ + #define RADIUS 4 + const float gaussian[RADIUS + 1] = float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); + vec4 clr = texture(tex1, texCoord); + if (clr.a == 0.0) discard; + float weight = gaussian[0]; + vec3 val = clr.rgb; + vec3 sum = weight * val; + vec2 axis = vec2(0.0, 1.0/texture_size.y); + vec2 px = texCoord; + + for (int i = -RADIUS; i <= RADIUS; ++i){ + // We handle the center pixel above so skip that case + if (i == 0) continue; + // Filter scale effects how many pixels the kernel actually covers + //vec2 p = px + axis * i * aoRadius; + vec2 p = px + axis * i * aoRadius; + + vec3 val = texture(tex1, p).rgb; + float w = gaussian[abs(i)]; + // Decrease weight as depth difference increases. This prevents us from + // blurring across depth discontinuities + //w *= max(0.f, 1.f - (ao_params.edge_sharpness * 400.f) * abs(z_pos - z)); + sum += val * w; + weight += w; + } + val = sum / (weight + 0.0001); + color = vec4(val, clr.a); +} diff --git a/surfice.app/Contents/Resources/ao3_depth.glsl b/surfice.app/Contents/Resources/ao3_depth.glsl new file mode 100755 index 0000000..125e340 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3_depth.glsl @@ -0,0 +1,41 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 +uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +#define PI2 PI * 2 +smooth in vec2 texCoord; +out vec4 color; +// True if we're blurring vertically, false if horizontally since we +// do the blurring in two passes, once for horizontal and once for vertical +//uniform ivec2 axis; + +float getDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} + +#define NUM_SAMPLES 7 +#define NUM_RINGS 4 +const float ANGLE_STEP = PI2 * float( NUM_RINGS ) / float( NUM_SAMPLES ); +const float INV_NUM_SAMPLES = 1.0 / float( NUM_SAMPLES ); + + +void main(void){ + vec4 clr = texture(tex1, texCoord); + if (clr.a == 0.0) discard; + clr.r = getDepth(texCoord); + clr.g = clr.r; + clr.b = clr.r; + color = clr; + +} diff --git a/surfice.app/Contents/Resources/ao3_orig.glsl b/surfice.app/Contents/Resources/ao3_orig.glsl new file mode 100755 index 0000000..603a247 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3_orig.glsl @@ -0,0 +1,94 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 +uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +smooth in vec2 texCoord; +out vec4 color; +//general stuff +int samples = 32; //ao sample count +float aoclamp = 0.25; //depth clamp - reduces haloing at screen edges +bool noise = true; //use noise instead of pattern for sample dithering +float noiseamount = 0.0002; //dithering amount +float diffarea = 0.5; //self-shadowing reduction +//float gdisplace = 0.4; //gauss bell center +float gdisplace = 0.35; //gauss bell center +vec2 rand(vec2 coord) { + float noiseX = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.25)+(fract(coord.t*(texture_size.y/2.0))*0.75))*2.0-1.0; + float noiseY = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.75)+(fract(coord.t*(texture_size.y/2.0))*0.25))*2.0-1.0; + if (noise) { + noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0; + noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0; + } + return vec2(noiseX,noiseY)*noiseamount; +} +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} +float compareDepths(in float depth1, in float depth2,inout int far) { + float garea = 2.0; //gauss bell width + float diff = (depth1 - depth2)*100.0; //depth difference (0-100) + if (diff 0) { + float temp2 = compareDepths(readDepth(texCoord-coordwh),depth,far); + temp += (1.0-temp)*temp2; + } + return temp; +} + +float getAO(void) { + vec2 noise = rand(texCoord); + float ao = 0.0; + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + ao = smoothstep(0.0, 1.0, ao); + ao = (1.0 - ao) * fracAO; + return ao; +} +void main(void) { + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + if (fracAO > 0.0) + t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + depth = clamp(depth, 0.0, 1.0); + color = mix(t1, t2, blend1 * depth); +} + diff --git a/surfice.app/Contents/Resources/ao3_twinklebear.glsl b/surfice.app/Contents/Resources/ao3_twinklebear.glsl new file mode 100755 index 0000000..6784c1e --- /dev/null +++ b/surfice.app/Contents/Resources/ao3_twinklebear.glsl @@ -0,0 +1,119 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 +uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +smooth in vec2 texCoord; +out vec4 color; +vec2 pixFrac = 1.0/texture_size; //texture spacing for one pixel + +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} + +vec3 worldFromScreen(vec2 tx) { //texture positon 0..1, 0..1, + return vec3(tx, readDepth(tx)); +} + +vec3 getNormal(vec2 tx) { //compute normal given texture coordinate "tx" + vec3 p = worldFromScreen(tx); //center + vec3 p1 = worldFromScreen(tx+ vec2(0.0, pixFrac.y)); //up + vec3 p2 = worldFromScreen(tx+ vec2(pixFrac.x, 0.0));//right + vec3 normal = cross(p2-p, p1-p); + return normalize(normal); +} + +float random() { + vec3 scale = vec3(12.9898, 78.233, 151.7182); + return fract(sin(dot(gl_FragCoord.xyz, scale)) * 43758.5453); +} + +vec3 getOffsetPositionVS(vec2 screenOrigin, vec2 unitOffset, float screenSpaceRadius) { + // Offset by screenSpaceRadius pixels in the direction of unitOffset + vec2 screenOffset = screenOrigin + screenSpaceRadius * unitOffset * pixFrac; + //vec2 pixFrac2 = vec2(1.0, 1.0); + //vec2 screenOffset = screenOrigin + screenSpaceRadius * unitOffset * pixFrac2; + + // Get the world coordinate from the offset screen space coordinate + return worldFromScreen(screenOffset); +} + +void main(void) { + float kappa = 0.8; + float sigma = 3.8; + #define M_PI 3.14159265 + const int NUM_SAMPLES = 27; + const int NUM_SPIRAL_TURNS = 16; + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + //texture_size + vec3 normal = getNormal(texCoord); + normal.z = normal.z; + vec3 pos = worldFromScreen(texCoord); + //color.rgb = normal; + float sampleNoise = random(); + float initialAngle = 2.0 * M_PI * sampleNoise; + float screenSpaceSampleRadius = aoRadius; + //float screenSpaceSampleRadius = 16.0 * pixFrac.x * fracAO; + float ao_value = 0.0; + for (int sampleNumber = 0; sampleNumber < NUM_SAMPLES; sampleNumber++) { + // Step 1: + // sample the points surrounding the central pixel one in a spiral pattern + float sampleProgress = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); + float angle = sampleProgress * (float(NUM_SPIRAL_TURNS) * 2.0 * M_PI) + initialAngle; + float sampleDistance = sampleProgress * screenSpaceSampleRadius; + vec2 angleUnitVector = vec2(cos(angle), sin(angle)); + float beta = 0.0005; + // Step 2: + // Get the 3d coordinate corresponding to the sample on the spiral + vec3 q = getOffsetPositionVS(texCoord, angleUnitVector, sampleDistance); + vec3 v = q - pos; + // The original estimator in the paper, from Alchemy AO + // I tried getting their new recommended estimator running but couldn't get it to look nice, + // from taking a look at their AO shader it also looks like we compute this value quite differently + ao_value += max(0, dot(v, normal + pos.z * beta)) / (dot(v, v) + 0.01); + } + // The original method in paper, from Alchemy AO + ao_value = max(0, 1.f - 2.f * sigma / NUM_SAMPLES * ao_value); + ao_value = pow(ao_value, kappa); + //float ao_valuer = 0.0; + //if (abs(dFdx(pos.z)) > 0.005) { + // ao_valuer = 1.0;// -= dFdx(ao_value) ; + //} + //if (abs(dFdy(pos.z)) > 0.005) { + // ao_valuer = 1.0;// -= dFdx(ao_value) ;//-= dFdy(ao_value) ; + //} + + color.rgb = vec3(ao_value, ao_value, ao_value); + /* + occlusion = 1.0 - occlusion / (4.0 * float(NUM_SAMPLES)); + //color.rgb = vec3(ao, ao, ao); + float INTENSITY = 200.0; + occlusion = clamp(pow(occlusion, 1.0 + INTENSITY), 0.0, 1.0); + color.rgb = vec3(occlusion,occlusion,occlusion); + + //return; + //vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + //t1.r = getAO(); + //t1.g = t1.r; + //t1.b = t1.r; + //color = t1; + //return; + //if (fracAO > 0.0) + // t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + //t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + //float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + //depth = clamp(depth, 0.0, 1.0); + //color = mix(t1, t2, blend1 * depth); + */ +} \ No newline at end of file diff --git a/surfice.app/Contents/Resources/ao3_twinklebear_final.glsl b/surfice.app/Contents/Resources/ao3_twinklebear_final.glsl new file mode 100755 index 0000000..54caa20 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3_twinklebear_final.glsl @@ -0,0 +1,110 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 +uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform float aoRadiusPx, aoRadiusDx; +uniform vec2 texture_size; +smooth in vec2 texCoord; +out vec4 color; +vec2 pixFrac = 1.0/texture_size; //texture spacing for one pixel + +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} + +vec3 worldFromScreen(vec2 tx) { //texture positon 0..1, 0..1, + return vec3(tx, readDepth(tx)); +} + +float random() { + vec3 scale = vec3(12.9898, 78.233, 151.7182); + return fract(sin(dot(gl_FragCoord.xyz, scale)) * 43758.5453); +} + +vec3 getOffsetPositionVS(vec2 screenOrigin, vec2 unitOffset, float screenSpaceRadius) { + // Offset by screenSpaceRadius pixels in the direction of unitOffset + vec2 screenOffset = screenOrigin + screenSpaceRadius * unitOffset * pixFrac; + //vec2 pixFrac2 = vec2(1.0, 1.0); + //vec2 screenOffset = screenOrigin + screenSpaceRadius * unitOffset * pixFrac2; + // Get the world coordinate from the offset screen space coordinate + return worldFromScreen(screenOffset); +} + +void main(void) { + float kappa = 0.8; + float beta = 0.0005; + float sigma = 3.8; + #define M_PI 3.14159265 + const int NUM_SAMPLES = 27; + const int NUM_SPIRAL_TURNS = 16; + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + //texture_size + vec3 pos = worldFromScreen(texCoord); + vec3 normal = normalize(cross(dFdx(pos), dFdy(pos))); + //color.rgb = normal; return; + float sampleNoise = random(); + float initialAngle = 2.0 * M_PI * sampleNoise; + float screenSpaceSampleRadius = aoRadiusPx;//aoRadius; + //float screenSpaceSampleRadius = 16.0 * pixFrac.x * fracAO; + float ao_value = 0.0; + for (int sampleNumber = 0; sampleNumber < NUM_SAMPLES; sampleNumber++) { + // Step 1: + // sample the points surrounding the central pixel one in a spiral pattern + float sampleProgress = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); + float angle = sampleProgress * (float(NUM_SPIRAL_TURNS) * 2.0 * M_PI) + initialAngle; + float sampleDistance = sampleProgress * screenSpaceSampleRadius; + vec2 angleUnitVector = vec2(cos(angle), sin(angle)); + // Step 2: + // Get the 3d coordinate corresponding to the sample on the spiral + vec3 q = getOffsetPositionVS(texCoord, angleUnitVector, sampleDistance); + vec3 v = q - pos; + // The original estimator in the paper, from Alchemy AO + // I tried getting their new recommended estimator running but couldn't get it to look nice, + // from taking a look at their AO shader it also looks like we compute this value quite differently + ao_value += max(0, dot(v, normal + pos.z * beta)) / (dot(v, v) + 0.01); + } + // The original method in paper, from Alchemy AO + ao_value = max(0, 1.f - 2.f * sigma / NUM_SAMPLES * ao_value); + ao_value = pow(ao_value, kappa); + //float ao_valuer = 0.0; + //if (abs(dFdx(pos.z)) > 0.005) { + // ao_valuer = 1.0;// -= dFdx(ao_value) ; + //} + //if (abs(dFdy(pos.z)) > 0.005) { + // ao_valuer = 1.0;// -= dFdx(ao_value) ;//-= dFdy(ao_value) ; + //} + + color.rgb = vec3(ao_value, ao_value, ao_value); + /* + occlusion = 1.0 - occlusion / (4.0 * float(NUM_SAMPLES)); + //color.rgb = vec3(ao, ao, ao); + float INTENSITY = 200.0; + occlusion = clamp(pow(occlusion, 1.0 + INTENSITY), 0.0, 1.0); + color.rgb = vec3(occlusion,occlusion,occlusion); + + //return; + //vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + //t1.r = getAO(); + //t1.g = t1.r; + //t1.b = t1.r; + //color = t1; + //return; + //if (fracAO > 0.0) + // t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + //t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + //float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + //depth = clamp(depth, 0.0, 1.0); + //color = mix(t1, t2, blend1 * depth); + */ +} \ No newline at end of file diff --git a/surfice.app/Contents/Resources/ao3_twinklebear_finalish.glsl b/surfice.app/Contents/Resources/ao3_twinklebear_finalish.glsl new file mode 100755 index 0000000..35b2620 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3_twinklebear_finalish.glsl @@ -0,0 +1,109 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 +uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +smooth in vec2 texCoord; +out vec4 color; +vec2 pixFrac = 1.0/texture_size; //texture spacing for one pixel + +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} + +vec3 worldFromScreen(vec2 tx) { //texture positon 0..1, 0..1, + return vec3(tx, readDepth(tx)); +} + +float random() { + vec3 scale = vec3(12.9898, 78.233, 151.7182); + return fract(sin(dot(gl_FragCoord.xyz, scale)) * 43758.5453); +} + +vec3 getOffsetPositionVS(vec2 screenOrigin, vec2 unitOffset, float screenSpaceRadius) { + // Offset by screenSpaceRadius pixels in the direction of unitOffset + vec2 screenOffset = screenOrigin + screenSpaceRadius * unitOffset * pixFrac; + //vec2 pixFrac2 = vec2(1.0, 1.0); + //vec2 screenOffset = screenOrigin + screenSpaceRadius * unitOffset * pixFrac2; + // Get the world coordinate from the offset screen space coordinate + return worldFromScreen(screenOffset); +} + +void main(void) { + float kappa = 0.8; + float beta = 0.0005; + float sigma = 3.8; + #define M_PI 3.14159265 + const int NUM_SAMPLES = 27; + const int NUM_SPIRAL_TURNS = 16; + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + //texture_size + vec3 pos = worldFromScreen(texCoord); + vec3 normal = normalize(cross(dFdx(pos), dFdy(pos))); + //color.rgb = normal; return; + float sampleNoise = random(); + float initialAngle = 2.0 * M_PI * sampleNoise; + float screenSpaceSampleRadius = 8;//aoRadius; + //float screenSpaceSampleRadius = 16.0 * pixFrac.x * fracAO; + float ao_value = 0.0; + for (int sampleNumber = 0; sampleNumber < NUM_SAMPLES; sampleNumber++) { + // Step 1: + // sample the points surrounding the central pixel one in a spiral pattern + float sampleProgress = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); + float angle = sampleProgress * (float(NUM_SPIRAL_TURNS) * 2.0 * M_PI) + initialAngle; + float sampleDistance = sampleProgress * screenSpaceSampleRadius; + vec2 angleUnitVector = vec2(cos(angle), sin(angle)); + // Step 2: + // Get the 3d coordinate corresponding to the sample on the spiral + vec3 q = getOffsetPositionVS(texCoord, angleUnitVector, sampleDistance); + vec3 v = q - pos; + // The original estimator in the paper, from Alchemy AO + // I tried getting their new recommended estimator running but couldn't get it to look nice, + // from taking a look at their AO shader it also looks like we compute this value quite differently + ao_value += max(0, dot(v, normal + pos.z * beta)) / (dot(v, v) + 0.01); + } + // The original method in paper, from Alchemy AO + ao_value = max(0, 1.f - 2.f * sigma / NUM_SAMPLES * ao_value); + ao_value = pow(ao_value, kappa); + //float ao_valuer = 0.0; + //if (abs(dFdx(pos.z)) > 0.005) { + // ao_valuer = 1.0;// -= dFdx(ao_value) ; + //} + //if (abs(dFdy(pos.z)) > 0.005) { + // ao_valuer = 1.0;// -= dFdx(ao_value) ;//-= dFdy(ao_value) ; + //} + + color.rgb = vec3(ao_value, ao_value, ao_value); + /* + occlusion = 1.0 - occlusion / (4.0 * float(NUM_SAMPLES)); + //color.rgb = vec3(ao, ao, ao); + float INTENSITY = 200.0; + occlusion = clamp(pow(occlusion, 1.0 + INTENSITY), 0.0, 1.0); + color.rgb = vec3(occlusion,occlusion,occlusion); + + //return; + //vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + //t1.r = getAO(); + //t1.g = t1.r; + //t1.b = t1.r; + //color = t1; + //return; + //if (fracAO > 0.0) + // t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + //t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + //float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + //depth = clamp(depth, 0.0, 1.0); + //color = mix(t1, t2, blend1 * depth); + */ +} \ No newline at end of file diff --git a/surfice.app/Contents/Resources/ao3_unused.glsl b/surfice.app/Contents/Resources/ao3_unused.glsl new file mode 100755 index 0000000..e9e9979 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3_unused.glsl @@ -0,0 +1,89 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +smooth in vec2 texCoord; +out vec4 color; +//general stuff +int samples = 48; //ao sample count +float aoclamp = 0.25; //depth clamp - reduces haloing at screen edges +bool noise = true; //use noise instead of pattern for sample dithering +float noiseamount = 0.0002; //dithering amount +float diffarea = 0.58; //self-shadowing reduction +float gdisplace = 0.4; //gauss bell center +vec2 rand(vec2 coord) { + float noiseX = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.25)+(fract(coord.t*(texture_size.y/2.0))*0.75))*2.0-1.0; + float noiseY = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.75)+(fract(coord.t*(texture_size.y/2.0))*0.25))*2.0-1.0; + if (noise) { + noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0; + noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0; + } + return vec2(noiseX,noiseY)*noiseamount; +} +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} +float compareDepths(in float depth1, in float depth2,inout int far) { + float garea = 2.0; //gauss bell width + float diff = (depth1 - depth2)*100.0; //depth difference (0-100) + if (diff 0) { + float temp2 = compareDepths(readDepth(texCoord-coordwh),depth,far); + temp += (1.0-temp)*temp2; + } + return temp; +} +float getAO(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + ao = smoothstep(0.0, 1.0, ao); + ao = (1.0 - ao) * fracAO; + return ao; +} +void main(void) { + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + vec4 t2 = texture(tex2, texCoord); + if (fracAO > 0.0) + t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + depth = clamp(depth, 0.0, 1.0); + color = mix(t1, t2, blend1 * depth); +} diff --git a/surfice.app/Contents/Resources/ao3almost.glsl b/surfice.app/Contents/Resources/ao3almost.glsl new file mode 100755 index 0000000..aa309ad --- /dev/null +++ b/surfice.app/Contents/Resources/ao3almost.glsl @@ -0,0 +1,221 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +#define M_PI 3.14159265 +smooth in vec2 texCoord; +out vec4 color; +//general stuff +int samples = 32; //ao sample count +float aoclamp = 0.25; //depth clamp - reduces haloing at screen edges +bool noise = true; //use noise instead of pattern for sample dithering +float noiseamount = 0.0002; //dithering amount +float diffarea = 0.1; //self-shadowing reduction +float gdisplace = 0.4; //gauss bell center +vec2 pixFrac = 1.0/texture_size; //texture spacing for one pixel + +vec2 rand(vec2 coord) { + float noiseX = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.25)+(fract(coord.t*(texture_size.y/2.0))*0.75))*2.0-1.0; + float noiseY = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.75)+(fract(coord.t*(texture_size.y/2.0))*0.25))*2.0-1.0; + if (noise) { + noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0; + noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0; + } + return vec2(noiseX,noiseY)*noiseamount; +} +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} +float compareDepths(in float depth1, in float depth2,inout int far) { + float garea = 2.0; //gauss bell width + float diff = (depth1 - depth2)*100.0; //depth difference (0-100) + if (diff 0) { + float temp2 = compareDepths(readDepth(texCoord-coordwh),depth,far); + temp += (1.0-temp)*temp2; + } + return temp; +} +float getAOorig(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + ao = smoothstep(0.0, 1.0, ao); + ao = (1.0 - ao) * fracAO; + return ao; +} + +float getAO(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += readDepth(vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + //ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + return depth; + //if (ao < depth) + // ao = 0.5; + //else + // ao = 0.0; + //ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + //ao = smoothstep(0.0, 1.0, ao); + //ao = (1.0 - ao) * fracAO; + return ao; +} + +vec3 worldFromScreen(vec2 tx) { //texture positon 0..1, 0..1, + return vec3(tx, readDepth(tx)); +} + +vec3 getNormal(vec2 tx) { //compute normal given texture coordinate "tx" + vec3 p = worldFromScreen(tx); //center + vec3 p1 = worldFromScreen(tx+ vec2(0.0, pixFrac.y)); //up + vec3 p2 = worldFromScreen(tx+ vec2(pixFrac.x, 0.0));//right + vec3 normal = cross(p2-p, p1-p); + return normalize(normal); +} + + +float random(vec3 scale) { + return fract(sin(dot(gl_FragCoord.xyz, scale)) * 43758.5453); +} + + vec3 getOffsetPositionVS(vec2 screenOrigin, vec2 unitOffset, float screenSpaceRadius) { + // Offset by screenSpaceRadius pixels in the direction of unitOffset + vec2 screenOffset = screenOrigin + + screenSpaceRadius * unitOffset * pixFrac; + + // Get the world coordinate from the offset screen space coordinate + return worldFromScreen(screenOffset); + } + +void main(void) { + + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + //texture_size + vec3 normalAtOrigin = getNormal(texCoord); + vec3 worldSpaceOrigin = worldFromScreen(texCoord); + color.rgb = normalAtOrigin; + + const int NUM_SAMPLES = 32; + const int NUM_SPIRAL_TURNS = 7; + const float EPSILON = 0.1; + const float BIAS = 0.5; + + vec3 randomScale = vec3(12.9898, 78.233, 151.7182); + float sampleNoise = random(randomScale); + float initialAngle = 2.0 * M_PI * sampleNoise; + float WORLD_SPACE_RADIUS = 0.2; // radius of influence in world space + // radius of influence in screen space + float screenSpaceSampleRadius = aoRadius; //<-xxxx + float occlusion = 0.0; + float ao = 0.0; + for (int sampleNumber = 0; sampleNumber < NUM_SAMPLES; sampleNumber++) { + // Step 1: + // Looking at the 2D image of the scene, sample the points surrounding the current one + // in a spiral pattern + + float sampleProgress = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES)); + float angle = sampleProgress * (float(NUM_SPIRAL_TURNS) * 2.0 * M_PI) + initialAngle; + float sampleDistance = sampleProgress * screenSpaceSampleRadius; + vec2 angleUnitVector = vec2(cos(angle), sin(angle)); + + // Step 2: + // Get the 3d coordinate corresponding to the sample on the spiral + vec3 worldSpaceSample = getOffsetPositionVS(texCoord, angleUnitVector, sampleDistance); + ao += worldSpaceSample.z; + // Step 3: + // Approximate occlusion from this sample + vec3 originToSample = worldSpaceSample - worldSpaceOrigin; + float squaredDistanceToSample = dot(originToSample, originToSample); + + // vn is proportional to how close the sample point is to the origin point along + // the normal at the origin + float vn = dot(originToSample, normalAtOrigin) - BIAS; + + // f is proportional to how close the sample point is to the origin point in the + // sphere of influence in world space + + float radiusSquared = WORLD_SPACE_RADIUS * WORLD_SPACE_RADIUS; + float f = max(radiusSquared - squaredDistanceToSample, 0.0) / radiusSquared; + float sampleOcclusion = f * f * f * max(vn / (EPSILON + squaredDistanceToSample), 0.0); + + // Accumulate occlusion + occlusion += sampleOcclusion; + + } + ao = ao / NUM_SAMPLES; + //if (occlusion > 0.0) + occlusion = 1.0; + + color.rgb = vec3(occlusion,ao,ao); + return; + occlusion = 1.0 - occlusion / (4.0 * float(NUM_SAMPLES)); + color.rgb = vec3(ao, ao, ao); + float INTENSITY = 200.0; + occlusion = clamp(pow(occlusion, 1.0 + INTENSITY), 0.0, 1.0); + color.rgb = vec3(occlusion,occlusion,occlusion); + + //return; + //vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + //t1.r = getAO(); + //t1.g = t1.r; + //t1.b = t1.r; + //color = t1; + //return; + //if (fracAO > 0.0) + // t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + //t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + //float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + //depth = clamp(depth, 0.0, 1.0); + //color = mix(t1, t2, blend1 * depth); +} \ No newline at end of file diff --git a/surfice.app/Contents/Resources/ao3best.glsl b/surfice.app/Contents/Resources/ao3best.glsl new file mode 100755 index 0000000..0757dd6 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3best.glsl @@ -0,0 +1,155 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +smooth in vec2 texCoord; +out vec4 color; +//general stuff +int samples = 32; //ao sample count +float aoclamp = 0.25; //depth clamp - reduces haloing at screen edges +bool noise = true; //use noise instead of pattern for sample dithering +float noiseamount = 0.0002; //dithering amount +float diffarea = 0.1; //self-shadowing reduction +float gdisplace = 0.4; //gauss bell center +vec2 rand(vec2 coord) { + float noiseX = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.25)+(fract(coord.t*(texture_size.y/2.0))*0.75))*2.0-1.0; + float noiseY = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.75)+(fract(coord.t*(texture_size.y/2.0))*0.25))*2.0-1.0; + if (noise) { + noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0; + noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0; + } + return vec2(noiseX,noiseY)*noiseamount; +} +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} +float compareDepths(in float depth1, in float depth2,inout int far) { + float garea = 2.0; //gauss bell width + float diff = (depth1 - depth2)*100.0; //depth difference (0-100) + if (diff 0) { + float temp2 = compareDepths(readDepth(texCoord-coordwh),depth,far); + temp += (1.0-temp)*temp2; + } + return temp; +} +float getAOorig(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + ao = smoothstep(0.0, 1.0, ao); + ao = (1.0 - ao) * fracAO; + return ao; +} + +float getAO(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += readDepth(vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + //ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + return depth; + //if (ao < depth) + // ao = 0.5; + //else + // ao = 0.0; + //ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + //ao = smoothstep(0.0, 1.0, ao); + //ao = (1.0 - ao) * fracAO; + return ao; +} + +vec3 getNormal(vec2 texCenter, float dir) { + vec2 pixFrac = dir/texture_size; + vec2 tx = texCenter.xy; //center + vec3 p = vec3(tx, readDepth(tx)); + tx = texCenter.xy+ vec2(0.0, pixFrac.y); //up + vec3 p1 = vec3(tx, readDepth(tx)); + tx = texCenter.xy + vec2(pixFrac.x, 0.0); //right + vec3 p2 = vec3(tx, readDepth(tx)); + vec3 normal = cross(p2-p, p1-p); + return normalize(normal); +} + +/*vec3 getNormal2(vec2 texCenter) { + vec2 pixFrac = 0.5/texture_size; + vec3 n1 = getNormal(texCenter+pixFrac, -1.0); + vec3 n2 = getNormal(texCenter-pixFrac, 1.0); + return normalize(n1+n2); +}*/ + +void main(void) { + + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + + + //texture_size + vec3 n = getNormal(texCoord, 1.0); + //vec3 n = getNormal2(texCoord); + //n = (n + 1)/2; //-1..1 -> 0..1 + //n = abs(n); //-1..1 -> 0..1 + color.rgb = n; + //return; + //vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + //t1.r = getAO(); + //t1.g = t1.r; + //t1.b = t1.r; + //color = t1; + //return; + //if (fracAO > 0.0) + // t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + //t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + //float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + //depth = clamp(depth, 0.0, 1.0); + //color = mix(t1, t2, blend1 * depth); +} \ No newline at end of file diff --git a/surfice.app/Contents/Resources/ao3x.glsl b/surfice.app/Contents/Resources/ao3x.glsl new file mode 100755 index 0000000..1685fb0 --- /dev/null +++ b/surfice.app/Contents/Resources/ao3x.glsl @@ -0,0 +1,125 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +smooth in vec2 texCoord; +out vec4 color; +//general stuff +int samples = 32; //ao sample count +float aoclamp = 0.25; //depth clamp - reduces haloing at screen edges +bool noise = true; //use noise instead of pattern for sample dithering +float noiseamount = 0.0002; //dithering amount +float diffarea = 0.1; //self-shadowing reduction +float gdisplace = 0.4; //gauss bell center +vec2 rand(vec2 coord) { + float noiseX = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.25)+(fract(coord.t*(texture_size.y/2.0))*0.75))*2.0-1.0; + float noiseY = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.75)+(fract(coord.t*(texture_size.y/2.0))*0.25))*2.0-1.0; + if (noise) { + noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0; + noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0; + } + return vec2(noiseX,noiseY)*noiseamount; +} +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} +float compareDepths(in float depth1, in float depth2,inout int far) { + float garea = 2.0; //gauss bell width + float diff = (depth1 - depth2)*100.0; //depth difference (0-100) + if (diff 0) { + float temp2 = compareDepths(readDepth(texCoord-coordwh),depth,far); + temp += (1.0-temp)*temp2; + } + return temp; +} +float getAOorig(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + ao = smoothstep(0.0, 1.0, ao); + ao = (1.0 - ao) * fracAO; + return ao; +} + +float getAO(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += readDepth(vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + //ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + return depth; + //if (ao < depth) + // ao = 0.5; + //else + // ao = 0.0; + //ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + //ao = smoothstep(0.0, 1.0, ao); + //ao = (1.0 - ao) * fracAO; + return ao; +} +void main(void) { + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + t1.r = getAO(); + t1.g = t1.r; + t1.b = t1.r; + color = t1; + return; + if (fracAO > 0.0) + t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + depth = clamp(depth, 0.0, 1.0); + color = mix(t1, t2, blend1 * depth); +} \ No newline at end of file diff --git a/surfice.app/Contents/Resources/normal.glsl b/surfice.app/Contents/Resources/normal.glsl new file mode 100755 index 0000000..0757dd6 --- /dev/null +++ b/surfice.app/Contents/Resources/normal.glsl @@ -0,0 +1,155 @@ +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec2 Coord; +smooth out vec2 texCoord; +void main () { + gl_Position = vec4 (Vert, 1.0); + texCoord = Coord; +} +//frag +#version 330 + uniform sampler2D tex1, tex2, depth_texture1, depth_texture2; +uniform float blend1, alpha1, fracAO, aoRadius; +uniform vec2 texture_size; +#define PI 3.14159265 +smooth in vec2 texCoord; +out vec4 color; +//general stuff +int samples = 32; //ao sample count +float aoclamp = 0.25; //depth clamp - reduces haloing at screen edges +bool noise = true; //use noise instead of pattern for sample dithering +float noiseamount = 0.0002; //dithering amount +float diffarea = 0.1; //self-shadowing reduction +float gdisplace = 0.4; //gauss bell center +vec2 rand(vec2 coord) { + float noiseX = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.25)+(fract(coord.t*(texture_size.y/2.0))*0.75))*2.0-1.0; + float noiseY = ((fract(1.0-coord.s*(texture_size.x/2.0))*0.75)+(fract(coord.t*(texture_size.y/2.0))*0.25))*2.0-1.0; + if (noise) { + noiseX = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233))) * 43758.5453),0.0,1.0)*2.0-1.0; + noiseY = clamp(fract(sin(dot(coord ,vec2(12.9898,78.233)*2.0)) * 43758.5453),0.0,1.0)*2.0-1.0; + } + return vec2(noiseX,noiseY)*noiseamount; +} +float readDepth(in vec2 coord) { + return 1.0 - ((texture(depth_texture1, coord).x + 0.87) * 0.534); +} +float compareDepths(in float depth1, in float depth2,inout int far) { + float garea = 2.0; //gauss bell width + float diff = (depth1 - depth2)*100.0; //depth difference (0-100) + if (diff 0) { + float temp2 = compareDepths(readDepth(texCoord-coordwh),depth,far); + temp += (1.0-temp)*temp2; + } + return temp; +} +float getAOorig(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + ao = smoothstep(0.0, 1.0, ao); + ao = (1.0 - ao) * fracAO; + return ao; +} + +float getAO(void) { + vec2 noise = rand(texCoord); + float depth = readDepth(texCoord); + float dd = (1.0-depth)*aoRadius; + float w = (1.0 / texture_size.x)/clamp(depth,aoclamp,1.0)+(noise.x*(1.0-noise.x)); + float h = (1.0 / texture_size.y)/clamp(depth,aoclamp,1.0)+(noise.y*(1.0-noise.y)); + float ao = 0.0; + float dl = PI*(3.0-sqrt(5.0)); + float dz = 1.0/float(samples); + float l = 0.0; + float z = 1.0 - dz/2.0; + for (int i = 0; i <= samples; i ++) { + float r = sqrt(1.0-z); + ao += readDepth(vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + //ao += calAO(depth, vec2(cos(l)*r*w*dd,sin(l)*r*h*dd)); + z = z - dz; + l = l + dl; + } + ao /= float(samples); + return depth; + //if (ao < depth) + // ao = 0.5; + //else + // ao = 0.0; + //ao = clamp(ao, 0.0, 0.4) * 2.5; //threshold then LERP 0..1 + //ao = smoothstep(0.0, 1.0, ao); + //ao = (1.0 - ao) * fracAO; + return ao; +} + +vec3 getNormal(vec2 texCenter, float dir) { + vec2 pixFrac = dir/texture_size; + vec2 tx = texCenter.xy; //center + vec3 p = vec3(tx, readDepth(tx)); + tx = texCenter.xy+ vec2(0.0, pixFrac.y); //up + vec3 p1 = vec3(tx, readDepth(tx)); + tx = texCenter.xy + vec2(pixFrac.x, 0.0); //right + vec3 p2 = vec3(tx, readDepth(tx)); + vec3 normal = cross(p2-p, p1-p); + return normalize(normal); +} + +/*vec3 getNormal2(vec2 texCenter) { + vec2 pixFrac = 0.5/texture_size; + vec3 n1 = getNormal(texCenter+pixFrac, -1.0); + vec3 n2 = getNormal(texCenter-pixFrac, 1.0); + return normalize(n1+n2); +}*/ + +void main(void) { + + vec4 t1 = texture(tex1, texCoord); + if (t1.a == 0.0) discard; + + + //texture_size + vec3 n = getNormal(texCoord, 1.0); + //vec3 n = getNormal2(texCoord); + //n = (n + 1)/2; //-1..1 -> 0..1 + //n = abs(n); //-1..1 -> 0..1 + color.rgb = n; + //return; + //vec4 t2 = texture(tex2, texCoord); + //float ao = 1.0 - getAO(); color = vec4(ao, ao, ao, 1.0); return; + //t1.r = getAO(); + //t1.g = t1.r; + //t1.b = t1.r; + //color = t1; + //return; + //if (fracAO > 0.0) + // t1.rgb = clamp(t1.rgb-getAO(), 0.0, 1.0); + //t1.rgb = mix(t2.rgb,t1.rgb, alpha1); + //float depth = 1.0 - (3.0 * (texture(depth_texture2, texCoord).x - texture(depth_texture1, texCoord).x)); + //depth = clamp(depth, 0.0, 1.0); + //color = mix(t1, t2, blend1 * depth); +} \ No newline at end of file diff --git a/surfice.app/Contents/Resources/script/startup.gls b/surfice.app/Contents/Resources/script/startup.gls new file mode 100755 index 0000000..6ca1750 --- /dev/null +++ b/surfice.app/Contents/Resources/script/startup.gls @@ -0,0 +1,9 @@ +begin + resetdefaults(); + azimuthelevation(70, 15); + meshload('BrainMesh_ICBM152Right.mz3'); + overlayload('motor_4t95vol.nii.gz'); + overlayminmax(1,2,12); + +end. + diff --git a/surfice.app/Contents/Resources/shaders/MatCap.txt b/surfice.app/Contents/Resources/shaders/MatCap.txt index decbc96..31f042b 100755 --- a/surfice.app/Contents/Resources/shaders/MatCap.txt +++ b/surfice.app/Contents/Resources/shaders/MatCap.txt @@ -3,6 +3,7 @@ Brighten|float|0.5|1.5|2.5 SurfaceColor|float|0.0|1.0|1.0 Edge|float|0|0.2|1.0 PenWidth|float|0.01|1|1 +AOradius|float|0|16|32 MatCap|set|1|1|1 Material Capture Shader http://www.alecjacobson.com/weblog/?p=4827l|note //vert diff --git a/surfice.app/Contents/Resources/shaders/White_SSAO_flat.txt b/surfice.app/Contents/Resources/shaders/White_SSAO_flat.txt new file mode 100755 index 0000000..8cdfc48 --- /dev/null +++ b/surfice.app/Contents/Resources/shaders/White_SSAO_flat.txt @@ -0,0 +1,42 @@ +//pref +Ambient|float|0.0|0.5|1 +Diffuse|float|0.0|0.7|1 +Specular|float|0.0|0.2|1 +Shininess|float|1|60|120 +AOradius|float|0|8|16 +Blinn-Phong shading with Lambertian diffuse. Copyright 2015 Chris Rorden, BSD2clause.|note +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec3 Norm; +layout(location = 6) in vec4 Clr; +out vec3 vClr, vL, vV; +flat out vec3 vN; +out vec4 vP; +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ModelViewMatrix; +uniform mat3 NormalMatrix; +uniform vec3 LightPos = vec3(0.0, 20.0, 30.0); +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.rgb; +} +//frag +#version 330 +in vec4 vP; +flat in vec4 vN; +in vec3 vClr, vL, vV; +out vec4 color; +uniform float Ambient = 0.5; +uniform float Diffuse = 0.7; +uniform float Specular = 0.2; +uniform float Shininess = 60.0; +uniform vec4 ClipPlane = vec4(2.0, 0.0, 0.0, 0.0); +void main() { + if ((ClipPlane[0] < 1.5) && (dot( ClipPlane, vP) > 0.0)) discard; + color = vec4(1.0, 1.0, 1.0, 1.0); +} \ No newline at end of file diff --git a/surfice.app/Contents/Resources/shaders/aWhite_SSAO_only.txt b/surfice.app/Contents/Resources/shaders/aWhite_SSAO_only.txt new file mode 100755 index 0000000..a3bad09 --- /dev/null +++ b/surfice.app/Contents/Resources/shaders/aWhite_SSAO_only.txt @@ -0,0 +1,40 @@ +//pref +Ambient|float|0.0|0.5|1 +Diffuse|float|0.0|0.7|1 +Specular|float|0.0|0.2|1 +Shininess|float|1|60|120 +AOradius|float|0|8|48 +Blinn-Phong shading with Lambertian diffuse. Copyright 2015 Chris Rorden, BSD2clause.|note +//vert +#version 330 +layout(location = 0) in vec3 Vert; +layout(location = 3) in vec3 Norm; +layout(location = 6) in vec4 Clr; +out vec3 vClr, vN, vL, vV; +out vec4 vP; +uniform mat4 ModelViewProjectionMatrix; +uniform mat4 ModelViewMatrix; +uniform mat3 NormalMatrix; +uniform vec3 LightPos = vec3(0.0, 20.0, 30.0); +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.rgb; +} +//frag +#version 330 +in vec4 vP; +in vec3 vClr, vN, vL, vV; +out vec4 color; +uniform float Ambient = 0.5; +uniform float Diffuse = 0.7; +uniform float Specular = 0.2; +uniform float Shininess = 60.0; +uniform vec4 ClipPlane = vec4(2.0, 0.0, 0.0, 0.0); +void main() { + if ((ClipPlane[0] < 1.5) && (dot( ClipPlane, vP) > 0.0)) discard; + color = vec4(1.0, 1.0, 1.0, 1.0); +} \ No newline at end of file diff --git a/surfice.lps b/surfice.lps index a116421..172d754 100644 --- a/surfice.lps +++ b/surfice.lps @@ -3,7 +3,7 @@ - + @@ -18,9 +18,8 @@ - - - + + @@ -30,7 +29,7 @@ - + @@ -40,37 +39,41 @@ - + - - - - + + + + + - + - - - + + + + + - - - - + + + + + @@ -78,7 +81,7 @@ - + @@ -86,7 +89,7 @@ - + @@ -94,7 +97,7 @@ - + @@ -102,7 +105,7 @@ - + @@ -110,7 +113,7 @@ - + @@ -118,32 +121,30 @@ - + - - - + + + - - + - - + - - - + + + @@ -152,16 +153,15 @@ - + - + - - + @@ -169,7 +169,7 @@ - + @@ -177,7 +177,7 @@ - + @@ -186,13 +186,14 @@ - + - - + + + @@ -202,7 +203,7 @@ - + @@ -210,15 +211,16 @@ - + - - - + + + + @@ -227,15 +229,14 @@ - + - - - + + + - @@ -243,14 +244,14 @@ - + - + @@ -259,266 +260,245 @@ - + - - - - - - - - - - - + + + - - - + + + - - - + + + - + - - + + - - - + + + - + - - - - - - - - - + + - + - - + + - + - - - - + + + - - - - + + + - - + + - + - - + + - - - + + + - + - - + - - + + - + - - - + + - - + + - + - - - - + + + - + - - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/track.pas b/track.pas index 828869f..3485574 100644 --- a/track.pas +++ b/track.pas @@ -52,6 +52,9 @@ TTrack = class {$endif} public constructor Create; + {$ifndef isTerminalApp} + function HasScalarPerFiberColor: boolean; + {$endif} function SimplifyMM(Tol, minLength: float): boolean; function LoadFromFile(const FileName: string): boolean; procedure SaveBfloat(const FileName: string); @@ -190,7 +193,7 @@ procedure TTrack.Close; end; end; -function vector2RGB(pt1, pt2: TPoint3F; var len: single): TPoint3f; +function vector2RGB(pt1, pt2: TPoint3F; out len: single): TPoint3f; begin len := sqrt (sqr(pt1.X - pt2.X) + sqr(pt1.Y - pt2.Y) + sqr(pt1.Z - pt2.Z) ); if (len = 0) then begin @@ -245,8 +248,10 @@ procedure TTrack.BuildListStrip; startPt, endPt:TPoint3f; isScalarPerFiberColor : boolean = false; isScalarPerVertexColor: boolean = false; + hideFiber: boolean; begin randomize; + //if length(Scalars) > 0 then // GLForm1.Caption := format('selected %d available %d count %d streamline count %d',[ScalarSelected,length(Scalars), length(Scalars[0].scalar), n_count ]); if (ScalarSelected >= 0) and (length(Scalars) > ScalarSelected) then begin @@ -255,7 +260,6 @@ procedure TTrack.BuildListStrip; else isScalarPerVertexColor := true; end; - // exit; maxLinks := 0; n_faces := 0; @@ -271,6 +275,7 @@ procedure TTrack.BuildListStrip; //first pass: find mesh size setlength(trackLinks, ntracks); i := 0; + nfiber := 0; while i < ntracks do begin trackLinks[i] := 0; m := asInt( tracks[i]); @@ -283,7 +288,13 @@ procedure TTrack.BuildListStrip; endPt.Y := tracks[j+i+2]; endPt.Z := tracks[j+i+3]; normRGB := vector2RGB(startPt, endPt, len); - if len >= minFiberLength then begin + hideFiber := false; + if len < minFiberLength then hideFiber := true; + if (isScalarPerFiberColor) and (gPrefs.HideDarkTracks) and (Scalars[ScalarSelected].scalar[nfiber] < Scalars[ScalarSelected].mnView) then + hideFiber := true; + if (isScalarPerFiberColor) and (gPrefs.HideBrightTracks) and (Scalars[ScalarSelected].scalar[nfiber] > Scalars[ScalarSelected].mxView) then + hideFiber := true; + if not hideFiber then begin trackLinks[i] := m; n_vertices := n_vertices + 2*m+8; //Duplicate vertices + 8 for the Begin and End Imposter n_indices := n_indices + 2*m+11; //Same as Above + 3 Primitive Restart @@ -297,6 +308,7 @@ procedure TTrack.BuildListStrip; end; end; //len >= minFiberLength i := i + 1 + (3 * m); + nfiber := nfiber + 1; end; if (maxLinks < 1) then exit; @@ -449,6 +461,17 @@ procedure TTrack.BuildListStrip; n_faces := 0; end; // BuildList() +function TTrack.HasScalarPerFiberColor: boolean; +begin + result := false; + if (ScalarSelected >= 0) and (length(Scalars) > ScalarSelected) then begin + if length(Scalars[ScalarSelected].scalar) = n_count then + result := true; //one color per fiber + //else + // isScalarPerVertexColor := true; + end; +end; + procedure TTrack.BuildListTubes ; // create displaylist where tracks are drawn as connected cylinders //const @@ -469,6 +492,7 @@ procedure TTrack.BuildListTubes ; perVertexScalars: array of single; isScalarPerFiberColor : boolean = false; isScalarPerVertexColor: boolean = false; + hideFiber : boolean; begin if (ScalarSelected >= 0) and (length(Scalars) > ScalarSelected) then begin if length(Scalars[ScalarSelected].scalar) = n_count then @@ -493,6 +517,7 @@ procedure TTrack.BuildListTubes ; //first pass: find mesh size setlength(trackLinks, ntracks); i := 0; + nfiber := 0; while i < ntracks do begin trackLinks[i] := 0; m := asInt( tracks[i]); @@ -505,7 +530,13 @@ procedure TTrack.BuildListTubes ; endPt.Y := tracks[j+i+2]; endPt.Z := tracks[j+i+3]; normRGB := vector2RGB(startPt, endPt, len); //here only used for length - if len >= minFiberLength then begin + hideFiber := false; + if len < minFiberLength then hideFiber := true; + if (isScalarPerFiberColor) and (gPrefs.HideDarkTracks) and (Scalars[ScalarSelected].scalar[nfiber] < Scalars[ScalarSelected].mnView) then + hideFiber := true; + if (isScalarPerFiberColor) and (gPrefs.HideBrightTracks) and (Scalars[ScalarSelected].scalar[nfiber] > Scalars[ScalarSelected].mxView) then + hideFiber := true; + if not HideFiber then begin trackLinks[i] := m; n_vertices := n_vertices + (m * numCylVert); n_faces := n_faces + ((m - 1) * numCylFace); //fence post problem @@ -514,6 +545,7 @@ procedure TTrack.BuildListTubes ; end; end; //len >= minFiberLength i := i + 1 + (3 * m); + nfiber := nfiber + 1; end; //GLForm1.Caption := inttostr(n_faces); if (n_faces < 1) then exit;