Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Features/contour lines #376

Merged
merged 5 commits into from
Jan 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions docs/Contour-Lines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Feature Contour Lines

![](./images/contourTeaser.png)

Synopsis: Contour lines for texture layers
Status: Work-In-Progress
Interacts with: [Feature-Multitexturing](./Feature-Multitexture.md)

# UI


The feature only works in combination with multilayer opcs. By using surface properties, choose a particular layer as a secondary texture:

![](./images/multitexture-ui.png)

Next, in the contour section, enable it and set distance of the lines, as well as line width and line border (both in the domain of the value chosen for texturing, here `Ele`).

![](./images/contour1.png)

The whole setup then looks like:

![](./images/contour0.png)

# Implementation

UI and logics implemented as a separate app, see: https://github.com/pro3d-space/PRo3D/blob/6416a1176dea28043548c9797436934f779a3e54/src/PRo3D.Core/VisualizationAndTFApp.fs

The line color is blended with the surface color in a separate shader: https://github.com/pro3d-space/PRo3D/blob/6416a1176dea28043548c9797436934f779a3e54/src/PRo3D.Base/Utilities.fs#L744
The shader uses hermite interpolation for smooth lines: https://github.com/pro3d-space/PRo3D/blob/6416a1176dea28043548c9797436934f779a3e54/src/PRo3D.Base/Utilities.fs#L722


Caveats:
- Currently the color cannot be chaned.
- It only works for secondary texture layers (shaders need to re-organized to be more flexible here).
Binary file added docs/images/contour0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/contour1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/contourTeaser.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/multitexture-ui.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes.
90 changes: 90 additions & 0 deletions provex/index.html

Large diffs are not rendered by default.

57 changes: 51 additions & 6 deletions src/PRo3D.Base/Utilities.fs
Original file line number Diff line number Diff line change
Expand Up @@ -671,6 +671,7 @@ module Shader =
member x.TransferFunctionMode : TransferFunctionMode = uniform?TransferFunctionMode
member x.TFRange : V2d = uniform?TFRange
member x.TFBlendFactor : float = uniform?TFBlendFactor
member x.SecondaryTextureContour : V4d = uniform?SecondaryTextureContour

let secondaryTexture (v : Effects.Vertex) =
fragment {
Expand All @@ -680,15 +681,17 @@ module Shader =
| TextureCombiner.Primary ->
color <- v.c
| _ ->
let range = uniform.TFRange
let e = secondaryTextureSampler.Sample(v.tc)
let width = range.Y - range.X
let my = (e.X - range.X) / width

let secondaryColor =
match uniform.TransferFunctionMode with
| TransferFunctionMode.Ramp ->
let range = uniform.TFRange
let e = secondaryTextureSampler.Sample(v.tc)
if e.X > range.X && e.X < range.Y then
let my = (e.X - range.X) / (range.Y - range.X)
let c = transferFunctionSampler.Sample(V2d(my,0.0))
c
if e.X >= range.X && e.X <= range.Y then
let mappedColor = transferFunctionSampler.Sample(V2d(my,0.0))
mappedColor
else
v.c
| TransferFunctionMode.Passthrough ->
Expand All @@ -708,6 +711,48 @@ module Shader =
return color
}

[<ReflectedDefinition>]
let lineAlpha (v : float) (center : float) (lineWidth: float) (lineSmooth : float) =
let start = center - lineWidth * 0.5
let stop = center + lineSmooth * 0.5
if v >= start && v <= stop then
1.0
else
let alpha =
Fun.Smoothstep(v, start - lineSmooth * 0.5, start) -
Fun.Smoothstep(v, stop, stop + lineSmooth * 0.5)
alpha


let contourLines (v : Effects.Vertex) =
fragment {
let contourSettings = uniform.SecondaryTextureContour

let lineColor =
if contourSettings.X > 0 then

let range = uniform.TFRange
let e = secondaryTextureSampler.Sample(v.tc)
let width = range.Y - range.X
let my = (e.X - range.X) / width

let distance = contourSettings.X
let lineWidth = contourSettings.Y
let lineSmoothing = contourSettings.Z

let contourDistance = my % distance
let lineAlpha = lineAlpha contourDistance (distance * 0.5) lineWidth lineSmoothing

V4d(0.0,0.0,0.0, Fun.Clamp(lineAlpha, 0.0, 1.0))
else
V4d.OOOO


let finalColor = v.c.XYZ * (1.0 - lineColor.W)
return V4d(finalColor, 1.0)
}


let depthCalculation2 (v : FootPrintVertex) =
fragment {
let mutable color = v.c
Expand Down
2 changes: 2 additions & 0 deletions src/PRo3D.Core/PRo3D.Core.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
<Compile Include="Core-Types.fs" />
<Compile Include="ReferenceSystem-Model.fs" />
<Compile Include="Transformation-Model.fs" />
<Compile Include="VisualizationAndTFModel.fs" />
<Compile Include="VisualizationAndTFApp.fs" />
<Compile Include="Surface-Model.fs" />
<Compile Include="glTF.fs" />
<Compile Include="SceneObjects-Model.fs" />
Expand Down
7 changes: 7 additions & 0 deletions src/PRo3D.Core/Surface-Model.fs
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,8 @@ type Surface = {
homePosition : Option<CameraView>
transformation : Transformations
radiometry : Radiometry

contourModel : ContourLineModel
}

module Surface =
Expand Down Expand Up @@ -777,6 +779,8 @@ module Surface =

filterByDistance = false
filterDistance = Initial.filterDistance 10.0

contourModel = ContourLineModel.initial
}
}

