PerPixel Shader
Posted: Wed Dec 25, 2013 12:22 am
# UPDATE #
You can now use textures.
The shader currently has 3 passes. When I get time I 'll cut it down to two.
There's also an issue with OpenGL. So, for the time being it's DirectX only.
##
The standard lighting in Purebasic uses an entites vertices and normals to calculate it's lighting.
If an entity has very few vertices the lighting can be poor quality. To fix this you can use a shader that gives accurate lighting based on pixels.
This will take more power to run compared to the standard lighting, but nowadays most computers should handle this without a problem.
Here's an image of a low poly sphere with PerPixel Lighting. The plane beneath the sphere is also low poly.

EDIT:
I forgot to mention this shader is from the OGRE wiki. This shader is free to use for whatever you like.
http://www.ogre3d.org/tikiwiki/tiki-ind ... ighting+II
The original poster kinda made a mess by adding several different shader possibilities into one.
So, I just grabbed the parts I liked.
Here's a download with everything ready to go.
It also includes the required CG.dll to run this shader.
PerPixel.zip
The CG.dll is from Nvidia's CG Toolkit located here.
https://developer.nvidia.com/cg-toolkit
The files below are the same ones from the download above. I'm just posting them for future reference for when the download is no more.
I'm not really going to explain in great detail how to set up the files.
You can look at my previous shader topics or just ask me if you need more info on how to setup these files.
Save exactly as stated and put them all in the same directory on your computer. You can use notepad or something like Yaose.
PerPixel.cg
PerPixel.material
PerPixel.program
Here's the Purebasic code to run the shader.
You'll need to set the Add3DArchive() to the location of the cg and material files.
That's all there is to it. Just ask if you have any questions and let me know if you see any errors.
If anyone wants to make improvements or additions to this shader. Please post your changes for us all to see and try.
You don't have too, but it's a nice treat for us all.
I wish everyone a Merry Christmas and a Happy New Year!
You can now use textures.
The shader currently has 3 passes. When I get time I 'll cut it down to two.
There's also an issue with OpenGL. So, for the time being it's DirectX only.
##
The standard lighting in Purebasic uses an entites vertices and normals to calculate it's lighting.
If an entity has very few vertices the lighting can be poor quality. To fix this you can use a shader that gives accurate lighting based on pixels.
This will take more power to run compared to the standard lighting, but nowadays most computers should handle this without a problem.
Here's an image of a low poly sphere with PerPixel Lighting. The plane beneath the sphere is also low poly.

