Hi,
Getting started with shaders in AppGameKit can be a bit daunting (at least it was quite the challenge for me).
Eventually figured it out and there has been some interest expressed in a small demo for people to pull apart and learn a bit from.
The shaders here are modified from the output of
GetObjectMeshVSSource() and
GetObjectMeshPSSource() which is created when calling
SetObjectNormalMap().
I found this very helpful for getting an idea of how AppGameKit interfaces with GLSL. Also the
guide on Shaders here.
Here is a very simple implementation of normal mapping using a custom shader.
Main source:-
// Project: shaders
// Created: 2020-06-09
// show all errors
SetErrorMode(1)
// set window properties
SetWindowTitle( "Simple Shader Demo" )
SetWindowSize( 1024, 768, 0 )
SetWindowAllowResize( 1 ) // allow the user to resize the window
// set display properties
SetVirtualResolution( 1024, 768 )
SetOrientationAllowed( 1, 1, 1, 1 ) // allow both portrait and landscape on mobile devices
SetSyncRate( 90, 0 )
SetScissor( 0,0,0,0 )
UseNewDefaultFonts( 1 )
SetAntialiasMode(1)
SetSunColor(255,255,255)
SetSunDirection( -45, -45, -10 )
SetSunActive(1)
SetAmbientColor( 0, 0, 0 )
sphere = CreateObjectSphere( 10, 50, 50 )
SetObjectImage( sphere, LoadImage( "brickwall.jpg" ), 0 ) // diffuse in channel 0
SetObjectImage( sphere, LoadImage( "brickwall_normal.jpg" ), 2 ) // normal in channel 2
// create a sphere
SetObjectPosition( sphere, 0, 0, 0 )
// load the normalmap shader example
working_shader = LoadShader("normalmap.vs","normalmap.ps")
// Create a light
CreatePointLight( 1, -30, 10, -10, 200, 255, 255, 255 )
// Inside the pixel shader GetPSLighting() returns nothing unless we enable pixel light mode
SetPointLightMode( 1, 1 )
SetCameraRotation( 1, 0, 0, 0 )
SetCameraPosition( 1, 0, 0, -20 )
SetObjectShader( sphere, working_shader )
do
RotateObjectLocalY( sphere, 0.3 )
RotateObjectLocalX( sphere, 0.2 )
Print( ScreenFPS() )
Sync()
loop
normalmap.vs (modified from the auto-generated vertex shader, put this into the media folder)
attribute highp vec3 position;
attribute mediump vec3 normal;
attribute mediump vec2 uv;
varying highp vec3 posVarying;
varying mediump vec3 normalVarying;
varying mediump vec3 tangentVarying;
varying mediump vec3 biTangentVarying;
varying mediump vec2 uvVarying;
varying mediump vec3 lightVarying;
uniform highp mat3 agk_WorldNormal;
uniform highp mat4 agk_World;
uniform highp mat4 agk_ViewProj;
uniform mediump vec4 uvBounds0;
mediump vec3 GetVSLighting( mediump vec3 normal, highp vec3 pos );
void main()
{
uvVarying = uv * uvBounds0.xy + uvBounds0.zw;
highp vec4 pos = agk_World * vec4( position, 1.0 );
gl_Position = agk_ViewProj * pos;
mediump vec3 norm = normalize( agk_WorldNormal * normal );
posVarying = pos.xyz;
normalVarying = norm;
lightVarying = GetVSLighting( norm, posVarying );
// ###### Normal mapping preparation #########
// Calculate tangent and binormal vectors
mediump vec3 tangent;
if( normal.y > 0.999 ) {
tangent = vec3( normal.y,0.0,0.0);
} else {
if( normal.y < -0.999 ) {
tangent = vec3( -normal.y,0.0,0.0);
} else {
tangent = normalize( vec3(-normal.z, 0.0, normal.x) );
}
}
mediump vec3 binormal = normalize( vec3( normal.y * tangent.z, normal.z * tangent.x - normal.x * tangent.z, -normal.y * tangent.x ) );
tangentVarying = normalize( agk_WorldNormal * tangent );
biTangentVarying = normalize( agk_WorldNormal * binormal );
}
normalmap.ps (modified from auto-generated pixel shader, put this into the media folder)
uniform sampler2D texture0; // diffuse
uniform sampler2D texture2; // normal
// ######## Interpolated Variables from Vertex Shader #########
varying highp vec3 posVarying;
varying mediump vec3 tangentVarying;
varying mediump vec3 biTangentVarying;
varying mediump vec3 normalVarying;
varying mediump vec3 lightVarying;
varying mediump vec2 uvVarying;
// ######## Functions from AGK #########
mediump vec3 GetPSLighting( mediump vec3 normal, highp vec3 pos );
mediump vec3 ApplyFog( mediump vec3 color, highp vec3 pointPos );
// ######## provided by AGK ###########
uniform vec4 agk_MeshDiffuse;
uniform vec3 agk_CameraPos;
uniform highp mat4 agk_View;
uniform highp mat4 agk_World;
uniform highp mat3 agk_WorldNormal;
uniform highp mat4 agk_WorldViewProj;
void main()
{
vec3 color = agk_MeshDiffuse.xyz;
// ######## Normal Map #########
vec3 norm = normalize( normalVarying );
vec3 normalMap = normalize(texture2D( texture2, uvVarying ).rgb * 2.0 - 1.0 );
mediump mat3 TBN = mat3( normalize( tangentVarying ), -normalize( biTangentVarying ), norm );
vec3 worldNormal = TBN * normalMap;
// ######## Main Lighting ######
vec3 light = lightVarying + GetPSLighting( worldNormal, posVarying );
// ######## Composit Color ########
color *= texture2D(texture0, uvVarying ).rgb * light;
color = ApplyFog( color, posVarying );
gl_FragColor = vec4( color, 1.0);
}
The two images used in this demo are attached to this post.
Hope this helps someone looking for a way into custom shaders for AGK.
If at first you don't succeed, sky-diving isn't for you.