Skip to content

Commit

Permalink
Merge pull request #276 from vsg-dev/TextureProjection
Browse files Browse the repository at this point in the history
Texture projection example
  • Loading branch information
robertosfield authored Nov 28, 2023
2 parents 7603c77 + 3fc99d1 commit f945275
Show file tree
Hide file tree
Showing 6 changed files with 1,117 additions and 0 deletions.
349 changes: 349 additions & 0 deletions data/shaders/textureprojection_phong.frag
Original file line number Diff line number Diff line change
@@ -0,0 +1,349 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
#pragma import_defines (VSG_POINT_SPRITE, VSG_DIFFUSE_MAP, VSG_GREYSCALE_DIFFUSE_MAP, VSG_EMISSIVE_MAP, VSG_LIGHTMAP_MAP, VSG_NORMAL_MAP, VSG_SPECULAR_MAP, VSG_TWO_SIDED_LIGHTING, SHADOWMAP_DEBUG)

#define VIEW_DESCRIPTOR_SET 1
#define MATERIAL_DESCRIPTOR_SET 2
#define CUSTOM_DESCRIPTOR_SET 0

#extension GL_EXT_nonuniform_qualifier : enable

#ifdef VSG_DIFFUSE_MAP
layout(set = MATERIAL_DESCRIPTOR_SET, binding = 0) uniform sampler2D diffuseMap;
#endif

#ifdef VSG_NORMAL_MAP
layout(set = MATERIAL_DESCRIPTOR_SET, binding = 2) uniform sampler2D normalMap;
#endif

#ifdef VSG_LIGHTMAP_MAP
layout(set = MATERIAL_DESCRIPTOR_SET, binding = 3) uniform sampler2D aoMap;
#endif

#ifdef VSG_EMISSIVE_MAP
layout(set = MATERIAL_DESCRIPTOR_SET, binding = 4) uniform sampler2D emissiveMap;
#endif

#ifdef VSG_SPECULAR_MAP
layout(set = MATERIAL_DESCRIPTOR_SET, binding = 5) uniform sampler2D specularMap;
#endif

layout(set = MATERIAL_DESCRIPTOR_SET, binding = 10) uniform MaterialData
{
vec4 ambientColor;
vec4 diffuseColor;
vec4 specularColor;
vec4 emissiveColor;
float shininess;
float alphaMask;
float alphaMaskCutoff;
} material;

layout(set = VIEW_DESCRIPTOR_SET, binding = 0) uniform LightData
{
vec4 values[2048];
} lightData;


layout(set = VIEW_DESCRIPTOR_SET, binding = 2) uniform sampler2DArrayShadow shadowMaps;

// Custom state
layout(set = CUSTOM_DESCRIPTOR_SET, binding = 0) uniform TextureCount
{
uint value;
} textureCount;

layout(set = CUSTOM_DESCRIPTOR_SET, binding = 1) uniform TexGenMatrices
{
mat4 matrix[128];
} texgenMatrices;

layout(set = CUSTOM_DESCRIPTOR_SET, binding = 2) uniform sampler2DArray projectedTextures;


layout(location = 0) in vec3 eyePos;
layout(location = 1) in vec3 normalDir;
layout(location = 2) in vec4 vertexColor;
#ifndef VSG_POINT_SPRITE
layout(location = 3) in vec2 texCoord0;
#endif
layout(location = 5) in vec3 viewDir;

layout(location = 0) out vec4 outColor;

// Find the normal for this fragment, pulling either from a predefined normal map
// or from the interpolated mesh normal and tangent attributes.
vec3 getNormal()
{
vec3 result;
#ifdef VSG_NORMAL_MAP
// Perturb normal, see http://www.thetenthplanet.de/archives/1180
vec3 tangentNormal = texture(normalMap, texCoord0).xyz * 2.0 - 1.0;

//tangentNormal *= vec3(2,2,1);

vec3 q1 = dFdx(eyePos);
vec3 q2 = dFdy(eyePos);
vec2 st1 = dFdx(texCoord0);
vec2 st2 = dFdy(texCoord0);

vec3 N = normalize(normalDir);
vec3 T = normalize(q1 * st2.t - q2 * st1.t);
vec3 B = -normalize(cross(N, T));
mat3 TBN = mat3(T, B, N);

result = normalize(TBN * tangentNormal);
#else
result = normalize(normalDir);
#endif
#ifdef VSG_TWO_SIDED_LIGHTING
if (!gl_FrontFacing)
result = -result;
#endif
return result;
}

