###============================================================================== # Doom 3 Interaction Vertex/Fragment Program # # Custom Blinn-Phong Lighting Model (Isotropic) ###============================================================================== # # -------------------------------------- # input: # # attrib[8] = texture coordinates # attrib[9] = global tangent # attrib[10] = global bitangent # attrib[11] = global normal # # env[0] = diffuse modifier # env[1] = specular modifier # env[2] = ? # env[3] = ? # env[4] = localLightOrigin # env[5] = localViewOrigin # env[6] = lightProjection S # env[7] = lightProjection T # env[8] = lightProjection Q # env[9] = lightFalloff S # env[10] = bumpMatrix S # env[11] = bumpMatrix T # env[12] = diffuseMatrix S # env[13] = diffuseMatrix T # env[14] = specularMatrix S # env[15] = specularMatrix T # env[16] = vertex color modulate # env[17] = vertex color add # #-------------------------------------- # output: # # texture 0 = normalization cube map # texture 1 = per-surface normal map # texture 2 = 1D light falloff texture # texture 3 = 2D light projection texture # texture 4 = per-surface diffuse map # texture 5 = per-surface specular map # texture 6 = specular lookup table # #-------------------------------------- # note: lightFallTC = fragment.texcoord[2] # lightProjTC = fragment.texcoord[3] ###============================================================================== !!ARBvp1.0 OPTION ARB_position_invariant; # Instruction Count: 29 PARAM defaultTC = { 0.0, 0.5, 0.0, 1.0 }; TEMP R0; # calculate vector to light in R0 ADD R0, program.env[4], -vertex.position; # put into texture space for TEX0 DP3 result.texcoord[0].x, vertex.attrib[9], R0; DP3 result.texcoord[0].y, vertex.attrib[10], R0; DP3 result.texcoord[0].z, vertex.attrib[11], R0; # texture 1 takes the base coordinates by the texture matrix MOV result.texcoord[1], defaultTC; DP4 result.texcoord[1].x, vertex.attrib[8], program.env[10]; DP4 result.texcoord[1].y, vertex.attrib[8], program.env[11]; # texture 2 takes the base coordinates by the texture matrix DP4 result.texcoord[2].x, vertex.attrib[8], program.env[12]; DP4 result.texcoord[2].y, vertex.attrib[8], program.env[13]; DP4 result.texcoord[2].z, vertex.attrib[8], program.env[14]; DP4 result.texcoord[2].w, vertex.attrib[8], program.env[15]; # texture 3 has three texgens DP4 result.texcoord[3].x, vertex.position, program.env[6]; DP4 result.texcoord[3].y, vertex.position, program.env[7]; DP4 result.texcoord[3].z, vertex.position, program.env[9]; DP4 result.texcoord[3].w, vertex.position, program.env[8]; # calculate vector to viewer in R0 ADD R0, program.env[5], -vertex.position; # put into texture space for TEX6 DP3 result.texcoord[4].x, vertex.attrib[9], R0; DP3 result.texcoord[4].y, vertex.attrib[10], R0; DP3 result.texcoord[4].z, vertex.attrib[11], R0; # tangent space -> world space conversion matrix DP3 result.texcoord[5].x, vertex.attrib[9], program.env[6]; DP3 result.texcoord[5].y, vertex.attrib[10], program.env[6]; DP3 result.texcoord[5].z, vertex.attrib[11], program.env[6]; DP3 result.texcoord[6].x, vertex.attrib[9], program.env[7]; DP3 result.texcoord[6].y, vertex.attrib[10], program.env[7]; DP3 result.texcoord[6].z, vertex.attrib[11], program.env[7]; DP3 result.texcoord[7].x, vertex.attrib[9], program.env[9]; DP3 result.texcoord[7].y, vertex.attrib[10], program.env[9]; DP3 result.texcoord[7].z, vertex.attrib[11], program.env[9]; # generate the vertex color, which can be 1.0, color, or 1.0 - color # for 1.0 : env[16] = 0.0, env[17] = 1.0 # for color : env[16] = 1.0, env[17] = 0.0 # for 1.0 - color : env[16] = -1.0, env[17] = 1.0 MAD result.color, vertex.color, program.env[16], program.env[17]; END #================================================================================== !!ARBfp1.0 OPTION ARB_precision_hint_nicest; # Instruction Count: ALU: 97 TEX: 6 Total: 103 OUTPUT oColor = result.color; ATTRIB vColor = fragment.color; ATTRIB lightVecTC = fragment.texcoord[0]; ATTRIB normalTC = fragment.texcoord[1]; ATTRIB diffspecTC = fragment.texcoord[2]; ATTRIB lightProjTC = fragment.texcoord[3]; ATTRIB viewVecTC = fragment.texcoord[4]; ATTRIB tangent = fragment.texcoord[5]; ATTRIB bitangent = fragment.texcoord[6]; ATTRIB normal = fragment.texcoord[7]; PARAM lightColor = program.env[0]; PARAM specColor = program.env[1]; PARAM const = { 1.0, 2.0, 4.0, 5.0 }; PARAM const2 = { 0.25, 0.5, 0.75, 0.75 }; PARAM skyColor = { 1.0, 1.0, 1.0 }; PARAM grndColor = { 0.1, 0.1, 0.1 }; PARAM lumVec = { 0.212671, 0.715160, 0.072169 }; PARAM specExp = 256.0; PARAM M_PI = 3.1415926535897932384626433832795; PARAM M_8PI = 25.132741228718345907701147066236; PARAM M_inv2PI = 0.15915494309189533576888376337251; PARAM e = 2.7182818284590452353602874713527; PARAM gamma = { 2.4, 0.94786729857819905213270142180095, 0.41666666666666666666666666666667, 0.077399380804953560371517027863777 }; TEMP lightVec, viewVec, halfVec, normalVec, wNormalVec; TEMP diffuse, specular, gloss, rough, fresnel, color, ambient; TEMP light, hemi, atten, rim, lightFall, lightProj, lightCube, lightCol; TEMP NdotL, NdotV, NdotH, VdotH, VdotL; TEMP R1, R2; # calculate point light tc MOV R1, lightProjTC; MOV R1.z, lightFallTC.x; MAD R1.xyz, R1, 2.0, -1.0; # calculate projected light tc MOV R2, lightProjTC; MOV R2.z, -1.0; RCP R2.w, lightProjTC.w; MUL R2.xy, R2, R2.w; MAD R2.xy, R2, 2.0, -1.0; # sample projection cube map TEX lightCube, R1, texture[3], CUBE; TEX lightProj, R2, texture[3], CUBE; # calculate attenuation (x = point, y = projected) DP3 R1.x, R1, R1; POW R1.x, R1.x, 0.5.x; MOV R1.y, lightFallTC.x; ADD_SAT R1.xy, 1.0, -R1; MUL R1.xy, R1, R1; MUL lightCube, lightCube, R1.x; MUL lightProj, lightProj, R1.y; # early out - attenuation DP3 atten.w, atten, const.x; SGE atten.w, 0.0, atten.w; KIL -atten.w; # if w > 1.0, light = projected, else light = point SLT R1.x, 1.0, lightProjTC.w; CMP atten, -R1.x, lightProj, lightCube; # load texture maps TEX ambient, lightVecTC, texture[0], CUBE; TEX normalVec, normalTC, texture[1], 2D; TEX diffuse, diffspecTC.xyxy, texture[4], 2D; TEX gloss, diffspecTC.zwzw, texture[5], 2D; DP3 rough, gloss, lumVec; # scale normal vector to -1.0<->1.0 range and normalize MAD normalVec.xyz, normalVec.wyzx, const.y, -const.x; DP3 normalVec.w, normalVec, normalVec; RSQ normalVec.w, normalVec.w; MUL normalVec.xyz, normalVec, normalVec.w; # normalize the vector to the light DP3 lightVec.w, lightVecTC, lightVecTC; RSQ lightVec.w, lightVec.w; MUL lightVec.xyz, lightVecTC, lightVec.w; # calculate diffuse cosine DP3 NdotL.x, normalVec, lightVec; # calculate light w/ self shadowing ADD_SAT R1.x, lightVec.z, const2.y; ADD_SAT R1.x, R1.x, R1.x; MUL_SAT R1.x, R1.x, R1.x; MOV_SAT R1.y, NdotL.x; MUL R1.y, R1.y, R1.y; LRP R1.y, rough.w, R1.y, NdotL.x; MUL light, R1.x, R1.y; # early out - NdotL SLT ambient.w, ambient.w, const.x; SGE R1.w, 0.0, light.x; CMP R1.w, -ambient.w, 0.0, R1.w; KIL -R1.w; # normalize the vector to the viewer DP3 viewVec.w, viewVecTC, viewVecTC; RSQ viewVec.w, viewVec.w; MUL viewVec.xyz, viewVecTC, viewVec.w; # calculate the half angle vector and normalize ADD halfVec, lightVec, viewVec; DP3 halfVec.w, halfVec, halfVec; RSQ halfVec.w, halfVec.w; MUL halfVec.xyz, halfVec, halfVec.w; # transform normal to world space DP3 wNormalVec.x, normalVec, tangent; DP3 wNormalVec.y, normalVec, bitangent; DP3 wNormalVec.z, normalVec, normal; # normalize world space normal vector DP3 wNormalVec.w, wNormalVec, wNormalVec; RSQ wNormalVec.w, wNormalVec.w; MUL wNormalVec.xyz, wNormalVec, wNormalVec.w; # calculate vector dot products DP3 NdotV.x, normalVec, viewVec; DP3_SAT NdotH.x, normalVec, halfVec; DP3_SAT VdotH.x, viewVec, halfVec; DP3_SAT VdotL.x, viewVec, -lightVec; # sRGB -> Linear MUL R1, diffuse, gamma.w; ADD R2, diffuse, 0.055; MUL R2, R2, gamma.y; POW R2.x, R2.x, gamma.x; POW R2.y, R2.y, gamma.x; POW R2.z, R2.z, gamma.x; SGE diffuse, 0.04045, diffuse; CMP diffuse.xyz, -diffuse, R1, R2; # sikk - fix for materials with no diffuse map (e.g. Hellknight gob) DP3 R1.x, lightColor, -const.x; CMP lightCol, R1.x, lightColor, specColor; # sRGB -> Linear MUL R1, lightCol, gamma.w; ADD R2, lightCol, 0.055; MUL R2, R2, gamma.y; POW R2.x, R2.x, gamma.x; POW R2.y, R2.y, gamma.x; POW R2.z, R2.z, gamma.x; SGE lightCol, 0.04045, lightCol; CMP lightCol.xyz, -lightCol, R1, R2; # calculate specular term MUL rough.x, rough.x, specExp.x; MUL rough.y, VdotH.x, VdotH.x; RCP rough.y, rough.y; ADD R1.xy, rough.x, { 2.0, 4.0 }; MUL R1.x, R1.x, R1.y; MUL R1.y, rough.x, 0.5; EX2 R1.y, -R1.y; ADD R1.y, R1.y, rough.x; MUL R1.y, R1.y, M_8PI; RCP R1.y, R1.y; MUL rough.z, R1.x, R1.y; ADD fresnel.x, const.x, -VdotH.x; POW_SAT fresnel.x, fresnel.x, const.w; MUL_SAT fresnel.x, fresnel.x, rough.w; MUL_SAT fresnel, fresnel.x, 16.0; LRP fresnel, gloss, const.x, fresnel; MAX NdotH.x, NdotH.x, 0.00001; POW specular, NdotH.x, rough.x; MUL specular, specular, rough.y; MUL specular, specular, rough.z; # modulate specular by fresnel and add diffuse color MAD color, specular, fresnel, diffuse; # calculate hemisphere lighting ambient term MAD hemi.w, wNormalVec.z, const2.y, const2.y; LRP hemi, hemi.w, skyColor, grndColor; CMP light, -ambient.w, hemi, light; # rim light ABS R1.x, NdotV.x; # use abs since some translucent materials use light interaction ADD R1.x, const.x, -R1.x; POW R1.x, R1.x, const.w; MUL_SAT R1.y, VdotL.x, VdotL.x; MAD_SAT R1.z, rough.w, -2.0, const.x; MUL_SAT R1, R1.xzzz, R1.yzzz; MUL rim, R1.x, R1.y; LRP rim, color, 1.0, rim; CMP color, -ambient.w, color, rim; # cancel rim lighting for ambient lights # final modulation MUL color, color, light; MUL color, color, lightCol; MUL color, color, atten; # Linear -> sRGB MUL R1, color, 12.92; POW R2.x, color.x, gamma.z; POW R2.y, color.y, gamma.z; POW R2.z, color.z, gamma.z; MAD R2, R2, 1.055, -0.055; SGE color, 0.0031308, color; CMP color.xyz, -color, R1, R2; # modify by the vertex color MUL oColor.xyz, color, vColor; END