From 2f260493672d2b2e653a2706f80e99f38727d799 Mon Sep 17 00:00:00 2001 From: Edwin Jakobs Date: Sun, 14 Jun 2020 20:53:42 +0200 Subject: [PATCH] [orx-dnk3] Add segmentContourRenderer --- build.gradle | 2 +- .../src/demo/kotlin/DemoSegmentContours01.kt | 49 +++++++++++++++++++ orx-dnk3/src/main/kotlin/Facet.kt | 16 +++++- orx-dnk3/src/main/kotlin/Material.kt | 9 +++- orx-dnk3/src/main/kotlin/PBRMaterial.kt | 25 ++++++++-- orx-dnk3/src/main/kotlin/RenderPass.kt | 8 +-- orx-dnk3/src/main/kotlin/SceneRenderer.kt | 12 +---- orx-dnk3/src/main/kotlin/ShaderUtilities.kt | 9 +++- .../src/main/kotlin/post/SegmentContours.kt | 8 +++ .../renderers/SegmentContourRenderer.kt | 34 +++++++++++++ .../shaders/segment-contours-msaa-8.frag | 34 +++++++++++++ .../resources/shaders/segment-contours.frag | 33 +++++++++++++ 12 files changed, 214 insertions(+), 25 deletions(-) create mode 100644 orx-dnk3/src/demo/kotlin/DemoSegmentContours01.kt create mode 100644 orx-dnk3/src/main/kotlin/post/SegmentContours.kt create mode 100644 orx-dnk3/src/main/kotlin/renderers/SegmentContourRenderer.kt create mode 100644 orx-dnk3/src/main/resources/shaders/segment-contours-msaa-8.frag create mode 100644 orx-dnk3/src/main/resources/shaders/segment-contours.frag diff --git a/build.gradle b/build.gradle index 1ba2316c..2bd610cf 100644 --- a/build.gradle +++ b/build.gradle @@ -14,7 +14,7 @@ buildscript { apply plugin: 'org.jetbrains.dokka' project.ext { - openrndrVersion = "0.3.43-rc.11" + openrndrVersion = "0.3.43-rc.12" kotlinVersion = "1.3.72" spekVersion = "2.0.10" libfreenectVersion = "0.5.7-1.5.3" diff --git a/orx-dnk3/src/demo/kotlin/DemoSegmentContours01.kt b/orx-dnk3/src/demo/kotlin/DemoSegmentContours01.kt new file mode 100644 index 00000000..00dcbc65 --- /dev/null +++ b/orx-dnk3/src/demo/kotlin/DemoSegmentContours01.kt @@ -0,0 +1,49 @@ +import org.openrndr.application +import org.openrndr.color.ColorRGBa +import org.openrndr.draw.BufferMultisample +import org.openrndr.extensions.SingleScreenshot +import org.openrndr.extra.dnk3.* +import org.openrndr.extra.dnk3.gltf.buildSceneNodes +import org.openrndr.extra.dnk3.gltf.loadGltfFromFile +import org.openrndr.extra.dnk3.renderers.segmentContourRenderer +import org.openrndr.extras.camera.Orbital +import org.openrndr.math.Vector3 +import org.openrndr.math.mod_ +import java.io.File + +fun main() = application { + configure { + width = 1280 + height = 720 + //multisample = WindowMultisample.SampleCount(8) + } + + program { + if (System.getProperty("takeScreenshot") == "true") { + extend(SingleScreenshot()) { + this.outputFile = System.getProperty("screenshotPath") + } + } + + val gltf = loadGltfFromFile(File("demo-data/gltf-models/fox/Fox.glb")) + val scene = Scene(SceneNode()) + + val sceneData = gltf.buildSceneNodes() + scene.root.children.addAll(sceneData.scenes.first()) + + // -- create a renderer, try it with BufferMultisample.SampleCount(8) for better results + val renderer = segmentContourRenderer(BufferMultisample.Disabled) + extend(Orbital()) { + far = 500.0 + lookAt = Vector3(0.0, 40.0, 0.0) + eye = Vector3(150.0, 40.0, 200.0) + fov = 40.0 + } + + extend { + sceneData.animations[2].applyToTargets(seconds.mod_(sceneData.animations[2].duration)) + drawer.clear(ColorRGBa.PINK) + renderer.draw(drawer, scene) + } + } +} \ No newline at end of file diff --git a/orx-dnk3/src/main/kotlin/Facet.kt b/orx-dnk3/src/main/kotlin/Facet.kt index 197cb717..fa8a0fb4 100644 --- a/orx-dnk3/src/main/kotlin/Facet.kt +++ b/orx-dnk3/src/main/kotlin/Facet.kt @@ -15,18 +15,26 @@ enum class FacetType(val shaderFacet: String) { EMISSIVE("f_emission"), AMBIENT("f_ambient"), OCCLUSION("f_occlusion"), + FRAGMENT_ID("f_fragmentID"), COLOR("m_color"), } abstract class FacetCombiner(val facets: Set, val targetOutput: String) { abstract fun generateShader(): String + override fun toString(): String { + return "FacetCombiner(facets=$facets, targetOutput='$targetOutput')" + } + + } abstract class ColorBufferFacetCombiner(facets: Set, targetOutput: String, val format: ColorFormat, val type: ColorType, - val blendMode: BlendMode = BlendMode.BLEND) : FacetCombiner(facets, targetOutput) + val blendMode: BlendMode = BlendMode.BLEND) : FacetCombiner(facets, targetOutput) { + +} class MomentsFacet : ColorBufferFacetCombiner(setOf(FacetType.WORLD_POSITION), "moments", ColorFormat.RG, ColorType.FLOAT16) { override fun generateShader(): String { @@ -111,6 +119,12 @@ class ClipPositionFacet : ColorBufferFacetCombiner(setOf(FacetType.CLIP_POSITION override fun generateShader() = "o_$targetOutput.rgb = gl_FragCoord.xyz;" } +class FragmentIDFacet: ColorBufferFacetCombiner(setOf(FacetType.FRAGMENT_ID), "fragmentID", ColorFormat.R, ColorType.UINT16_INT) { + override fun generateShader(): String { + return "o_$targetOutput = f_fragmentID;" + } +} + class LDRColorFacet : ColorBufferFacetCombiner(setOf(FacetType.DIFFUSE, FacetType.SPECULAR), "color", ColorFormat.RGBa, ColorType.UINT8) { override fun generateShader() = """ vec3 finalColor = (max(vec3(0.0), f_diffuse.rgb) + max(vec3(0.0),f_specular.rgb) + max(vec3(0.0), f_emission.rgb)) * (1.0 - f_fog.a) + f_fog.rgb * f_fog.a; diff --git a/orx-dnk3/src/main/kotlin/Material.kt b/orx-dnk3/src/main/kotlin/Material.kt index a9f79013..d0f4fdbb 100644 --- a/orx-dnk3/src/main/kotlin/Material.kt +++ b/orx-dnk3/src/main/kotlin/Material.kt @@ -8,6 +8,7 @@ import org.openrndr.draw.shadeStyle interface Material { var doubleSided: Boolean var transparent: Boolean + val fragmentID: Int fun generateShadeStyle(context: MaterialContext, primitiveContext: PrimitiveContext): ShadeStyle fun applyToShadeStyle(context: MaterialContext, shadeStyle: ShadeStyle) } @@ -15,13 +16,19 @@ interface Material { class DummyMaterial : Material { override var doubleSided: Boolean = true override var transparent: Boolean = false - + override var fragmentID = 0 override fun generateShadeStyle(context: MaterialContext, primitiveContext: PrimitiveContext): ShadeStyle { return shadeStyle { + fragmentPreamble = """ + int f_fragmentID = p_fragmentID; + """.trimIndent() + fragmentTransform = """ x_fill.rgb = vec3(normalize(v_viewNormal).z); """.trimIndent() + + parameter("fragmentID", fragmentID) } } diff --git a/orx-dnk3/src/main/kotlin/PBRMaterial.kt b/orx-dnk3/src/main/kotlin/PBRMaterial.kt index 73fc53f8..6e39102f 100644 --- a/orx-dnk3/src/main/kotlin/PBRMaterial.kt +++ b/orx-dnk3/src/main/kotlin/PBRMaterial.kt @@ -264,11 +264,18 @@ class Texture(var source: TextureSource, } } +private var fragmentIDCounter = 1 + class PBRMaterial : Material { override fun toString(): String { return "PBRMaterial(textures: $textures, color: $color, metalness: $metalness, roughness: $roughness, emissive: $emission))" } + override var fragmentID = fragmentIDCounter.apply { + fragmentIDCounter++ + + } + override var doubleSided: Boolean = false override var transparent: Boolean = false var environmentMap = false @@ -277,6 +284,7 @@ class PBRMaterial : Material { var roughness = 1.0 var emission = ColorRGBa.BLACK + var fragmentPreamble: String? = null var vertexPreamble: String? = null var vertexTransform: String? = null var parameters = mutableMapOf() @@ -304,6 +312,7 @@ class PBRMaterial : Material { val needLight = needLight(materialContext) val preambleFS = """ vec4 m_color = p_color; + uint f_fragmentID = uint(p_fragmentID); float m_f0 = 0.5; float m_roughness = p_roughness; float m_metalness = p_metalness; @@ -415,11 +424,12 @@ class PBRMaterial : Material { val vs = (this@PBRMaterial.vertexTransform ?: "") + textureVS + skinVS shadeStyle { + fragmentPreamble = this@PBRMaterial.fragmentPreamble ?: "" vertexPreamble = """ $shaderNoRepetitionVert ${(this@PBRMaterial.vertexPreamble) ?: ""} """.trimIndent() - fragmentPreamble = """ + fragmentPreamble += """ |$shaderLinePlaneIntersect |$shaderProjectOnPlane |$shaderSideOfPlane @@ -431,10 +441,14 @@ class PBRMaterial : Material { this.vertexTransform = vs fragmentTransform = fs materialContext.pass.combiners.map { - if (rt.colorBuffers.size <= 1) { - this.output(it.targetOutput, 0) - } else - this.output(it.targetOutput, rt.colorBufferIndex(it.targetOutput)) + if (rt is ProgramRenderTarget) { + this.output(it.targetOutput, ShadeStyleOutput(0)) + } else { + val index = rt.colorBufferIndex(it.targetOutput) + val type = rt.colorBuffer(index).type + val format = rt.colorBuffer(0).format + this.output(it.targetOutput, ShadeStyleOutput(index, format, type)) + } } } } @@ -453,6 +467,7 @@ class PBRMaterial : Material { shadeStyle.parameter("color", color) shadeStyle.parameter("metalness", metalness) shadeStyle.parameter("roughness", roughness) + shadeStyle.parameter("fragmentID", fragmentID) parameters.forEach { (k, v) -> when (v) { diff --git a/orx-dnk3/src/main/kotlin/RenderPass.kt b/orx-dnk3/src/main/kotlin/RenderPass.kt index 67716204..50ab4b4e 100644 --- a/orx-dnk3/src/main/kotlin/RenderPass.kt +++ b/orx-dnk3/src/main/kotlin/RenderPass.kt @@ -5,12 +5,12 @@ import org.openrndr.draw.DepthFormat import org.openrndr.draw.RenderTarget import org.openrndr.draw.renderTarget -class RenderPass(val combiners: List, +data class RenderPass(val combiners: List, val renderOpaque: Boolean = true, val renderTransparent: Boolean = false, - val depthWrite: Boolean = true + val depthWrite: Boolean = true, + val multisample: BufferMultisample = BufferMultisample.Disabled) -) val DefaultPass = RenderPass(listOf(LDRColorFacet())) val DefaultOpaquePass = RenderPass(listOf(LDRColorFacet()), renderOpaque = true, renderTransparent = false) @@ -18,7 +18,7 @@ val DefaultTransparentPass = RenderPass(listOf(LDRColorFacet()), renderOpaque = val LightPass = RenderPass(emptyList()) val VSMLightPass = RenderPass(listOf(MomentsFacet())) -fun RenderPass.createPassTarget(width: Int, height: Int, depthFormat: DepthFormat = DepthFormat.DEPTH24, multisample: BufferMultisample = BufferMultisample.Disabled): RenderTarget { +fun RenderPass.createPassTarget(width: Int, height: Int, depthFormat: DepthFormat = DepthFormat.DEPTH24, multisample: BufferMultisample = this.multisample): RenderTarget { return renderTarget(width, height, multisample = multisample) { for (combiner in combiners) { when (combiner) { diff --git a/orx-dnk3/src/main/kotlin/SceneRenderer.kt b/orx-dnk3/src/main/kotlin/SceneRenderer.kt index e9f2d18b..49088315 100644 --- a/orx-dnk3/src/main/kotlin/SceneRenderer.kt +++ b/orx-dnk3/src/main/kotlin/SceneRenderer.kt @@ -110,7 +110,7 @@ class SceneRenderer { if (pass == outputPasses[0]) { outputPassTarget?.let { drawer.withTarget(it) { - clear(ColorRGBa.PINK) + clear(ColorRGBa.TRANSPARENT) } } } @@ -136,18 +136,8 @@ class SceneRenderer { val postContext = PostContext(lightContext, drawer.view.inversed) for (postStep in postSteps) { -// if (postStep is FilterPostStep) { -// if (postStep.filter is Ssao) { -// postStep.filter.projection = drawer.projection -// } -// if (postStep.filter is Sslr) { -// val p = Matrix44.scale(drawer.width / 2.0, drawer.height / 2.0, 1.0) * Matrix44.translate(Vector3(1.0, 1.0, 0.0)) * drawer.projection -// postStep.filter.projection = p -// } -// } postStep.apply(buffers, postContext) } - } drawer.popStyle() diff --git a/orx-dnk3/src/main/kotlin/ShaderUtilities.kt b/orx-dnk3/src/main/kotlin/ShaderUtilities.kt index 7d64b716..b3fe515e 100644 --- a/orx-dnk3/src/main/kotlin/ShaderUtilities.kt +++ b/orx-dnk3/src/main/kotlin/ShaderUtilities.kt @@ -1,6 +1,7 @@ package org.openrndr.extra.dnk3 val shaderNoRepetition = """ +// -- shaderNoRepetition float sum( vec3 v ) { return v.x+v.y+v.z; } // based on https://www.shadertoy.com/view/Xtl3zf @@ -35,7 +36,7 @@ vec4 textureNoTile(in sampler2D noiseTex, in sampler2D tex, in vec2 noiseOffset, """ val shaderNoRepetitionVert = """ -// shaderNoRepetitionVert +// -- shaderNoRepetitionVert float sum( vec3 v ) { return v.x+v.y+v.z; } // based on https://www.shadertoy.com/view/Xtl3zf @@ -67,7 +68,7 @@ vec4 textureNoTile(in sampler2D tex, in vec2 noiseOffset, in vec2 x) """ val shaderProjectOnPlane = """ -// shaderProjectOnPlane +// -- shaderProjectOnPlane vec3 projectOnPlane(vec3 p, vec3 pc, vec3 pn) { float distance = dot(pn, p-pc); return p - distance * pn; @@ -75,18 +76,21 @@ vec3 projectOnPlane(vec3 p, vec3 pc, vec3 pn) { """.trimIndent() val shaderSideOfPlane = """ +// -- shaderSideOfPlane int sideOfPlane(in vec3 p, in vec3 pc, in vec3 pn){ if (dot(p-pc,pn) >= 0.0) return 1; else return 0; } """.trimIndent() val shaderLinePlaneIntersect = """ +// -- shaderLinePlaneIntersect vec3 linePlaneIntersect(in vec3 lp, in vec3 lv, in vec3 pc, in vec3 pn){ return lp+lv*(dot(pn,pc-lp)/dot(pn,lv)); } """.trimIndent() val shaderVSM = """ +|// -- shaderVSM |float linstep(float min, float max, float v) |{ | return clamp((v - min) / (max - min), 0, 1); @@ -112,6 +116,7 @@ V - eye - world vertex position L - world light pos - world vertex position */ val shaderGGX = """ +// -- shaderGGX #define bias 0.125 #define HASHSCALE 443.8975 vec2 hash22(vec2 p) { diff --git a/orx-dnk3/src/main/kotlin/post/SegmentContours.kt b/orx-dnk3/src/main/kotlin/post/SegmentContours.kt new file mode 100644 index 00000000..f9527acf --- /dev/null +++ b/orx-dnk3/src/main/kotlin/post/SegmentContours.kt @@ -0,0 +1,8 @@ +package org.openrndr.extra.dnk3.post + +import org.openrndr.draw.Filter +import org.openrndr.draw.filterShaderFromUrl +import org.openrndr.resourceUrl + +class SegmentContoursMSAA8 : Filter(filterShaderFromUrl(resourceUrl("/shaders/segment-contours-msaa-8.frag"))) +class SegmentContours : Filter(filterShaderFromUrl(resourceUrl("/shaders/segment-contours.frag"))) diff --git a/orx-dnk3/src/main/kotlin/renderers/SegmentContourRenderer.kt b/orx-dnk3/src/main/kotlin/renderers/SegmentContourRenderer.kt new file mode 100644 index 00000000..b928c6b8 --- /dev/null +++ b/orx-dnk3/src/main/kotlin/renderers/SegmentContourRenderer.kt @@ -0,0 +1,34 @@ +package org.openrndr.extra.dnk3.renderers + +import org.openrndr.draw.BufferMultisample +import org.openrndr.draw.ColorFormat +import org.openrndr.draw.ColorType +import org.openrndr.extra.dnk3.* +import org.openrndr.extra.dnk3.post.SegmentContours +import org.openrndr.extra.dnk3.post.SegmentContoursMSAA8 + +fun segmentContourRenderer(multisample: BufferMultisample = BufferMultisample.Disabled): SceneRenderer { + val sr = SceneRenderer() + sr.outputPasses.clear() + sr.outputPasses.add( + RenderPass( + listOf(FragmentIDFacet()), + multisample = multisample + ) + ) + sr.postSteps.add( + FilterPostStep(1.0, + when (multisample) { + BufferMultisample.Disabled -> SegmentContours() + BufferMultisample.SampleCount(8) -> SegmentContoursMSAA8() + else -> error("unsupported multisampling mode $multisample") + }, + listOf("fragmentID"), + "segments", + ColorFormat.RGB, + ColorType.UINT8 + ) + ) + sr.drawFinalBuffer = true + return sr +} \ No newline at end of file diff --git a/orx-dnk3/src/main/resources/shaders/segment-contours-msaa-8.frag b/orx-dnk3/src/main/resources/shaders/segment-contours-msaa-8.frag new file mode 100644 index 00000000..04a05932 --- /dev/null +++ b/orx-dnk3/src/main/resources/shaders/segment-contours-msaa-8.frag @@ -0,0 +1,34 @@ +#version 330 + +uniform usampler2DMS tex0; +in vec2 v_texCoord0; +out vec4 o_output; + +void main() { + ivec2 ts = textureSize(tex0); + ivec2 pixel = ivec2(v_texCoord0 * ts); + + ivec2 c = pixel; + ivec2 n = c + ivec2(0, -1); + ivec2 s = c + ivec2(0, 1); + ivec2 w = c + ivec2(-1, 0); + ivec2 e = c + ivec2(1, 0); + + + float sf = 0.0; + for (int i = 0; i < 8; ++i) { + float f = 1.0; + uint sc = texelFetch(tex0, c, i).r; + uint sn = texelFetch(tex0, n, i).r; + uint ss = texelFetch(tex0, s, i).r; + uint se = texelFetch(tex0, e, i).r; + uint sw = texelFetch(tex0, w, i).r; + + if (sc == se) f -= 0.25; + if (sc == sw) f -= 0.25; + if (sc == sn) f -= 0.25; + if (sc == ss) f -= 0.25; + sf+= f; + } + o_output = vec4(vec3(sf/4.0), 1.0); +} \ No newline at end of file diff --git a/orx-dnk3/src/main/resources/shaders/segment-contours.frag b/orx-dnk3/src/main/resources/shaders/segment-contours.frag new file mode 100644 index 00000000..91bd0806 --- /dev/null +++ b/orx-dnk3/src/main/resources/shaders/segment-contours.frag @@ -0,0 +1,33 @@ +#version 330 + +uniform usampler2D tex0; +in vec2 v_texCoord0; +out vec4 o_output; + +void main() { + ivec2 ts = textureSize(tex0, 0); + ivec2 pixel = ivec2(v_texCoord0 * ts); + + ivec2 c = pixel; + ivec2 n = c + ivec2(0, -1); + ivec2 s = c + ivec2(0, 1); + ivec2 w = c + ivec2(-1, 0); + ivec2 e = c + ivec2(1, 0); + + float sf = 0.0; + for (int i = 0; i < 1; ++i) { + float f = 1.0; + uint sc = texelFetch(tex0, c, i).r; + uint sn = texelFetch(tex0, n, i).r; + uint ss = texelFetch(tex0, s, i).r; + uint se = texelFetch(tex0, e, i).r; + uint sw = texelFetch(tex0, w, i).r; + + if (sc == se) f -= 0.25; + if (sc == sw) f -= 0.25; + if (sc == sn) f -= 0.25; + if (sc == ss) f -= 0.25; + sf+= f; + } + o_output = vec4(vec3(sf/0.5), 1.0); +} \ No newline at end of file