Urho3D Wiki
mNo edit summary
Tags: Visual edit apiedit
(Added explanations to an issue)
Tags: Visual edit apiedit
Line 1: Line 1:
  +
'''Note:''' There's currently an unfixed issue with texture sampling when using this method, see bottom.
 
[[File:Urho quad texture.jpg|none|thumb|400x400px]]
 
[[File:Urho quad texture.jpg|none|thumb|400x400px]]
 
This method means having four textures in one image like this:
 
This method means having four textures in one image like this:
Line 25: Line 26:
 
#if defined(SPOTLIGHT)<br> lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);<br> #elif defined(CUBEMASK)<br> lightColor = textureCube(sLightCubeMap, vCubeMaskVec).rgb * cLightColor.rgb;<br> #else<br> lightColor = cLightColor.rgb;<br> #endif<br><br>
 
#if defined(SPOTLIGHT)<br> lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);<br> #elif defined(CUBEMASK)<br> lightColor = textureCube(sLightCubeMap, vCubeMaskVec).rgb * cLightColor.rgb;<br> #else<br> lightColor = cLightColor.rgb;<br> #endif<br><br>
 
#ifdef SPECULAR<br> float spec = GetSpecular(normal, cCameraPosPS - vWorldPos.xyz, lightDir, cMatSpecColor.a);<br> finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a);<br> #else<br> finalColor = diff * lightColor * diffColor.rgb;<br> #endif<br><br> #ifdef AMBIENT<br> finalColor += cAmbientColor * diffColor.rgb;<br> finalColor += cMatEmissiveColor;<br> gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);<br> #else<br> gl_FragColor = vec4(GetLitFog(finalColor, fogFactor), diffColor.a);<br> #endif<br> #elif defined(PREPASS)<br> // Fill light pre-pass G-Buffer<br> float specPower = cMatSpecColor.a / 255.0;<br><br> gl_FragData[0] = vec4(normal * 0.5 + 0.5, specPower);<br> gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);<br> #elif defined(DEFERRED)<br> // Fill deferred G-buffer<br> float specIntensity = specColor.g;<br> float specPower = cMatSpecColor.a / 255.0;<br><br> gl_FragData[0] = vec4(GetFog(vVertexLight * diffColor.rgb, fogFactor), 1.0);<br> gl_FragData[1] = fogFactor * vec4(diffColor.rgb, specIntensity);<br> gl_FragData[2] = vec4(normal * 0.5 + 0.5, specPower);<br> gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);<br> #else<br> // Ambient & per-vertex lighting<br> vec3 finalColor = vVertexLight * diffColor.rgb;<br><br> #ifdef MATERIAL<br> // Add light pre-pass accumulation result<br> // Lights are accumulated at half intensity. Bring back to full intensity now<br> vec4 lightInput = 2.0 * texture2DProj(sLightBuffer, vScreenPos);<br> vec3 lightSpecColor = lightInput.a * lightInput.rgb / max(GetIntensity(lightInput.rgb), 0.001);<br><br> finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor;<br> #endif<br> gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);<br> #endif<br>}
 
#ifdef SPECULAR<br> float spec = GetSpecular(normal, cCameraPosPS - vWorldPos.xyz, lightDir, cMatSpecColor.a);<br> finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a);<br> #else<br> finalColor = diff * lightColor * diffColor.rgb;<br> #endif<br><br> #ifdef AMBIENT<br> finalColor += cAmbientColor * diffColor.rgb;<br> finalColor += cMatEmissiveColor;<br> gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);<br> #else<br> gl_FragColor = vec4(GetLitFog(finalColor, fogFactor), diffColor.a);<br> #endif<br> #elif defined(PREPASS)<br> // Fill light pre-pass G-Buffer<br> float specPower = cMatSpecColor.a / 255.0;<br><br> gl_FragData[0] = vec4(normal * 0.5 + 0.5, specPower);<br> gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);<br> #elif defined(DEFERRED)<br> // Fill deferred G-buffer<br> float specIntensity = specColor.g;<br> float specPower = cMatSpecColor.a / 255.0;<br><br> gl_FragData[0] = vec4(GetFog(vVertexLight * diffColor.rgb, fogFactor), 1.0);<br> gl_FragData[1] = fogFactor * vec4(diffColor.rgb, specIntensity);<br> gl_FragData[2] = vec4(normal * 0.5 + 0.5, specPower);<br> gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);<br> #else<br> // Ambient & per-vertex lighting<br> vec3 finalColor = vVertexLight * diffColor.rgb;<br><br> #ifdef MATERIAL<br> // Add light pre-pass accumulation result<br> // Lights are accumulated at half intensity. Bring back to full intensity now<br> vec4 lightInput = 2.0 * texture2DProj(sLightBuffer, vScreenPos);<br> vec3 lightSpecColor = lightInput.a * lightInput.rgb / max(GetIntensity(lightInput.rgb), 0.001);<br><br> finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor;<br> #endif<br> gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);<br> #endif<br>}
  +
  +
