Transparent Black Pixel Shader

Everything related to 3D programming
User avatar
Samuel
Enthusiast
Enthusiast
Posts: 755
Joined: Sun Jul 29, 2012 10:33 pm
Location: United States

Transparent Black Pixel Shader

Post by Samuel »

Hello everyone,
Well, I haven't posted any shader examples in a while. I moved on to other 3D options in Purebasic almost a year ago so I'm a little rusty when it comes to writing material scripts. Hopefully everything will work smoothly for those interested in it.

First off here's what the shader looks like. The left entities are using the shader and the right ones are not.
Image
Nothing fancy all it does is take the pure black pixels and then discards them. It does leave jagged edges, and sadly there's not much you can do to get rid of them.

Well, technically you can get rid of them, but then you have to deal with transparent triangles being out of order. And reordering the triangles in Purebasic is simply not possible and I don't see a good enough reason why it ever would be.
In other words you have to choose either jagged edges with correct ordering or smooth edges which have the possibility of incorrect ordering.

Now a simple explanation on how to use this shader with the textures you want. If you open TransparentMaterial.MATERIAL in notepad (or some other text editor) and scroll to the bottom you should find

Code: Select all

material Transparent01 : TransparentTexture
{
	set $Texture Image01.png
}

material Transparent02 : TransparentTexture
{
	set $Texture Image02.png
}
I'll break down what these lines mean. The Transparent01 and Transparent02 are the Name$ that you call from Purebasic with GetScriptMaterial(#Material, Name$).
Image01.png and Image02.png are the actual image that the shader will use. In other words you need to write one of these out for every material that has a unique image.
For example if I were to add another one to the list it might look something like this.

Code: Select all

material Transparent01 : TransparentTexture
{
	set $Texture Image01.png
}

material Transparent02 : TransparentTexture
{
	set $Texture Image02.png
}

material Stars : TransparentTexture
{
	set $Texture NightSky.png
}
And I'd call the new material in Purebasic like so.

Code: Select all

MaterialHandle = GetScriptMaterial(#PB_Any, "Stars")
That's about all you need to do as the end user of this shader.
This script includes both GLSL and HLSL shaders so you don't need to worry about it not working on your system. Just include all the files and the script will pick whichever one is currently in use by your program.

Now then here's the link to all the files and the example code to run them. Just start up the pb file and it should run without an issue. If there are problems let me know and I'll see what I can do to fix them.
Shader Transparent.zip

I'll also post the script and shaders below, but you can ignore them if you downloaded the files from the link above.
Enjoy! :)



If you copy and paste them into notepad just make sure you save them exactly as labeled below.
TransparentMaterial.MATERIAL

Code: Select all

// GLSL simple transparency
vertex_program transparencyVSGLSL glsl 
{
	source TransparentGLSL.vert
}

fragment_program transparencyFSGLSL glsl 
{
	source TransparentGLSL.frag
	default_params
	{
		param_named TexTU int 0
	}
}

// HLSL simple transparency
vertex_program transparencyVSHLSL hlsl
{
	source TransparentHLSL.hlsl
	entry_point AlphaTexture_Vert
	target vs_1_1  

	default_params
	{
		param_named_auto worldViewProj worldviewproj_matrix
	}  
}

fragment_program transparencyFSHLSL hlsl
{
	source TransparentHLSL.hlsl
	entry_point AlphaTexture_Frag
	target ps_2_0
} 

// Delegates
vertex_program transparencyVp unified
{
	delegate transparencyVSGLSL
	delegate transparencyVSHLSL
}

fragment_program transparencyFp unified
{
	delegate transparencyFSGLSL
	delegate transparencyFSHLSL
}

abstract material TransparentTexture
{
	technique
	{
		pass
		{
			vertex_program_ref transparencyVp
			{
			}

			fragment_program_ref transparencyFp
			{  
			}

			texture_unit
			{
				texture $Texture
				tex_coord_set 0
			}
		}
	}

	technique
	{
		pass
		{
			texture_unit
			{
				texture $Texture
				tex_coord_set 0
			}
		}
	}
}

material Transparent01 : TransparentTexture
{
	set $Texture Image01.png
}

material Transparent02 : TransparentTexture
{
	set $Texture Image02.png
}
TransparentHLSL.HLSL

Code: Select all

void AlphaTexture_Vert(
			float4 position : POSITION,
			float2 uv       : TEXCOORD0,
			uniform float4x4 worldViewProj,
			out     float4   oPosition : POSITION,
			out     float2   oUv       : TEXCOORD0)

