Pārlūkot izejas kodu

'frontend' wipwork for the probe array. takes up to 50 probes, calcs a weighted blend, and displays them all in a batch.

Azaezel 6 gadi atpakaļ
vecāks
revīzija
086a841535

+ 124 - 85
Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayP.hlsl

@@ -7,37 +7,38 @@
 struct ConvexConnectP
 {
    float4 pos : TORQUE_POSITION;
-   float4 wsEyeDir : TEXCOORD0;
-   float4 ssPos : TEXCOORD1;
+   float4 uv0 : TEXCOORD1;
    float4 vsEyeDir : TEXCOORD2;
 };
 
 TORQUE_UNIFORM_SAMPLER2D(deferredBuffer, 0);
 TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 1);
 TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 2);
-TORQUE_UNIFORM_SAMPLERCUBE(cubeMap, 3);
-TORQUE_UNIFORM_SAMPLERCUBE(irradianceCubemap, 4);
 TORQUE_UNIFORM_SAMPLER2D(BRDFTexture, 5);
-uniform float cubeMips;
 
 uniform float4 rtParams0;
-
-uniform float3 probeWSPos;
-uniform float3 probeLSPos;
 uniform float4 vsFarPlane;
-
-uniform float  radius;
-uniform float2 attenuation;
-
-uniform float4x4 worldToObj;
 uniform float4x4 cameraToWorld;
-
 uniform float3 eyePosWorld;
-uniform float3 bbMin;
-uniform float3 bbMax;
-
-uniform float useSphereMode;
 