vec3 computeLighting(vec3 ambientColor, vec3 diffuseColor, vec3 specularColor, vec3 emissiveColor, float shininess, float ambientOcclusion, vec3 ld, vec3 nd, vec3 vd)
{
vec3 color = vec3(0.0);
color.rgb += ambientColor;

float diff = max(dot(ld, nd), 0.0);
color.rgb += diffuseColor * diff;

if (diff > 0.0)
{
vec3 halfDir = normalize(ld + vd);
color.rgb += specularColor * pow(max(dot(halfDir, nd), 0.0), shininess);
}

vec3 result = color + emissiveColor;
result *= ambientOcclusion;

return result;
}


void main()
{
float brightnessCutoff = 0.001;

#ifdef VSG_POINT_SPRITE
vec2 texCoord0 = gl_PointCoord.xy;
#endif

vec4 diffuseColor = vertexColor * material.diffuseColor;

bool matchedProjectedTexture = false;

for(int ti = 0; ti < textureCount.value; ++ti)
{
vec4 tc = texgenMatrices.matrix[ti] * vec4(eyePos, 1.0);
if (tc.w > 0.0)
{
tc.xy = (tc.xy * (0.5 / tc.w)) + vec2(0.5, 0.5);
if (tc.x >= 0.0 && tc.x <= 1.0 && tc.y >= 0.0 && tc.y <= 1.0)
{
matchedProjectedTexture = true;

diffuseColor *= texture(projectedTextures, vec3(tc.xy, ti));
break;
}
}
}

#ifdef VSG_DIFFUSE_MAP
if (!matchedProjectedTexture)
{
#ifdef VSG_GREYSCALE_DIFFUSE_MAP
float v = texture(diffuseMap, texCoord0.st).s;
diffuseColor *= vec4(v, v, v, 1.0);
#else
diffuseColor *= texture(diffuseMap, texCoord0.st);
#endif
}
#endif

vec4 ambientColor = diffuseColor * material.ambientColor * material.ambientColor.a;
vec4 specularColor = material.specularColor;
vec4 emissiveColor = material.emissiveColor;
float shininess = material.shininess;
float ambientOcclusion = 1.0;

if (material.alphaMask == 1.0f)
{
if (diffuseColor.a < material.alphaMaskCutoff)
discard;
}

#ifdef VSG_EMISSIVE_MAP
emissiveColor *= texture(emissiveMap, texCoord0.st);
#endif

#ifdef VSG_LIGHTMAP_MAP
ambientOcclusion *= texture(aoMap, texCoord0.st).r;
#endif

#ifdef VSG_SPECULAR_MAP
specularColor *= texture(specularMap, texCoord0.st);
#endif

vec3 nd = getNormal();
vec3 vd = normalize(viewDir);

vec3 color = vec3(0.0, 0.0, 0.0);

vec4 lightNums = lightData.values[0];
int numAmbientLights = int(lightNums[0]);
int numDirectionalLights = int(lightNums[1]);
int numPointLights = int(lightNums[2]);
int numSpotLights = int(lightNums[3]);
int index = 1;

if (numAmbientLights>0)
{
// ambient lights
for(int i = 0; i<numAmbientLights; ++i)
{
vec4 lightColor = lightData.values[index++];
color += (ambientColor.rgb * lightColor.rgb) * (lightColor.a);
}
}

// index used to step through the shadowMaps array
int shadowMapIndex = 0;

if (numDirectionalLights>0)
{
// directional lights
for(int i = 0; i<numDirectionalLights; ++i)
{
vec4 lightColor = lightData.values[index++];
vec3 direction = -lightData.values[index++].xyz;
vec4 shadowMapSettings = lightData.values[index++];

float brightness = lightColor.a;

// check shadow maps if required
bool matched = false;
while ((shadowMapSettings.r > 0.0 && brightness > brightnessCutoff) && !matched)
{
mat4 sm_matrix = mat4(lightData.values[index++],
lightData.values[index++],
lightData.values[index++],
lightData.values[index++]);

vec4 sm_tc = (sm_matrix) * vec4(eyePos, 1.0);

if (sm_tc.x >= 0.0 && sm_tc.x <= 1.0 && sm_tc.y >= 0.0 && sm_tc.y <= 1.0 && sm_tc.z >= 0.0 /* && sm_tc.z <= 1.0*/)
{
matched = true;

float coverage = texture(shadowMaps, vec4(sm_tc.st, shadowMapIndex, sm_tc.z)).r;
brightness *= (1.0-coverage);

#ifdef SHADOWMAP_DEBUG
if (shadowMapIndex==0) color = vec3(1.0, 0.0, 0.0);
else if (shadowMapIndex==1) color = vec3(0.0, 1.0, 0.0);
else if (shadowMapIndex==2) color = vec3(0.0, 0.0, 1.0);
else if (shadowMapIndex==3) color = vec3(1.0, 1.0, 0.0);
else if (shadowMapIndex==4) color = vec3(0.0, 1.0, 1.0);
else color = vec3(1.0, 1.0, 1.0);
#endif
}

++shadowMapIndex;
shadowMapSettings.r -= 1.0;
}

if (shadowMapSettings.r > 0.0)
{
// skip lightData and shadowMap entries for shadow maps that we haven't visited for this light
// so subsequent light pointions are correct.
index += 4 * int(shadowMapSettings.r);
shadowMapIndex += int(shadowMapSettings.r);
}

// if light is too dim/shadowed to effect the rendering skip it
if (brightness <= brightnessCutoff ) continue;

float unclamped_LdotN = dot(direction, nd);

float diff = max(unclamped_LdotN, 0.0);
color.rgb += (diffuseColor.rgb * lightColor.rgb) * (diff * brightness);

if (shininess > 0.0 && diff > 0.0)
{
vec3 halfDir = normalize(direction + vd);
color.rgb += specularColor.rgb * (pow(max(dot(halfDir, nd), 0.0), shininess) * brightness);
}
}
}

if (numPointLights>0)
{
// point light
for(int i = 0; i<numPointLights; ++i)
{
vec4 lightColor = lightData.values[index++];
vec3 position = lightData.values[index++].xyz;

float brightness = lightColor.a;

// if light is too dim/shadowed to effect the rendering skip it
if (brightness <= brightnessCutoff ) continue;

vec3 delta = position - eyePos;
float distance2 = delta.x * delta.x + delta.y * delta.y + delta.z * delta.z;
vec3 direction = delta / sqrt(distance2);
float scale = brightness / distance2;

float unclamped_LdotN = dot(direction, nd);

float diff = scale * max(unclamped_LdotN, 0.0);

color.rgb += (diffuseColor.rgb * lightColor.rgb) * diff;
if (shininess > 0.0 && diff > 0.0)
{
vec3 halfDir = normalize(direction + vd);
color.rgb += specularColor.rgb * (pow(max(dot(halfDir, nd), 0.0), shininess) * scale);
}
}
}

if (numSpotLights>0)
{
// spot light
for(int i = 0; i<numSpotLights; ++i)
{
vec4 lightColor = lightData.values[index++];
vec4 position_cosInnerAngle = lightData.values[index++];
vec4 lightDirection_cosOuterAngle = lightData.values[index++];

float brightness = lightColor.a;

// if light is too dim/shadowed to effect the rendering skip it
if (brightness <= brightnessCutoff ) continue;

vec3 delta = position_cosInnerAngle.xyz - eyePos;
float distance2 = delta.x * delta.x + delta.y * delta.y + delta.z * delta.z;
vec3 direction = delta / sqrt(distance2);

float dot_lightdirection = dot(lightDirection_cosOuterAngle.xyz, -direction);
float scale = (brightness * smoothstep(lightDirection_cosOuterAngle.w, position_cosInnerAngle.w, dot_lightdirection)) / distance2;

float unclamped_LdotN = dot(direction, nd);

float diff = scale * max(unclamped_LdotN, 0.0);
color.rgb += (diffuseColor.rgb * lightColor.rgb) * diff;
if (shininess > 0.0 && diff > 0.0)
{
vec3 halfDir = normalize(direction + vd);
color.rgb += specularColor.rgb * (pow(max(dot(halfDir, nd), 0.0), shininess) * scale);
}
}
}

outColor.rgb = (color * ambientOcclusion) + emissiveColor.rgb;
outColor.a = diffuseColor.a;
}
1 change: 1 addition & 0 deletions examples/nodes/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ add_subdirectory(vsggroups)
add_subdirectory(vsglights)
add_subdirectory(vsgtransform)
add_subdirectory(vsgshadow)
add_subdirectory(vsgtextureprojection)

if (vsgXchange_FOUND)
add_subdirectory(vsgpagedlod)
Expand Down
15 changes: 15 additions & 0 deletions examples/nodes/vsgtextureprojection/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
set(SOURCES
custom_phong.cpp
vsgtextureprojection.cpp
)

add_executable(vsgtextureprojection ${SOURCES})

target_link_libraries(vsgtextureprojection vsg::vsg)

if (vsgXchange_FOUND)
target_compile_definitions(vsgtextureprojection PRIVATE vsgXchange_FOUND)
target_link_libraries(vsgtextureprojection vsgXchange::vsgXchange)
endif()

install(TARGETS vsgtextureprojection RUNTIME DESTINATION bin)
Loading

0 comments on commit f945275

Please sign in to comment.