{
	position = mul(worldViewProj, position);

	oPosition = position;

	oUv = uv;
}
 

void AlphaTexture_Frag(
			float4 position    : POSITION,
			float2 uv          : TEXCOORD0,
			out float4 oColour : COLOR,
			uniform sampler2D TextureMap : register(s0))

{   
	float4 Color = tex2D(TextureMap, uv.xy);

	float Black = Color.r + Color.g + Color.b;

	if(Black == 0)
		discard;

	oColour = Color;
}

TransparentGLSL.VERT

Code: Select all

varying vec2 TexCoord;

void main(void)
{
	TexCoord = gl_MultiTexCoord0.xy;
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

TransparentGLSL.FRAG

Code: Select all

varying vec2 TexCoord;
uniform sampler2D TexTU;

void main(void)
{   
	vec4 Color = texture2D(TexTU, TexCoord);
 
	if (Color.rgb == vec3(0.0,0.0,0.0))
		discard; 

	gl_FragColor = Color;
}
User avatar
DK_PETER
Addict
Addict
Posts: 898
Joined: Sat Feb 19, 2011 10:06 am
Location: Denmark
Contact:

Re: Transparent Black Pixel Shader

Post by DK_PETER »

Very nice example, Samuel.
Thanks.
Current configurations:
Ubuntu 20.04/64 bit - Window 10 64 bit
Intel 6800K, GeForce Gtx 1060, 32 gb ram.
Amd Ryzen 9 5950X, GeForce 3070, 128 gb ram.
tastyraspberry
User
User
Posts: 39
Joined: Fri Sep 28, 2012 10:22 am

Re: Transparent Black Pixel Shader

Post by tastyraspberry »

I realise I am resurrecting an old thread.

@Samuel:

How would you go around replacing the texture in the shader 'on the fly'? I've tried

Code: Select all

LoadTexture(0, "Image03.png") 
    AddMaterialLayer(#ShaderMaterial1, TextureID(0), #PB_Material_Replace, 0)
but it doesn't seem to work? Is there a simple way to do this? Or do I need EntityCustomParameter(...)

Michael
User avatar
Samuel
Enthusiast
Enthusiast
Posts: 755
Joined: Sun Jul 29, 2012 10:33 pm
Location: United States

Re: Transparent Black Pixel Shader

Post by Samuel »

I remember me and Alexi having some difficulty with that a few years back. The only solution we could come up with was recreating the texture's image on the hard drive and then reparsing the material scripts. Which wasn't efficient, but it worked.

Hmm, after looking through the newer 3D commands I think GetScriptTexture() might do the trick. If GetScriptTexture() is returning the texture's handle then you might be able to alter the texture by just drawing over it.
tastyraspberry
User
User
Posts: 39
Joined: Fri Sep 28, 2012 10:22 am

Re: Transparent Black Pixel Shader

Post by tastyraspberry »

Hi Samuel,

Thanks for the answer. I think you can do it by

Code: Select all

        RemoveMaterialLayer(#ShaderMaterial1)
        AddMaterialLayer(#ShaderMaterial1, TextureID(TextureBlue), #PB_Material_Replace)
which seems encouraging.. I think removing it first must unregister the Texture with material script...

I'll play around a bit more and see what I can do...

Michael

Code: Select all


If InitEngine3D(#PB_Engine3D_DebugLog) = 0
    MessageRequester("ERROR!", "Failed to initialize the 3D engine.", #PB_MessageRequester_Ok)
    End
EndIf

If InitSprite() = 0
    MessageRequester("ERROR!", "Failed to initialize the sprite environment.", #PB_MessageRequester_Ok)
    End
EndIf

If InitKeyboard() = 0
    MessageRequester("ERROR!", "Failed to initialize the keyboard environment.", #PB_MessageRequester_Ok)
    End
EndIf

Enumeration
    #Window
    #Camera
    #Node
    #Light
    #Sphere
    #Plane
    #ShaderEntity1
    #ShaderEntity2
    #RegularEntity1
    #RegularEntity2
    #ShaderMaterial1
    #ShaderMaterial2
    #RegularTexture1
    #RegularTexture2
    #RegularMaterial1
    #RegularMaterial2
EndEnumeration

ExamineDesktops()
DesktopW = DesktopWidth(0)
DesktopH = DesktopHeight(0)

OpenWindow(#Window, 0, 0, DesktopW, DesktopH, "Black To Alpha Shader")
OpenWindowedScreen(WindowID(#Window), 0, 0, DesktopW, DesktopH)



TextureBlue.i = CreateTexture(#PB_Any, 256, 256)
StartDrawing(TextureOutput(TextureBlue))
Box(0, 0, TextureWidth(TextureBlue)/2, TextureHeight(TextureBlue)/2, RGB(0, 0, 255))
StopDrawing()
MaterialBlue.i = CreateMaterial(#PB_Any, TextureID(TextureBlue))


Add3DArchive("scripts/", #PB_3DArchive_FileSystem)
Add3DArchive("shaders/", #PB_3DArchive_FileSystem)
Add3DArchive("textures/", #PB_3DArchive_FileSystem)
Parse3DScripts() ;We need to Parse the Archives when using scripts and shaders
LoadTexture(#RegularTexture1, "Image01.png")

CreateSphere(#Sphere, 1)
CreateSphere(#Plane, 1)

;Load First Shader
GetScriptMaterial(#ShaderMaterial1, "Transparent01")
MaterialFilteringMode(#ShaderMaterial1, #PB_Material_None)
MaterialCullingMode(#ShaderMaterial1, #PB_Material_NoCulling)

;Load Second Shader
GetScriptMaterial(#ShaderMaterial2, "Transparent02")
MaterialFilteringMode(#ShaderMaterial2, #PB_Material_None)
MaterialCullingMode(#ShaderMaterial2, #PB_Material_NoCulling)

;Create First Shader Entity
CreateEntity(#ShaderEntity1, MeshID(#Sphere), MaterialID(#ShaderMaterial1), -4, 0, 0)
RotateEntity(#ShaderEntity1, 0, 180, 0)

;Create Second Shader Entity
CreateEntity(#ShaderEntity2, MeshID(#Plane), MaterialID(#ShaderMaterial2), 4, 0, 0)
RotateEntity(#ShaderEntity2, 0, 180, 0)


;####
;The Materials and Entities Below are not using the shaders.
;They are just for a before and after effect.

CreateMaterial(#RegularMaterial1, TextureID(#RegularTexture1))
MaterialFilteringMode(#RegularMaterial1, #PB_Material_None)

LoadTexture(#RegularTexture2, "Image02.png")
CreateMaterial(#RegularMaterial2, TextureID(#RegularTexture2))
MaterialFilteringMode(#RegularMaterial2, #PB_Material_None)

CreateEntity(#RegularEntity1, MeshID(#Plane), MaterialID(#RegularMaterial1), 4, 0, -4)
RotateEntity(#RegularEntity1, 0, 180, 0)

CreateEntity(#RegularEntity2, MeshID(#Sphere), MaterialID(#RegularMaterial2), -4, 0, -4)
RotateEntity(#RegularEntity2, 0, 180, 0)
;####


CreateCamera(#Camera, 0, 0, 100, 100)
MoveCamera  (#Camera, 0, 0, 20)
CameraLookAt(#Camera, 0, 0, 0)
CameraBackColor(#Camera, RGB(50, 100, 150))

CreateLight(#Light, RGB(255,255,255), 5, 5, 5)

CreateNode(#Node, 0, 0, 0)
AttachNodeObject(#Node, CameraID(#Camera))

Repeat
    
    Event = WindowEvent()
    
    If ExamineKeyboard()
        If KeyboardPushed(#PB_Key_Up)
            MoveCamera(#Camera, 0, 0, -0.2)
        ElseIf KeyboardPushed(#PB_Key_Down)
            MoveCamera(#Camera, 0, 0, 0.2)
        EndIf
        If KeyboardPushed(#PB_Key_Left)
            RotateNode(#Node, 0, -1, 0, #PB_Relative)
            CameraLookAt(#Camera, 0, 0, 0)
        ElseIf KeyboardPushed(#PB_Key_Right)
            RotateNode(#Node, 0, 1, 0, #PB_Relative)
            CameraLookAt(#Camera, 0, 0, 0)
        EndIf
        If KeyboardReleased(#PB_Key_W)
            CameraRenderMode(#Camera, #PB_Camera_Wireframe)
        ElseIf KeyboardReleased(#PB_Key_E)
            CameraRenderMode(#Camera, #PB_Camera_Textured)
        EndIf
    EndIf
    
    If KeyboardReleased(#PB_Key_Space)
        RemoveMaterialLayer(#ShaderMaterial1)
        AddMaterialLayer(#ShaderMaterial1, TextureID(TextureBlue), #PB_Material_Replace)
    EndIf
    
    RenderWorld()
    FlipBuffers()
    
Until Event = #PB_Event_CloseWindow Or KeyboardPushed(#PB_Key_Escape)


End
Post Reply