=== The texture sampling issue ===
  +
[After writing this issue and trying to use this technique for improving the terrain shader I noticed quite a bummer:]
  +
[[File:Urho quad stripes.jpg|none|thumb|400x400px]]Theoretically this can be fixed by doing manual texture sampling in the shader by using texelFetch instead of texture2D but it seems to be super slow. My FPS in FullHD dropped from >200 to ~40. [I got another idea on how to fix the issue with a faster method, working on it.]

Revision as of 19:26, 13 July 2015

Note: There's currently an unfixed issue with texture sampling when using this method, see bottom.

Urho quad texture

This method means having four textures in one image like this:

Blender bricks quad

Diffuse, normal, specular and height map (the height map is not used in this material). A similar method could be used to pack three textures (which would be better in this case as only three are used) or even more materials in one image file.

This has two advantages:

The material file:

<material>
<technique name="Techniques/quad.xml"/>
<texture name="Textures/blender_bricks_quad.jpg" unit="diffuse"/>
<parameter name="MatDiffColor" value="1.0 1.0 1.0 1"/>
<parameter name="MatSpecColor" value="2.5 2.5 2.5 30"/>
</material>

unit="diffuse" has no real meaning here as this image is not only used for diffuse. This just says that this texture is number 0 which is important for the shader as it expects the one texture at "place" 0.

The technique: "Techniques/quad.xml"

<technique vs="quad" ps="quad">
<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" />
</technique>

The GLSL shader (based on the terrain shader and parts from LitBase): "Shaders/quad.glsl"

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

varying vec4 vTexCoord;

varying vec3 vNormal;
varying vec4 vTangent;
varying vec4 vWorldPos;
#ifdef PERPIXEL
#ifdef SHADOW
varying vec4 vShadowPos[NUMCASCADES];
#endif
#ifdef SPOTLIGHT
varying vec4 vSpotPos;
#endif
#ifdef POINTLIGHT
varying vec3 vCubeMaskVec;
#endif
#else
varying vec3 vVertexLight;
varying vec4 vScreenPos;
#ifdef ENVCUBEMAP
varying vec3 vReflectionVec;
#endif
#if defined(LIGHTMAP) || defined(AO)
varying vec2 vTexCoord2;
#endif
#endif

uniform sampler2D sTexture0;

void VS()
{
mat4 modelMatrix = iModelMatrix;
vec3 worldPos = GetWorldPos(modelMatrix);
gl_Position = GetClipPos(worldPos);
vNormal = GetWorldNormal(modelMatrix);
vWorldPos = vec4(worldPos, GetDepth(gl_Position));
vec3 tangent = GetWorldTangent(modelMatrix);
vec3 bitangent = cross(tangent, vNormal) * iTangent.w;
vTexCoord = vec4(GetTexCoord(iTexCoord), bitangent.xy);
vTangent = vec4(tangent, bitangent.z);
#ifdef PERPIXEL
// Per-pixel forward lighting
vec4 projWorldPos = vec4(worldPos, 1.0);

#ifdef SHADOW
// Shadow projection: transform from world space to shadow space
for (int i = 0; i < NUMCASCADES; i++)
vShadowPos[i] = GetShadowPos(i, projWorldPos);
#endif
#ifdef SPOTLIGHT
// Spotlight projection: transform from world space to projector texture coordinates
vSpotPos = projWorldPos * cLightMatrices[0];
#endif

#ifdef POINTLIGHT
vCubeMaskVec = (worldPos - cLightPos.xyz) * mat3(cLightMatrices[0][0].xyz, cLightMatrices[0][1].xyz, cLightMatrices[0][2].xyz);
#endif
#else
// Ambient & per-vertex lighting
#if defined(LIGHTMAP) || defined(AO)
// If using lightmap, disregard zone ambient light
// If using AO, calculate ambient in the PS
vVertexLight = vec3(0.0, 0.0, 0.0);
vTexCoord2 = iTexCoord2;
#else
vVertexLight = GetAmbient(GetZonePos(worldPos));
#endif
#ifdef NUMVERTEXLIGHTS
for (int i = 0; i < NUMVERTEXLIGHTS; ++i)
vVertexLight += GetVertexLight(i, worldPos, vNormal) * cVertexLights[i * 3].rgb;
#endif
vScreenPos = GetScreenPos(gl_Position);
#ifdef ENVCUBEMAP
vReflectionVec = worldPos - cCameraPos;
#endif #endif
}