Expand Down Expand Up @@ -863,6 +867,9 @@ module Surface =

filterByDistance = match filterByDistance with |Some v -> v |None -> false
filterDistance = match filterDistance with |Some d -> Initial.filterDistance d |None -> Initial.filterDistance 10.0


contourModel = ContourLineModel.initial
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/PRo3D.Core/Surface/Surface-Properties.fs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,16 @@ module SurfaceProperties =
| SetColorMappingName of Option<string>
| SetTextureCombiner of TextureCombiner
| SetBlendFactor of float
| CountourAppMessage of ContourLineApp.Action

| SetHomePosition //of Guid //of Option<CameraView>
| ToggleFilterByDistance //of Guid //of Option<CameraView>
| SetFilterDistance of Numeric.Action //of Guid //of Option<CameraView>

let update (model : Surface) (act : Action) =
match act with
| CountourAppMessage act ->
{ model with contourModel = ContourLineApp.update model.contourModel act }
| SetFillMode mode ->
{ model with fillMode = mode }
| SetCullMode mode ->
Expand Down
28 changes: 28 additions & 0 deletions src/PRo3D.Core/Surface/SurfaceApp.fs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ module SurfaceUtils =

filterByDistance = false
filterDistance = Surface.Initial.filterDistance 10.0


contourModel = ContourLineModel.initial
}


Expand Down Expand Up @@ -1388,6 +1391,25 @@ module SurfaceApp =
return (GroupsApp.viewUI model.surfaces|> UI.map GroupsMessage)
}

let viewSurfaceProperty (model : AdaptiveSurfaceModel) (f : AdaptiveSurface -> DomNode<_>) : DomNode<_> =
let e =
adaptive {
match! model.surfaces.singleSelectLeaf with
| Some selected ->
match! AMap.tryFind selected model.surfaces.flat with
| None ->
return div [] []
| Some s ->
match s with
| AdaptiveSurfaces s ->
return f s
| _ ->
return div [] []
| _ ->
return div [] []
}
Incremental.div AttributeMap.empty (AList.ofAValSingle e)

let viewTranslationTools (model:AdaptiveSurfaceModel) =
adaptive {
let! guid = model.surfaces.singleSelectLeaf
Expand Down Expand Up @@ -1544,6 +1566,12 @@ module SurfaceApp =
Incremental.div AttributeMap.empty (AList.ofAValSingle(viewRadiometryTools model))
]

yield GuiEx.accordion "Contours" "file image outline" false [
div [] [
viewSurfaceProperty model (fun s -> ContourLineApp.view s.contourModel |> UI.map (SurfaceAppAction.SurfacePropertiesMessage << SurfaceProperties.CountourAppMessage))
]
]

//yield GuiEx.accordion "Radiometry" "file image outline" false [
// Incremental.div AttributeMap.empty (AList.ofAValSingle(viewRadiometryTools model))
// Incremental.div AttributeMap.empty (AList.ofAValSingle(viewRadiometryTools model))
Expand Down
42 changes: 42 additions & 0 deletions src/PRo3D.Core/VisualizationAndTFApp.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace PRo3D.Core

open Adaptify.FSharp
open Aardvark.Base
open PRo3D.Core
open Aardvark.UI
open Aardvark.UI.Primitives
open PRo3D.Base
open FSharp.Data.Adaptive
open PRo3D.Core
open PRo3D.Core.Surface

module ContourLineApp =

type Action =
| SetDistance of Numeric.Action
| SetLineWidth of Numeric.Action
| SetBorder of Numeric.Action
| ToggleEnabled
| SetTargetTexture of Option<TextureLayer>



let update (m : ContourLineModel) (action : Action) =
match action with
| SetDistance a -> { m with distance = Numeric.update m.distance a }
| SetLineWidth a -> { m with width = Numeric.update m.width a }
| SetBorder a -> { m with border = Numeric.update m.border a }
| ToggleEnabled -> { m with enabled = not m.enabled }
| SetTargetTexture a -> { m with targetLayer = a }


let view (model : AdaptiveContourLineModel) =
require GuiEx.semui (
Html.table [
Html.row "" []
Html.row "enabled" [GuiEx.iconCheckBox model.enabled ToggleEnabled]
Html.row "distance: " [Numeric.view' [NumericInputType.Slider; NumericInputType.InputBox] model.distance |> UI.map SetDistance ]
Html.row "width: " [Numeric.view' [NumericInputType.Slider; NumericInputType.InputBox] model.width |> UI.map SetLineWidth ]
Html.row "border: " [Numeric.view' [NumericInputType.Slider; NumericInputType.InputBox] model.border |> UI.map SetBorder ]
]
)
Loading
Loading