Outline v2


#1

Old version: github.com/1vanK/Urho3DOutline

Now with multiple colors and without coping of mesh

Renderpath

<renderpath>
    <rendertarget name="outlineMask" sizedivisor="1 1" format="rgba" filter="true" />
    <rendertarget name="outlineBlurredMaskH" sizedivisor="2 2" format="rgba" filter="true" />
    <rendertarget name="outlineBlurredMaskV" sizedivisor="2 2" format="rgba" filter="true" />
    <command type="clear" color="fog" depth="1.0" stencil="0" />
    <command type="clear" color="0 0 0 0" output="outlineMask" />
    <command type="scenepass" pass="base" vertexlights="true" metadata="base" />
    <command type="forwardlights" pass="light" />
    <command type="scenepass" pass="postopaque" />
    <command type="scenepass" pass="refract">
        <texture unit="environment" name="viewport" />
    </command>
    <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" />
    <command type="scenepass" pass="postalpha" sort="backtofront" />
    <command type="scenepass" pass="outline" output="outlineMask" />
    <command type="quad" vs="Outline" ps="Outline" psdefines="BLURH" output="outlineBlurredMaskH">
        <texture unit="diffuse" name="outlineMask" />
    </command>
    <command type="quad" vs="Outline" ps="Outline" psdefines="BLURV" output="outlineBlurredMaskV">
        <texture unit="diffuse" name="outlineBlurredMaskH" />
    </command>
    <command type="quad" vs="Outline" ps="Outline" psdefines="OUTPUT" output="viewport">
        <texture unit="diffuse" name="outlineBlurredMaskV" />
        <texture unit="normal" name="outlineMask" />
        <texture unit="specular" name="viewport" />
    </command>
</renderpath>

Outline.glsl

#include "Uniforms.glsl"
#include "Samplers.glsl"
#include "Transform.glsl"
#include "ScreenPos.glsl"

varying vec2 vTexCoord;
varying vec2 vScreenPos;

#ifdef COMPILEPS
    uniform vec4 cOutlineColor;
    uniform vec2 cOutlineBlurredMaskHInvSize;
#endif

void VS()
{
    mat4 modelMatrix = iModelMatrix;
    vec3 worldPos = GetWorldPos(modelMatrix);
    gl_Position = GetClipPos(worldPos);
    vTexCoord = GetQuadTexCoord(gl_Position);
    vScreenPos = GetScreenPosPreDiv(gl_Position);
}

