public Vector4 ReserveOtherShadows(Light light, int visibleLightIndex) { if (light.shadows != LightShadows.None && light.shadowStrength > 0f) { float maskChannel = -1f; LightBakingOutput lightBaking = light.bakingOutput; if (lightBaking.lightmapBakeType == LightmapBakeType.Mixed && lightBaking.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; maskChannel = lightBaking.occlusionMaskChannel; } bool isPoint = light.type == LightType.Point; int newLightCount = shadowedOtherLightCount + (isPoint ? 6 : 1); if (newLightCount > maxShadowedOtherLightCount || !cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds b)) { return(new Vector4(-light.shadowStrength, 0f, 0f, maskChannel)); } shadowedOtherLights[shadowedOtherLightCount] = new ShadowedOtherLight { visibleLightIndex = visibleLightIndex, slopeScaleBias = light.shadowBias, normalBias = light.shadowNormalBias, isPoint = isPoint }; Vector4 data = new Vector4( light.shadowStrength, shadowedOtherLightCount, isPoint ? 1f : 0f, maskChannel); shadowedOtherLightCount = newLightCount; return(data); } return(new Vector4(0f, 0f, 0f, -1f)); }
protected override void ReadFromImpl(object obj) { base.ReadFromImpl(obj); Light uo = (Light)obj; shadows = uo.shadows; shadowStrength = uo.shadowStrength; shadowResolution = uo.shadowResolution; layerShadowCullDistances = uo.layerShadowCullDistances; cookieSize = uo.cookieSize; cookie = ToID(uo.cookie); renderMode = uo.renderMode; areaSize = uo.areaSize; lightmapBakeType = uo.lightmapBakeType; type = uo.type; spotAngle = uo.spotAngle; color = uo.color; colorTemperature = uo.colorTemperature; intensity = uo.intensity; bounceIntensity = uo.bounceIntensity; shadowCustomResolution = uo.shadowCustomResolution; shadowBias = uo.shadowBias; shadowNormalBias = uo.shadowNormalBias; shadowNearPlane = uo.shadowNearPlane; range = uo.range; flare = ToID(uo.flare); bakingOutput = uo.bakingOutput; cullingMask = uo.cullingMask; lightShadowCasterMode = uo.lightShadowCasterMode; shadowRadius = uo.shadowRadius; shadowAngle = uo.shadowAngle; }
public Vector4 ReserveDirectionalShadows(Light light, int visibleLightIndex) { if (currentDirectionalLightShadowCount < maxDirectionalShadowCount && light.shadows != LightShadows.None && light.shadowStrength > 0f) { float maskChannel; LightBakingOutput lightBakingOutput = light.bakingOutput; if (lightBakingOutput.lightmapBakeType == LightmapBakeType.Mixed && lightBakingOutput.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; maskChannel = lightBakingOutput.occlusionMaskChannel; // can not use the light index because it may be changed in runtime } else { maskChannel = -1; } // GetShadowCasterBounds now returns true for directional lights even when there is nothing within the shadow range if (!cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds b)) { // the shadow strength of light is negative, see GetDirectionalShadowAttenuation in WindsmoonShadow.hlsl // if the stength is positive, the shader may be handle the shadow as realtime shadow return(new Vector4(-light.shadowStrength, 0f, 0, maskChannel)); } directionalShadows[currentDirectionalLightShadowCount] = new DirectionalShadow() { visibleLightIndex = visibleLightIndex, slopeScaleBias = light.shadowBias, nearPlaneOffset = light.shadowNearPlane }; return(new Vector4(light.shadowStrength, shadowSettings.DirectionalShadowSetting.CascadeCount * currentDirectionalLightShadowCount++, light.shadowNormalBias, maskChannel)); } return(new Vector4(0f, 0f, 0f, -1)); }
static void ApplyRendererInfo(RendererInfo[] infos, int[] lightmapOffsetIndex, LightInfo[] lightsInfo) { for (int i = 0; i < infos.Length; i++) { var info = infos[i]; info.renderer.lightmapIndex = lightmapOffsetIndex[info.lightmapIndex]; info.renderer.lightmapScaleOffset = info.lightmapOffsetScale; // You have to release shaders. Material[] mat = info.renderer.sharedMaterials; for (int j = 0; j < mat.Length; j++) { if (mat[j] != null && Shader.Find(mat[j].shader.name) != null) { mat[j].shader = Shader.Find(mat[j].shader.name); } } } for (int i = 0; i < lightsInfo.Length; i++) { LightBakingOutput bakingOutput = new LightBakingOutput(); bakingOutput.isBaked = true; bakingOutput.lightmapBakeType = (LightmapBakeType)lightsInfo[i].lightmapBaketype; bakingOutput.mixedLightingMode = (MixedLightingMode)lightsInfo[i].mixedLightingMode; lightsInfo[i].light.bakingOutput = bakingOutput; } }
/// <summary> /// 储备方向光阴影 Vector2存取强度和光线的索引 支持四盏光的ShadowMask /// </summary> /// <param name="light"></param> /// <param name="visibleLightIndex"></param> public Vector4 ReserveDirectionalShadows(Light light, int visibleLightIndex) { //检测阴影强度 None &&cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds b) if (shadowedDirLightCount < maxShadowedDirLightCount && light.shadows != LightShadows.None && light.shadowStrength > 0f) { float maskChannel = -1; //shadowMask LightBakingOutput lightBaking = light.bakingOutput; if (lightBaking.lightmapBakeType == LightmapBakeType.Mixed && lightBaking.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; maskChannel = lightBaking.occlusionMaskChannel; } //直接Return 出去 不需要Cacade数据 阴影跑出CullSphere里面 if (!cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds b)) { //负数防止Shader 采样ShadowMap return(new Vector4(-light.shadowStrength, 0f, 0f, maskChannel)); } ShadowDirectionalLights[shadowedDirLightCount] = new ShadowDirectionalLight { visibleLightIndex = visibleLightIndex, slopeScaleBias = light.shadowBias, nearPlaneOffset = light.shadowNearPlane }; //* 级联ShadowMap的数量 return(new Vector4(light.shadowStrength, settings.directional.cascadeCount * shadowedDirLightCount++, light.shadowNormalBias, maskChannel)); } return(new Vector4(0f, 0f, 0f, -1f)); }
public Vector4 ReserveDirectionalShadows(Light light, int visibleLightIndex) { if (shadowedDirectionalLightCount < maxShadowedDirectionalLightCount && light.shadows != LightShadows.None && light.shadowStrength > 0f //&& //cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds b) ) { float maskChannel = -1; LightBakingOutput lightBaking = light.bakingOutput; if (lightBaking.lightmapBakeType == LightmapBakeType.Mixed && lightBaking.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; maskChannel = lightBaking.occlusionMaskChannel; } if (!cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds b)) { return(new Vector4(-light.shadowStrength, 0f, 0f, maskChannel)); } shadowedDirectionalLights[shadowedDirectionalLightCount] = new ShadowedDirectionalLight { visibleLightIndex = visibleLightIndex, slopeScaleBias = light.shadowBias, nearPlaneOffset = light.shadowNearPlane }; return(new Vector4(light.shadowStrength, shadowSettings.directional.cascadeCount * shadowedDirectionalLightCount++, light.shadowNormalBias, maskChannel)); } return(new Vector4(0f, 0f, 0f, -1f)); }
public void Apply() { lightingData.ApplyLightmapsTex(); ApplyLightmapsRenderData(); //下面代码不设置会没有烘焙的影子 LightBakingOutput bakingOutput = new LightBakingOutput(); bakingOutput.isBaked = true; bakingOutput.lightmapBakeType = LightmapBakeType.Mixed; bakingOutput.mixedLightingMode = MixedLightingMode.Shadowmask; dirLight.bakingOutput = bakingOutput; }
public Vector4 ReserveOtherShadows(Light light, int visibleLightIndex) { if (light.shadows != LightShadows.None && light.shadowStrength > 0f) { LightBakingOutput lightBaking = light.bakingOutput; if (lightBaking.lightmapBakeType == LightmapBakeType.Mixed && lightBaking.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; return(new Vector4(light.shadowStrength, 0f, 0f, lightBaking.occlusionMaskChannel)); } } return(new Vector4(0f, 0f, 0f, -1f)); }
public static int constructor(IntPtr l) { int result; try { LightBakingOutput lightBakingOutput = default(LightBakingOutput); LuaObject.pushValue(l, true); LuaObject.pushValue(l, lightBakingOutput); result = 2; } catch (Exception e) { result = LuaObject.error(l, e); } return(result); }
void Update() { if (isBaked != bakeLight.bakingOutput.isBaked || lightmapBakeType != bakeLight.bakingOutput.lightmapBakeType || mixedLightingMode != bakeLight.bakingOutput.mixedLightingMode || probeOcclusionLightIndex != bakeLight.bakingOutput.probeOcclusionLightIndex || occlusionMaskChannel != bakeLight.bakingOutput.occlusionMaskChannel) { LightBakingOutput output = new LightBakingOutput(); output.isBaked = isBaked; output.occlusionMaskChannel = occlusionMaskChannel; output.mixedLightingMode = mixedLightingMode; output.occlusionMaskChannel = probeOcclusionLightIndex; output.lightmapBakeType = lightmapBakeType; bakeLight.bakingOutput = output; } }
public Vector4 ReserveDirectioanlShadows(Light light, int visibleLightIndex) { if (ShadowedDirectionalLightCount < maxShadowedDirectionalLightCount && light.shadows != LightShadows.None && light.shadowStrength > 0f //&& //cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds b) ) //the getshadowCasterBound will return false if the light does not effect any oject(can cast shadow) in shadow range { float maskChannel = -1; //we will decide wether to use the shadow mask depend on if the lights are using thi shadow mask LightBakingOutput lightBaking = light.bakingOutput; if (lightBaking.lightmapBakeType == LightmapBakeType.Mixed && lightBaking.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; maskChannel = lightBaking.occlusionMaskChannel; } //Inform Shader the light does not affect anything, used for baked light attenuation if (!cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds b)) { return(new Vector4(-light.shadowStrength, 0f, maskChannel)); } ShadowedDirectionalLights[ShadowedDirectionalLightCount] = new ShadowedDirectionalLight { visibleLightIndex = visibleLightIndex, slopScaleBias = light.shadowBias, nearPlaneOffset = light.shadowNearPlane }; return(new Vector4(light.shadowStrength, shadowSettings.directional.cascadeCount * ShadowedDirectionalLightCount++, light.shadowNormalBias, maskChannel)); } else { return(new Vector4(0f, 0f, 0f, -1f)); } }
public Vector4 ReserveOtherShadows(Light light, int visibleLightIndex) { if (light.shadows == LightShadows.None || light.shadowStrength <= 0) { return(new Vector4(0f, 0f, 0f, -1f)); } int occlusionMaskChannel = -1; LightBakingOutput lightBakingOutput = light.bakingOutput; if (lightBakingOutput.lightmapBakeType == LightmapBakeType.Mixed && lightBakingOutput.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; occlusionMaskChannel = lightBakingOutput.occlusionMaskChannel; } bool isPoint = light.type == LightType.Point; int newLightCount = currentOtherShadowCount + (isPoint ? 6 : 1); if (newLightCount >= maxOtherShadaowCount || !cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds bounds)) { // the shadow strength of light is negative, see GetDirectionalShadowAttenuation in WindsmoonShadow.hlsl // if the stength is positive, the shader may be handle the shadow as realtime shadow return(new Vector4(-light.shadowStrength, 0f, 0f, occlusionMaskChannel)); } otherShadows[currentOtherShadowCount] = new OtherShadow() { VisibleLightIndex = visibleLightIndex, SlopeScaleBias = light.shadowBias, NoramlBias = light.shadowNormalBias, IsPoint = isPoint }; Vector4 data = new Vector4(light.shadowStrength, currentOtherShadowCount, isPoint ? 1f : 0f, occlusionMaskChannel); currentOtherShadowCount = newLightCount; return(data); }
public Vector3 ReserveDirectionalShadows(Light light, int visibleLightIndex) { // GetShadowCasterBounds return true if the light affects at least one shadow casting object in the Scene if (currentDirectionalLightShadowCount >= maxDirectionalShadowCount || light.shadows == LightShadows.None || light.shadowStrength <= 0f || cullingResults.GetShadowCasterBounds(visibleLightIndex, out Bounds bouds) == false) { return(Vector3.zero); } LightBakingOutput lightBakingOutput = light.bakingOutput; if (lightBakingOutput.lightmapBakeType == LightmapBakeType.Mixed && lightBakingOutput.mixedLightingMode == MixedLightingMode.Shadowmask) { useShadowMask = true; } directionalShadows[currentDirectionalLightShadowCount] = new DirectionalShadow() { visibleLightIndex = visibleLightIndex, slopeScaleBias = light.shadowBias, nearPlaneOffset = light.shadowNearPlane }; return(new Vector3(light.shadowStrength, shadowSettings.DirectionalShadowSetting.CascadeCount * currentDirectionalLightShadowCount++, light.shadowNormalBias)); }
static void ApplyRendererInfo(RendererInfo[] infos, int lightmapOffsetIndex, LightInfo[] lightsInfo) { for (int i = 0; i < infos.Length; i++) { var info = infos[i]; if (info.renderer != null) { info.renderer.lightmapIndex = info.lightmapIndex + lightmapOffsetIndex; info.renderer.lightmapScaleOffset = info.lightmapOffsetScale; } } for (int i = 0; i < lightsInfo.Length; i++) { LightBakingOutput bakingOutput = new LightBakingOutput { isBaked = true, lightmapBakeType = (LightmapBakeType)lightsInfo[i].lightmapBaketype, mixedLightingMode = (MixedLightingMode)lightsInfo[i].mixedLightingMode }; lightsInfo[i].light.bakingOutput = bakingOutput; } }
public Vector4 ReserveOtherShadows(Light light, int visibleLightIndex) { if (light.shadows != LightShadows.None && light.shadowStrength > 0f) { LightBakingOutput lightBaking = light.bakingOutput; // But because their range is limited it is possible for multiple lights to use the same channel, as long as they don't overlap. //Thus the shadow mask can support an arbitrary amount of lights, but only up to four per texel. If multiple lights end up overlapping //while trying to claim the same channel then the least important lights will be forced to Baked mode until there is no longer a conflict. //如果灯光太多,会出现多个light取同一个channel,会将不重要的light强制变成baked,也就不会进行计算了 if ( lightBaking.lightmapBakeType == LightmapBakeType.Mixed && lightBaking.mixedLightingMode == MixedLightingMode.Shadowmask ) { useShadowMask = true; return(new Vector4( light.shadowStrength, 0f, 0f, lightBaking.occlusionMaskChannel )); } } return(new Vector4(0f, 0f, 0f, -1f)); }
/// <summary> /// 配置灯光环境 /// </summary> void ConfigureLights() { mainLightExists = false; bool shadowmaskExists = false; bool subtractiveLighting = false; shadowTileCount = 0; for (int i = 0; i < cull.visibleLights.Count; i++) { if (i == maxVisibleLights) //超过最大灯光数量跳出循环 { break; } VisibleLight light = cull.visibleLights[i]; //visibleLightColors[i] = light.finalColor; Vector4 attenuation = Vector4.zero; attenuation.w = 1; Vector4 shadow = Vector4.zero; LightBakingOutput baking = light.light.bakingOutput; //标识 visibleLightOcclusionMasks[i] = occlusionMasks[baking.occlusionMaskChannel + 1]; if (baking.lightmapBakeType == LightmapBakeType.Mixed) { shadowmaskExists |= baking.mixedLightingMode == MixedLightingMode.Shadowmask; //subtractiveLighting |= baking.mixedLightingMode == MixedLightingMode.Subtractive; if (baking.mixedLightingMode == MixedLightingMode.Subtractive) { subtractiveLighting = true; //设置的颜色设置进去 cameraBuffer.SetGlobalColor(subtractiveShadowColorId, RenderSettings.subtractiveShadowColor); } } if (light.lightType == LightType.Directional) { Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightDirectionsOrPositions[i] = v; shadow = ConfigureShadows(i, light.light); shadow.z = 1f; //标识处理方向光 if (i == 0 && shadow.x > 0f && shadowCascades > 0) { mainLightExists = true; shadowTileCount -= 1; } } else { visibleLightDirectionsOrPositions[i] = light.localToWorld.GetColumn(3); //获取点光源位置 attenuation.x = 1f / Mathf.Max(light.range * light.range, 0.00001f); if (light.lightType == LightType.Spot) { Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightSpotDirections[i] = v; float outerRad = Mathf.Deg2Rad * 0.5f * light.spotAngle; float outerCos = Mathf.Cos(outerRad); float outerTan = Mathf.Tan(outerRad); float innerCos = Mathf.Cos(Mathf.Atan(((64f - 18f) / 64f) * outerTan)); float angleRange = Mathf.Max(innerCos - outerCos, 0.001f); attenuation.z = 1f / angleRange; attenuation.w = -outerCos * attenuation.z; //阴影 //Light shadowLight = light.light; //Bounds shadowBounds; //if (shadowLight.shadows != LightShadows.None && cull.GetShadowCasterBounds(i, out shadowBounds)) //{ // shadowTileCount += 1; // shadow.x = shadowLight.shadowStrength; //x分量存阴影强度 // shadow.y = shadowLight.shadows == LightShadows.Soft ? 1f : 0f; //} shadow = ConfigureShadows(i, light.light); } else { visibleLightSpotDirections[i] = Vector4.one; } } visibleLightColors[i] = light.finalColor; visibleLightAttenuations[i] = attenuation; shadowData[i] = shadow; } bool useDistanceShadowmask = QualitySettings.shadowmaskMode == ShadowmaskMode.DistanceShadowmask; //是否存在shadowMask CoreUtils.SetKeyword(cameraBuffer, shadowmaskKeyword, shadowmaskExists && !useDistanceShadowmask); CoreUtils.SetKeyword(cameraBuffer, subtractiveLightingKeyword, subtractiveLighting); CoreUtils.SetKeyword(cameraBuffer, distanceShadowmask, shadowmaskExists && useDistanceShadowmask); //for (; i < maxVisibleLights; i++) //还原清除后面灯光颜色(0,0,0,0) //{ // visibleLightColors[i] = Color.clear; //} //告诉Unity 超出最大灯光数量的索引设置为-1使其不起作用 if (mainLightExists || cull.visibleLights.Count > maxVisibleLights) { int[] lightIndices = cull.GetLightIndexMap(); if (mainLightExists) { lightIndices[0] = -1; } for (int i = maxVisibleLights; i < cull.visibleLights.Count; i++) { lightIndices[i] = -1; } cull.SetLightIndexMap(lightIndices); } }
void ConfigureLights() { mainLightExists = false; shadowTileCount = 0; bool shadowmaskExists = false; for (int i = 0; i < cull.visibleLights.Length; i++) { if (i == maxVisibleLights) { break; } VisibleLight light = cull.visibleLights[i]; visibleLightColors[i] = light.finalColor; Vector4 attenuation = Vector4.zero; attenuation.w = 1f; Vector4 shadow = Vector4.zero; // shadowmask ? LightBakingOutput baking = light.light.bakingOutput; visibleLightOcclusionMasks[i] = occlusionMasks[baking.occlusionMaskChannel + 1]; if (baking.lightmapBakeType == LightmapBakeType.Mixed) { shadowmaskExists |= baking.mixedLightingMode == MixedLightingMode.Shadowmask; } if (light.lightType == LightType.Directional) { Vector4 v = light.localToWorldMatrix.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightDirectionsOrPositions[i] = v; shadow = ConfigureShadows(i, light.light); shadow.z = 1f;// flag if (i == 0 && shadow.x > 0f && shadowCascades > 0) { mainLightExists = true; shadowTileCount -= 1; } } else { visibleLightDirectionsOrPositions[i] = light.localToWorldMatrix.GetColumn(3); attenuation.x = 1f / Mathf.Max(light.range * light.range, 0.00001f); if (light.lightType == LightType.Spot) { Vector4 v = light.localToWorldMatrix.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightSpotDirections[i] = v; float outerRad = Mathf.Deg2Rad * 0.5f * light.spotAngle; float outerCos = Mathf.Cos(outerRad); float outerTan = Mathf.Tan(outerRad); float innerCos = Mathf.Cos(Mathf.Atan((46f / 64f) * outerTan)); float angleRange = Mathf.Max(innerCos - outerCos, 0.001f); attenuation.z = 1f / angleRange; attenuation.w = -outerCos * attenuation.z; shadow = ConfigureShadows(i, light.light); } else { visibleLightSpotDirections[i] = Vector4.one; } } visibleLightAttenuations[i] = attenuation; shadowData[i] = shadow; } // shadowmask bool useDistanceShadowmask = QualitySettings.shadowmaskMode == ShadowmaskMode.DistanceShadowmask; CoreUtils.SetKeyword(cameraBuffer, shadowmaskKeyword, shadowmaskExists && !useDistanceShadowmask); CoreUtils.SetKeyword(cameraBuffer, distanceShadowmaskKeyword, shadowmaskExists && useDistanceShadowmask); if (mainLightExists || cull.visibleLights.Length > maxVisibleLights) { NativeArray <int> lightIndices = cull.GetLightIndexMap(Allocator.Temp); if (mainLightExists) { lightIndices[0] = -1; } for (int i = maxVisibleLights; i < cull.visibleLights.Length; i++) { lightIndices[i] = -1; } cull.SetLightIndexMap(lightIndices); } }
private void ConfigureLights() { mainLightExists = false; bool shadowmaskExists = false; bool subtractiveLighting = false; shadowTileCount = 0; for (int i = 0; i < cullingResults.visibleLights.Length; i++) { if (i == maxVisibleLights) { break; } VisibleLight light = cullingResults.visibleLights[i]; // finalColor字段存储了光源的颜色,该颜色数据是由光源的color属性和intensity属性相乘后的结果,并经过了颜色空间的校正。 visibleLightColors[i] = light.finalColor; Vector4 attenuation = Vector4.zero; attenuation.w = 1f; // 为了保证不同类型的光照计算的一致性(用同样的shader代码),将w分量设置为1。 Vector4 shadow = Vector4.zero; LightBakingOutput baking = light.light.bakingOutput; // 有四种可能的掩码,我们可以在静态数组(occlusionMasks)中预定义。 // 但也有可能有些灯光不使用阴影遮罩。我们将通过将第一个遮罩组件设置为-1来指示这一点。 // 如果灯光不使用阴影遮罩,则通道为-1,因此在检索预定义的 occlusionMasks 时+1。 visibleLightOcclusionMasks[i] = occlusionMasks[baking.occlusionMaskChannel + 1]; if (baking.lightmapBakeType == LightmapBakeType.Mixed) { shadowmaskExists |= baking.mixedLightingMode == MixedLightingMode.Shadowmask; // 判读是否存在烘培阴影。 if (baking.mixedLightingMode == MixedLightingMode.Subtractive) { subtractiveLighting = true; cameraBuffer.SetGlobalColor(subtractiveShadowColorId, UnityEngine.RenderSettings.subtractiveShadowColor.linear); } } if (light.lightType == LightType.Directional) { // 方向光的光源方向信息可以通过光源的旋转信息获得,光源的方向是它的z轴方向。 // 我们可以通过VisibleLight.localToWorldMatrix矩阵获取在世界坐标系中的该信息。这个矩阵的第三列定义了光源的本地Z轴方向。 Vector4 v = light.localToWorldMatrix.GetColumn(2); // 在shader中我们使用从物体朝向光源的向量方向进行计算,所以将获得的光源方向进行取反操作。 v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightDirectionsOrPositions[i] = v; // 设置阴影。 shadow = ConfigureShadows(i, light.light); shadow.z = 1f; // 用阴影数据的z分量来区分是方向光还是聚光灯。 if (i == 0 && shadow.x > 0f && ShadowCascades > 0) { mainLightExists = true; // 我们会为主光源提供单独的渲染贴图,所以当我们拥有主光源时,让图块计数减1, // 并且在RenderShadows函数中将其从常规阴影贴图渲染中排除。 shadowTileCount -= 1; } } else if (light.lightType == LightType.Point || light.lightType == LightType.Spot) { // 点光源不关心光的方向而关心光源的位置。这个矩阵的第四列定义了光源的世界位置。 visibleLightDirectionsOrPositions[i] = light.localToWorldMatrix.GetColumn(3); attenuation.x = 1f / Mathf.Max(light.range * light.range, 0.00001f); if (light.lightType == LightType.Spot) { // 聚光灯的光源方向。 Vector4 v = light.localToWorldMatrix.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightSpotDirections[i] = v; // 聚光灯的衰减。 float outerRad = Mathf.Deg2Rad * 0.5f * light.spotAngle; float outerCos = Mathf.Cos(outerRad); float outerTan = Mathf.Tan(outerRad); float innerCos = Mathf.Cos(Mathf.Atan(((46f / 64f) * outerTan))); float angleRange = Mathf.Max(innerCos - outerCos, 0.001f); attenuation.z = 1f / angleRange; attenuation.w = -outerCos * attenuation.z; // 设置阴影。 shadow = ConfigureShadows(i, light.light); } else { visibleLightSpotDirections[i] = Vector4.one; } } // 填充点光源或聚光灯的光照范围。 visibleLightAttenuations[i] = attenuation; shadowData[i] = shadow; } cameraBuffer.SetGlobalVectorArray(visibleLightColorsId, visibleLightColors); cameraBuffer.SetGlobalVectorArray(visibleLightDirectionsOrPositionsId, visibleLightDirectionsOrPositions); cameraBuffer.SetGlobalVectorArray(visibleLightAttenuationsId, visibleLightAttenuations); // 点光源。 cameraBuffer.SetGlobalVectorArray(visibleLightSpotDirectionsId, visibleLightSpotDirections); // 聚光灯。 cameraBuffer.SetGlobalVectorArray(visibleLightOcclusionMasksId, visibleLightOcclusionMasks); // 尽管目前我们已经支持到场景中最多16个光源,但是依然无法避免有可能会存在更多光源的情况。 // 当超出时,我们需要告诉Unity需要将一些光源舍弃以避免数组的越界。 // 如果主光源存在,在渲染前将主光源移出可见光列表,以防止在shader中计算多次(会导致像素光数量上限变成5个)。 if (mainLightExists || cullingResults.visibleLights.Length > maxVisibleLights) { var lightIndexs = cullingResults.GetLightIndexMap(Unity.Collections.Allocator.TempJob); if (mainLightExists) { lightIndexs[0] = -1; } for (int i = maxVisibleLights; i < cullingResults.visibleLights.Length; i++) { lightIndexs[i] = -1; } cullingResults.SetLightIndexMap(lightIndexs); lightIndexs.Dispose(); } bool useDistanceShadowmask = QualitySettings.shadowmaskMode == ShadowmaskMode.DistanceShadowmask; CoreUtils.SetKeyword(cameraBuffer, shadowmaskKeyword, shadowmaskExists && !useDistanceShadowmask); CoreUtils.SetKeyword(cameraBuffer, distanceShadowmaskKeyword, shadowmaskExists && useDistanceShadowmask); CoreUtils.SetKeyword(cameraBuffer, subtractiveLightingKeyword, subtractiveLighting); }
void ConfigureLights() { mainLightExists = false; bool shadowmaskExists = false; bool subtractiveLighting = false; shadowTileCount = 0; for (int i = 0; i < cull.visibleLights.Count; i++) { if (i == maxVisibleLights) { break; } VisibleLight light = cull.visibleLights[i]; visibleLightColors[i] = light.finalColor; Vector4 attenuation = Vector4.zero; attenuation.w = 1f; Vector4 shadow = Vector4.zero; LightBakingOutput baking = light.light.bakingOutput; visibleLightOcclusionMasks[i] = occlusionMasks[baking.occlusionMaskChannel + 1]; if (baking.lightmapBakeType == LightmapBakeType.Mixed) { shadowmaskExists |= baking.mixedLightingMode == MixedLightingMode.Shadowmask; //subtractiveLighting |= // baking.mixedLightingMode == MixedLightingMode.Subtractive; if (baking.mixedLightingMode == MixedLightingMode.Subtractive) { subtractiveLighting = true; cameraBuffer.SetGlobalColor( subtractiveShadowColorId, RenderSettings.subtractiveShadowColor.linear ); } } if (light.lightType == LightType.Directional) { //因为要求出光源的朝向,相当于要知道光源transform.forward,矩阵第三列是光源z轴在世界坐标系下表示,也就是forward Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightDirectionsOrPositions[i] = v; shadow = ConfigureShadows(i, light.light); shadow.z = 1f; if (i == 0 && shadow.x > 0f && shadowCascades > 0) { mainLightExists = true; shadowTileCount -= 1; } } else { //第四列是光源原点在世界坐标系中的位置 visibleLightDirectionsOrPositions[i] = light.localToWorld.GetColumn(3); attenuation.x = 1f / Mathf.Max(light.range * light.range, 0.00001f); if (light.lightType == LightType.Spot) { Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; //存储spot光源方向 visibleLightSpotDirections[i] = v; float outerRad = Mathf.Deg2Rad * 0.5f * light.spotAngle; float outerCos = Mathf.Cos(outerRad); float outerTan = Mathf.Tan(outerRad); float innerCos = Mathf.Cos(Mathf.Atan(((46f / 64f) * outerTan))); float angleRange = Mathf.Max(innerCos - outerCos, 0.001f); attenuation.z = 1f / angleRange; attenuation.w = -outerCos * attenuation.z; shadow = ConfigureShadows(i, light.light); //Light shadowLight = light.light; //Bounds shadowBounds; //if (shadowLight.shadows != LightShadows.None && cull.GetShadowCasterBounds(i, out shadowBounds)) //{ // shadowTileCount += 1; // shadow.x = shadowLight.shadowStrength; // shadow.y = shadowLight.shadows == LightShadows.Soft ? 1f : 0f; //} } else { visibleLightSpotDirections[i] = Vector4.one; } } visibleLightAttenuations[i] = attenuation; shadowData[i] = shadow; } bool useDistanceShadowmask = QualitySettings.shadowmaskMode == ShadowmaskMode.DistanceShadowmask; CoreUtils.SetKeyword(cameraBuffer, shadowmaskKeyword, shadowmaskExists && !useDistanceShadowmask); CoreUtils.SetKeyword( cameraBuffer, distanceShadowmaskKeyword, shadowmaskExists && useDistanceShadowmask ); CoreUtils.SetKeyword(cameraBuffer, subtractiveLightingKeyword, subtractiveLighting); //如果超过maxVisibleLights数量的灯光,该脚本不会传输给Shader //但是Unity自身可能会对超出maxVisibleLights的灯光,进行unity_4LightIndices0赋值,下标会找不到,_VisibleLightColors越界 if (mainLightExists || cull.visibleLights.Count > maxVisibleLights) { int[] lightIndices = cull.GetLightIndexMap(); if (mainLightExists) { lightIndices[0] = -1; } for (int i = maxVisibleLights; i < cull.visibleLights.Count; i++) { lightIndices[i] = -1; } cull.SetLightIndexMap(lightIndices); } }
public static void RefreshScene(Scene scene, ftLightmapsStorage storage = null, bool updateNonBaked = false) { var sceneCount = SceneManager.sceneCount; if (globalMapsAdditional == null) { globalMapsAdditional = new List <LightmapAdditionalData>(); } var lmaps = new List <LightmapData>(); var lmapsAdditional = new List <LightmapAdditionalData>(); var existingLmaps = LightmapSettings.lightmaps; var existingLmapsAdditional = globalMapsAdditional; // Acquire storage if (storage == null) { if (!scene.isLoaded) { //Debug.LogError("dbg: Scene not loaded"); return; } SceneManager.SetActiveScene(scene); var go = FindInScene("!ftraceLightmaps", scene); if (go == null) { //Debug.LogError("dbg: no storage"); return; } storage = go.GetComponent <ftLightmapsStorage>(); if (storage == null) { //Debug.LogError("dbg: no storage 2"); return; } } if (storage.idremap == null || storage.idremap.Length != storage.maps.Count) { storage.idremap = new int[storage.maps.Count]; } // Decide which global engine lightmapping mode to use // TODO: allow mixing different modes directionalMode = storage.dirMaps.Count != 0; bool patchedDirection = false; LightmapSettings.lightmapsMode = directionalMode ? LightmapsMode.CombinedDirectional : LightmapsMode.NonDirectional; // Set dummy directional tex for non-directional lightmaps in directional mode if (directionalMode) { for (int i = 0; i < existingLmaps.Length; i++) { if (directionalMode && existingLmaps[i].lightmapDir == null) { var lm = existingLmaps[i]; lm.lightmapDir = GetEmptyDirectionTex(storage); existingLmaps[i] = lm; patchedDirection = true; } } } // Detect if changes to lightmap array are necessary bool sameArray = false; if (existingLmaps.Length == storage.maps.Count) { sameArray = true; for (int i = 0; i < storage.maps.Count; i++) { if (existingLmaps[i].lightmapColor != storage.maps[i]) { sameArray = false; break; } if (storage.rnmMaps0.Count > i && (existingLmapsAdditional.Count <= i || existingLmapsAdditional[i].rnm0 != storage.rnmMaps0[i])) { sameArray = false; break; } } } if (!sameArray) // create new lightmap array { if (sceneCount >= 1) { // first add old for (int i = 0; i < existingLmaps.Length; i++) { // skip empty lightmaps (can be created by 5.6 ldata asset or vertex color) // ... unless there are valid lightmaps around them bool lightmapIsEmpty = existingLmaps[i] == null || (existingLmaps[i].lightmapColor == null && existingLmaps[i].shadowMask == null); bool lightmapCanBeSkipped = lightmapIsEmpty && (i == 0 || i == existingLmaps.Length - 1); if (!lightmapCanBeSkipped) { lmaps.Add(existingLmaps[i]); if (existingLmapsAdditional.Count > i) { lmapsAdditional.Add(existingLmapsAdditional[i]); } } } } for (int i = 0; i < storage.maps.Count; i++) { var texlm = storage.maps[i]; Texture2D texmask = null; Texture2D texdir = null; Texture2D texrnm0 = null; Texture2D texrnm1 = null; Texture2D texrnm2 = null; int mapMode = 0; if (storage.masks.Count > i) { texmask = storage.masks[i]; } if (storage.dirMaps.Count > i) { texdir = storage.dirMaps[i]; } if (storage.rnmMaps0.Count > i) { texrnm0 = storage.rnmMaps0[i]; texrnm1 = storage.rnmMaps1[i]; texrnm2 = storage.rnmMaps2[i]; mapMode = storage.mapsMode[i]; } bool found = false; int firstEmpty = -1; for (int j = 0; j < lmaps.Count; j++) { if (lmaps[j].lightmapColor == texlm && lmaps[j].shadowMask == texmask) { // lightmap already added - reuse storage.idremap[i] = j; found = true; //Debug.LogError("reused "+j); // additional maps array could be flushed due to script recompilation - recover if (texrnm0 != null && (lmapsAdditional.Count <= j || lmapsAdditional[j].rnm0 == null)) { while (lmapsAdditional.Count <= j) { lmapsAdditional.Add(new LightmapAdditionalData()); } var l = new LightmapAdditionalData(); l.rnm0 = texrnm0; l.rnm1 = texrnm1; l.rnm2 = texrnm2; l.mode = mapMode; lmapsAdditional[j] = l; } break; } else if (firstEmpty < 0 && lmaps[j].lightmapColor == null && lmaps[j].shadowMask == null) { // free (deleted) entry in existing lightmap list - possibly reuse storage.idremap[i] = j; firstEmpty = j; } } if (!found) { LightmapData lm; if (firstEmpty >= 0) { lm = lmaps[firstEmpty]; } else { lm = new LightmapData(); } lm.lightmapColor = texlm; if (storage.masks.Count > i) { lm.shadowMask = texmask; } if (storage.dirMaps.Count > i && texdir != null) { lm.lightmapDir = texdir; } else if (directionalMode) { lm.lightmapDir = GetEmptyDirectionTex(storage); } if (firstEmpty < 0) { lmaps.Add(lm); storage.idremap[i] = lmaps.Count - 1; } else { lmaps[firstEmpty] = lm; } if (storage.rnmMaps0.Count > i) { var l = new LightmapAdditionalData(); l.rnm0 = texrnm0; l.rnm1 = texrnm1; l.rnm2 = texrnm2; l.mode = mapMode; if (firstEmpty < 0) { //Debug.LogError("added "+(lmaps.Count-1)); while (lmapsAdditional.Count < lmaps.Count - 1) { lmapsAdditional.Add(new LightmapAdditionalData()); } lmapsAdditional.Add(l); } else { //Debug.LogError("set " + firstEmpty); while (lmapsAdditional.Count < firstEmpty + 1) { lmapsAdditional.Add(new LightmapAdditionalData()); } lmapsAdditional[firstEmpty] = l; } } } } } else // reuse existing lightmap array, only remap IDs { for (int i = 0; i < storage.maps.Count; i++) { storage.idremap[i] = i; //Debug.LogError("full reuse"); /*if (storage.rnmMaps0.Count > i) * { * var l = new LightmapAdditionalData(); * l.rnm0 = storage.rnmMaps0[i]; * l.rnm1 = storage.rnmMaps1[i]; * l.rnm2 = storage.rnmMaps2[i]; * l.mode = storage.mapsMode[i]; * lmapsAdditional.Add(l); * }*/ } } #if UNITY_EDITOR // Set editor lighting mode Lightmapping.giWorkflowMode = Lightmapping.GIWorkflowMode.OnDemand; Lightmapping.realtimeGI = storage.usesRealtimeGI; Lightmapping.bakedGI = true; #endif // Replace the lightmap array if needed if (sameArray && patchedDirection) { LightmapSettings.lightmaps = existingLmaps; } if (!sameArray) { LightmapSettings.lightmaps = lmaps.ToArray(); globalMapsAdditional = lmapsAdditional; } /* * // Debug * var lms = LightmapSettings.lightmaps; * for(int i=0; i<lms.Length; i++) * { * var name1 = ((lms[i]==null || lms[i].lightmapColor==null) ? "-" : lms[i].lightmapColor.name); * var name2 = (globalMapsAdditional.Count > i ?(globalMapsAdditional[i].rnm0==null?"x":globalMapsAdditional[i].rnm0.name) : "-"); * Debug.LogError(i+" "+name1+" "+name2); * } */ // Attempt to update skybox probe if (RenderSettings.ambientMode == UnityEngine.Rendering.AmbientMode.Skybox)// && Lightmapping.lightingDataAsset == null) { var probe = RenderSettings.ambientProbe; int isEmpty = -1; for (int i = 0; i < 3; i++) { for (int j = 0; j < 9; j++) { // default bugged probes are [almost] black or 1302? float a = Mathf.Abs(probe[i, j]); if (a > 1000.0f || a < 0.000001f) { isEmpty = 1; break; } if (probe[i, j] != 0) { isEmpty = 0; break; } } if (isEmpty >= 0) { break; } } if (isEmpty != 0) { DynamicGI.UpdateEnvironment(); } } // Set lightmap data on mesh renderers var emptyVec4 = new Vector4(1, 1, 0, 0); for (int i = 0; i < storage.bakedRenderers.Count; i++) { var r = storage.bakedRenderers[i]; if (r == null) { continue; } //if (r.isPartOfStaticBatch) continue; var id = storage.bakedIDs[i]; Mesh vmesh = null; if (i < storage.bakedVertexColorMesh.Count) { vmesh = storage.bakedVertexColorMesh[i]; } if (vmesh != null) { r.additionalVertexStreams = vmesh; r.lightmapIndex = 0xFFFF; var prop = new MaterialPropertyBlock(); prop.SetFloat("bakeryLightmapMode", 1); r.SetPropertyBlock(prop); continue; } int globalID = (id < 0 || id >= storage.idremap.Length) ? id : storage.idremap[id]; r.lightmapIndex = globalID; if (!r.isPartOfStaticBatch) { // scaleOffset is baked on static batches already var scaleOffset = id < 0 ? emptyVec4 : storage.bakedScaleOffset[i]; r.lightmapScaleOffset = scaleOffset; } if (r.lightmapIndex >= 0 && globalID < globalMapsAdditional.Count) { var lmap = globalMapsAdditional[globalID]; if (lmap.rnm0 != null) { var prop = new MaterialPropertyBlock(); prop.SetTexture("_RNM0", lmap.rnm0); prop.SetTexture("_RNM1", lmap.rnm1); prop.SetTexture("_RNM2", lmap.rnm2); prop.SetFloat("bakeryLightmapMode", lmap.mode); r.SetPropertyBlock(prop); } } } // Set lightmap data on definitely-not-baked mesh renderers (can be possibly avoided) if (updateNonBaked) { for (int i = 0; i < storage.nonBakedRenderers.Count; i++) { var r = storage.nonBakedRenderers[i]; if (r == null) { continue; } if (r.isPartOfStaticBatch) { continue; } r.lightmapIndex = 0xFFFE; } } // Set lightmap data on terrains for (int i = 0; i < storage.bakedRenderersTerrain.Count; i++) { var r = storage.bakedRenderersTerrain[i]; if (r == null) { continue; } var id = storage.bakedIDsTerrain[i]; r.lightmapIndex = (id < 0 || id >= storage.idremap.Length) ? id : storage.idremap[id]; var scaleOffset = id < 0 ? emptyVec4 : storage.bakedScaleOffsetTerrain[i]; r.lightmapScaleOffset = scaleOffset; } // Set shadowmask parameters on lights for (int i = 0; i < storage.bakedLights.Count; i++) { #if UNITY_2017_3_OR_NEWER var output = new LightBakingOutput(); output.isBaked = true; output.lightmapBakeType = LightmapBakeType.Mixed; output.mixedLightingMode = MixedLightingMode.Shadowmask; output.occlusionMaskChannel = storage.bakedLightChannels[i]; output.probeOcclusionLightIndex = storage.bakedLights[i].bakingOutput.probeOcclusionLightIndex; storage.bakedLights[i].bakingOutput = output; //#else //var light = storage.bakedLights[i]; #endif } // Increment lightmap refcounts if (lightmapRefCount == null) { lightmapRefCount = new List <int>(); } for (int i = 0; i < storage.idremap.Length; i++) { int currentID = storage.idremap[i]; while (lightmapRefCount.Count <= currentID) { lightmapRefCount.Add(0); } if (lightmapRefCount[currentID] < 0) { lightmapRefCount[currentID] = 0; } lightmapRefCount[currentID]++; } //if (loadedStorages == null) loadedStorages = new List<ftLightmapsStorage>(); //if (loadedStorages.Contains(storage)) loadedStorages.Add(storage); //return appendOffset; }
void ConfigureLights() { mainLightExist = false; bool shadowmaskExists = false; bool subtractiveLighting = false; shadowTileCount = 0; for (int i = 0; i < cull.visibleLights.Count; i++) { if (i == maxVisibleLights) { break; } VisibleLight light = cull.visibleLights[i]; visibleLightColors[i] = light.finalColor; Vector4 attenuation = Vector4.zero; attenuation.w = 1f; Vector4 shadow = Vector4.zero; LightBakingOutput baking = light.light.bakingOutput; visibleLightOcclusionMasks[i] = occlusionMasks[baking.occlusionMaskChannel + 1]; if (baking.lightmapBakeType == LightmapBakeType.Mixed) { shadowmaskExists |= baking.mixedLightingMode == MixedLightingMode.Shadowmask; if (baking.mixedLightingMode == MixedLightingMode.Subtractive) { subtractiveLighting = true; cameraBuffer.SetGlobalColor(subtractiveShadowColorID, RenderSettings.subtractiveShadowColor.linear); } } if (light.lightType == LightType.Directional) { Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightDirectionsOrPositions[i] = v; shadow = ConfigureShadows(i, light.light); shadow.z = 1f; if (i == 0 && shadow.x > 0f && shadowCascades > 0) { mainLightExist = true; shadowTileCount -= 1; } } else { visibleLightDirectionsOrPositions[i] = light.localToWorld.GetColumn(3); attenuation.x = 1f / Mathf.Max(light.range * light.range, 0.00001f); if (light.lightType == LightType.Spot) { Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightSpotDirections[i] = v; float outerAngle = Mathf.Deg2Rad * light.spotAngle; float outerCos = Mathf.Cos(outerAngle * 0.5f); float innerAngle = 2.0f * Mathf.Atan(Mathf.Tan(outerAngle * 0.5f) * (64.0f - 18.0f) / 64.0f); float innerCos = Mathf.Cos(innerAngle * 0.5f); float angleRange = Mathf.Max(0.001f, innerCos - outerCos); attenuation.z = 1.0f / angleRange; attenuation.w = -outerCos * attenuation.z; Light shadowLight = light.light; shadow = ConfigureShadows(i, shadowLight); } else { visibleLightSpotDirections[i] = Vector4.one; } } visibleLightAttenuations[i] = attenuation; shadowData[i] = shadow; } bool useDistanceShadowmask = QualitySettings.shadowmaskMode == ShadowmaskMode.DistanceShadowmask; CoreUtils.SetKeyword(cameraBuffer, shadowmaskKeyword, shadowmaskExists && !useDistanceShadowmask); CoreUtils.SetKeyword(cameraBuffer, distanceShadowmaskKeyword, shadowmaskExists && useDistanceShadowmask); CoreUtils.SetKeyword(cameraBuffer, subtractiveLightingKeyword, subtractiveLighting); if (mainLightExist || cull.visibleLights.Count > maxVisibleLights) { int[] lightIndices = cull.GetLightIndexMap(); if (mainLightExist) { lightIndices[0] = -1; } for (int i = maxVisibleLights; i < cull.visibleLights.Count; i++) { lightIndices[i] = -1; } cull.SetLightIndexMap(lightIndices); } }
private void ConfigureLights() { mainLightExists = false; bool shadowmaskExists = false; bool subtractiveLighting = false; shadowTileCount = 0; for (int i = 0; i < cull.visibleLights.Count && i < maxVisibleLights; i++) { VisibleLight light = cull.visibleLights[i]; visibleLightColors[i] = light.finalColor; Vector4 attenuation = Vector4.zero; attenuation.w = 1f; Vector4 shadow = Vector4.zero; LightBakingOutput baking = light.light.bakingOutput; visibleLightOcclusionMasks[i] = occlusionMasks[baking.occlusionMaskChannel + 1]; if (baking.lightmapBakeType == LightmapBakeType.Mixed) { shadowmaskExists |= baking.mixedLightingMode == MixedLightingMode.Shadowmask; if (baking.mixedLightingMode == MixedLightingMode.Subtractive) { subtractiveLighting = true; cameraBuffer.SetGlobalColor(subtractiveShadowColorID, RenderSettings.subtractiveShadowColor.linear); } } if (light.lightType == LightType.Directional) { //光线按照局部Z轴照射 第三列是Z轴旋转 Vector4 v = light.localToWorld.GetColumn(2); //在shader中 我们需要的光的方向是 从表面到光的 所以要求反 //第四个分量总是零 只用对 x y z 求反 v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightDirectionsOrPositions[i] = v; shadow = ConfigureShadows(i, light.light); //z=1 是方向光 shadow.z = 1f; if (i == 0 && shadow.x > 0f && shadowCascades > 0) { mainLightExists = true; shadowTileCount -= 1; } } else { //第三个储存的是位置 w是1 visibleLightDirectionsOrPositions[i] = light.localToWorld.GetColumn(3); attenuation.x = 1f / Mathf.Max(light.range * light.range, 0.000001f); if (light.lightType == LightType.Spot) { //聚光灯需要 方向 拿Z轴 即矩阵第三行 Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightSpotDirections[i] = v; float outerRad = Mathf.Deg2Rad * 0.5f * light.spotAngle; //灯光角的一半 外面不显示 float outerCos = Mathf.Cos(outerRad); //内圈 不衰减 float outerTan = Mathf.Tan(outerRad); //外圈衰减 float innerCos = Mathf.Cos(Mathf.Atan(((64f - 18f) / 64f) * outerTan)); float angleRange = Mathf.Max(innerCos - outerCos, 0.0001f); attenuation.z = 1f / angleRange; attenuation.w = -outerCos * attenuation.z; shadow = ConfigureShadows(i, light.light); } else { visibleLightSpotDirections[i] = Vector4.one; } } visibleLightAttenuations[i] = attenuation; shadowData[i] = shadow; } bool useDistanceShadowmask = QualitySettings.shadowmaskMode == ShadowmaskMode.DistanceShadowmask; CoreUtils.SetKeyword(cameraBuffer, shadowmaskKeyword, shadowmaskExists && !useDistanceShadowmask); CoreUtils.SetKeyword(cameraBuffer, distanceShadowmaskKeyword, shadowmaskExists && useDistanceShadowmask); CoreUtils.SetKeyword(cameraBuffer, subtractiveLightingKeyword, subtractiveLighting); //剔除额外的光 和 主光源 if (mainLightExists || cull.visibleLights.Count > maxVisibleLights) { int[] lightIndices = cull.GetLightIndexMap(); if (mainLightExists) { lightIndices[0] = -1; } for (int i = maxVisibleLights; i < cull.visibleLights.Count; i++) { lightIndices[i] = -1; } cull.SetLightIndexMap(lightIndices); } }
/// <summary> /// 初始化光照相关信息 /// </summary> void ConfigureLights() { mainLightExists = false; bool shadowmaskExists = false; bool subtractiveLighting = false; shadowTileCount = 0; for (int i = 0; i < cull.visibleLights.Count; i++) { if (i == maxVisiableLights) //最多光源数量,超过的忽略不再处理 { break; } var light = cull.visibleLights[i]; visiableLightColors[i] = light.finalColor; Vector4 attenuation = Vector4.zero; attenuation.w = 1f; //不影响其他光源类型 Vector4 shadow = Vector4.zero; LightBakingOutput baking = light.light.bakingOutput; visibleLightOcclusionMasks[i] = occlusionMasks[baking.occlusionMaskChannel + 1]; if (baking.lightmapBakeType == LightmapBakeType.Mixed) { shadowmaskExists |= baking.mixedLightingMode == MixedLightingMode.Shadowmask; //subtractiveLighting |= baking.mixedLightingMode == MixedLightingMode.Subtractive; if (baking.mixedLightingMode == MixedLightingMode.Subtractive) { subtractiveLighting = true; cameraBuffer.SetGlobalColor(subtractiveShadowColorId, RenderSettings.subtractiveShadowColor.linear); } } if (light.lightType == LightType.Directional) { Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visiableLightDirectionsOrPositions[i] = v; shadow = ConfigureShadows(i, light.light); shadow.z = 1f; if (i == 0 && shadow.x > 0f && shadowCascades > 0) { mainLightExists = true; shadowTileCount -= 1; } } else { //光源的位置 visiableLightDirectionsOrPositions[i] = light.localToWorld.GetColumn(3); attenuation.x = 1f / Mathf.Max(light.range * light.range, 0.00001f); if (light.lightType == LightType.Spot) { Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visiableLightSpotDirections[i] = v; float outerRad = Mathf.Deg2Rad * 0.5f * light.spotAngle; float outerCos = Mathf.Cos(outerRad); float outerTan = Mathf.Tan(outerRad); float innerCos = Mathf.Cos(Mathf.Atan((46f / 64f) * outerTan)); float angleRange = Mathf.Max(innerCos - outerCos, 0.0001f); attenuation.z = 1f / angleRange; attenuation.w = -outerCos * attenuation.z; shadow = ConfigureShadows(i, light.light); } else { //Point Light visiableLightSpotDirections[i] = Vector4.one; } } visiableLightAttenuations[i] = attenuation; shadowData[i] = shadow; } bool useDistanceShadowmaks = QualitySettings.shadowmaskMode == ShadowmaskMode.DistanceShadowmask; CoreUtils.SetKeyword(cameraBuffer, shadowmaskKeyword, shadowmaskExists && !useDistanceShadowmaks); CoreUtils.SetKeyword(cameraBuffer, distanceShadowMaskKeyword, shadowmaskExists && useDistanceShadowmaks); CoreUtils.SetKeyword(cameraBuffer, subtractiveLightingKeyword, subtractiveLighting); //超过最大光源个数限制时,设置为-1的灯(不存在的灯) if (mainLightExists || cull.visibleLights.Count > maxVisiableLights) { int[] lightIndices = cull.GetLightIndexMap(); if (mainLightExists) { lightIndices[0] = -1; } for (int i = maxVisiableLights; i < cull.visibleLights.Count; i++) { lightIndices[i] = -1; } cull.SetLightIndexMap(lightIndices); } }
void ConfigureLights() { mainLightExists = false; bool shadowmaskExists = false; bool subtractiveLighting = false; shadowTileCount = 0; for (int i = 0; i < cull.visibleLights.Count; i++) { if (i == maxVisibleLights) { break; } VisibleLight light = cull.visibleLights[i]; visibleLightColors[i] = light.finalColor; Vector4 attenuation = Vector4.zero; attenuation.w = 1f; //if no spot light, factor =1 Vector4 shadow = Vector4.zero; //shadowmask settings LightBakingOutput baking = light.light.bakingOutput; visibleLightOcclusionMasks[i] = occlusionMasks[baking.occlusionMaskChannel + 1]; if (baking.lightmapBakeType == LightmapBakeType.Mixed) { shadowmaskExists |= baking.mixedLightingMode == MixedLightingMode.Shadowmask; if (baking.mixedLightingMode == MixedLightingMode.Subtractive) { subtractiveLighting = true; cameraBuffer.SetGlobalColor( subtractiveShadowColorId, RenderSettings.subtractiveShadowColor.linear ); } } //light settings if (light.lightType == LightType.Directional) { Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; //change to vector surfaceToLight visibleLightDirectionsOrPositions[i] = v; shadow = ConfigureShadows(i, light.light); shadow.z = 1f; //directional light index =0, cast shadow, use cascades if (i == 0 && shadow.x > 0f && shadowCascades > 0) { mainLightExists = true; shadowTileCount -= 1; //cascaded shadow map is not included in tiled shadow map } } else { visibleLightDirectionsOrPositions[i] = light.localToWorld.GetColumn(3); attenuation.x = 1f / Mathf.Max(light.range * light.range, 0.00001f); if (light.lightType == LightType.Spot) { Vector4 v = light.localToWorld.GetColumn(2); v.x = -v.x; v.y = -v.y; v.z = -v.z; visibleLightSpotDirections[i] = v; float outerRad = Mathf.Deg2Rad * 0.5f * light.spotAngle; float outerCos = Mathf.Cos(outerRad); float outerTan = Mathf.Tan(outerRad); float innerCos = Mathf.Cos(Mathf.Atan(((46f / 64f) * outerTan))); float angleRange = Mathf.Max(innerCos - outerCos, 0.001f); attenuation.z = 1f / angleRange; attenuation.w = -outerCos * attenuation.z; //buffer shadowData shadow = ConfigureShadows(i, light.light); } else { //indicator of pointlight visibleLightSpotDirections[i] = Vector4.one; } } visibleLightAttenuations[i] = attenuation; shadowData[i] = shadow; } //number of lights exceeds upper limit if (mainLightExists || cull.visibleLights.Count > maxVisibleLights) { int[] lightIndices = cull.GetLightIndexMap(); if (mainLightExists) { //remove main light from diffuseLight render, avoid a second render lightIndices[0] = -1; } for (int i = maxVisibleLights; i < cull.visibleLights.Count; i++) { lightIndices[i] = -1; } cull.SetLightIndexMap(lightIndices); } bool useDistanceShadowmask = QualitySettings.shadowmaskMode == ShadowmaskMode.DistanceShadowmask; //enable shadowmask keyword CoreUtils.SetKeyword(cameraBuffer, shadowmaskKeyword, shadowmaskExists && !useDistanceShadowmask); //if use shadowmask mode CoreUtils.SetKeyword(cameraBuffer, distanceShadowmaskKeyword, shadowmaskExists && useDistanceShadowmask); //if use distance shadowmask CoreUtils.SetKeyword(cameraBuffer, subtractiveLightingKeyword, subtractiveLighting); }
/// <summary> /// Read the data into the specified value. /// </summary> /// <param name="value">Value.</param> /// <param name="reader">Reader.</param> public override void ReadInto(object value, ISaveGameReader reader) { UnityEngine.Light light = (UnityEngine.Light)value; foreach (string property in reader.Properties) { switch (property) { case "type": light.type = reader.ReadProperty <UnityEngine.LightType> (); break; case "color": light.color = reader.ReadProperty <UnityEngine.Color> (); break; case "colorTemperature": light.colorTemperature = reader.ReadProperty <System.Single> (); break; case "intensity": light.intensity = reader.ReadProperty <System.Single> (); break; case "bounceIntensity": light.bounceIntensity = reader.ReadProperty <System.Single> (); break; case "shadows": light.shadows = reader.ReadProperty <UnityEngine.LightShadows> (); break; case "shadowStrength": light.shadowStrength = reader.ReadProperty <System.Single> (); break; case "shadowResolution": light.shadowResolution = reader.ReadProperty <UnityEngine.Rendering.LightShadowResolution> (); break; case "shadowCustomResolution": light.shadowCustomResolution = reader.ReadProperty <System.Int32> (); break; case "shadowBias": light.shadowBias = reader.ReadProperty <System.Single> (); break; case "shadowNormalBias": light.shadowNormalBias = reader.ReadProperty <System.Single> (); break; case "shadowNearPlane": light.shadowNearPlane = reader.ReadProperty <System.Single> (); break; case "range": light.range = reader.ReadProperty <System.Single> (); break; case "spotAngle": light.spotAngle = reader.ReadProperty <System.Single> (); break; case "cookieSize": light.cookieSize = reader.ReadProperty <System.Single> (); break; case "cookie": if (light.cookie == null) { light.cookie = reader.ReadProperty <UnityEngine.Texture> (); } else { reader.ReadIntoProperty <UnityEngine.Texture> (light.cookie); } break; case "flare": if (light.flare == null) { light.flare = reader.ReadProperty <UnityEngine.Flare> (); } else { reader.ReadIntoProperty <UnityEngine.Flare> (light.flare); } break; case "renderMode": light.renderMode = reader.ReadProperty <UnityEngine.LightRenderMode> (); break; case "alreadyLightmapped": #if UNITY_2017_3_OR_NEWER LightBakingOutput bakingOutput = light.bakingOutput; bakingOutput.isBaked = reader.ReadProperty <System.Boolean> (); light.bakingOutput = bakingOutput; #else light.alreadyLightmapped = reader.ReadProperty <System.Boolean> (); #endif break; case "cullingMask": light.cullingMask = reader.ReadProperty <System.Int32> (); break; case "enabled": light.enabled = reader.ReadProperty <System.Boolean> (); break; case "tag": light.tag = reader.ReadProperty <System.String> (); break; case "name": light.name = reader.ReadProperty <System.String> (); break; case "hideFlags": light.hideFlags = reader.ReadProperty <UnityEngine.HideFlags> (); break; } } }