EDIT:
I forgot to mention this shader is from the OGRE wiki. This shader is free to use for whatever you like.
http://www.ogre3d.org/tikiwiki/tiki-ind ... ighting+II
The original poster kinda made a mess by adding several different shader possibilities into one.
So, I just grabbed the parts I liked.
Here's a download with everything ready to go.
It also includes the required CG.dll to run this shader.
PerPixel.zip
The CG.dll is from Nvidia's CG Toolkit located here.
https://developer.nvidia.com/cg-toolkit
The files below are the same ones from the download above. I'm just posting them for future reference for when the download is no more.
I'm not really going to explain in great detail how to set up the files.
You can look at my previous shader topics or just ask me if you need more info on how to setup these files.
Save exactly as stated and put them all in the same directory on your computer. You can use notepad or something like Yaose.
PerPixel.cg
Code: Select all
float3 expand(float3 v)
{
return (v - 0.5) * 2;
}
void OneTexture_vp(float4 position : POSITION,
float2 uv : TEXCOORD0,
out float4 oPosition : POSITION,
out float2 oUv : TEXCOORD0,
uniform float4x4 worldViewProj,
uniform float scale)
{
oPosition = mul(worldViewProj, position);
oUv = uv * scale;
}
void Ambient_vp(
float4 position : POSITION,
out float4 oPosition : POSITION,
out float4 colour : COLOR,
uniform float4x4 worldViewProj,
uniform float4 ambient)
{
oPosition = mul(worldViewProj, position);
colour = ambient;
}
void Perpixel_Vert(
float4 position : POSITION,
float3 normal : NORMAL,
uniform float4 lightPosition,
uniform float3 eyePosition,
uniform float4x4 worldviewproj,
out float4 oClipPos : POSITION,
out float4 oPos : TEXCOORD0,
out float3 oNorm : TEXCOORD1,
out float4 oLightPos : TEXCOORD2,
out float3 oEyePos : TEXCOORD3
)
{
oClipPos = mul(worldviewproj, position);
oPos = position;
oNorm = normal;
oLightPos = lightPosition;
oEyePos = eyePosition;
}
void PerPixel_Frag(
float4 pos : TEXCOORD0,
float3 normal : TEXCOORD1,
float4 lightpos : TEXCOORD2,
float3 eyepos : TEXCOORD3,
uniform float4 lightDiffuse,
uniform float4 lightSpecular,
uniform float exponent,
out float4 oColor : COLOR
)
{
float3 N = normalize(normal);
float3 EyeDir = normalize(eyepos - pos.xyz);
float3 LightDir = normalize(lightpos.xyz - (pos * lightpos.w));
float3 HalfAngle = normalize(LightDir + EyeDir);
float NdotL = dot(LightDir, N);
float NdotH = dot(HalfAngle, N);
float4 Lit = lit(NdotL,NdotH,exponent);
oColor = lightDiffuse * Lit.y + lightSpecular * Lit.z;
}
PerPixel.material
Code: Select all
abstract material PerPixel
{
technique
{
pass
{
vertex_program_ref Ambient
{
param_named ambient float4 $Ambient
}
}
pass
{
iteration once_per_light
scene_blend add
vertex_program_ref Perpixel_Vert
{
}
fragment_program_ref PerPixel_Frag
{
param_named exponent float $SpecularSize
}
}
pass
{
vertex_program_ref OneTexture
{
param_named scale float $Scale
}
scene_blend modulate
texture_unit TextureMap
{
filtering trilinear
}
}
}
}
material RockPerPixel : PerPixel
{
set $Ambient "0 0 0 1"
set $SpecularSize 64
set $Scale 1
set_texture_alias TextureMap Rocks.png
}
//material [Script Name] : [Script Template]
//{
// set $Ambient "0 0 0 1"
// ["Red Green Blue Alpha" Values Between "0" and "1"]
// set $SpecularSize 64
// [Specular Recommended Value Between "32" and "512"]
// set $Scale 1
// [Texture Repeat]
// set_texture_alias TextureMap Rocks.png
// [Replace "Rocks.png" With Your Texture]
//}
Code: Select all
vertex_program OneTexture cg
{
source PerPixel.cg
entry_point OneTexture_vp
profiles vs_1_1 arbvp1
default_params
{
param_named_auto worldViewProj worldviewproj_matrix
}
}
vertex_program Ambient cg
{
source PerPixel.cg
entry_point Ambient_vp
profiles vs_1_1 arbvp1
default_params
{
param_named_auto worldViewProj worldviewproj_matrix
}
}
vertex_program Perpixel_Vert cg
{
source PerPixel.cg
entry_point Perpixel_Vert
profiles vs_1_1 arbvp1
default_params
{
param_named_auto lightPosition light_position_object_space 0
param_named_auto eyePosition camera_position_object_space
param_named_auto worldviewproj worldviewproj_matrix
}
}
fragment_program PerPixel_Frag cg
{
source PerPixel.cg
entry_point PerPixel_Frag
profiles ps_2_0 arbfp1
default_params
{
param_named_auto lightDiffuse light_diffuse_colour 0
param_named_auto lightSpecular light_specular_colour 0
}
}
Here's the Purebasic code to run the shader.
You'll need to set the Add3DArchive() to the location of the cg and material files.
Code: Select all
;#### Requires Nvidia's CG Toolkit to be installed onto your computer (https://developer.nvidia.com/cg-toolkit)####
;#### or have the required CG.dll in the Root Directory of your app ####
If InitEngine3D(#PB_Engine3D_EnableCG | #PB_Engine3D_DebugLog)=0
End
EndIf
If InitSprite()=0
End
EndIf
If InitKeyboard()=0
End
EndIf
Enumeration
#Window
#Font
#Help
#Camera
#LowPolySphere
#Plane
#SphereMesh
#Sphere1
#Sphere2
#Sphere3
#Sphere4
#Mat1
#Mat2
#Mat3
#Mat4
#Light1
#Light2
#Light3
#Light4
#Node1
#Node2
#PerPixelMat
#RockMat
EndEnumeration
ExamineDesktops()
DeskTopW = DesktopWidth(0)
DeskTopH = DesktopHeight(0)
Wireframe=0
Material=0
ShowHelp=0
If LoadFont(#Font, "Courier New", 10,#PB_Font_Bold)
SetGadgetFont(#PB_Default, FontID(#Font))
EndIf
CPU$ = CPUName()
If OpenWindow(#Window, 0, 0, DeskTopW, DeskTopH, "Per Pixel Lighting. Have a Merry Christmas and a Happy New Year!")
If OpenWindowedScreen(WindowID(#Window), 0, 0, DeskTopW, DeskTopH, 0, 0, 0)
;#### Set Archive To Root Location ####
Add3DArchive("/", #PB_3DArchive_FileSystem)
Parse3DScripts()
;#### Create Sprite For Information ####
CreateSprite(#Help, 300, 200)
StartDrawing(SpriteOutput(#Help))
Box(0,0,300,200,RGB(20,20,20))
StopDrawing()
;#### Create Lights ####
CreateLight(#Light1, RGB( 0, 0, 0), 5, 5, 5)
SetLightColor(#Light1,#PB_Light_DiffuseColor,RGB(200,0,0))
SetLightColor(#Light1,#PB_Light_SpecularColor,RGB(255,100,0))
CreateLight(#Light2, RGB( 0, 0, 0), -5, 5, 5)
SetLightColor(#Light2,#PB_Light_DiffuseColor,RGB(0,200,0))
SetLightColor(#Light2,#PB_Light_SpecularColor,RGB(0,255,100))
CreateLight(#Light3, RGB( 0, 0, 0), 0, 5, -7.5)
SetLightColor(#Light3,#PB_Light_DiffuseColor,RGB(0,0,200))
SetLightColor(#Light3,#PB_Light_SpecularColor,RGB(0,100,255))
CreateLight(#Light4, RGB( 0, 0, 0), 0, -4.5, 0)
SetLightColor(#Light4,#PB_Light_DiffuseColor,RGB(200,200,200))
SetLightColor(#Light4,#PB_Light_SpecularColor,RGB(255,255,255))
;#### Load The Script For The Per Pixel Lighting ####
GetScriptMaterial(#PerPixelMat,"RockPerPixel")
LoadTexture(#RockMat,"Rocks.png")
CreateMaterial(#RockMat,TextureID(#RockMat))
;#### Create Textures And Materials ####
CreateTexture(#Mat1,32,32)
CreateTexture(#Mat2,32,32)
CreateTexture(#Mat3,32,32)
CreateTexture(#Mat4,32,32)
StartDrawing(TextureOutput(#Mat1))
Box(0,0,32,32,RGB(200,0,0))
StopDrawing()
StartDrawing(TextureOutput(#Mat2))
Box(0,0,32,32,RGB(0,200,0))
StopDrawing()
StartDrawing(TextureOutput(#Mat3))
Box(0,0,32,32,RGB(0,0,200))
StopDrawing()
StartDrawing(TextureOutput(#Mat4))
Box(0,0,32,32,RGB(200,200,200))
StopDrawing()
CreateMaterial(#Mat1,TextureID(#Mat1))
CreateMaterial(#Mat2,TextureID(#Mat2))
CreateMaterial(#Mat3,TextureID(#Mat3))
CreateMaterial(#Mat4,TextureID(#Mat4))
SetMaterialColor(#RockMat,#PB_Material_SpecularColor,RGB(255,255,255))
SetMaterialColor(#RockMat,#PB_Material_AmbientColor,RGB(0,0,0))
MaterialShininess(#RockMat,64)
;#### Create Nodes, Meshes, And Entities ####
CreateNode(#Node1, 0, 0, 0)
CreateNode(#Node2, 0, 0, 0)
CreateSphere(#SphereMesh,0.25)
CreatePlane(#Plane,200,200,1,1,10,10)
CreateSphere(#LowPolySphere,3,12,6)
CreateEntity(#LowPolySphere, MeshID(#LowPolySphere), MaterialID(#PerPixelMat))
CreateEntity(#Plane, MeshID(#Plane), MaterialID(#PerPixelMat),0,-5,0)
CreateEntity(#Sphere1, MeshID(#SphereMesh), MaterialID(#Mat1),LightX(#Light1),LightY(#Light1),LightZ(#Light1))
CreateEntity(#Sphere2, MeshID(#SphereMesh), MaterialID(#Mat2),LightX(#Light2),LightY(#Light2),LightZ(#Light2))
CreateEntity(#Sphere3, MeshID(#SphereMesh), MaterialID(#Mat3),LightX(#Light3),LightY(#Light3),LightZ(#Light3))
CreateEntity(#Sphere4, MeshID(#SphereMesh), MaterialID(#Mat4),LightX(#Light4),LightY(#Light4),LightZ(#Light4))
;#### Setup Camera ####
CreateCamera(#Camera, 0,0,100,100)
MoveCamera(#Camera, 0, 0, 20)
CameraLookAt(#Camera, 0, 0, 0)
CameraBackColor(#Camera, RGB(40, 40, 40))
;#### Attach Objects To Nodes ####
AttachNodeObject(#Node1,CameraID(#Camera))
AttachNodeObject(#Node2,LightID(#Light1))
AttachNodeObject(#Node2,LightID(#Light2))
AttachNodeObject(#Node2,LightID(#Light3))
AttachNodeObject(#Node2,LightID(#Light4))
AttachNodeObject(#Node2,EntityID(#Sphere1))
AttachNodeObject(#Node2,EntityID(#Sphere2))
AttachNodeObject(#Node2,EntityID(#Sphere3))
AttachNodeObject(#Node2,EntityID(#Sphere4))
Repeat
;#### Examine Keyboard For Key Presses ####
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(#Node1,0,-1,0,#PB_Relative)
CameraLookAt(#Camera, 0, 0, 0)
ElseIf KeyboardPushed(#PB_Key_Right)
RotateNode(#Node1,0,1,0,#PB_Relative)
CameraLookAt(#Camera, 0, 0, 0)
EndIf
If KeyboardReleased(#PB_Key_W)
If Wireframe=0
CameraRenderMode(#Camera, #PB_Camera_Wireframe)
Wireframe=1
Else
CameraRenderMode(#Camera, #PB_Camera_Textured)
Wireframe=0
EndIf
EndIf
If KeyboardReleased(#PB_Key_E)
If Material=0
SetEntityMaterial(#LowPolySphere, MaterialID(#RockMat))
Material=1
Else
SetEntityMaterial(#LowPolySphere, MaterialID(#PerPixelMat))
Material=0
EndIf
EndIf
If KeyboardReleased(#PB_Key_H)
If ShowHelp=0
ShowHelp=1
Else
ShowHelp=0
EndIf
EndIf
EndIf
;#### Rotate The Node That Has Lights Attached ####
RotateNode(#Node2,0,1,0,#PB_Relative)
RenderWorld()
;#### Update Sprite Information ####
If ShowHelp = 0
CurrentFPS = Engine3DFrameRate(#PB_Engine3D_Current)
AverageFPS = Engine3DFrameRate(#PB_Engine3D_Average)
MaximumFPS = Engine3DFrameRate(#PB_Engine3D_Maximum)
MinimumFPS = Engine3DFrameRate(#PB_Engine3D_Minimum)
CountTris = CountRenderedTriangles()
StartDrawing(SpriteOutput(#Help))
Box(0,0,300,200,RGB(20,20,20))
DrawingFont(FontID(#Font))
DrawText(2,2,CPU$,RGB(255,0,0),RGB(20,20,20))
DrawText(2,22,"Current FPS : "+Str(CurrentFPS),RGB(0,255,255),RGB(20,20,20))
DrawText(2,42,"Average FPS : "+Str(AverageFPS),RGB(0,255,255),RGB(20,20,20))
DrawText(2,62,"Maximum FPS : "+Str(MaximumFPS),RGB(0,255,255),RGB(20,20,20))
DrawText(2,82,"Minimum FPS : "+Str(MinimumFPS),RGB(0,255,255),RGB(20,20,20))
DrawText(2,102,"Rendered Triangles : "+Str(CountTris),RGB(0,255,0),RGB(20,20,20))
DrawText(2,122,"(Press W To Swap CameraRenderMode)",RGB(255,255,255),RGB(20,20,20))
DrawText(2,142,"(Press E To Swap Sphere's Lighting",RGB(255,255,0),RGB(20,20,20))
DrawText(2,162," Type From PerPixel To Standard)",RGB(255,255,0),RGB(20,20,20))
DrawText(2,182,"(Press H To Toggle Help)",RGB(255,155,255),RGB(20,20,20))
StopDrawing()
DisplayTransparentSprite(#Help,20,20)
If FirstFrame = 0
Engine3DFrameRate(#PB_Engine3D_Reset)
FirstFrame = 1
EndIf
EndIf
FlipBuffers()
Until WindowEvent() = #PB_Event_CloseWindow Or KeyboardPushed(#PB_Key_Escape)
EndIf
EndIf
End
If anyone wants to make improvements or additions to this shader. Please post your changes for us all to see and try.
You don't have too, but it's a nice treat for us all.
I wish everyone a Merry Christmas and a Happy New Year!