+//cubemap arrays require all the same size. so shared mips# value
+uniform float cubeMips;
+#define MAX_PROBES 50
+
+uniform float numProbes;
+TORQUE_UNIFORM_SAMPLERCUBEARRAY(cubeMap[MAX_PROBES], 3);
+TORQUE_UNIFORM_SAMPLERCUBEARRAY(irradianceCubemap[MAX_PROBES] 4);
+uniform float3    inProbePosArray[MAX_PROBES];
+uniform float4x4  worldToObjArray[MAX_PROBES];
+uniform float3    bbMinArray[MAX_PROBES];
+uniform float3    bbMaxArray[MAX_PROBES];
+uniform float     useSphereMode[MAX_PROBES];
+uniform float     radius[MAX_PROBES];
+uniform float2    attenuation[MAX_PROBES];
+
+// Box Projected IBL Lighting
+// Based on: http://www.gamedev.net/topic/568829-box-projected-cubemap-environment-mapping/
+// and https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
 float3 boxProject(float3 wsPosition, float3 reflectDir, float3 boxWSPos, float3 boxMin, float3 boxMax)
 { 
    float3 nrdir = reflectDir;
@@ -52,12 +53,23 @@ float3 boxProject(float3 wsPosition, float3 reflectDir, float3 boxWSPos, float3
    return posonbox - boxWSPos;
 }
 
+float3 iblBoxDiffuse( Surface     surface, 
+                     TORQUE_SAMPLERCUBE(irradianceCube), 
+                     float3        boxPos,
+                     float3        boxMin,
+                     float3        boxMax)
+{
+   float3 cubeN = boxProject(surface.P, surface.N, boxPos, boxMin, boxMax);
+   cubeN.z *=-1;
+   return TORQUE_TEXCUBELOD(irradianceCube, float4(cubeN,0)).xyz;
+}
+
 float3 iblBoxSpecular(float3 normal, float3 wsPos, float roughness, float3 surfToEye,
                      TORQUE_SAMPLER2D(brdfTexture), 
-                    //TORQUE_SAMPLERCUBE(radianceCube),
-                    float3 boxPos,
-                    float3 boxMin,
-                    float3 boxMax)
+                     TORQUE_SAMPLERCUBE(radianceCube),
+                     float3 boxPos,
+                     float3 boxMin,
+                     float3 boxMax)
 {
    float ndotv = clamp(dot(normal, surfToEye), 0.0, 1.0);
 
@@ -65,88 +77,115 @@ float3 iblBoxSpecular(float3 normal, float3 wsPos, float roughness, float3 surfT
    float2 brdf = TORQUE_TEX2DLOD(brdfTexture, float4(roughness, ndotv,0.0,0.0)).xy;
 
     // Radiance (Specular)
-	float maxmip = pow(cubeMips+1,2);
-   float lod = roughness*maxmip;
+   float lod = roughness*cubeMips;
    float3 r = reflect(surfToEye, normal);
    float3 cubeR = normalize(r);
    cubeR = boxProject(wsPos, cubeR, boxPos, boxMin, boxMax);
 	
-   float3 radiance = float3(1,1,1);//TORQUE_TEXCUBELOD(radianceCube, float4(cubeR, lod)).xyz * (brdf.x + brdf.y);
+   float3 radiance = TORQUE_TEXCUBELOD(radianceCube, float4(cubeR, lod)).xyz * (brdf.x + brdf.y);
     
    return radiance;
 }
 
-float4 main(ConvexConnectP IN) : SV_TARGET
+float defineBoxSpaceInfluence(float3 surfPosWS, float3 probePos, float4x4 worldToObj, float radius, float atten)
 {
-    // Compute scene UV
-   float3 ssPos = IN.ssPos.xyz / IN.ssPos.w; 
-   float2 uvScene = getUVFromSSPos( ssPos, rtParams0 );
+    float3 surfPosLS = mul( worldToObj, float4(surfPosWS,1.0)).xyz;
+
+    float3 boxMinLS = probePos-(float3(1,1,1)*radius);
+    float3 boxMaxLS = probePos+(float3(1,1,1)*radius);
+
+    float boxOuterRange = length(boxMaxLS - boxMinLS);
+    float boxInnerRange = boxOuterRange / atten;
+
+    float3 localDir = float3(abs(surfPosLS.x), abs(surfPosLS.y), abs(surfPosLS.z));
+    localDir = (localDir - boxInnerRange) / (boxOuterRange - boxInnerRange);
 
+    return max(localDir.x, max(localDir.y, localDir.z)) * -1;
+}
+
+float4 main( ConvexConnectP IN ) : SV_TARGET
+{
    //eye ray WS/LS
    float3 vsEyeRay = getDistanceVectorToPlane( -vsFarPlane.w, IN.vsEyeDir.xyz, vsFarPlane );
    float3 wsEyeRay = mul(cameraToWorld, float4(vsEyeRay, 0)).xyz;
    
    //unpack normal and linear depth 
-   float4 normDepth = TORQUE_DEFERRED_UNCONDITION(deferredBuffer, uvScene);
+   float4 normDepth = TORQUE_DEFERRED_UNCONDITION(deferredBuffer, IN.uv0);
    
    //create surface
    Surface surface = createSurface( normDepth, TORQUE_SAMPLER2D_MAKEARG(colorBuffer),TORQUE_SAMPLER2D_MAKEARG(matInfoBuffer),
-                                    uvScene, eyePosWorld, wsEyeRay, cameraToWorld);		  
-	float blendVal = 1.0;
-
-    [unroll]
-    for(float i=0; i < 10; i++)
-    {
-        float3 probeWSPos = float3(i * 1.1, 0, 2);
-        float3 L = probeWSPos - surface.P;
-		blendVal = 1.0-length(L)/radius;
-		clip(blendVal);		
-    }
-
-    //render into the bound space defined above
-	float3 surfToEye = normalize(surface.P - eyePosWorld);
-	float3 irradiance = float3(1,0,0);//TORQUE_TEXCUBELOD(irradianceCubemap, float4(surface.N,0)).xyz;
-	float3 specular = iblBoxSpecular(surface.N, surface.P, surface.roughness, surfToEye, TORQUE_SAMPLER2D_MAKEARG(BRDFTexture)/*, TORQUE_SAMPLERCUBE_MAKEARG(cubeMap)*/, probeWSPos, bbMin, bbMax);
+                                    IN.uv0, eyePosWorld, wsEyeRay, cameraToWorld);	
+   //early out if emissive
+   if (getFlag(surface.matFlag, 0))
+   {   
+      discard;
+   }                                    
+	float blendVal[MAX_PROBES];
+   float3 surfToEye = normalize(surface.P - eyePosWorld);
+
+   int i;
+   float3 irradiance = float3(0,0,0);
+   float3 specular = float3(0,0,0);
+	float blendSum = 0;
+	float invBlendSum = 0;
+      
+   for(i=0; i < numProbes; i++)
+   {
+      float3 probeWS = inProbePosArray[i];
+      float3 L = probeWS - surface.P;
+      
+      if(useSphereMode[i])
+      {
+         float3 L = inProbePosArray[i] - surface.P;
+         blendVal[i] = 1.0-length(L)/radius[i];
+         blendVal[i] = max(0,blendVal[i]);
+      }
+      else
+      {
+         float tempAttenVal = 3.5;
+         blendVal[i] = defineBoxSpaceInfluence(surface.P, inProbePosArray[i], worldToObjArray[i], radius[i], tempAttenVal);
+         blendVal[i] = max(0,blendVal[i]);		
+      }
+		blendSum += blendVal[i];
+      invBlendSum +=(1.0f - blendVal[i]);
+   }
+	
+   // Weight0 = normalized NDF, inverted to have 1 at center, 0 at boundary.
+   // And as we invert, we need to divide by Num-1 to stay normalized (else sum is > 1). 
+   // respect constraint B.
+   // Weight1 = normalized inverted NDF, so we have 1 at center, 0 at boundary
+   // and respect constraint A.
+   for(i=0; i < numProbes; i++)
+   {
+      blendVal[i] = (1.0f - ( blendVal[i] / blendSum)) / (numProbes - 1);
+      blendVal[i] *= ((1.0f - blendVal[i]) / invBlendSum);
+      blendSum += blendVal[i];
+   }
+
+    // Normalize blendVal
+   if (blendSum == 0.0f) // Possible with custom weight
+   {
+      blendSum = 1.0f;
+   }
+
+   float invBlendSumWeighted = 1.0f / blendSum;
+   for (int i = 0; i < numProbes; ++i)
+   {
+      blendVal[i] *= invBlendSumWeighted;
+   }
+    
+   float3 irradiance = float3(0,0,0);
+   float3 specular = float3(0,0,0);
    float3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
-   specular *= F;
    //energy conservation
-	float3 kD = 1.0.xxx - F;
-	kD *= 1.0 - surface.metalness;
+   float3 kD = 1.0.xxx - F;
+   kD *= 1.0 - surface.metalness;
+   for (int i = 0; i < numProbes; ++i)
+   {
+      irradiance += blendVal[i]*iblBoxDiffuse(surface,TORQUE_SAMPLERCUBE_MAKEARG(irradianceCubemap[i]), inProbePosArray[i], bbMinArray[i], bbMaxArray[i]);
+      specular += blendVal[i]*F*iblBoxSpecular(surface.N, surface.P, surface.roughness, surfToEye, TORQUE_SAMPLER2D_MAKEARG(BRDFTexture), TORQUE_SAMPLERCUBE_MAKEARG(cubeMap[i]), inProbePosArray[i], bbMinArray[i], bbMaxArray[i]);
+   }
    //final diffuse color
    float3 diffuse = kD * irradiance * surface.baseColor.rgb;
-
-   return float4(diffuse + specular * surface.ao, blendVal);
-
-    /*float3 N = getCubeDir(face,IN.uv);
-    float3 irradiance = 0;
-    
-    // tangent space calculation from origin point
-    float3 up    = float3(0.0, 0.0, 1.0);
-    float3 right = cross(up, N);
-    up           = cross(N, right);
-       
-    float sampleDelta = 0.025;
-    int nrSamples = 0;
-    for(float phi = 0.0; phi < M_2PI_F; phi += sampleDelta)
-    {
-        for(float theta = 0.0; theta < M_HALFPI_F; theta += sampleDelta)
-        {
-            // spherical to cartesian (in tangent space)
-            float3 tangentSample = float3(sin(theta) * cos(phi),  sin(theta) * sin(phi), cos(theta));
-            // tangent space to world
-            float3 sampleVec = tangentSample.x * right + tangentSample.y * up + tangentSample.z * N; 
-
-            irradiance += TORQUE_TEXCUBE(environmentMap, sampleVec).rgb * cos(theta) * sin(theta);
-            nrSamples++;
-        }
-    }
-    irradiance = M_PI_F * irradiance * (1.0 / float(nrSamples));
-    
-    return float4(irradiance, 1.0);*/
-
-    //return float4(1,0,0,1);
-
-    //float4 texCoord = float4( 1,0,0, 1 );    
-
-    //return texCoord;
-}
+	return float4(diffuse + specular * surface.ao, blendVal);
+}

