/// <summary> /// /// </summary> private void UpdateShaders() { if (!mShadersSupported) { return; } int i = 0; foreach (BatchedGeometry.SubBatch it in mBatch.SubBatches.Values) { BatchedGeometry.SubBatch subBatch = it; Material mat = mUnfadedMaterials[i++]; //check ig lighting should be enabled bool lightningEnabled = false; for (int t = 0; t < mat.TechniqueCount; t++) { Technique tech = mat.GetTechnique(t); for (int p = 0; p < tech.PassCount; p++) { Pass pass = tech.GetPass(p); if (pass.LightingEnabled) { lightningEnabled = true; break; } if (lightningEnabled) { break; } } } //Compile the CG shader script based on various material / fade options string tmpName = string.Empty; tmpName += "BatchPage_"; if (mFadeEnabled) { tmpName += "fade_"; } if (lightningEnabled) { tmpName += "lit_"; } tmpName += "vp"; string vertexProgName = tmpName; //If the shader hasn't been created yet, create it if (HighLevelGpuProgramManager.Instance.GetByName(tmpName) == null) { string vertexProgSource = "void main( \n" + " float4 iPosition : POSITION, \n"+ " float3 normal : NORMAL, \n"+ " float2 iUV : TEXCOORD0, \n"+ " float4 iColor : COLOR, \n"+ " out float4 oPosition : POSITION, \n"+ " out float2 oUV : TEXCOORD0, \n"+ " out float4 oColor : COLOR, \n"+ " out float4 oFog : FOG, \n"; if (lightningEnabled) { vertexProgSource += " uniform float4 objSpaceLight, \n"+ " uniform float4 lightDiffuse, \n"+ " uniform float4 lightAmbient, \n"; } if (mFadeEnabled) { vertexProgSource += " uniform float3 camPos, \n"; } vertexProgSource += " uniform float4x4 worldViewProj, \n"+ " uniform float fadeGap, \n"+ " uniform float invisibleDist )\n" + "{ \n"; if (lightningEnabled) { vertexProgSource += //Perform lighting calculations (no specular) " float3 light = normalize(objSpaceLight.xyz - (iPosition.xyz * objSpaceLight.w)); \n"+ " float diffuseFactor = max(dot(normal, light), 0); \n"+ " oColor = (lightAmbient + diffuseFactor * lightDiffuse) * iColor; \n"; } else { vertexProgSource += " oColor = iColor; \n"; } if (mFadeEnabled) { vertexProgSource += //Fade out in the distance " float dist = distance(camPos.xz, iPosition.xz); \n"+ " oColor.a *= (invisibleDist - dist) / fadeGap; \n"; } vertexProgSource += " oUV = iUV; \n"+ " oPosition = mul(worldViewProj, iPosition); \n"+ " oFog.x = oPosition.z; \n"+ "}"; HighLevelGpuProgram vertexShader = HighLevelGpuProgramManager.Instance.CreateProgram( vertexProgName, ResourceGroupManager.DefaultResourceGroupName, "cg", GpuProgramType.Vertex); vertexShader.Source = vertexProgSource; vertexShader.SetParam("profiles", "vs_1_1 arbvp1"); vertexShader.SetParam("entry_point", "main"); vertexShader.Load(); } //Now that the shader is ready to be applied, apply it string materialSignature = string.Empty; materialSignature += "BatchMat|"; materialSignature += mat.Name + "|"; if (mFadeEnabled) { materialSignature += mVisibleDist + "|"; materialSignature += mInvisibleDist + "|"; } //Search for the desired material Material generatedMaterial = (Material)MaterialManager.Instance.GetByName(materialSignature); if (generatedMaterial == null) { //Clone the material generatedMaterial = mat.Clone(materialSignature); //And apply the fade shader for (int t = 0; t < generatedMaterial.TechniqueCount; t++) { Technique tech = generatedMaterial.GetTechnique(t); for (int p = 0; p < tech.PassCount; p++) { Pass pass = tech.GetPass(p); //Setup vertex program if (pass.VertexProgramName == "") { pass.VertexProgramName = vertexProgName; } try { GpuProgramParameters gparams = pass.VertexProgramParameters; if (lightningEnabled) { gparams.SetNamedAutoConstant("objSpaceLight", GpuProgramParameters.AutoConstantType.LightPositionObjectSpace, 0); gparams.SetNamedAutoConstant("lightDiffuse", GpuProgramParameters.AutoConstantType.LightDiffuseColor, 0); gparams.SetNamedAutoConstant("lightAmbient", GpuProgramParameters.AutoConstantType.AmbientLightColor, 0); } gparams.SetNamedAutoConstant("worldViewProj", GpuProgramParameters.AutoConstantType.WorldViewProjMatrix, 0); if (mFadeEnabled) { gparams.SetNamedAutoConstant("camPos", GpuProgramParameters.AutoConstantType.CameraPositionObjectSpace, 0); //set fade ranges gparams.SetNamedAutoConstant("invisibleDist", GpuProgramParameters.AutoConstantType.Custom, 0); gparams.SetNamedConstant("invisibleDist", mInvisibleDist); gparams.SetNamedAutoConstant("fadeGap", GpuProgramParameters.AutoConstantType.Custom, 0); gparams.SetNamedConstant("fadeGap", mInvisibleDist - mVisibleDist); if (pass.AlphaRejectFunction == CompareFunction.AlwaysPass) { pass.SetSceneBlending(SceneBlendType.TransparentAlpha); } } } catch { throw new Exception("Error configuring batched geometry transitions." + "If you're using materials with custom vertex shaders, they will need to implement fade transitions to be compatible with BatchPage."); } } } } //Apply the material subBatch.Material = generatedMaterial; } }
/// <summary> /// /// </summary> internal void UpdateShaders() { if (mShaderNeedsUpdate) { mShaderNeedsUpdate = false; //Proceed only if there is no custom vertex shader and the user's computer supports vertex shaders RenderSystemCapabilities caps = Root.Singleton.RenderSystem.Capabilities; if (caps.HasCapability(Capabilities.VertexPrograms)) { //Generate a string ID that identifies the current set of vertex shader options string tmpName = string.Empty; tmpName += "GrassVS_"; if (mAnimate) { tmpName += "anim_"; } if (mBlend) { tmpName += "blend_"; } tmpName += mRenderTechnique.ToString() + "_"; tmpName += mFadeTechnique.ToString() + "_"; if (mFadeTechnique == FadeTechnique.Grow || mFadeTechnique == FadeTechnique.AlphaGrow) { tmpName += mMaxHeight + "_"; } tmpName += "vp"; string vsName = tmpName; //Generate a string ID that identifies the material combined with the vertex shader string matName = mMaterial.Name + "_" + vsName; //Check if the desired material already exists (if not, create it) Material tmpMat = (Material)MaterialManager.Instance.GetByName(matName); if (tmpMat == null) { //Clone the original material tmpMat = mMaterial.Clone(matName); //Disable lighting tmpMat.Lighting = false; //Check if the desired shader already exists (if not, compile it) HighLevelGpuProgram vertexShader = (HighLevelGpuProgram)HighLevelGpuProgramManager.Instance.GetByName(vsName); if (vertexShader == null) { //Generate the grass shader string vertexProgSource = string.Empty; vertexProgSource += "void main( \n" + " float4 iPosition : POSITION, \n"+ " float4 iColor : COLOR, \n"+ " float2 iUV : TEXCOORD0, \n"+ " out float4 oPosition : POSITION, \n"+ " out float4 oColor : COLOR, \n"+ " out float2 oUV : TEXCOORD0, \n"; if (mAnimate) { vertexProgSource += " uniform float time, \n"+ " uniform float frequency, \n"+ " uniform float4 direction, \n"; } if (mFadeTechnique == FadeTechnique.Grow || mFadeTechnique == FadeTechnique.AlphaGrow) { vertexProgSource += " uniform float grassHeight, \n"; } if (mRenderTechnique == GrassTechnique.Sprite) { vertexProgSource += " float4 iNormal : NORMAL, \n"; } vertexProgSource += " uniform float4x4 worldViewProj, \n"+ " uniform float3 camPos, \n"+ " uniform float fadeRange ) \n"+ "{ \n"+ " oColor.rgb = iColor.rgb; \n"+ " float4 position = iPosition; \n"+ " float dist = distance(camPos.xz, position.xz); \n"; if (mFadeTechnique == FadeTechnique.Alpha || mFadeTechnique == FadeTechnique.AlphaGrow) { vertexProgSource += //Fade out in the distance " oColor.a = 2.0f - (2.0f * dist / fadeRange); \n"; } else { vertexProgSource += " oColor.a = 1.0f; \n"; } vertexProgSource += " float oldposx = position.x; \n"; if (mRenderTechnique == GrassTechnique.Sprite) { vertexProgSource += //Face the camera " float3 dirVec = (float3)position - (float3)camPos; \n"+ " float3 p = normalize(cross(float4(0,1,0,0), dirVec)); \n"+ " position += float4(p.x * iNormal.x, iNormal.y, p.z * iNormal.x, 0); \n"; } if (mAnimate) { vertexProgSource += " if (iUV.y == 0.0f){ \n"+ //Wave grass in breeze " float offset = sin(time + oldposx * frequency); \n"+ " position += direction * offset; \n"+ " } \n"; } if (mBlend && mAnimate) { vertexProgSource += " else { \n"; } else if (mBlend) { vertexProgSource += " if (iUV.y != 0.0f){ \n"; } if (mBlend) { vertexProgSource += //Blend the base of nearby grass into the terrain " if (oColor.a >= 1.0f) \n"+ " oColor.a = 4.0f * ((dist / fadeRange) - 0.1f); \n"+ " } \n"; } if (mFadeTechnique == FadeTechnique.Grow || mFadeTechnique == FadeTechnique.AlphaGrow) { vertexProgSource += " float offset = (2.0f * dist / fadeRange) - 1.0f; \n"+ " position.y -= grassHeight * clamp(offset, 0, 1); "; } vertexProgSource += " oPosition = mul(worldViewProj, position); \n"; vertexProgSource += " oUV = iUV;\n"+ "}"; vertexShader = HighLevelGpuProgramManager.Instance.CreateProgram( vsName, ResourceGroupManager.DefaultResourceGroupName, "cg", GpuProgramType.Vertex); vertexShader.Source = vertexProgSource; vertexShader.SetParam("profiles", "vs_1_1 arbvp1"); vertexShader.SetParam("entry_point", "main"); vertexShader.Load(); } //Now the vertex shader (vertexShader) has either been found or just generated //(depending on whether or not it was already generated). //Apply the shader to the material Pass pass = tmpMat.GetTechnique(0).GetPass(0); pass.VertexProgramName = vsName; GpuProgramParameters gparams = pass.VertexProgramParameters; gparams.SetNamedAutoConstant("worldViewProj", GpuProgramParameters.AutoConstantType.WorldViewProjMatrix, 0); gparams.SetNamedAutoConstant("camPos", GpuProgramParameters.AutoConstantType.CameraPositionObjectSpace, 0); gparams.SetNamedAutoConstant("fadeRange", GpuProgramParameters.AutoConstantType.Custom, 1); if (mAnimate) { gparams.SetNamedAutoConstant("time", GpuProgramParameters.AutoConstantType.Custom, 1); gparams.SetNamedAutoConstant("frequency", GpuProgramParameters.AutoConstantType.Custom, 1); gparams.SetNamedAutoConstant("direction", GpuProgramParameters.AutoConstantType.Custom, 4); } if (mFadeTechnique == FadeTechnique.Grow || mFadeTechnique == FadeTechnique.AlphaGrow) { gparams.SetNamedAutoConstant("grassHeight", GpuProgramParameters.AutoConstantType.Custom, 1); gparams.SetNamedConstant("grassHeight", mMaxHeight * 1.05f); } float farViewDist = mGeom.DetailLevels[0].FarRange; pass.VertexProgramParameters.SetNamedConstant("fadeRange", farViewDist / 1.225f); //Note: 1.225 ~= sqrt(1.5), which is necessary since the far view distance is measured from the centers //of pages, while the vertex shader needs to fade grass completely out (including the closest corner) //before the page center is out of range. } //Now the material (tmpMat) has either been found or just created (depending on whether or not it was already //created). The appropriate vertex shader should be applied and the material is ready for use. //Apply the new material mMaterial = tmpMat; } } }
/// <summary> /// /// </summary> /// <param name="mgr"></param> /// <param name="rootSceneNode"></param> /// <param name="method"></param> public StaticBillboardSet(SceneManager mgr, SceneNode rootSceneNode, BillboardMethod method) { mSceneMgr = mgr; mRenderMethod = method; mVisible = true; mFadeEnabled = false; mBBOrigin = BillboardOrigin.Center; //Fall back to Compatible if vertex shaders are not available if (mRenderMethod == BillboardMethod.Accelerated) { RenderSystemCapabilities caps = Root.Singleton.RenderSystem.Capabilities; if (!caps.HasCapability(Capabilities.VertexPrograms)) { mRenderMethod = BillboardMethod.Compatible; } } mNode = rootSceneNode.CreateChildSceneNode(); mEntityName = GetUniqueID("SBSEntity"); if (mRenderMethod == BillboardMethod.Accelerated) { //Accelerated billboard method mEntity = null; mUFactor = 1.0f; mVFactor = 1.0f; //Load vertex shader to align billboards to face the camera (if not loaded already) if (++mSelfInstances == 1) { //First shader, simple camera-alignment HighLevelGpuProgram vertexShader = (HighLevelGpuProgram)HighLevelGpuProgramManager.Instance.GetByName("Sprite_vp"); if (vertexShader == null) { string vertexProg = string.Empty; vertexProg = "void Sprite_vp( \n"+ " float4 position : POSITION, \n"+ " float3 normal : NORMAL, \n"+ " float4 color : COLOR, \n"+ " float2 uv : TEXCOORD0, \n"+ " out float4 oPosition : POSITION, \n"+ " out float2 oUv : TEXCOORD0, \n"+ " out float4 oColor : COLOR, \n"+ " out float4 oFog : FOG, \n"+ " uniform float4x4 worldViewProj, \n"+ " uniform float uScroll, \n"+ " uniform float vScroll, \n"+ " uniform float4 preRotatedQuad[4] ) \n"+ "{ \n"+ //Face the camera " float4 vCenter = float4( position.x, position.y, position.z, 1.0f ); \n"+ " float4 vScale = float4( normal.x, normal.y, normal.x, 1.0f ); \n"+ " oPosition = mul( worldViewProj, vCenter + (preRotatedQuad[normal.z] * vScale) ); \n"+ //Color " oColor = color; \n"+ //UV Scroll " oUv = uv; \n"+ " oUv.x += uScroll; \n"+ " oUv.y += vScroll; \n"+ //Fog " oFog.x = oPosition.z; \n"+ "}"; vertexShader = HighLevelGpuProgramManager.Instance.CreateProgram( "Sprite_vp", ResourceGroupManager.DefaultResourceGroupName, "cg", GpuProgramType.Vertex); vertexShader.Source = vertexProg; vertexShader.SetParam("profiles", "vs_1_1 arbvp1"); vertexShader.SetParam("entry_point", "Sprite_vp"); vertexShader.Load(); } //Second shader, camera alignment and distance based fading HighLevelGpuProgram vertexShader2 = (HighLevelGpuProgram)HighLevelGpuProgramManager.Instance.GetByName("SpriteFade_vp"); if (vertexShader2 == null) { string vertexProg2 = string.Empty; vertexProg2 = "void SpriteFade_vp( \n"+ " float4 position : POSITION, \n"+ " float3 normal : NORMAL, \n"+ " float4 color : COLOR, \n"+ " float2 uv : TEXCOORD0, \n"+ " out float4 oPosition : POSITION, \n"+ " out float2 oUv : TEXCOORD0, \n"+ " out float4 oColor : COLOR, \n"+ " out float4 oFog : FOG, \n"+ " uniform float4x4 worldViewProj, \n"+ " uniform float3 camPos, \n"+ " uniform float fadeGap, \n"+ " uniform float invisibleDist, \n" + " uniform float uScroll, \n"+ " uniform float vScroll, \n"+ " uniform float4 preRotatedQuad[4] ) \n"+ "{ \n"+ //Face the camera " float4 vCenter = float4( position.x, position.y, position.z, 1.0f ); \n"+ " float4 vScale = float4( normal.x, normal.y, normal.x, 1.0f ); \n"+ " oPosition = mul( worldViewProj, vCenter + (preRotatedQuad[normal.z] * vScale) ); \n"+ " oColor.rgb = color.rgb; \n"+ //Fade out in the distance " float dist = distance(camPos.xz, position.xz); \n"+ " oColor.a = (invisibleDist - dist) / fadeGap; \n"+ //UV scroll " oUv = uv; \n"+ " oUv.x += uScroll; \n"+ " oUv.y += vScroll; \n"+ //Fog " oFog.x = oPosition.z; \n"+ "}"; vertexShader2 = HighLevelGpuProgramManager.Instance.CreateProgram( "SpriteFade_vp", ResourceGroupManager.DefaultResourceGroupName, "cg", GpuProgramType.Vertex); vertexShader2.Source = vertexProg2; vertexShader2.SetParam("profiles", "vs_1_1 arbvp1"); vertexShader2.SetParam("entry_point", "SpriteFade_vp"); vertexShader2.Load(); } } } else { //Compatible billboard method mFallbackSet = mSceneMgr.CreateBillboardSet(GetUniqueID("SBS"), 100); mNode.AttachObject(mFallbackSet); } }