diff --git a/CHANGELOG.md b/CHANGELOG.md index de7bfa84..5c114e2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ - Fix issues with unrelated functions being treated as overloads (e.g., closures) - Skip unused functions in module code generation, improving performance - Avoid reloading modules if their content does not change, improving performance +- Add an ocean sample to the `omni.warp` extension. ## [1.3.3] - 2024-09-04 diff --git a/exts/omni.warp/data/scenes/.thumbs/256x256/ocean.usda.png b/exts/omni.warp/data/scenes/.thumbs/256x256/ocean.usda.png new file mode 100644 index 00000000..3c875e78 Binary files /dev/null and b/exts/omni.warp/data/scenes/.thumbs/256x256/ocean.usda.png differ diff --git a/exts/omni.warp/data/scenes/assets/geometries/ocean.usd b/exts/omni.warp/data/scenes/assets/geometries/ocean.usd new file mode 100644 index 00000000..35216350 --- /dev/null +++ b/exts/omni.warp/data/scenes/assets/geometries/ocean.usd @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfd64485d86f2c286edbcf3e300307a6fb1b4ba41072a4a3809aaa2fbcf604da +size 23939186 diff --git a/exts/omni.warp/data/scenes/ocean.usda b/exts/omni.warp/data/scenes/ocean.usda new file mode 100644 index 00000000..5e87beec --- /dev/null +++ b/exts/omni.warp/data/scenes/ocean.usda @@ -0,0 +1,518 @@ +#usda 1.0 +( + customLayerData = { + dictionary cameraSettings = { + string boundCamera = "/CameraRoot/Camera" + } + dictionary renderSettings = { + bool "rtx:ambientOcclusion:enabled" = 0 + bool "rtx:directLighting:domeLight:enabled" = 0 + bool "rtx:indirectDiffuse:enabled" = 0 + int "rtx:post:dlss:execMode" = 0 + double "rtx:sceneDb:ambientLightIntensity" = 2 + bool "rtx:shadows:enabled" = 0 + bool "rtx:translucency:reflectAtAllBounce" = 1 + } + } + defaultPrim = "World" + endTimeCode = 36000 + metersPerUnit = 1 + startTimeCode = 0 + timeCodesPerSecond = 60 + upAxis = "Y" +) + +def Xform "World" +{ + def OmniGraph "ActionGraph" + { + token evaluationMode = "Automatic" + token evaluator:type = "execution" + token fabricCacheBacking = "Shared" + int2 fileFormatVersion = (1, 9) + token pipelineStage = "pipelineStageSimulation" + + def OmniGraphNode "on_loaded" ( + prepend apiSchemas = ["NodeGraphNodeAPI"] + ) + { + token node:type = "omni.graph.action.OnLoaded" + int node:typeVersion = 1 + custom uint outputs:execOut ( + customData = { + bool isExecution = 1 + } + ) + uniform token ui:nodegraph:node:expansionState = "minimized" + uniform float2 ui:nodegraph:node:pos = (280, -160) + } + + def OmniGraphNode "on_tick" ( + prepend apiSchemas = ["NodeGraphNodeAPI"] + ) + { + custom uint inputs:framePeriod = 0 + custom bool inputs:onlyPlayback = 1 + token node:type = "omni.graph.action.OnTick" + int node:typeVersion = 2 + custom double outputs:absoluteSimTime + custom double outputs:deltaSeconds + custom double outputs:frame + custom bool outputs:isPlaying + custom uint outputs:tick ( + customData = { + bool isExecution = 1 + } + ) + custom double outputs:time + custom double outputs:timeSinceStart + custom double state:accumulatedSeconds = 0 + custom uint state:frameCount = 0 + uniform token ui:nodegraph:node:expansionState = "minimized" + uniform float2 ui:nodegraph:node:pos = (230, -35) + } + + def OmniGraphNode "get_camera_position" ( + prepend apiSchemas = ["NodeGraphNodeAPI"] + ) + { + custom rel inputs:prim = ( + customData = { + dictionary omni = { + dictionary graph = { + string relType = "target" + } + } + } + ) + custom token inputs:primPath + custom bool inputs:usePath = 0 + token node:type = "omni.graph.ui_nodes.GetCameraPosition" + int node:typeVersion = 2 + custom point3d outputs:position + uniform token ui:nodegraph:node:expansionState = "minimized" + uniform float2 ui:nodegraph:node:pos = (280, 110) + } + + def OmniGraphNode "read_prims" ( + prepend apiSchemas = ["NodeGraphNodeAPI"] + ) + { + custom int inputs:_debugStamp + custom bool inputs:applySkelBinding = 0 + custom string inputs:attrNamesToImport = "*" + custom bool inputs:computeBoundingBox = 0 + custom bool inputs:enableBundleChangeTracking = 1 + custom bool inputs:enableChangeTracking + custom string inputs:pathPattern = "" + custom rel inputs:prims = ( + customData = { + dictionary omni = { + dictionary graph = { + string relType = "target" + } + } + } + ) + custom string inputs:typePattern = "*" + custom timecode inputs:usdTimecode = nan + token node:type = "omni.graph.nodes.ReadPrimsV2" + int node:typeVersion = 1 + custom rel outputs_primsBundle ( + customData = { + dictionary omni = { + dictionary graph = { + string relType = "bundle" + } + } + } + ) + custom bool state:applySkelBinding = 0 + custom string state:attrNamesToImport + custom bool state:computeBoundingBox = 0 + custom bool state:enableBundleChangeTracking + custom bool state:enableChangeTracking + custom uint64[] state:inputPrimPaths = [] + custom string state:pathPattern + custom uint64[] state:primPaths = [] + custom string state:typePattern + custom timecode state:usdTimecode = -1 + uniform token ui:nodegraph:node:expansionState = "minimized" + uniform float2 ui:nodegraph:node:pos = (440, 230) + + def Output "outputs_primsBundle" ( + active = false + ) + { + } + } + + def OmniGraphNode "ocean_deformer" ( + apiSchemas = ["NodeGraphNodeAPI"] + ) + { + custom float inputs:amplitude + custom vector3f inputs:cameraPos = (0, 0, 0) + prepend vector3f inputs:cameraPos.connect = + custom float inputs:clipmapCellSize = 32 + custom float inputs:direction = 3.1 + custom float inputs:directionality = 1 + custom uint inputs:execIn ( + customData = { + bool isExecution = 1 + } + ) + prepend uint inputs:execIn.connect = [ + , + , + ] + custom rel inputs:mesh ( + customData = { + dictionary omni = { + dictionary graph = { + string relType = "bundle" + } + } + } + ) + prepend rel inputs:mesh = + custom float inputs:scale = 1 + custom double inputs:time = 0 + double inputs:time.connect = + custom float inputs:waterDepth = 50 + custom float inputs:waveAmplitude = 1 + custom float inputs:windSpeed = 30.7 + token node:type = "omni.warp.WarpSampleOceanDeform" + int node:typeVersion = 1 + custom uint outputs:execOut ( + customData = { + bool isExecution = 1 + } + ) + custom rel outputs_mesh ( + customData = { + dictionary omni = { + dictionary graph = { + string relType = "bundle" + } + } + } + ) + uniform token ui:nodegraph:node:expansionState = "minimized" + uniform float2 ui:nodegraph:node:pos = (725, 0) + } + + def OmniGraphNode "write_prims" ( + prepend apiSchemas = ["NodeGraphNodeAPI"] + ) + { + custom string inputs:attrNamesToExport = "points" + custom uint inputs:execIn + prepend uint inputs:execIn.connect = + custom token inputs:layerIdentifier + custom string inputs:pathPattern = "*" + custom rel inputs:prims = ( + customData = { + dictionary omni = { + dictionary graph = { + string relType = "target" + } + } + } + ) + custom rel inputs:primsBundle = ( + customData = { + dictionary omni = { + dictionary graph = { + string relType = "bundle" + } + } + } + ) + custom bool inputs:scatterUnderTargets = 0 + custom string inputs:typePattern = "*" + custom bool inputs:usdWriteBack = 0 + token node:type = "omni.graph.nodes.WritePrimsV2" + int node:typeVersion = 1 + custom uint outputs:execOut ( + customData = { + bool isExecution = 1 + } + ) + custom string state:attrNamesToExport = "*" + custom token state:layerIdentifier + custom string state:pathPattern = "*" + custom uint64 state:primBundleDirtyId + custom uint64[] state:prims = [] + custom bool state:scatterUnderTargets = 0 + custom string state:typePattern = "*" + custom bool state:usdWriteBack = 1 + uniform token ui:nodegraph:node:expansionState = "minimized" + uniform float2 ui:nodegraph:node:pos = (1050, 50) + } + } + + def Scope "Looks" + { + def Material "OceanWater" + { + token outputs:mdl:displacement.connect = + token outputs:mdl:surface.connect = + token outputs:mdl:volume.connect = + + def Shader "Shader" + { + uniform token info:implementationSource = "sourceAsset" + uniform asset info:mdl:sourceAsset = @http://omniverse-content-production.s3-us-west-2.amazonaws.com/Materials/Base/Natural/Water_Opaque.mdl@ + uniform token info:mdl:sourceAsset:subIdentifier = "Water_Opaque" + color3f inputs:diffuse_color_constant = (0.022957334, 0.039920207, 0.05405408) ( + customData = { + float3 default = (0.008, 0.02, 0.03) + } + displayGroup = "Albedo" + displayName = "Albedo Color" + doc = "This is the albedo base color" + hidden = false + ) + color3f inputs:diffuse_tint = (0.6096809, 0.6351467, 0.6525097) ( + customData = { + float3 default = (1, 1, 1) + } + displayGroup = "Albedo" + displayName = "Color Tint" + doc = "When enabled, this color value is multiplied over the final albedo color" + hidden = false + ) + asset inputs:normalmap_texture = @@ ( + colorSpace = "raw" + customData = { + asset default = @http://omniverse-content-production.s3-us-west-2.amazonaws.com/Materials/Base/Natural/Water/Water_Normal.png@ + } + displayGroup = "Normal" + displayName = "Normal Map" + hidden = false + ) + float inputs:reflection_roughness_constant = 0.04 ( + customData = { + float default = 0 + dictionary range = { + float max = 1 + float min = 0 + } + } + displayGroup = "Reflectivity" + displayName = "Roughness Amount" + doc = "Higher roughness values lead to more blurry reflections" + hidden = false + ) + token outputs:out + } + } + } + + def "MeshIn" ( + prepend payload = @./assets/geometries/ocean.usd@ + ) + { + token visibility = "invisible" + float3 xformOp:rotateXYZ = (0, 0, 0) + float3 xformOp:scale = (1, 1, 1) + double3 xformOp:translate = (0, 0, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + } + + def "MeshOut" ( + prepend payload = @./assets/geometries/ocean.usd@ + ) + { + float3 xformOp:rotateXYZ = (0, 0, 0) + float3 xformOp:scale = (1, 1, 1) + double3 xformOp:translate = (0, 0, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + + over "Plane" ( + prepend apiSchemas = ["MaterialBindingAPI"] + ) + { + rel material:binding = ( + bindMaterialAs = "weakerThanDescendants" + ) + } + } +} + +def "Environment" +{ + def Xform "Sky" + { + def Xform "SkySphere" ( + kind = "model" + ) + { + float3[] extent = [(0, 0, 0)] + rel material:binding = ( + bindMaterialAs = "strongerThanDescendants" + ) + bool primvars:doNotCastShadows = 1 + token visibility = "inherited" + float3 xformOp:rotateZYX = (0, 0, 0) + float3 xformOp:scale = (10000, 10000, 10000) + double3 xformOp:translate = (0, 0, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZYX", "xformOp:scale"] + + def Mesh "Sphere" + { + float3[] extent = [(-0.0005, -0.0005, 0), (0.0005, 0.0005, 0.0005)] + int[] faceVertexCounts = [4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4] + int[] faceVertexIndices = [25, 11, 3, 10, 24, 14, 7, 13, 23, 17, 5, 16, 22, 9, 1, 19, 21, 18, 4, 15, 20, 19, 1, 10, 16, 5, 19, 20, 7, 16, 20, 13, 13, 20, 10, 3, 8, 0, 18, 21, 2, 8, 21, 12, 12, 21, 15, 6, 18, 0, 9, 22, 4, 18, 22, 17, 17, 22, 19, 5, 15, 4, 17, 23, 6, 15, 23, 14, 14, 23, 16, 7, 12, 6, 14, 24, 2, 12, 24, 11, 11, 24, 13, 3, 8, 2, 11, 25, 0, 8, 25, 9, 9, 25, 10, 1] + normal3f[] normals = [(1, 0, 0), (0.70708334, -0.70708334, 0), (0.5773492, -0.5773492, -0.5773492), (0.70708334, 0, -0.70708334), (0, -1, 0), (-0.70708334, -0.70708334, 0), (-0.5773492, -0.5773492, -0.5773492), (0, -0.70708334, -0.70708334), (-1, 0, 0), (-0.70708334, 0.70708334, 0), (-0.5773492, 0.5773492, -0.5773492), (-0.70708334, 0, -0.70708334), (0, 1, 0), (0.70708334, 0.70708334, 0), (0.5773492, 0.5773492, -0.5773492), (0, 0.70708334, -0.70708334), (0, 0, 1), (0, 0.70708334, 0.70708334), (-0.5773492, 0.5773492, 0.5773492), (-0.70708334, 0, 0.70708334), (0, 0, -1), (0, 0.70708334, -0.70708334), (0.5773492, 0.5773492, -0.5773492), (0.70708334, 0, -0.70708334), (-0.70708334, 0, -0.70708334), (-0.5773492, 0.5773492, -0.5773492), (0, 0.70708334, -0.70708334), (0, 0, -1), (-0.5773492, -0.5773492, -0.5773492), (-0.70708334, 0, -0.70708334), (0, 0, -1), (0, -0.70708334, -0.70708334), (0, -0.70708334, -0.70708334), (0, 0, -1), (0.70708334, 0, -0.70708334), (0.5773492, -0.5773492, -0.5773492), (0.70708334, 0, 0.70708334), (0.5773492, 0.5773492, 0.5773492), (0, 0.70708334, 0.70708334), (0, 0, 1), (0.5773492, -0.5773492, 0.5773492), (0.70708334, 0, 0.70708334), (0, 0, 1), (0, -0.70708334, 0.70708334), (0, -0.70708334, 0.70708334), (0, 0, 1), (-0.70708334, 0, 0.70708334), (-0.5773492, -0.5773492, 0.5773492), (0, 0.70708334, 0.70708334), (0.5773492, 0.5773492, 0.5773492), (0.70708334, 0.70708334, 0), (0, 1, 0), (-0.5773492, 0.5773492, 0.5773492), (0, 0.70708334, 0.70708334), (0, 1, 0), (-0.70708334, 0.70708334, 0), (-0.70708334, 0.70708334, 0), (0, 1, 0), (0, 0.70708334, -0.70708334), (-0.5773492, 0.5773492, -0.5773492), (-0.70708334, 0, 0.70708334), (-0.5773492, 0.5773492, 0.5773492), (-0.70708334, 0.70708334, 0), (-1, 0, 0), (-0.5773492, -0.5773492, 0.5773492), (-0.70708334, 0, 0.70708334), (-1, 0, 0), (-0.70708334, -0.70708334, 0), (-0.70708334, -0.70708334, 0), (-1, 0, 0), (-0.70708334, 0, -0.70708334), (-0.5773492, -0.5773492, -0.5773492), (0, -0.70708334, 0.70708334), (-0.5773492, -0.5773492, 0.5773492), (-0.70708334, -0.70708334, 0), (0, -1, 0), (0.5773492, -0.5773492, 0.5773492), (0, -0.70708334, 0.70708334), (0, -1, 0), (0.70708334, -0.70708334, 0), (0.70708334, -0.70708334, 0), (0, -1, 0), (0, -0.70708334, -0.70708334), (0.5773492, -0.5773492, -0.5773492), (0.70708334, 0, 0.70708334), (0.5773492, -0.5773492, 0.5773492), (0.70708334, -0.70708334, 0), (1, 0, 0), (0.5773492, 0.5773492, 0.5773492), (0.70708334, 0, 0.70708334), (1, 0, 0), (0.70708334, 0.70708334, 0), (0.70708334, 0.70708334, 0), (1, 0, 0), (0.70708334, 0, -0.70708334), (0.5773492, 0.5773492, -0.5773492)] ( + interpolation = "faceVarying" + ) + point3f[] points = [(-0.8177715, -0.8177715, -0.8177715), (-0.8177715, -0.8177715, 0.8177715), (-0.8177715, 0.8177715, -0.8177715), (-0.8177715, 0.8177715, 0.8177715), (0.8177715, -0.8177715, -0.8177715), (0.8177715, -0.8177715, 0.8177715), (0.8177715, 0.8177715, -0.8177715), (0.8177715, 0.8177715, 0.8177715), (-1.0015614, 0, -1.0015614), (-1.0015614, -1.0015614, 0), (-1.0015614, 0, 1.0015614), (-1.0015614, 1.0015614, 0), (0, 1.0015614, -1.0015614), (0, 1.0015614, 1.0015614), (1.0015614, 1.0015614, 0), (1.0015614, 0, -1.0015614), (1.0015614, 0, 1.0015614), (1.0015614, -1.0015614, 0), (0, -1.0015614, -1.0015614), (0, -1.0015614, 1.0015614), (0, 0, 1.4164218), (0, 0, -1.4164218), (0, -1.4164218, 0), (1.4164218, 0, 0), (0, 1.4164218, 0), (-1.4164218, 0, 0)] + float2[] primvars:st = [(0.5, 0.125), (0.5, 0.25), (0.625, 0.25), (0.625, 0.125), (0.5, 0.375), (0.5, 0.5), (0.625, 0.5), (0.625, 0.375), (0.5, 0.625), (0.5, 0.75), (0.625, 0.75), (0.625, 0.625), (0.5, 0.875), (0.5, 1), (0.625, 1), (0.625, 0.875), (0.25, 0.625), (0.25, 0.75), (0.375, 0.75), (0.375, 0.625), (0.75, 0.625), (0.75, 0.75), (0.875, 0.75), (0.875, 0.625), (0.625, 0.625), (0.625, 0.75), (0.75, 0.75), (0.75, 0.625), (0.625, 0.5), (0.625, 0.625), (0.75, 0.625), (0.75, 0.5), (0.75, 0.5), (0.75, 0.625), (0.875, 0.625), (0.875, 0.5), (0.125, 0.625), (0.125, 0.75), (0.25, 0.75), (0.25, 0.625), (0.125, 0.5), (0.125, 0.625), (0.25, 0.625), (0.25, 0.5), (0.25, 0.5), (0.25, 0.625), (0.375, 0.625), (0.375, 0.5), (0.375, 0.875), (0.375, 1), (0.5, 1), (0.5, 0.875), (0.375, 0.75), (0.375, 0.875), (0.5, 0.875), (0.5, 0.75), (0.5, 0.75), (0.5, 0.875), (0.625, 0.875), (0.625, 0.75), (0.375, 0.625), (0.375, 0.75), (0.5, 0.75), (0.5, 0.625), (0.375, 0.5), (0.375, 0.625), (0.5, 0.625), (0.5, 0.5), (0.5, 0.5), (0.5, 0.625), (0.625, 0.625), (0.625, 0.5), (0.375, 0.375), (0.375, 0.5), (0.5, 0.5), (0.5, 0.375), (0.375, 0.25), (0.375, 0.375), (0.5, 0.375), (0.5, 0.25), (0.5, 0.25), (0.5, 0.375), (0.625, 0.375), (0.625, 0.25), (0.375, 0.125), (0.375, 0.25), (0.5, 0.25), (0.5, 0.125), (0.375, 0), (0.375, 0.125), (0.5, 0.125), (0.5, 0), (0.5, 0), (0.5, 0.125), (0.625, 0.125), (0.625, 0)] ( + interpolation = "faceVarying" + ) + uniform token subdivisionScheme = "none" + matrix4d xformOp:transform = ( (100, 0, 0, 0), (0, -0.000016292067812173627, -100, 0), (0, 100, -0.000016292067812173627, 0), (0, 0, 0, 1) ) + uniform token[] xformOpOrder = ["xformOp:transform"] + } + } + + def Scope "Looks" + { + def Material "SkyMaterial" + { + token outputs:mdl:displacement.connect = + token outputs:mdl:surface.connect = + token outputs:mdl:volume.connect = + + def Shader "Shader" + { + uniform token info:implementationSource = "sourceAsset" + uniform asset info:mdl:sourceAsset = @https://omniverse-content-production.s3.us-west-2.amazonaws.com/Assets/Skies/2022_1/Skies/Sky_Elements/materials/procedural/CumulusLight.mdl@ + uniform token info:mdl:sourceAsset:subIdentifier = "CumulusLight" + float inputs:Azimuth = -91.8089 ( + customData = { + float default = -175.76622 + dictionary range = { + float max = 100000 + float min = -100000 + } + } + displayGroup = "Coords" + ) + float inputs:Declination = 7.9998345 ( + customData = { + float default = 18 + dictionary range = { + float max = 100000 + float min = -100000 + } + } + displayGroup = "Coords" + ) + float inputs:Elevation = 11.692829 ( + customData = { + float default = 46.50608 + dictionary range = { + float max = 100000 + float min = -100000 + } + } + displayGroup = "Coords" + ) + float inputs:Latitude = 51.426 ( + customData = { + float default = 64.326 + dictionary range = { + float max = 100000 + float min = -100000 + } + } + displayGroup = "Coords" + ) + float inputs:SHA = -81.25645 ( + customData = { + float default = -2.9412704 + dictionary range = { + float max = 100000 + float min = -100000 + } + } + displayGroup = "Coords" + ) + bool inputs:SunPositionFromTOD = 0 ( + customData = { + bool default = 1 + } + displayGroup = "Coords" + ) + float inputs:TimeOfDay = 6.93 ( + customData = { + float default = 3.696 + dictionary range = { + float max = 100000 + float min = -100000 + } + } + displayGroup = "Coords" + ) + float inputs:TimeOfDaySpeed = 0 ( + customData = { + float default = 1.057 + dictionary range = { + float max = 100000 + float min = -100000 + } + } + displayGroup = "Coords" + ) + token outputs:out + } + } + } + + def DomeLight "DomeLight" ( + apiSchemas = ["ShapingAPI"] + kind = "model" + ) + { + color3f color = (1, 1, 1) + float intensity = 1 + rel material:binding = ( + bindMaterialAs = "weakerThanDescendants" + ) + float shaping:cone:angle = 180 + float shaping:cone:softness + float shaping:focus + color3f shaping:focusTint + asset shaping:ies:file + token texture:format = "latlong" + token visibility = "inherited" + float3 xformOp:rotateZYX = (270, 0, 0) + float3 xformOp:translate = (0, 0, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateZYX"] + } + } +} + +def Xform "CameraRoot" +{ + double3 xformOp:rotateXYZ = (-5, 180, 0) + double3 xformOp:scale = (1, 1, 1) + double3 xformOp:translate = (0, 0, 0) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"] + + def Camera "Camera" + { + float2 clippingRange = (1, 10000000) + float focalLength = 25 + float focusDistance = 2500 + float fStop = 0 + bool omni:kit:cameraLock = 0 + double3 xformOp:rotateYXZ = (0, 0, 0) + double3 xformOp:scale = (1, 1, 1) + double3 xformOp:translate = (0, 0, 500) + uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateYXZ", "xformOp:scale"] + } +} diff --git a/exts/omni.warp/omni/warp/nodes/_impl/OgnSampleOceanDeform.ogn b/exts/omni.warp/omni/warp/nodes/_impl/OgnSampleOceanDeform.ogn new file mode 100644 index 00000000..5dd6f3cb --- /dev/null +++ b/exts/omni.warp/omni/warp/nodes/_impl/OgnSampleOceanDeform.ogn @@ -0,0 +1,105 @@ +{ + "WarpSampleOceanDeform": { + "version": 1, + "categoryDefinitions": "../../../../config/warp_categories.json", + "description": "Mesh deformer modeling ocean waves.", + "categories": ["warp"], + "language": "Python", + "uiName": "Ocean Deform", + "cudaPointers": "cpu", + "inputs": { + "execIn": { + "type": "execution", + "description": "Input execution." + }, + "mesh": { + "type": "bundle", + "uiName": "Mesh", + "description": "Input mesh geometry.", + "memoryType": "cuda" + }, + "directionality": { + "type": "float", + "uiName": "Directionality", + "description": "Isotropic vs directional wave motion", + "default": 0, + "minimum": 0.0, + "maximum": 1.0 + }, + "amplitude": { + "type": "float", + "uiName": "Amplitude", + "description": "Wave amplitude factor.", + "default": 1.0, + "minimum": 0.001, + "maximum": 1000.0 + }, + "direction": { + "type": "float", + "uiName": "Direction", + "description": "Wave direction.", + "default": 0, + "minimum": 0.0, + "maximum": 1.0 + }, + "scale": { + "type": "float", + "uiName": "Horizontal Scale", + "description": "Horizontal wave scaling, can be used to match scene units.", + "default": 1.0, + "minimum": 0.001, + "maximum": 1000.0 + }, + "waterDepth": { + "type": "float", + "uiName": "Water Depth", + "description": "Water depth (1..1000 m).", + "default": 50.0, + "minimum": 1.0, + "maximum": 1000.0 + }, + "windSpeed": { + "type": "float", + "uiName": "Wind Speed", + "description": "Wind speed (m/s) 10m above ocean (0..30).", + "default": 10.0, + "minimum": 0.0, + "maximum": 30.0 + }, + "cameraPos": { + "type": "vectorf[3]", + "uiName": "Camera Position", + "default": [ + 0.0, + 0.0, + 0.0 + ], + "description": "Camera position to use to move the clipmap." + }, + "clipmapCellSize": { + "type": "float", + "uiName": "Clipmap Cell Size", + "description": "Size of a single cell at the centre of the clipmap grid.", + "default": 1.0 + }, + "time": { + "type": "double", + "uiName": "Time", + "description": "Time.", + "default": 0 + } + }, + "outputs": { + "execOut": { + "type": "execution", + "description": "Output execution." + }, + "mesh": { + "type": "bundle", + "uiName": "Mesh", + "description": "Output mesh geometry.", + "memoryType": "cuda" + } + } + } +} diff --git a/exts/omni.warp/omni/warp/nodes/_impl/OgnSampleOceanDeform.py b/exts/omni.warp/omni/warp/nodes/_impl/OgnSampleOceanDeform.py new file mode 100644 index 00000000..204832fd --- /dev/null +++ b/exts/omni.warp/omni/warp/nodes/_impl/OgnSampleOceanDeform.py @@ -0,0 +1,292 @@ +# Copyright (c) 2023 NVIDIA CORPORATION. All rights reserved. +# NVIDIA CORPORATION and its licensors retain all intellectual property +# and proprietary rights in and to this software, related documentation +# and any modifications thereto. Any use, reproduction, disclosure or +# distribution of this software and related documentation without an express +# license agreement from NVIDIA CORPORATION is strictly prohibited. + +"""Sample node deforming an ocean surface.""" + +import traceback + +import omni.graph.core as og +import omni.warp.nodes +from omni.warp.nodes.ogn.OgnSampleOceanDeformDatabase import OgnSampleOceanDeformDatabase + +import warp as wp + +PROFILE_EXTENT = 410.0 +PROFILE_RES = 8192 +PROFILE_WAVENUM = 1000 +MIN_WAVE_LENGTH = 0.1 +MAX_WAVE_LENGTH = 250.0 + + +# Kernels +# ------------------------------------------------------------------------------ + + +# fractional part of a (w.r.t. floor(a)) +@wp.func +def frac(a: float): + return a - wp.floor(a) + + +# square of a +@wp.func +def sqr(a: float): + return a * a + + +@wp.func +def alpha_beta_spectrum(omega: float, peak_omega: float, alpha: float, beta: float, gravity: float): + return (alpha * gravity * gravity / wp.pow(omega, 5.0)) * wp.exp(-beta * wp.pow(peak_omega / omega, 4.0)) + + +@wp.func +def jonswap_peak_sharpening(omega: float, peak_omega: float, gamma: float): + sigma = float(0.07) + if omega > peak_omega: + sigma = float(0.09) + return wp.pow(gamma, wp.exp(-0.5 * sqr((omega - peak_omega) / (sigma * peak_omega)))) + + +@wp.func +def jonswap_spectrum(omega: float, gravity: float, wind_speed: float, fetch_km: float, gamma: float): + # https://wikiwaves.org/Ocean-Wave_Spectra#JONSWAP_Spectrum + fetch = 1000.0 * fetch_km + alpha = 0.076 * wp.pow(wind_speed * wind_speed / (gravity * fetch), 0.22) + peak_omega = 22.0 * wp.pow(wp.abs(gravity * gravity / (wind_speed * fetch)), 1.0 / 3.0) + return jonswap_peak_sharpening(omega, peak_omega, gamma) * alpha_beta_spectrum( + omega, peak_omega, alpha, 1.25, gravity + ) + + +@wp.func +def TMA_spectrum(omega: float, gravity: float, wind_speed: float, fetch_km: float, gamma: float, water_depth: float): + # https://dl.acm.org/doi/10.1145/2791261.2791267 + omegaH = omega * wp.sqrt(water_depth / gravity) + omegaH = wp.max(0.0, wp.min(2.2, omegaH)) + phi = 0.5 * omegaH * omegaH + if omegaH > 1.0: + phi = 1.0 - 0.5 * sqr(2.0 - omegaH) + return phi * jonswap_spectrum(omega, gravity, wind_speed, fetch_km, gamma) + + +# warp kernel definitions +@wp.kernel +def update_profile( + profile: wp.array(dtype=wp.vec3), + profile_res: int, + profile_data_num: int, + min_lambda: float, + max_lambda: float, + profile_extend: float, + time: float, + wind_speed: float, + water_depth: float, +): + x = wp.tid() + randState = wp.rand_init(7) + # sampling parameters + omega0 = wp.sqrt(wp.tau * 9.80665 / min_lambda) + omega1 = wp.sqrt(wp.tau * 9.80665 / max_lambda) + omega_delta = wp.abs(omega1 - omega0) / float(profile_data_num) + # we blend three displacements for seamless spatial profile tiling + space_pos_1 = profile_extend * float(x) / float(profile_res) + space_pos_2 = space_pos_1 + profile_extend + space_pos_3 = space_pos_1 - profile_extend + p1 = wp.vec2(0.0, 0.0) + p2 = wp.vec2(0.0, 0.0) + p3 = wp.vec2(0.0, 0.0) + for i in range(profile_data_num): + omega = wp.abs(omega0 + (omega1 - omega0) * float(i) / float(profile_data_num)) # linear sampling of omega + k = omega * omega / 9.80665 + phase = -time * omega + wp.randf(randState) * 2.0 * wp.pi + amplitude = float(10000.0) * wp.sqrt( + wp.abs(2.0 * omega_delta * TMA_spectrum(omega, 9.80665, wind_speed, 100.0, 3.3, water_depth)) + ) + p1 = wp.vec2( + p1[0] + amplitude * wp.sin(phase + space_pos_1 * k), p1[1] - amplitude * wp.cos(phase + space_pos_1 * k) + ) + p2 = wp.vec2( + p2[0] + amplitude * wp.sin(phase + space_pos_2 * k), p2[1] - amplitude * wp.cos(phase + space_pos_2 * k) + ) + p3 = wp.vec2( + p3[0] + amplitude * wp.sin(phase + space_pos_3 * k), p3[1] - amplitude * wp.cos(phase + space_pos_3 * k) + ) + # cubic blending coefficients + s = float(float(x) / float(profile_res)) + c1 = float(2.0 * s * s * s - 3.0 * s * s + 1.0) + c2 = float(-2.0 * s * s * s + 3.0 * s * s) + disp_out = wp.vec3( + (p1[0] + c1 * p2[0] + c2 * p3[0]) / float(profile_data_num), + (p1[1] + c1 * p2[1] + c2 * p3[1]) / float(profile_data_num), + 0.0, + ) + profile[x] = disp_out + + +@wp.kernel +def update_points( + points: wp.array(dtype=wp.vec3), + profile: wp.array(dtype=wp.vec3), + profile_res: int, + profile_extent: float, + amplitude: float, + directionality: float, + direction: float, + cam_pos: wp.vec3, + clipmap_cell_size: float, + out_points: wp.array(dtype=wp.vec3), +): + tid = wp.tid() + p_crd = wp.vec3( + points[tid][0] + wp.floor(cam_pos[0] / clipmap_cell_size) * clipmap_cell_size, + points[tid][1], + points[tid][2] + wp.floor(cam_pos[2] / clipmap_cell_size) * clipmap_cell_size, + ) + + randState = wp.rand_init(7) + disp_x = float(0.0) + disp_y = float(0.0) + disp_z = float(0.0) + w_sum = float(0.0) + direction_count = 128 + for d in range(0, direction_count): + r = float(d) * wp.tau / float(direction_count) + 0.02 + dir_x = wp.cos(r) + dir_y = wp.sin(r) + # directional amplitude + t = wp.abs(direction - r) + if t > wp.pi: + t = wp.tau - t + t = pow(t, 1.2) + dir_amp = (2.0 * t * t * t - 3.0 * t * t + 1.0) * 1.0 + (-2.0 * t * t * t + 3.0 * t * t) * ( + 1.0 - directionality + ) + dir_amp = dir_amp / (1.0 + 10.0 * directionality) + rand_phase = wp.randf(randState) + x_crd = (p_crd[0] * dir_x + p_crd[2] * dir_y) / profile_extent + rand_phase + pos_0 = int(wp.floor(x_crd * float(profile_res))) % profile_res + if x_crd < 0.0: + pos_0 = pos_0 + profile_res - 1 + pos_1 = int(pos_0 + 1) % profile_res + p_disp_0 = profile[pos_0] + p_disp_1 = profile[pos_1] + w = frac(x_crd * float(profile_res)) + prof_height_x = dir_amp * float((1.0 - w) * p_disp_0[0] + w * p_disp_1[0]) + prof_height_y = dir_amp * float((1.0 - w) * p_disp_0[1] + w * p_disp_1[1]) + disp_x = disp_x + dir_x * prof_height_x + disp_y = disp_y + prof_height_y + disp_z = disp_z + dir_y * prof_height_x + w_sum = w_sum + 1.0 + + # write output vertex position + out_points[tid] = wp.vec3( + p_crd[0] + amplitude * disp_x / w_sum, + p_crd[1] + amplitude * disp_y / w_sum, + p_crd[2] + amplitude * disp_z / w_sum, + ) + + +# Internal State +# ------------------------------------------------------------------------------ + + +class InternalState: + """Convenience class for maintaining per-node state information""" + + def __init__(self): + self.profile = wp.zeros(PROFILE_RES, dtype=wp.vec3) + + +# Compute +# ------------------------------------------------------------------------------ + + +def compute(db: OgnSampleOceanDeformDatabase) -> None: + """Evaluates the node.""" + if not db.inputs.mesh.valid or not db.outputs.mesh.valid: + return + + state = db.internal_state + + amplitude = max(0.0001, min(1000.0, db.inputs.amplitude)) + direction = db.inputs.direction % 6.28318530718 + directionality = max(0.0, min(1.0, 0.02 * db.inputs.directionality)) + wind_speed = max(0.0, min(30.0, db.inputs.windSpeed)) + water_depth = max(1.0, min(1000.0, db.inputs.waterDepth)) + scale = min(10000.0, max(0.001, db.inputs.scale)) + + # create 1D profile buffer for this timestep using wave paramters + wp.launch( + kernel=update_profile, + dim=(PROFILE_RES,), + inputs=( + state.profile, + PROFILE_RES, + PROFILE_WAVENUM, + MIN_WAVE_LENGTH, + MAX_WAVE_LENGTH, + PROFILE_EXTENT, + db.inputs.time, + wind_speed, + water_depth, + ), + ) + + # Copy the input geometry mesh bundle and read its contents. + db.outputs.mesh = db.inputs.mesh + + # Retrieve the input and output point data. + points = omni.warp.nodes.mesh_get_points(db.inputs.mesh) + out_points = omni.warp.nodes.mesh_get_points(db.outputs.mesh) + + # update point positions using the profile buffer created above + wp.launch( + kernel=update_points, + dim=len(points), + inputs=( + points, + state.profile, + PROFILE_RES, + PROFILE_EXTENT * scale, + amplitude, + directionality, + direction, + db.inputs.cameraPos, + db.inputs.clipmapCellSize, + ), + outputs=(out_points,), + ) + + +# Node Entry Point +# ------------------------------------------------------------------------------ + + +class OgnSampleOceanDeform: + """ + Mesh deformer modeling ocean waves. + """ + + @staticmethod + def internal_state(): + """Returns an object that will contain per-node state information""" + return InternalState() + + @staticmethod + def compute(db) -> bool: + """Compute the outputs from the current input""" + device = omni.warp.nodes.device_get_cuda_compute() + + try: + with wp.ScopedDevice(device): + compute(db) + except Exception: + db.log_error(traceback.format_exc()) + return + + # Fire the execution for the downstream nodes. + db.outputs.execOut = og.ExecutionAttributeState.ENABLED