+ 52 - 0
Templates/Full/game/shaders/common/lighting/advanced/reflectionProbeArrayV.hlsl

@@ -0,0 +1,52 @@
+//-----------------------------------------------------------------------------
+// Copyright (c) 2012 GarageGames, LLC
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to
+// deal in the Software without restriction, including without limitation the
+// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+// sell copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+// IN THE SOFTWARE.
+//-----------------------------------------------------------------------------
+
+#include "../../hlslStructs.hlsl"
+#include "../../shaderModel.hlsl"
+#include "../../torque.hlsl"
+
+struct GFXVertexPT
+{
+   float3 pos : POSITION;
+   float4 uv : TEXCOORD1;
+};
+
+struct ConnectData
+{
+   float4 hpos : TORQUE_POSITION;
+   float4 uv0 : TEXCOORD1;
+   float4 vsEyeDir : TEXCOORD2;
+};
+
+uniform float4 rtParams0;
+uniform float4x4 worldViewOnly;
+
+ConnectData main( GFXVertexPT IN )
+{
+   ConnectData OUT;
+   
+   OUT.hpos = float4(IN.pos,1.0);
+   OUT.uv0 = float4(viewportCoordToRenderTarget( IN.uv, rtParams0 ),0,0); 
+   OUT.vsEyeDir = mul(worldViewOnly, float4(IN.pos, 1.0));
+   
+   return OUT;
+}