void PS()
{
vec4 diffColor=cMatDiffColor.rgba*texture2D(sTexture0,vec2(vTexCoord.x/4,vTexCoord.y));

// Get material specular albedo
vec3 specColor = cMatSpecColor.rgb*texture2D(sTexture0,vec2(vTexCoord.x/4+0.5,vTexCoord.y)).rgb;

// Get normal
mat3 tbn = mat3(vTangent.xyz, vec3(vTexCoord.zw, vTangent.w), vNormal);
vec3 normal = normalize(tbn * DecodeNormal(texture2D(sTexture0,vec2(vTexCoord.x/4+0.25,vTexCoord.y))));

// Get fog factor
#ifdef HEIGHTFOG
float fogFactor = GetHeightFogFactor(vWorldPos.w, vWorldPos.y);
#else
float fogFactor = GetFogFactor(vWorldPos.w);
#endif

#if defined(PERPIXEL)
// Per-pixel forward lighting
vec3 lightColor;
vec3 lightDir;
vec3 finalColor;
float diff = GetDiffuse(normal, vWorldPos.xyz, lightDir);
#ifdef SHADOW
diff *= GetShadow(vShadowPos, vWorldPos.w);
#endif
#if defined(SPOTLIGHT)
lightColor = vSpotPos.w > 0.0 ? texture2DProj(sLightSpotMap, vSpotPos).rgb * cLightColor.rgb : vec3(0.0, 0.0, 0.0);
#elif defined(CUBEMASK)
lightColor = textureCube(sLightCubeMap, vCubeMaskVec).rgb * cLightColor.rgb;
#else
lightColor = cLightColor.rgb;
#endif

#ifdef SPECULAR
float spec = GetSpecular(normal, cCameraPosPS - vWorldPos.xyz, lightDir, cMatSpecColor.a);
finalColor = diff * lightColor * (diffColor.rgb + spec * specColor * cLightColor.a);
#else
finalColor = diff * lightColor * diffColor.rgb;
#endif

#ifdef AMBIENT
finalColor += cAmbientColor * diffColor.rgb;
finalColor += cMatEmissiveColor;
gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
#else
gl_FragColor = vec4(GetLitFog(finalColor, fogFactor), diffColor.a);
#endif
#elif defined(PREPASS)
// Fill light pre-pass G-Buffer
float specPower = cMatSpecColor.a / 255.0;

gl_FragData[0] = vec4(normal * 0.5 + 0.5, specPower);
gl_FragData[1] = vec4(EncodeDepth(vWorldPos.w), 0.0);
#elif defined(DEFERRED)
// Fill deferred G-buffer
float specIntensity = specColor.g;
float specPower = cMatSpecColor.a / 255.0;

gl_FragData[0] = vec4(GetFog(vVertexLight * diffColor.rgb, fogFactor), 1.0);
gl_FragData[1] = fogFactor * vec4(diffColor.rgb, specIntensity);
gl_FragData[2] = vec4(normal * 0.5 + 0.5, specPower);
gl_FragData[3] = vec4(EncodeDepth(vWorldPos.w), 0.0);
#else
// Ambient & per-vertex lighting
vec3 finalColor = vVertexLight * diffColor.rgb;

#ifdef MATERIAL
// Add light pre-pass accumulation result
// Lights are accumulated at half intensity. Bring back to full intensity now
vec4 lightInput = 2.0 * texture2DProj(sLightBuffer, vScreenPos);
vec3 lightSpecColor = lightInput.a * lightInput.rgb / max(GetIntensity(lightInput.rgb), 0.001);

finalColor += lightInput.rgb * diffColor.rgb + lightSpecColor * specColor;
#endif
gl_FragColor = vec4(GetFog(finalColor, fogFactor), diffColor.a);
#endif
}

The texture sampling issue

[After writing this issue and trying to use this technique for improving the terrain shader I noticed quite a bummer:]

Urho quad stripes

Theoretically this can be fixed by doing manual texture sampling in the shader by using texelFetch instead of texture2D but it seems to be super slow. My FPS in FullHD dropped from >200 to ~40. [I got another idea on how to fix the issue with a faster method, working on it.]