void PS()
{
    #ifdef MASK
        gl_FragColor = vec4(cOutlineColor.rgb, 1.0);
    #endif

    #ifdef BLURH
        vec4 rgba = texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(-1.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(1.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(-2.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(2.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        gl_FragColor = rgba;
    #endif

    #ifdef BLURV
        vec4 rgba = texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, -1.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, 1.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, -2.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, 2.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        gl_FragColor = rgba;
    #endif

    #ifdef OUTPUT
        vec4 blurredMask = texture2D(sDiffMap, vTexCoord);
        vec4 mask = texture2D(sNormalMap, vTexCoord);
        vec4 viewport = texture2D(sSpecMap, vTexCoord);
        blurredMask = clamp(blurredMask - mask.a, 0.0, 1.0);
        blurredMask *= 2.0;
        gl_FragColor = viewport + blurredMask;
    #endif
}

Techniques/NoTextureOutline.xml

<technique vs="LitSolid" ps="LitSolid" vsdefines="NOUV" >
    <pass name="base" />
    <pass name="litbase" psdefines="AMBIENT" />
    <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
    <pass name="prepass" psdefines="PREPASS" />
    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
    <pass name="deferred" psdefines="DEFERRED" />
    <pass name="depth" vs="Depth" ps="Depth" />
    <pass name="shadow" vs="Shadow" ps="Shadow" />
    <pass name="outline" vs="Outline" ps="Outline" psdefines="MASK" depthwrite="false" />
</technique>

Material

<material>
	<technique name="Techniques/NoTextureOutline.xml" />
	<parameter name="MatDiffColor" value="1 1 1 1" />
	<parameter name="MatSpecColor" value="1 1 1 300" />
    <parameter name="OutlineColor" value="1 0 0 0" />
</material>

EDIT: Example topic1840-10.html#p10978


#2

Nice work!
Can be very useful for highlighting objects for indication.


#3

Modified version:
Outline is visible through other objects like Dota 2 and Left 4 Dead 2 (disabled depth test and enabled sorting).
Also some fixes (more correct mixing outline with viewport and more correct blurring).

shader Outline.glsl

#include "Uniforms.glsl"
#include "Samplers.glsl"
#include "Transform.glsl"
#include "ScreenPos.glsl"

varying vec2 vTexCoord;
varying vec2 vScreenPos;

#ifdef COMPILEPS
    uniform vec4 cOutlineColor;
    uniform vec2 cOutlineBlurredMaskHInvSize;
#endif

void VS()
{
    mat4 modelMatrix = iModelMatrix;
    vec3 worldPos = GetWorldPos(modelMatrix);
    gl_Position = GetClipPos(worldPos);
    vTexCoord = GetQuadTexCoord(gl_Position);
    vScreenPos = GetScreenPosPreDiv(gl_Position);
}

void PS()
{
    #ifdef MASK
        gl_FragColor = vec4(cOutlineColor.rgb, 1.0);
    #endif

    #ifdef BLURH
        vec4 rgba = texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.1;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(-1.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(1.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.4;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(-2.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(2.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.1;
        gl_FragColor = rgba;
    #endif

    #ifdef BLURV
        vec4 rgba = texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.1;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, -1.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, 1.0) * cOutlineBlurredMaskHInvSize) * 0.4;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, -2.0) * cOutlineBlurredMaskHInvSize) * 0.2;
        rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, 2.0) * cOutlineBlurredMaskHInvSize) * 0.1;
        gl_FragColor = rgba;
    #endif

    #ifdef OUTPUT
        vec4 blurredMask = texture2D(sDiffMap, vTexCoord);
        vec4 mask = texture2D(sNormalMap, vTexCoord);
        vec4 viewport = texture2D(sSpecMap, vTexCoord);
        blurredMask = clamp(blurredMask - mask.a, 0.0, 1.0);
        gl_FragColor = viewport * (1.0 - blurredMask.a) + blurredMask;
    #endif
}

renderpath

<renderpath> <rendertarget name="outlineMask" sizedivisor="1 1" format="rgba" filter="true" /> <rendertarget name="outlineBlurredMaskH" sizedivisor="2 2" format="rgba" filter="true" /> <rendertarget name="outlineBlurredMaskV" sizedivisor="2 2" format="rgba" filter="true" /> <command type="clear" color="fog" depth="1.0" stencil="0" /> <command type="clear" color="0 0 0 0" output="outlineMask" /> <command type="scenepass" pass="base" vertexlights="true" metadata="base" /> <command type="forwardlights" pass="light" /> <command type="scenepass" pass="postopaque" /> <command type="scenepass" pass="refract"> <texture unit="environment" name="viewport" /> </command> <command type="scenepass" pass="alpha" vertexlights="true" sort="backtofront" metadata="alpha" /> <command type="scenepass" pass="postalpha" sort="backtofront" /> <command type="scenepass" pass="outline" output="outlineMask" sort="backtofront" /> <command type="quad" vs="Outline" ps="Outline" psdefines="BLURH" output="outlineBlurredMaskH"> <texture unit="diffuse" name="outlineMask" /> </command> <command type="quad" vs="Outline" ps="Outline" psdefines="BLURV" output="outlineBlurredMaskV"> <texture unit="diffuse" name="outlineBlurredMaskH" /> </command> <command type="quad" vs="Outline" ps="Outline" psdefines="OUTPUT" output="viewport"> <texture unit="diffuse" name="outlineBlurredMaskV" /> <texture unit="normal" name="outlineMask" /> <texture unit="specular" name="viewport" /> </command> </renderpath>

Technique DiffOutline.xml

<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
    <pass name="base" />
    <pass name="litbase" psdefines="AMBIENT" />
    <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
    <pass name="prepass" psdefines="PREPASS" />
    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
    <pass name="deferred" psdefines="DEFERRED" />
    <pass name="depth" vs="Depth" ps="Depth" />
    <pass name="shadow" vs="Shadow" ps="Shadow" />
    <pass name="outline" vs="Outline" ps="Outline" psdefines="MASK" depthtest="always" depthwrite="false" />
</technique>

material MushroomOutline.xml

<material>
    <technique name="Techniques/DiffOutline.xml" />
    <texture unit="diffuse" name="Textures/Mushroom.dds" />
    <parameter name="MatSpecColor" value="0.1 0.1 0.1 16" />
    <parameter name="OutlineColor" value="1 0 0 0" />
</material>

#4

Big size of glow (more samples):

Outline.glsl

[code]#include “Uniforms.glsl”
#include “Samplers.glsl”
#include “Transform.glsl”
#include “ScreenPos.glsl”

varying vec2 vTexCoord;
varying vec2 vScreenPos;

#ifdef COMPILEPS
uniform vec4 cOutlineColor;
uniform vec2 cOutlineBlurredMaskHInvSize;
#endif

void VS()
{
mat4 modelMatrix = iModelMatrix;
vec3 worldPos = GetWorldPos(modelMatrix);
gl_Position = GetClipPos(worldPos);
vTexCoord = GetQuadTexCoord(gl_Position);
vScreenPos = GetScreenPosPreDiv(gl_Position);
}

void PS()
{
#ifdef MASK
gl_FragColor = vec4(cOutlineColor.rgb, 1.0);
#endif

#ifdef BLURH
    vec4 rgba = texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(-1.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(1.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(-2.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(2.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(-3.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(3.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(-4.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(4.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(-5.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(5.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    gl_FragColor = rgba;
#endif

#ifdef BLURV
    vec4 rgba = texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, -1.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, 1.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, -2.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, 2.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, -3.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, 3.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, -4.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, 4.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, -5.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    rgba += texture2D(sDiffMap, vTexCoord + vec2(0.0, 5.0) * cOutlineBlurredMaskHInvSize) * 0.091;
    gl_FragColor = rgba;
#endif

#ifdef OUTPUT
    vec4 blurredMask = texture2D(sDiffMap, vTexCoord);
    vec4 mask = texture2D(sNormalMap, vTexCoord);
    vec4 viewport = texture2D(sSpecMap, vTexCoord);
    blurredMask = clamp(blurredMask - mask.a, 0.0, 1.0);
    gl_FragColor = viewport * (1.0 - blurredMask.a) + blurredMask;
#endif

}
[/code]


#5

Very nice! Thank you for this.


#6

Great work! :slight_smile:


#7

final version of shader

[code]#include “Uniforms.glsl”
#include “Samplers.glsl”
#include “Transform.glsl”
#include “ScreenPos.glsl”

varying vec2 vTexCoord;
varying vec2 vScreenPos;

#ifdef COMPILEPS
uniform vec4 cOutlineColor;
uniform vec2 cOutlineBlurredMaskHInvSize;
#endif

void VS()
{
mat4 modelMatrix = iModelMatrix;
vec3 worldPos = GetWorldPos(modelMatrix);
gl_Position = GetClipPos(worldPos);
vTexCoord = GetQuadTexCoord(gl_Position);
vScreenPos = GetScreenPosPreDiv(gl_Position);
}

void PS()
{
#ifdef MASK
gl_FragColor = vec4(cOutlineColor.rgb, 1.0);
#endif

#ifdef BLURH
    vec4 rgba = texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cOutlineBlurredMaskHInvSize)
              + texture2D(sDiffMap, vTexCoord + vec2(-1.0, 0.0) * cOutlineBlurredMaskHInvSize)
              + texture2D(sDiffMap, vTexCoord + vec2(1.0, 0.0) * cOutlineBlurredMaskHInvSize)
              + texture2D(sDiffMap, vTexCoord + vec2(-2.0, 0.0) * cOutlineBlurredMaskHInvSize)
              + texture2D(sDiffMap, vTexCoord + vec2(2.0, 0.0) * cOutlineBlurredMaskHInvSize);
    gl_FragColor = rgba * 0.2;
#endif

#ifdef BLURV
    vec4 rgba = texture2D(sDiffMap, vTexCoord + vec2(0.0, 0.0) * cOutlineBlurredMaskHInvSize)
              + texture2D(sDiffMap, vTexCoord + vec2(0.0, -1.0) * cOutlineBlurredMaskHInvSize)
              + texture2D(sDiffMap, vTexCoord + vec2(0.0, 1.0) * cOutlineBlurredMaskHInvSize)
              + texture2D(sDiffMap, vTexCoord + vec2(0.0, -2.0) * cOutlineBlurredMaskHInvSize)
              + texture2D(sDiffMap, vTexCoord + vec2(0.0, 2.0) * cOutlineBlurredMaskHInvSize);
    gl_FragColor = rgba * 0.2;
#endif

#ifdef OUTPUT
    vec4 blurredMask = texture2D(sDiffMap, vTexCoord);
    vec4 mask = texture2D(sNormalMap, vTexCoord);
    vec4 viewport = texture2D(sSpecMap, vTexCoord);
    blurredMask = clamp(blurredMask - mask.a, 0.0, 1.0);
    blurredMask *= 3.0;
    gl_FragColor = viewport * (1.0 - blurredMask.a) + blurredMask;
#endif

}
[/code]


#8

This is a great improvement! very nice :slight_smile:


#9

Thanks for sharing this. This is something that definitely will come in handy.


#10

Awesome! :mrgreen:
Great improvement over the first version.


#11

Since people want to use it, open a repo with permissive license?


#12

code license: public domain


#13

Thank you for sharing this. Great example to learn glsl in urho3d.
I suggest to put it together in a new github repo. Many people will be interested to try out.


#14

Why not update the existing GitHub repo with the new shader? Or are you planning to?


#15

This is a different approach, perhaps the old version will be useful to someone. In any case, I see no point in duplicating the same thing in several places :slight_smile:


#16

Small example how to use it for select/deselect objects github.com/1vanK/Urho3DOutlineSelectionExample

EDIT: Press RMB for moving and rotating camera, and LMB for select


#17

nice!
Is it possible use this for animated models?
like this :


#18

[quote=“codingmonkey”]nice!
Is it possible use this for animated models?
like this :

It is possible for any material :slight_smile: just add to technique:

<pass name="outline" vs="Outline" ps="Outline" psdefines="MASK" depthtest="always" depthwrite="false" />

#19

Another (and simplest) method was made possible by the patch github.com/urho3d/Urho3D/commit … 5eea396080

Shader Outline.glsl:

[code]#include “Uniforms.glsl”
#include “Transform.glsl”

#ifdef COMPILEVS
uniform float cOutlineWidth = 0.01;
#endif

#ifdef COMPILEPS
uniform vec4 cOutlineColor = vec4(1.0, 1.0, 1.0, 1.0);
#endif

void VS()
{
mat4 modelMatrix = iModelMatrix;
vec3 worldPos = GetWorldPos(modelMatrix);
vec3 vNormal = GetWorldNormal(modelMatrix);
// Scale along normal
worldPos += vNormal * cOutlineWidth;
gl_Position = GetClipPos(worldPos);
}

void PS()
{
gl_FragColor = cOutlineColor.rgba;
}
[/code]

Technique DiffOutline.xml:

<technique vs="LitSolid" ps="LitSolid" psdefines="DIFFMAP">
    <pass name="base" />
    <pass name="litbase" psdefines="AMBIENT" />
    <pass name="light" depthtest="equal" depthwrite="false" blend="add" />
    <pass name="prepass" psdefines="PREPASS" />
    <pass name="material" psdefines="MATERIAL" depthtest="equal" depthwrite="false" />
    <pass name="deferred" psdefines="DEFERRED" />
    <pass name="depth" vs="Depth" ps="Depth" />
    <pass name="shadow" vs="Shadow" ps="Shadow" />
    
    <!-- ADDED -->
    <pass name="postopaque" depthwrite="false" vs="Outline" ps="Outline" cull="cw" />
</technique>

Material MushroomOutline.xml:

<material>
    <technique name="Techniques/DiffOutline.xml" />
    <texture unit="diffuse" name="Textures/Mushroom.dds" />
    <parameter name="MatSpecColor" value="0.1 0.1 0.1 16" />
    
    <!-- ADDED -->
    <parameter name="OutlineWidth" value="0.01" />
    <parameter name="OutlineColor" value="1 1 0 1" />
</material>

Note: it works correctly only for models with smooth shading


UnityChan Toon Shader ver2 repo
#20

This is really nice, do you think you can make a voxel based one, like this one ? twitter.com/_chrisro/status/703373120313421825