+ 2 - 0
Templates/Full/game/shaders/common/shaderModel.hlsl

@@ -40,12 +40,14 @@
 #define TORQUE_UNIFORM_SAMPLER2DCMP(tex,regist) uniform Texture2D texture_##tex : register(T##regist); uniform SamplerComparisonState tex : register(S##regist)
 #define TORQUE_UNIFORM_SAMPLER3D(tex,regist) uniform Texture3D texture_##tex : register(T##regist); uniform SamplerState tex : register(S##regist)
 #define TORQUE_UNIFORM_SAMPLERCUBE(tex,regist) uniform TextureCube texture_##tex : register(T##regist); uniform SamplerState tex : register(S##regist)
+#define TORQUE_UNIFORM_SAMPLERCUBEARRAY(tex,regist) uniform TextureCubeArray texture_##tex : register(T##regist); uniform SamplerState tex : register(S##regist)
 // Sampling functions
 #define TORQUE_TEX1D(tex,coords) texture_##tex.Sample(tex,coords)
 #define TORQUE_TEX2D(tex,coords) texture_##tex.Sample(tex,coords)
 #define TORQUE_TEX2DPROJ(tex,coords) texture_##tex.Sample(tex,coords.xy / coords.w)
 #define TORQUE_TEX3D(tex,coords) texture_##tex.Sample(tex,coords)
 #define TORQUE_TEXCUBE(tex,coords) texture_##tex.Sample(tex,coords)
+#define TORQUE_TEXCUBEARRAY(tex,coords) texture_##tex.Sample(tex,coords)
 // The mipmap LOD is specified in coord.w
 #define TORQUE_TEX2DLOD(tex,coords) texture_##tex.SampleLevel(tex,coords.xy,coords.w)
 #define TORQUE_TEXCUBELOD(tex,coords) texture_##tex.SampleLevel(tex,coords.xyz,coords.w)