diff --git a/src/Multitexture.md b/src/Multitexture.md new file mode 100644 index 00000000..e69de29b diff --git a/src/PRo3D.Base/Multitexturing.fs b/src/PRo3D.Base/Multitexturing.fs index 92e8f7d6..62906b80 100644 --- a/src/PRo3D.Base/Multitexturing.fs +++ b/src/PRo3D.Base/Multitexturing.fs @@ -44,6 +44,7 @@ type TextureCombiner = | Primary = 1 | Secondary = 2 | Multiply = 3 + | Blend = 4 type TransferFunctionMode = | Unknown = 0 diff --git a/src/PRo3D.Base/Utilities.fs b/src/PRo3D.Base/Utilities.fs index 02ab77f1..0cd2b2ee 100644 --- a/src/PRo3D.Base/Utilities.fs +++ b/src/PRo3D.Base/Utilities.fs @@ -648,6 +648,7 @@ module Shader = member x.TextureCombiner : TextureCombiner = uniform?TextureCombiner member x.TransferFunctionMode : TransferFunctionMode = uniform?TransferFunctionMode member x.TFRange : V2d = uniform?TFRange + member x.TFBlendFactor : float = uniform?TFBlendFactor let secondaryTexture (v : Effects.Vertex) = fragment { @@ -668,6 +669,8 @@ module Shader = c else v.c + | TransferFunctionMode.Passthrough -> + secondaryTextureSampler.Sample(v.tc) | _ -> v.c match uniform.TextureCombiner with @@ -675,6 +678,8 @@ module Shader = color <- secondaryColor | TextureCombiner.Multiply -> color <- V4d(v.c.XYZ * secondaryColor.XYZ, 1.0) + | TextureCombiner.Blend -> + color <- V4d(v.c.XYZ * (1.0 - uniform.TFBlendFactor) + secondaryColor.XYZ * uniform.TFBlendFactor, 1.0) | _ -> color <- v.c diff --git a/src/PRo3D.Core/AardvarkUIReworks.fs b/src/PRo3D.Core/AardvarkUIReworks.fs index 3581e052..496d6072 100644 --- a/src/PRo3D.Core/AardvarkUIReworks.fs +++ b/src/PRo3D.Core/AardvarkUIReworks.fs @@ -49,7 +49,7 @@ module NoSemUi = ] - let numeric (cfg : NumericConfig<'a>) (atts : AttributeMap<'msg>) (value : aval<'a>) (update : 'a -> 'msg) = + let numeric (cfg : NumericConfig<'a>) (inputType : string) (atts : AttributeMap<'msg>) (value : aval<'a>) (update : 'a -> 'msg) = let value = if value.IsConstant then AVal.custom (fun t -> value.GetValue t) else value @@ -83,7 +83,7 @@ module NoSemUi = input (att [ attribute "value" (value.GetValue() |> pickle) - attribute "type" "text" + attribute "type" inputType attribute "min" (pickle cfg.min) attribute "max" (pickle cfg.max) attribute "step" (pickle cfg.smallStep) diff --git a/src/PRo3D.Core/Surface-Model.fs b/src/PRo3D.Core/Surface-Model.fs index 06957510..0d079d5e 100644 --- a/src/PRo3D.Core/Surface-Model.fs +++ b/src/PRo3D.Core/Surface-Model.fs @@ -377,8 +377,12 @@ type TransferFunction = { tf : ColorMaps.TF textureCombiner : TextureCombiner + blendFactor : float } +module TransferFunction = + let empty = { tf = ColorMaps.TF.Passthrough; textureCombiner = TextureCombiner.Primary; blendFactor = 1.0 } + [] type Surface = { @@ -411,7 +415,7 @@ type Surface = { textureLayers : IndexList primaryTexture : Option secondaryTexture : Option - transferFunction : Option + transferFunction : TransferFunction opcxPath : Option [] @@ -496,7 +500,7 @@ module Surface = textureLayers = textureLayers primaryTexture = selectedTexture secondaryTexture = None - transferFunction = None + transferFunction = TransferFunction.empty surfaceType = surfaceType |> enum preferredLoader = preferredLoader |> enum colorCorrection = colorCorrection diff --git a/src/PRo3D.Core/Surface/Surface-Properties.fs b/src/PRo3D.Core/Surface/Surface-Properties.fs index 5a67224c..a150e115 100644 --- a/src/PRo3D.Core/Surface/Surface-Properties.fs +++ b/src/PRo3D.Core/Surface/Surface-Properties.fs @@ -18,6 +18,11 @@ open PRo3D.Core.Surface module SurfaceProperties = + [] + let ramp = "Ramp" + [] + let passthrough = "Passthrough" + type Action = | SetFillMode of FillMode | SetCullMode of CullMode @@ -37,6 +42,7 @@ module SurfaceProperties = | SetTFMax of float | SetColorMappingName of Option | SetTextureCombiner of TextureCombiner + | SetBlendFactor of float | SetHomePosition //of Guid //of Option @@ -73,41 +79,31 @@ module SurfaceProperties = | SetSecondaryTexture texture -> { model with secondaryTexture = texture } |> Console.print - | SetTransferFunctionMode None -> - { model with transferFunction = None } - | SetTransferFunctionMode name -> + | SetTransferFunctionMode (Some name) -> match name with - | Some "Ramp" -> + | _ when name = ramp -> match model.transferFunction with - | Some { tf = ColorMaps.TF.Ramp(_,_,_); textureCombiner = _ } -> model - | _ -> { model with transferFunction = Some { tf = ColorMaps.TF.Ramp(0.0, 1.0, ColorMaps.colorMaps |> Map.toSeq |> Seq.head |> fst); textureCombiner = TextureCombiner.Multiply } } - | Some "Passthrough" -> - { model with transferFunction = Some { tf = ColorMaps.TF.Passthrough; textureCombiner = TextureCombiner.Multiply }} - | None -> { model with transferFunction = None } - | Some name -> + | { tf = ColorMaps.TF.Ramp(_,_,_); textureCombiner = _ } -> model + | _ -> { model with transferFunction = { model.transferFunction with tf = ColorMaps.TF.Ramp(0.0, 1.0, ColorMaps.colorMaps |> Map.toSeq |> Seq.head |> fst); } } + | _ when name = passthrough-> + { model with transferFunction = { model.transferFunction with tf = ColorMaps.TF.Passthrough }} + | _ -> Log.warn "unkonwn tf mode: %s" name model + | SetTransferFunctionMode None -> model + | SetTFMin min -> - match model.transferFunction with - | None -> model - | Some tf -> - { model with transferFunction = Some { tf with tf = ColorMaps.TF.trySetMin min tf.tf; } } + { model with transferFunction = { model.transferFunction with tf = ColorMaps.TF.trySetMin min model.transferFunction.tf; } } | SetTFMax max -> - match model.transferFunction with - | None -> model - | Some tf -> - { model with transferFunction = Some { tf with tf = ColorMaps.TF.trySetMax max tf.tf } } + { model with transferFunction = { model.transferFunction with tf = ColorMaps.TF.trySetMax max model.transferFunction.tf; } } + | SetColorMappingName None -> model | SetColorMappingName (Some name) -> - match model.transferFunction with - | None -> model - | Some tf -> - { model with transferFunction = Some { tf with tf = ColorMaps.TF.trySetName name tf.tf } } + { model with transferFunction = { model.transferFunction with tf = ColorMaps.TF.trySetName name model.transferFunction.tf } } | SetTextureCombiner c -> - match model.transferFunction with - | None -> model - | Some tf -> - { model with transferFunction = Some { tf with textureCombiner = c } } + { model with transferFunction = { model.transferFunction with textureCombiner = c } } + | SetBlendFactor f -> + { model with transferFunction = { model.transferFunction with blendFactor = f }} | SetHomePosition -> model @@ -172,47 +168,53 @@ module SurfaceProperties = let tfToName (tf : ColorMaps.TF) = match tf with - | ColorMaps.TF.Ramp(_,_,_) -> "Ramp" - | ColorMaps.TF.Passthrough -> "Passthrough" + | ColorMaps.TF.Ramp(_,_,_) -> ramp + | ColorMaps.TF.Passthrough -> passthrough - yield Html.row "Transfer Function" [ div [] [UI.dropDown'' (AList.ofList ["Passthrough"; "Ramp"]) (model.transferFunction |> AVal.map (function None -> None | Some tf -> Some (tfToName tf.tf))) SetTransferFunctionMode (fun a -> a)]] + yield Html.row "Transfer Function" [ div [] [UI.dropDown'' (AList.ofList [ramp; passthrough]) (model.transferFunction |> AVal.map (fun tf -> Some (tfToName tf.tf))) SetTransferFunctionMode (fun a -> a)]] yield Html.row "Secondary Texture:" [UI.dropDown'' model.textureLayers model.secondaryTexture (fun x -> SetSecondaryTexture x) (fun x -> x.label)] let! tf = model.transferFunction - match tf with - | None -> () - | Some tf -> - yield Html.row "Texture Combiner" [Html.SemUi.dropDown (AVal.constant tf.textureCombiner) SetTextureCombiner] - match tf.tf with - | ColorMaps.TF.Ramp(min,max,name) -> - yield Html.row "Min" [ - yield Aardvark.UI.NoSemUi.numeric { min = 0.0; max = 1.0; smallStep = 0.01; largeStep = 0.1 } AttributeMap.empty ( - match tf.tf with - | ColorMaps.TF.Ramp(min, max, name) -> min |> AVal.constant - | _ -> 0.0 |> AVal.constant - ) SetTFMin - ] - yield Html.row "Max" [ - yield Aardvark.UI.NoSemUi.numeric { min = 0.0; max = 1.0; smallStep = 0.01; largeStep = 0.1 } AttributeMap.empty ( - match tf.tf with - | ColorMaps.TF.Ramp(min, max, name) -> max |> AVal.constant - | _ -> 0.0 |> AVal.constant - ) SetTFMax - ] - let toColorMapName (tf : ColorMaps.TF) = - match tf with - | ColorMaps.TF.Ramp(_,_,s) -> Some s - | _ -> None - //let candidates = - // let availableColorMaps = ColorMaps.colorMaps |> List.map (fun (s,_) -> Some s, s) |> Map.ofList - // Map.union (Map.ofList [None, "No color map"]) availableColorMaps - //yield Simple.dropDown [] (toColorMapName tf.tf |> AVal.constant) SetColorMappingName candidates - yield Html.row "Color Map" [ - yield UI.dropDown'' (ColorMaps.colorMaps |> Map.toSeq |> Seq.map fst |> AList.ofSeq) (toColorMapName tf.tf |> AVal.constant) (fun x -> SetColorMappingName x) (fun s -> s) - ] - | _ -> () + yield Html.row "Texture Combiner" [Html.SemUi.dropDown (AVal.constant tf.textureCombiner) SetTextureCombiner] + + match tf.textureCombiner with + | TextureCombiner.Blend -> + yield + Html.row "Blend Factor" [Aardvark.UI.NoSemUi.numeric { min = 0.0; max = 1.0; smallStep = 0.01; largeStep = 0.1 } "range" AttributeMap.empty ( + tf.blendFactor |> AVal.constant + ) SetBlendFactor + ] + | _ -> + () + + match tf.tf with + | ColorMaps.TF.Ramp(min,max,name) -> + yield Html.row "Min" [ + yield Aardvark.UI.NoSemUi.numeric { min = 0.0; max = 1.0; smallStep = 0.01; largeStep = 0.1 } "text" AttributeMap.empty ( + match tf.tf with + | ColorMaps.TF.Ramp(min, max, name) -> min |> AVal.constant + | _ -> 0.0 |> AVal.constant + ) SetTFMin + ] + yield Html.row "Max" [ + yield Aardvark.UI.NoSemUi.numeric { min = 0.0; max = 1.0; smallStep = 0.01; largeStep = 0.1 } "text" AttributeMap.empty ( + match tf.tf with + | ColorMaps.TF.Ramp(min, max, name) -> max |> AVal.constant + | _ -> 0.0 |> AVal.constant + ) SetTFMax + ] + let toColorMapName (tf : ColorMaps.TF) = + match tf with + | ColorMaps.TF.Ramp(_,_,s) -> Some s + | _ -> None + + yield Html.row "Color Map" [ + yield UI.dropDown'' (ColorMaps.colorMaps |> Map.toSeq |> Seq.map fst |> AList.ofSeq) (toColorMapName tf.tf |> AVal.constant) (fun x -> SetColorMappingName x) (fun s -> s) + ] + | _ -> () + } ) diff --git a/src/PRo3D.Core/Surface/SurfaceApp.fs b/src/PRo3D.Core/Surface/SurfaceApp.fs index 731caa68..bf1ff5a7 100644 --- a/src/PRo3D.Core/Surface/SurfaceApp.fs +++ b/src/PRo3D.Core/Surface/SurfaceApp.fs @@ -78,7 +78,7 @@ module SurfaceUtils = primaryTexture = None secondaryTexture = None - transferFunction = None + transferFunction = TransferFunction.empty triangleSize = { Init.triangleSize with value = maxTriangleSize } diff --git a/src/PRo3D.Viewer/Viewer/Viewer-Utils.fs b/src/PRo3D.Viewer/Viewer/Viewer-Utils.fs index af07ca71..1b55c19f 100644 --- a/src/PRo3D.Viewer/Viewer/Viewer-Utils.fs +++ b/src/PRo3D.Viewer/Viewer/Viewer-Utils.fs @@ -390,50 +390,39 @@ module ViewerUtils = |> Sg.texture "SecondaryTextureTransferFunction" ( surf.transferFunction |> AVal.map (fun tf -> - match tf with - | None -> NullTexture.Instance - | Some tf -> - match tf.tf with - | ColorMaps.TF.Passthrough -> NullTexture.Instance - | ColorMaps.TF.Ramp(_,_,name) -> - match Map.tryFind name ColorMaps.colorMaps with - | None -> NullTexture.Instance - | Some l -> - try - l.Value :> ITexture - with e -> - Log.warn "SecondaryTextureTransferFunction: %A" e - NullTexture.Instance + match tf.tf with + | ColorMaps.TF.Passthrough -> NullTexture.Instance + | ColorMaps.TF.Ramp(_,_,name) -> + match Map.tryFind name ColorMaps.colorMaps with + | None -> NullTexture.Instance + | Some l -> + try + l.Value :> ITexture + with e -> + Log.warn "SecondaryTextureTransferFunction: %A" e + NullTexture.Instance ) ) |> Sg.uniform "TextureCombiner" ( - surf.transferFunction |> AVal.map (fun tf -> - match tf with - | None -> TextureCombiner.Unknown - | Some tf -> - tf.textureCombiner - ) + surf.transferFunction |> AVal.map (fun tf -> tf.textureCombiner) ) |> Sg.uniform "TransferFunctionMode" ( surf.transferFunction |> AVal.map (fun tf -> - match tf with - | None -> TransferFunctionMode.Unknown - | Some tf -> - match tf.tf with - | ColorMaps.TF.Passthrough -> TransferFunctionMode.Passthrough - | ColorMaps.TF.Ramp(_,_,_) -> TransferFunctionMode.Ramp + match tf.tf with + | ColorMaps.TF.Passthrough -> TransferFunctionMode.Passthrough + | ColorMaps.TF.Ramp(_,_,_) -> TransferFunctionMode.Ramp ) ) |> Sg.uniform "TFRange" ( surf.transferFunction |> AVal.map (fun tf -> - match tf with - | None -> V2d.OI - | Some tf -> - match tf.tf with - | ColorMaps.TF.Passthrough -> V2d.OI - | ColorMaps.TF.Ramp(min,max,_) -> V2d(min, max) + match tf.tf with + | ColorMaps.TF.Passthrough -> V2d.OI + | ColorMaps.TF.Ramp(min,max,_) -> V2d(min, max) ) ) + |> Sg.uniform "TFBlendFactor" ( + surf.transferFunction |> AVal.map (fun tf -> tf.blendFactor) + ) |> Sg.withEvents [ diff --git a/src/PRo3D.sln b/src/PRo3D.sln index 0fd5b72f..05022286 100644 --- a/src/PRo3D.sln +++ b/src/PRo3D.sln @@ -24,10 +24,14 @@ Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "PRo3D.Lite", "PRo3D.Lite\PR EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EC91D5A1-9C4B-45A2-843C-CB687BF9581F}" ProjectSection(SolutionItems) = preProject + ..\docs\Build-Deploy-System.md = ..\docs\Build-Deploy-System.md + Multitexture.md = Multitexture.md ..\paket.dependencies = ..\paket.dependencies + ..\docs\spice.md = ..\docs\spice.md + ..\docs\Structure.md = ..\docs\Structure.md EndProjectSection EndProject -Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Tests", "Tests\Tests.fsproj", "{D71C7F9E-2847-4218-9FE9-31777CD0B470}" +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Tests", "Tests\Tests.fsproj", "{D71C7F9E-2847-4218-9FE9-31777CD0B470}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution