Jump to content
Unity Insider Forum

Procedural Skybox mit Texturen


MustafGames

Recommended Posts

Hallo Leute,

 

vorne weg möchte ich sagen ich hab damit zum ersten mal mich mit Shader scripten beschäftigt und kenne mich so gut wie gar nicht damit aus. Folgendes ist passiert, ich hab einfach den built-In Skybox Shader der anhand von 6 Texturen die Skybox erstellt genommen und im Script alle Merkmale die mit den 6 Texturen zu tun haben kopiert. Gleichzeitig habe ich den built-in Procedural-Skybox-Shader kopiert und dort an den entsprechenden Stellen den Code aus dem anderen Shader eingefügt.

 

Der Shader:

 

 

Shader "Own/Procedural" {
Properties{
 [KeywordEnum(None, Simple, High Quality)] _SunDisk("Sun", Int) = 2
 _SunSize("Sun Size", Range(0,1)) = 0.04
 _AtmosphereThickness("Atmoshpere Thickness", Range(0,5)) = 1.0
 _SkyTint("Sky Tint", Color) = (.5, .5, .5, 1)
 _GroundColor("Ground", Color) = (.369, .349, .341, 1)
 _Exposure("Exposure", Range(0, 8)) = 1.3
 _Tint("Tint Color", Color) = (.5, .5, .5, .5)
 [NoScaleOffset] _FrontTex("Front [+Z]   (HDR)", 2D) = "grey" {}
[NoScaleOffset] _BackTex("Back [-Z]   (HDR)", 2D) = "grey" {}
[NoScaleOffset] _LeftTex("Left [+X]   (HDR)", 2D) = "grey" {}
[NoScaleOffset] _RightTex("Right [-X]   (HDR)", 2D) = "grey" {}
[NoScaleOffset] _UpTex("Up [+Y]   (HDR)", 2D) = "grey" {}
[NoScaleOffset] _DownTex("Down [-Y]   (HDR)", 2D) = "grey" {}
}
 SubShader{
 Tags{ "Queue" = "Background" "RenderType" = "Background" "PreviewType" = "Skybox" }
 Cull Off ZWrite Off
 Pass{
 CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
#include "Lighting.cginc"
#pragma multi_compile __ UNITY_COLORSPACE_GAMMA
#pragma multi_compile _SUNDISK_NONE _SUNDISK_SIMPLE _SUNDISK_HIGH_QUALITY
 half4 _Tint;
 uniform half _Exposure;  // HDR exposure
uniform half3 _GroundColor;
uniform half _SunSize;
uniform half3 _SkyTint;
uniform half _AtmosphereThickness;
#if defined(UNITY_COLORSPACE_GAMMA)
#define GAMMA 2
#define COLOR_2_GAMMA(color) color
#define COLOR_2_LINEAR(color) color*color
#define LINEAR_2_OUTPUT(color) sqrt(color)
#else
#define GAMMA 2.2
// HACK: to get gfx-tests in Gamma mode to agree until UNITY_ACTIVE_COLORSPACE_IS_GAMMA is working properly
#define COLOR_2_GAMMA(color) ((unity_ColorSpaceDouble.r>2.0) ? pow(color,1.0/GAMMA) : color)
#define COLOR_2_LINEAR(color) color
#define LINEAR_2_LINEAR(color) color
#endif
// RGB wavelengths
// .35 (.62=158), .43 (.68=174), .525 (.75=190)
static const float3 kDefaultScatteringWavelength = float3(.65, .57, .475);
static const float3 kVariableRangeForScatteringWavelength = float3(.15, .15, .15);
#define OUTER_RADIUS 1.025
static const float kOuterRadius = OUTER_RADIUS;
static const float kOuterRadius2 = OUTER_RADIUS*OUTER_RADIUS;
static const float kInnerRadius = 1.0;
static const float kInnerRadius2 = 1.0;
static const float kCameraHeight = 0.0001;
#define kRAYLEIGH (lerp(0, 0.0025, pow(_AtmosphereThickness,2.5)))  // Rayleigh constant
#define kMIE 0.0010	    // Mie constant
#define kSUN_BRIGHTNESS 20.0  // Sun brightness
#define kMAX_SCATTER 50.0 // Maximum scattering value, to prevent math overflows on Adrenos
static const half kSunScale = 400.0 * kSUN_BRIGHTNESS;
static const float kKmESun = kMIE * kSUN_BRIGHTNESS;
static const float kKm4PI = kMIE * 4.0 * 3.14159265;
static const float kScale = 1.0 / (OUTER_RADIUS - 1.0);
static const float kScaleDepth = 0.25;
static const float kScaleOverScaleDepth = (1.0 / (OUTER_RADIUS - 1.0)) / 0.25;
static const float kSamples = 2.0; // THIS IS UNROLLED MANUALLY, DON'T TOUCH
#define MIE_G (-0.990)
#define MIE_G2 0.9801
#define SKY_GROUND_THRESHOLD 0.02
	    // fine tuning of performance. You can override defines here if you want some specific setup
	    // or keep as is and allow later code to set it according to target api
	    // if set vprog will output color in final color space (instead of linear always)
	    // in case of rendering in gamma mode that means that we will do lerps in gamma mode too, so there will be tiny difference around horizon
	    // #define SKYBOX_COLOR_IN_TARGET_COLOR_SPACE 0
	    // sun disk rendering:
	    // no sun disk - the fastest option
#define SKYBOX_SUNDISK_NONE 0
	    // simplistic sun disk - without mie phase function
#define SKYBOX_SUNDISK_SIMPLE 1
	    // full calculation - uses mie phase function
#define SKYBOX_SUNDISK_HQ 2
	    // uncomment this line and change SKYBOX_SUNDISK_SIMPLE to override material settings
	    // #define SKYBOX_SUNDISK SKYBOX_SUNDISK_SIMPLE
#ifndef SKYBOX_SUNDISK
#if defined(_SUNDISK_NONE)
#define SKYBOX_SUNDISK SKYBOX_SUNDISK_NONE
#elif defined(_SUNDISK_SIMPLE)
#define SKYBOX_SUNDISK SKYBOX_SUNDISK_SIMPLE
#else
#define SKYBOX_SUNDISK SKYBOX_SUNDISK_HQ
#endif
#endif
#ifndef SKYBOX_COLOR_IN_TARGET_COLOR_SPACE
#if defined(SHADER_API_MOBILE)
#define SKYBOX_COLOR_IN_TARGET_COLOR_SPACE 1
#else
#define SKYBOX_COLOR_IN_TARGET_COLOR_SPACE 0
#endif
#endif
	    // Calculates the Rayleigh phase function
half getRayleighPhase(half eyeCos2)
{
 return 0.75 + 0.75*eyeCos2;
}
half getRayleighPhase(half3 light, half3 ray)
{
 half eyeCos = dot(light, ray);
 return getRayleighPhase(eyeCos * eyeCos);
}

struct appdata_t
{
 float4 vertex : POSITION;
};
struct v2f
{
 float4 pos    : SV_POSITION;
#if SKYBOX_SUNDISK == SKYBOX_SUNDISK_HQ
 // for HQ sun disk, we need vertex itself to calculate ray-dir per-pixel
 half3 vertex   : TEXCOORD0;
#elif SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
 half3 rayDir   : TEXCOORD0;
#else
 // as we dont need sun disk we need just rayDir.y (sky/ground threshold)
 half skyGroundFactor : TEXCOORD0;
#endif
 // calculate sky colors in vprog
 half3 groundColor  : TEXCOORD1;
 half3 skyColor  : TEXCOORD2;
#if SKYBOX_SUNDISK != SKYBOX_SUNDISK_NONE
 half3 sunColor  : TEXCOORD3;
#endif
};

float scale(float inCos)
{
 float x = 1.0 - inCos;
#if defined(SHADER_API_N3DS)
 // The polynomial expansion here generates too many swizzle instructions for the 3DS vertex assembler
 // Approximate by removing x^1 and x^2
 return 0.25 * exp(-0.00287 + x*x*x*(-6.80 + x*5.25));
#else
 return 0.25 * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
#endif
}
v2f vert(appdata_t v)
{
 v2f OUT;
 OUT.pos = UnityObjectToClipPos(v.vertex);
 float3 kSkyTintInGammaSpace = COLOR_2_GAMMA(_SkyTint); // convert tint from Linear back to Gamma
 float3 kScatteringWavelength = lerp(
  kDefaultScatteringWavelength - kVariableRangeForScatteringWavelength,
  kDefaultScatteringWavelength + kVariableRangeForScatteringWavelength,
  half3(1,1,1) - kSkyTintInGammaSpace); // using Tint in sRGB gamma allows for more visually linear interpolation and to keep (.5) at (128, gray in sRGB) point
 float3 kInvWavelength = 1.0 / pow(kScatteringWavelength, 4);
 float kKrESun = kRAYLEIGH * kSUN_BRIGHTNESS;
 float kKr4PI = kRAYLEIGH * 4.0 * 3.14159265;
 float3 cameraPos = float3(0,kInnerRadius + kCameraHeight,0);  // The camera's current position
			  // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
 float3 eyeRay = normalize(mul((float3x3)unity_ObjectToWorld, v.vertex.xyz));
 float far = 0.0;
 half3 cIn, cOut;
 if (eyeRay.y >= 0.0)
 {
  // Sky
  // Calculate the length of the "atmosphere"
  far = sqrt(kOuterRadius2 + kInnerRadius2 * eyeRay.y * eyeRay.y - kInnerRadius2) - kInnerRadius * eyeRay.y;
  float3 pos = cameraPos + far * eyeRay;
  // Calculate the ray's starting position, then calculate its scattering offset
  float height = kInnerRadius + kCameraHeight;
  float depth = exp(kScaleOverScaleDepth * (-kCameraHeight));
  float startAngle = dot(eyeRay, cameraPos) / height;
  float startOffset = depth*scale(startAngle);

  // Initialize the scattering loop variables
  float sampleLength = far / kSamples;
  float scaledLength = sampleLength * kScale;
  float3 sampleRay = eyeRay * sampleLength;
  float3 samplePoint = cameraPos + sampleRay * 0.5;
  // Now loop through the sample rays
  float3 frontColor = float3(0.0, 0.0, 0.0);
  // Weird workaround: WP8 and desktop FL_9_1 do not like the for loop here
  // (but an almost identical loop is perfectly fine in the ground calculations below)
  // Just unrolling this manually seems to make everything fine again.
  //    for(int i=0; i<int(kSamples); i++)
  {
   float height = length(samplePoint);
   float depth = exp(kScaleOverScaleDepth * (kInnerRadius - height));
   float lightAngle = dot(_WorldSpaceLightPos0.xyz, samplePoint) / height;
   float cameraAngle = dot(eyeRay, samplePoint) / height;
   float scatter = (startOffset + depth*(scale(lightAngle) - scale(cameraAngle)));
   float3 attenuate = exp(-clamp(scatter, 0.0, kMAX_SCATTER) * (kInvWavelength * kKr4PI + kKm4PI));
   frontColor += attenuate * (depth * scaledLength);
   samplePoint += sampleRay;
  }
  {
   float height = length(samplePoint);
   float depth = exp(kScaleOverScaleDepth * (kInnerRadius - height));
   float lightAngle = dot(_WorldSpaceLightPos0.xyz, samplePoint) / height;
   float cameraAngle = dot(eyeRay, samplePoint) / height;
   float scatter = (startOffset + depth*(scale(lightAngle) - scale(cameraAngle)));
   float3 attenuate = exp(-clamp(scatter, 0.0, kMAX_SCATTER) * (kInvWavelength * kKr4PI + kKm4PI));
   frontColor += attenuate * (depth * scaledLength);
   samplePoint += sampleRay;
  }

  // Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
  cIn = frontColor * (kInvWavelength * kKrESun);
  cOut = frontColor * kKmESun;
 }
 else
 {
  // Ground
  far = (-kCameraHeight) / (min(-0.001, eyeRay.y));
  float3 pos = cameraPos + far * eyeRay;
  // Calculate the ray's starting position, then calculate its scattering offset
  float depth = exp((-kCameraHeight) * (1.0 / kScaleDepth));
  float cameraAngle = dot(-eyeRay, pos);
  float lightAngle = dot(_WorldSpaceLightPos0.xyz, pos);
  float cameraScale = scale(cameraAngle);
  float lightScale = scale(lightAngle);
  float cameraOffset = depth*cameraScale;
  float temp = (lightScale + cameraScale);
  // Initialize the scattering loop variables
  float sampleLength = far / kSamples;
  float scaledLength = sampleLength * kScale;
  float3 sampleRay = eyeRay * sampleLength;
  float3 samplePoint = cameraPos + sampleRay * 0.5;
  // Now loop through the sample rays
  float3 frontColor = float3(0.0, 0.0, 0.0);
  float3 attenuate;
  //    for(int i=0; i<int(kSamples); i++) // Loop removed because we kept hitting SM2.0 temp variable limits. Doesn't affect the image too much.
  {
   float height = length(samplePoint);
   float depth = exp(kScaleOverScaleDepth * (kInnerRadius - height));
   float scatter = depth*temp - cameraOffset;
   attenuate = exp(-clamp(scatter, 0.0, kMAX_SCATTER) * (kInvWavelength * kKr4PI + kKm4PI));
   frontColor += attenuate * (depth * scaledLength);
   samplePoint += sampleRay;
  }
  cIn = frontColor * (kInvWavelength * kKrESun + kKmESun);
  cOut = clamp(attenuate, 0.0, 1.0);
 }
#if SKYBOX_SUNDISK == SKYBOX_SUNDISK_HQ
 OUT.vertex = -v.vertex;
#elif SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
 OUT.rayDir = half3(-eyeRay);
#else
 OUT.skyGroundFactor = -eyeRay.y / SKY_GROUND_THRESHOLD;
#endif
 // if we want to calculate color in vprog:
 // 1. in case of linear: multiply by _Exposure in here (even in case of lerp it will be common multiplier, so we can skip mul in fshader)
 // 2. in case of gamma and SKYBOX_COLOR_IN_TARGET_COLOR_SPACE: do sqrt right away instead of doing that in fshader
 OUT.groundColor = _Exposure * (cIn + COLOR_2_LINEAR(_GroundColor) * cOut);
 OUT.skyColor = _Exposure * (cIn * getRayleighPhase(_WorldSpaceLightPos0.xyz, -eyeRay));
#if SKYBOX_SUNDISK != SKYBOX_SUNDISK_NONE
 OUT.sunColor = _Exposure * (cOut * _LightColor0.xyz);
#endif
#if defined(UNITY_COLORSPACE_GAMMA) && SKYBOX_COLOR_IN_TARGET_COLOR_SPACE
 OUT.groundColor = sqrt(OUT.groundColor);
 OUT.skyColor = sqrt(OUT.skyColor);
#if SKYBOX_SUNDISK != SKYBOX_SUNDISK_NONE
 OUT.sunColor = sqrt(OUT.sunColor);
#endif
#endif
 //OUT.texcoord = v.texcoord;
 return OUT;
}

// Calculates the Mie phase function
half getMiePhase(half eyeCos, half eyeCos2)
{
 half temp = 1.0 + MIE_G2 - 2.0 * MIE_G * eyeCos;
 temp = pow(temp, pow(_SunSize,0.65) * 10);
 temp = max(temp,1.0e-4); // prevent division by zero, esp. in half precision
 temp = 1.5 * ((1.0 - MIE_G2) / (2.0 + MIE_G2)) * (1.0 + eyeCos2) / temp;
#if defined(UNITY_COLORSPACE_GAMMA) && SKYBOX_COLOR_IN_TARGET_COLOR_SPACE
 temp = pow(temp, .454545);
#endif
 return temp;
}
half calcSunSpot(half3 vec1, half3 vec2)
{
 half3 delta = vec1 - vec2;
 half dist = length(delta);
 half spot = 1.0 - smoothstep(0.0, _SunSize, dist);
 return kSunScale * spot * spot;
}
half4 frag(v2f IN) : SV_Target
{
 half3 col = half3(0.0, 0.0, 0.0);
 // if y > 1 [eyeRay.y < -SKY_GROUND_THRESHOLD] - ground
 // if y >= 0 and < 1 [eyeRay.y <= 0 and > -SKY_GROUND_THRESHOLD] - horizon
 // if y < 0 [eyeRay.y > 0] - sky
#if SKYBOX_SUNDISK == SKYBOX_SUNDISK_HQ
 half3 ray = normalize(mul((float3x3)unity_ObjectToWorld, IN.vertex));
 half y = ray.y / SKY_GROUND_THRESHOLD;
#elif SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
 half3 ray = IN.rayDir.xyz;
 half y = ray.y / SKY_GROUND_THRESHOLD;
#else
 half y = IN.skyGroundFactor;
#endif
 // if we did precalculate color in vprog: just do lerp between them
 col = lerp(IN.skyColor, IN.groundColor, saturate(y));
#if SKYBOX_SUNDISK != SKYBOX_SUNDISK_NONE
 if (y < 0.0)
 {
#if SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
  half mie = calcSunSpot(_WorldSpaceLightPos0.xyz, -ray);
#else // SKYBOX_SUNDISK_HQ
  half eyeCos = dot(_WorldSpaceLightPos0.xyz, ray);
  half eyeCos2 = eyeCos * eyeCos;
  half mie = getMiePhase(eyeCos, eyeCos2);
#endif
  col += mie * IN.sunColor;
 }
#endif
#if defined(UNITY_COLORSPACE_GAMMA) && !SKYBOX_COLOR_IN_TARGET_COLOR_SPACE
 col = LINEAR_2_OUTPUT(col);
#endif
 return half4(col,1.0);
}
 half4 skybox_frag(v2f i, sampler2D smp, half4 smpDecode)
{
 half4 tex = tex2D(smp, i.texcoord);
 half3 c = DecodeHDR(tex, smpDecode);
 c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
 c *= _Exposure;
 return half4(c, 1);
}
 ENDCG
}
  Pass{
  CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
  sampler2D _FrontTex;
 half4 _FrontTex_HDR;
 half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_FrontTex, _FrontTex_HDR); }
  ENDCG
 }
  Pass{
  CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
  sampler2D _BackTex;
 half4 _BackTex_HDR;
 half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_BackTex, _BackTex_HDR); }
  ENDCG
 }
  Pass{
  CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
  sampler2D _LeftTex;
 half4 _LeftTex_HDR;
 half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_LeftTex, _LeftTex_HDR); }
  ENDCG
 }
  Pass{
  CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
  sampler2D _RightTex;
 half4 _RightTex_HDR;
 half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_RightTex, _RightTex_HDR); }
  ENDCG
 }
  Pass{
  CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
  sampler2D _UpTex;
 half4 _UpTex_HDR;
 half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_UpTex, _UpTex_HDR); }
  ENDCG
 }
  Pass{
  CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
  sampler2D _DownTex;
 half4 _DownTex_HDR;
 half4 frag(v2f i) : SV_Target{ return skybox_frag(i,_DownTex, _DownTex_HDR); }
  ENDCG
 }

}

 Fallback Off
}

 

 

Fehler:

Shader error in 'Own/Procedural': 'tex2D': no matching 2 parameter intrinsic function; Possible intrinsic functions are: tex2D(sampler2D, float2|half2|min10float2|min16float2) tex2D(sampler2D, float2|half2|min10float2|min16float2, float2|half2|min10float2|min16float2, float2|half2|min10float2|min16float2) at line 395 (on d3d11)

Shader error in 'Own/Procedural': invalid subscript 'texcoord' at line 395 (on d3d11)

 

Wie gesagt habe ich dazu nicht wirklich viel Wissen und kann nur schätzen was, was ist. Ich persönlich benutze die Standard Shader und eigentlich bräuchte ich auch nur die wenn nicht die Skybox wäre.

 

Durch den Procedural Shader kann man einen schönen Tages-Zyklus erstellen mit Sonne die sich an das Hauptlicht anpasst von der Position her und dazu hat dann der andere Shader die Möglichkeit Texturen einzubinden. Damit könnte ich transparente Sternenhimmel-Texturen nutzen und diese dann langsam einblenden wenn es Nacht wird. Den Mond würde ich als eigenes Directional Light in der Scene lassen ohne ihn im Shader einzubinden.

 

Vielleicht gibt es dazu eine bessere Möglichkeit mit den Standart Shadern auch mein Ziel zu erreichen, mir fällt dazu nur keine Methode ein und den Skybox-Blend Shader möchte ich nicht nehmen den dieser ist nicht geeignet für normale Grafikkarten.

 

Mfg Mustaf

Link zu diesem Kommentar
Auf anderen Seiten teilen

Der Originalshadercode arbeitet mit diesem Struct und hier wird der Floatvektor texcoord definiert:

 

struct v2f {
 float4 vertex : SV_POSITION;
 float2 texcoord : TEXCOORD0;
};

 

Und dieser zweidimensionale Vektor wird in der Function tex2D erwartet:

half4 tex = tex2D(smp, i.texcoord);

 

Du hast diesen Struct umdefiniert und daher kommt der Fehler, bzw fehlt die Definition für "texcoord ". Ich möchte hier aber nicht weiter die beiden Shader zusammenführen, weil das kann doch einiges an Arbeit bedeuten.

 

Prinzipiell finde ich die Idee aber gut, der einfache Weg wäre ggf. mit abnehmender Intensität des directional lights (Sonne) die berechneten Texturen des prozedural Shaders in die Texturen des anderen Shader zu überblenden. Hierbei wäre die Zusammenfassung beider Shader sinnvoll.

 

Ein kleiner Hinweis:

Soweit ich weiß, gibt es maximal 4 verwendbare Texturkoordinaten (TEXCOORD0 - 3) und wie es scheint werden alle 4 vom prozeduralen Skyboxshader benutzt, vermutlich musst du einen entfernen, um dort die Texturkoordinaten für den 6-seitigen Skyboxshader zu übergeben.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Danke, ja das mit den 4 Texturkoordinaten hab ich bemerkt, nur die Frage ist welchen brauch man nicht unbedingt.

Das wegen tex2D da finde ich in keinen der beiden Shader eine Funktion. Ich finde nur im Shader mit den Texturen eine Gruppe.

 

 return half4(col,1.0);
}
 half4 skybox_frag(v2f i, sampler2D smp, half4 smpDecode)
{
 half4 tex = tex2D(smp, i.texcoord);
 half3 c = DecodeHDR(tex, smpDecode);
 c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
 c *= _Exposure;
 return half4(c, 1);
}
 ENDCG
}

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich habe mir das Ganze noch einmal angeschaut und ich würde den Cubemap Skyboxshader verwenden, da hier nur 1 Shaderpass verwendet wird und du diesen daher leichter mit dem prozeduralen Skyboxshader kombinieren kannst. Zudem habe ich gelesen, daß man wohl doch TEXCOORD4 verwenden kann.

 

Wenn beide Shader kombiniert sind, kannst du beide Texturen so überblenden (BlendAlpha würde dann über die Intensität der Sonne gesetzt):

http://answers.unity3d.com/questions/482701/shader-combine-two-textures-and-add-transparency.html

Link zu diesem Kommentar
Auf anderen Seiten teilen

Coole Sache, ich habe jetzt mal versucht diese zwei zu kombinieren.

Bin nun auf folgendes gestoßen ->

fixed4 frag(v2f i) : SV_Target
{
 half4 tex = texCUBE(_Tex, i.texcoord);
 half3 c = DecodeHDR(tex, _Tex_HDR);
 c = c * _Tint.rgb * unity_ColorSpaceDouble.rgb;
 c *= _Exposure;
 return half4(c, 1);
}
half4 frag(v2f IN) : SV_Target
{
 half3 col = half3(0.0, 0.0, 0.0);
 // if y > 1 [eyeRay.y < -SKY_GROUND_THRESHOLD] - ground
 // if y >= 0 and < 1 [eyeRay.y <= 0 and > -SKY_GROUND_THRESHOLD] - horizon
 // if y < 0 [eyeRay.y > 0] - sky
#if SKYBOX_SUNDISK == SKYBOX_SUNDISK_HQ
 half3 ray = normalize(mul((float3x3)unity_ObjectToWorld, IN.vertex));
 half y = ray.y / SKY_GROUND_THRESHOLD;
#elif SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
 half3 ray = IN.rayDir.xyz;
 half y = ray.y / SKY_GROUND_THRESHOLD;
#else
 half y = IN.skyGroundFactor;
#endif
 // if we did precalculate color in vprog: just do lerp between them
 col = lerp(IN.skyColor, IN.groundColor, saturate(y));
#if SKYBOX_SUNDISK != SKYBOX_SUNDISK_NONE
 if (y < 0.0)
 {
#if SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
  half mie = calcSunSpot(_WorldSpaceLightPos0.xyz, -ray);
#else // SKYBOX_SUNDISK_HQ
  half eyeCos = dot(_WorldSpaceLightPos0.xyz, ray);
  half eyeCos2 = eyeCos * eyeCos;
  half mie = getMiePhase(eyeCos, eyeCos2);
#endif
  col += mie * IN.sunColor;
 }
#endif
#if defined(UNITY_COLORSPACE_GAMMA) && !SKYBOX_COLOR_IN_TARGET_COLOR_SPACE
 col = LINEAR_2_OUTPUT(col);
#endif
 return half4(col,1.0);
}

 

Wie kombiniere ich beide Methoden sinnvoll oder muss ich das garnicht?

 

Folgender Fehler kommt:

'texCUBE': no matching 2 parameter intrinsic function; Possible intrinsic functions are: texCUBE(samplerCUBE, float3|half3|min10float3|min16float3) texCUBE(samplerCUBE, float3|half3|min10float3|min16float3, float3|half3|min10float3|min16float3, float3|half3|min10float3|min16float3) at line 347 (on d3d11)

 

Danke trotzdem für die Hilfe.

Ich weiß leider nicht was das meiste bedeutet hab davon eigentlich 0 Wissen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Nun habe ich eh schon viel Arbeit reingesteckt, da habe es es nun doch gemacht. Den Shader findest du dann unter "Skybox/Cube Procedural".

 

Es funktioniert allerdings derzeit nur für:

Sun = "High Quality"

 

Das war der Kompromiss, da leider doch nur 4 TEXCOORD's funktionierten!

 

Blend Alpha = 0 bedeutet Texturen 100%

Blend Alpha = 0.5 bedeutet Texturen 50% / prozedural Sky 50%

Blend Alpha = 1 prozedural Sky 100%

 

Die Rotation der Skyboxtextur funktioniert leider auch nicht mehr, da müsste man noch an der "vert"-Funktion basteln.

 

Shader "Skybox/Cube Procedural" {
Properties {
[KeywordEnum(None, Simple, High Quality)] _SunDisk ("Sun", Int) = 2
_SunSize ("Sun Size", Range(0,1)) = 0.04

_AtmosphereThickness ("Atmoshpere Thickness", Range(0,5)) = 1.0
_SkyTint ("Sky Tint", Color) = (.5, .5, .5, 1)
_GroundColor ("Ground", Color) = (.369, .349, .341, 1)
_Rotation("Rotation", Range(0, 360)) = 0
[NoScaleOffset] _Tex("Cubemap   (HDR)", Cube) = "grey" {}
_Exposure("Exposure", Range(0, 8)) = 1.3
_BlendAlpha("Blend Alpha", float) = 0
}
SubShader {
Tags { "Queue"="Background" "RenderType"="Background" "PreviewType"="Skybox" }
Cull Off ZWrite Off
Pass {
 CGPROGRAM
 #pragma vertex vert
 #pragma fragment frag
 #include "UnityCG.cginc"
 #include "Lighting.cginc"
 #pragma multi_compile __ UNITY_COLORSPACE_GAMMA
 #pragma multi_compile _SUNDISK_NONE _SUNDISK_SIMPLE _SUNDISK_HIGH_QUALITY
 samplerCUBE _Tex;
 uniform half _Exposure;  // HDR exposure
 uniform half3 _GroundColor;
 uniform half _SunSize;
 uniform half3 _SkyTint;
 uniform half _AtmosphereThickness;
 half4 _Tex_HDR;
 float _BlendAlpha;
#if defined(UNITY_COLORSPACE_GAMMA)
 #define GAMMA 2
 #define COLOR_2_GAMMA(color) color
 #define COLOR_2_LINEAR(color) color*color
 #define LINEAR_2_OUTPUT(color) sqrt(color)
#else
 #define GAMMA 2.2
 // HACK: to get gfx-tests in Gamma mode to agree until UNITY_ACTIVE_COLORSPACE_IS_GAMMA is working properly
 #define COLOR_2_GAMMA(color) ((unity_ColorSpaceDouble.r>2.0) ? pow(color,1.0/GAMMA) : color)
 #define COLOR_2_LINEAR(color) color
 #define LINEAR_2_LINEAR(color) color
#endif
 // RGB wavelengths
 // .35 (.62=158), .43 (.68=174), .525 (.75=190)
 static const float3 kDefaultScatteringWavelength = float3(.65, .57, .475);
 static const float3 kVariableRangeForScatteringWavelength = float3(.15, .15, .15);
 #define OUTER_RADIUS 1.025
 static const float kOuterRadius = OUTER_RADIUS;
 static const float kOuterRadius2 = OUTER_RADIUS*OUTER_RADIUS;
 static const float kInnerRadius = 1.0;
 static const float kInnerRadius2 = 1.0;
 static const float kCameraHeight = 0.0001;
 #define kRAYLEIGH (lerp(0, 0.0025, pow(_AtmosphereThickness,2.5)))  // Rayleigh constant
 #define kMIE 0.0010		// Mie constant
 #define kSUN_BRIGHTNESS 20.0  // Sun brightness
 #define kMAX_SCATTER 50.0 // Maximum scattering value, to prevent math overflows on Adrenos
 static const half kSunScale = 400.0 * kSUN_BRIGHTNESS;
 static const float kKmESun = kMIE * kSUN_BRIGHTNESS;
 static const float kKm4PI = kMIE * 4.0 * 3.14159265;
 static const float kScale = 1.0 / (OUTER_RADIUS - 1.0);
 static const float kScaleDepth = 0.25;
 static const float kScaleOverScaleDepth = (1.0 / (OUTER_RADIUS - 1.0)) / 0.25;
 static const float kSamples = 2.0; // THIS IS UNROLLED MANUALLY, DON'T TOUCH
 #define MIE_G (-0.990)
 #define MIE_G2 0.9801
 #define SKY_GROUND_THRESHOLD 0.02
 // fine tuning of performance. You can override defines here if you want some specific setup
 // or keep as is and allow later code to set it according to target api
 // if set vprog will output color in final color space (instead of linear always)
 // in case of rendering in gamma mode that means that we will do lerps in gamma mode too, so there will be tiny difference around horizon
 // #define SKYBOX_COLOR_IN_TARGET_COLOR_SPACE 0
 // sun disk rendering:
 // no sun disk - the fastest option
 #define SKYBOX_SUNDISK_NONE 0
 // simplistic sun disk - without mie phase function
 #define SKYBOX_SUNDISK_SIMPLE 1
 // full calculation - uses mie phase function
 #define SKYBOX_SUNDISK_HQ 2
 // uncomment this line and change SKYBOX_SUNDISK_SIMPLE to override material settings
 // #define SKYBOX_SUNDISK SKYBOX_SUNDISK_SIMPLE
#ifndef SKYBOX_SUNDISK
 #if defined(_SUNDISK_NONE)
  #define SKYBOX_SUNDISK SKYBOX_SUNDISK_NONE
 #elif defined(_SUNDISK_SIMPLE)
  #define SKYBOX_SUNDISK SKYBOX_SUNDISK_SIMPLE
 #else
  #define SKYBOX_SUNDISK SKYBOX_SUNDISK_HQ
 #endif
#endif
#ifndef SKYBOX_COLOR_IN_TARGET_COLOR_SPACE
 #if defined(SHADER_API_MOBILE)
  #define SKYBOX_COLOR_IN_TARGET_COLOR_SPACE 1
 #else
  #define SKYBOX_COLOR_IN_TARGET_COLOR_SPACE 0
 #endif
#endif
 // Calculates the Rayleigh phase function
 half getRayleighPhase(half eyeCos2)
 {
  return 0.75 + 0.75*eyeCos2;
 }
 half getRayleighPhase(half3 light, half3 ray)
 {
  half eyeCos = dot(light, ray);
  return getRayleighPhase(eyeCos * eyeCos);
 }

 struct appdata_t
 {
  float4 vertex : POSITION;
 };
 struct v2f
 {
  float4 pos	: SV_POSITION;
 #if SKYBOX_SUNDISK == SKYBOX_SUNDISK_HQ
  // for HQ sun disk, we need vertex itself to calculate ray-dir per-pixel
  half3 vertex   : TEXCOORD0;
 #elif SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
  half3 rayDir   : TEXCOORD0;
 #else
  // as we dont need sun disk we need just rayDir.y (sky/ground threshold)
  half skyGroundFactor : TEXCOORD0;
 #endif
  // calculate sky colors in vprog
  half3 groundColor  : TEXCOORD1;
  half3 skyColor  : TEXCOORD2;
 #if SKYBOX_SUNDISK != SKYBOX_SUNDISK_NONE
  half3 sunColor  : TEXCOORD3;
 #endif
//   float3 texcoord : TEXCOORD0;
 };

 float scale(float inCos)
 {
  float x = 1.0 - inCos;
 #if defined(SHADER_API_N3DS)
  // The polynomial expansion here generates too many swizzle instructions for the 3DS vertex assembler
  // Approximate by removing x^1 and x^2
  return 0.25 * exp(-0.00287 + x*x*x*(-6.80 + x*5.25));
 #else
  return 0.25 * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25))));
 #endif
 }
 v2f vert (appdata_t v)
 {
  v2f OUT;
  OUT.pos = UnityObjectToClipPos(v.vertex);
  float3 kSkyTintInGammaSpace = COLOR_2_GAMMA(_SkyTint); // convert tint from Linear back to Gamma
  float3 kScatteringWavelength = lerp (
kDefaultScatteringWavelength-kVariableRangeForScatteringWavelength,
kDefaultScatteringWavelength+kVariableRangeForScatteringWavelength,
half3(1,1,1) - kSkyTintInGammaSpace); // using Tint in sRGB gamma allows for more visually linear interpolation and to keep (.5) at (128, gray in sRGB) point
  float3 kInvWavelength = 1.0 / pow(kScatteringWavelength, 4);
  float kKrESun = kRAYLEIGH * kSUN_BRIGHTNESS;
  float kKr4PI = kRAYLEIGH * 4.0 * 3.14159265;
  float3 cameraPos = float3(0,kInnerRadius + kCameraHeight,0);  // The camera's current position
  // Get the ray from the camera to the vertex and its length (which is the far point of the ray passing through the atmosphere)
  float3 eyeRay = normalize(mul((float3x3)unity_ObjectToWorld, v.vertex.xyz));
  float far = 0.0;
  half3 cIn, cOut;
  if(eyeRay.y >= 0.0)
  {
// Sky
// Calculate the length of the "atmosphere"
far = sqrt(kOuterRadius2 + kInnerRadius2 * eyeRay.y * eyeRay.y - kInnerRadius2) - kInnerRadius * eyeRay.y;
float3 pos = cameraPos + far * eyeRay;
// Calculate the ray's starting position, then calculate its scattering offset
float height = kInnerRadius + kCameraHeight;
float depth = exp(kScaleOverScaleDepth * (-kCameraHeight));
float startAngle = dot(eyeRay, cameraPos) / height;
float startOffset = depth*scale(startAngle);

// Initialize the scattering loop variables
float sampleLength = far / kSamples;
float scaledLength = sampleLength * kScale;
float3 sampleRay = eyeRay * sampleLength;
float3 samplePoint = cameraPos + sampleRay * 0.5;
// Now loop through the sample rays
float3 frontColor = float3(0.0, 0.0, 0.0);
// Weird workaround: WP8 and desktop FL_9_1 do not like the for loop here
// (but an almost identical loop is perfectly fine in the ground calculations below)
// Just unrolling this manually seems to make everything fine again.
//	for(int i=0; i<int(kSamples); i++)
{
 float height = length(samplePoint);
 float depth = exp(kScaleOverScaleDepth * (kInnerRadius - height));
 float lightAngle = dot(_WorldSpaceLightPos0.xyz, samplePoint) / height;
 float cameraAngle = dot(eyeRay, samplePoint) / height;
 float scatter = (startOffset + depth*(scale(lightAngle) - scale(cameraAngle)));
 float3 attenuate = exp(-clamp(scatter, 0.0, kMAX_SCATTER) * (kInvWavelength * kKr4PI + kKm4PI));
 frontColor += attenuate * (depth * scaledLength);
 samplePoint += sampleRay;
}
{
 float height = length(samplePoint);
 float depth = exp(kScaleOverScaleDepth * (kInnerRadius - height));
 float lightAngle = dot(_WorldSpaceLightPos0.xyz, samplePoint) / height;
 float cameraAngle = dot(eyeRay, samplePoint) / height;
 float scatter = (startOffset + depth*(scale(lightAngle) - scale(cameraAngle)));
 float3 attenuate = exp(-clamp(scatter, 0.0, kMAX_SCATTER) * (kInvWavelength * kKr4PI + kKm4PI));
 frontColor += attenuate * (depth * scaledLength);
 samplePoint += sampleRay;
}
// Finally, scale the Mie and Rayleigh colors and set up the varying variables for the pixel shader
cIn = frontColor * (kInvWavelength * kKrESun);
cOut = frontColor * kKmESun;
  }
  else
  {
// Ground
far = (-kCameraHeight) / (min(-0.001, eyeRay.y));
float3 pos = cameraPos + far * eyeRay;
// Calculate the ray's starting position, then calculate its scattering offset
float depth = exp((-kCameraHeight) * (1.0/kScaleDepth));
float cameraAngle = dot(-eyeRay, pos);
float lightAngle = dot(_WorldSpaceLightPos0.xyz, pos);
float cameraScale = scale(cameraAngle);
float lightScale = scale(lightAngle);
float cameraOffset = depth*cameraScale;
float temp = (lightScale + cameraScale);
// Initialize the scattering loop variables
float sampleLength = far / kSamples;
float scaledLength = sampleLength * kScale;
float3 sampleRay = eyeRay * sampleLength;
float3 samplePoint = cameraPos + sampleRay * 0.5;
// Now loop through the sample rays
float3 frontColor = float3(0.0, 0.0, 0.0);
float3 attenuate;
//	for(int i=0; i<int(kSamples); i++) // Loop removed because we kept hitting SM2.0 temp variable limits. Doesn't affect the image too much.
{
 float height = length(samplePoint);
 float depth = exp(kScaleOverScaleDepth * (kInnerRadius - height));
 float scatter = depth*temp - cameraOffset;
 attenuate = exp(-clamp(scatter, 0.0, kMAX_SCATTER) * (kInvWavelength * kKr4PI + kKm4PI));
 frontColor += attenuate * (depth * scaledLength);
 samplePoint += sampleRay;
}
cIn = frontColor * (kInvWavelength * kKrESun + kKmESun);
cOut = clamp(attenuate, 0.0, 1.0);
  }
 #if SKYBOX_SUNDISK == SKYBOX_SUNDISK_HQ
  OUT.vertex	= -v.vertex;
 #elif SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
  OUT.rayDir	= half3(-eyeRay);
 #else
  OUT.skyGroundFactor = -eyeRay.y / SKY_GROUND_THRESHOLD;
 #endif
  // if we want to calculate color in vprog:
  // 1. in case of linear: multiply by _Exposure in here (even in case of lerp it will be common multiplier, so we can skip mul in fshader)
  // 2. in case of gamma and SKYBOX_COLOR_IN_TARGET_COLOR_SPACE: do sqrt right away instead of doing that in fshader
  OUT.groundColor = _Exposure * (cIn + COLOR_2_LINEAR(_GroundColor) * cOut);
  OUT.skyColor = _Exposure * (cIn * getRayleighPhase(_WorldSpaceLightPos0.xyz, -eyeRay));
 #if SKYBOX_SUNDISK != SKYBOX_SUNDISK_NONE
  OUT.sunColor = _Exposure * (cOut * _LightColor0.xyz);
 #endif
 #if defined(UNITY_COLORSPACE_GAMMA) && SKYBOX_COLOR_IN_TARGET_COLOR_SPACE
  OUT.groundColor = sqrt(OUT.groundColor);
  OUT.skyColor = sqrt(OUT.skyColor);
  #if SKYBOX_SUNDISK != SKYBOX_SUNDISK_NONE
OUT.sunColor= sqrt(OUT.sunColor);
  #endif
 #endif
  return OUT;
 }

 // Calculates the Mie phase function
 half getMiePhase(half eyeCos, half eyeCos2)
 {
  half temp = 1.0 + MIE_G2 - 2.0 * MIE_G * eyeCos;
  temp = pow(temp, pow(_SunSize,0.65) * 10);
  temp = max(temp,1.0e-4); // prevent division by zero, esp. in half precision
  temp = 1.5 * ((1.0 - MIE_G2) / (2.0 + MIE_G2)) * (1.0 + eyeCos2) / temp;
  #if defined(UNITY_COLORSPACE_GAMMA) && SKYBOX_COLOR_IN_TARGET_COLOR_SPACE
temp = pow(temp, .454545);
  #endif
  return temp;
 }
 half calcSunSpot(half3 vec1, half3 vec2)
 {
  half3 delta = vec1 - vec2;
  half dist = length(delta);
  half spot = 1.0 - smoothstep(0.0, _SunSize, dist);
  return kSunScale * spot * spot;
 }
 half4 frag (v2f IN) : SV_Target
 {
  half3 col = half3(0.0, 0.0, 0.0);
 // if y > 1 [eyeRay.y < -SKY_GROUND_THRESHOLD] - ground
 // if y >= 0 and < 1 [eyeRay.y <= 0 and > -SKY_GROUND_THRESHOLD] - horizon
 // if y < 0 [eyeRay.y > 0] - sky
 #if SKYBOX_SUNDISK == SKYBOX_SUNDISK_HQ
  half3 ray = normalize(mul((float3x3)unity_ObjectToWorld, IN.vertex));
  half y = ray.y / SKY_GROUND_THRESHOLD;
 #elif SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
  half3 ray = IN.rayDir.xyz;
  half y = ray.y / SKY_GROUND_THRESHOLD;
 #else
  half y = IN.skyGroundFactor;
 #endif
  // if we did precalculate color in vprog: just do lerp between them
  col = lerp(IN.skyColor, IN.groundColor, saturate(y));
 #if SKYBOX_SUNDISK != SKYBOX_SUNDISK_NONE
  if(y < 0.0)
  {
  #if SKYBOX_SUNDISK == SKYBOX_SUNDISK_SIMPLE
half mie = calcSunSpot(_WorldSpaceLightPos0.xyz, -ray);
  #else // SKYBOX_SUNDISK_HQ
half eyeCos = dot(_WorldSpaceLightPos0.xyz, ray);
half eyeCos2 = eyeCos * eyeCos;
half mie = getMiePhase(eyeCos, eyeCos2);
  #endif
col += mie * IN.sunColor;
  }
 #endif
 #if defined(UNITY_COLORSPACE_GAMMA) && !SKYBOX_COLOR_IN_TARGET_COLOR_SPACE
  col = LINEAR_2_OUTPUT(col);
 #endif
 half3 c = half3(0,0,0);
	#if SKYBOX_SUNDISK == SKYBOX_SUNDISK_HQ
  half4 tex = texCUBE(_Tex,-IN.vertex);
  c = DecodeHDR(tex, _Tex_HDR);
  c = c * _SkyTint.rgb * unity_ColorSpaceDouble.rgb;
	#endif

 fixed3 mixedcolor = (1 - _BlendAlpha) * c + _BlendAlpha * col;
 return half4(mixedcolor,1.0);
 }
 ENDCG
}
}

Fallback Off
}

 

Man könnte das Überblenden auch anders gestalten, z.b. den Farbwert des prozeduralen Sky's (col.r/col.g/col.b ) prüfen und wenn dieser sich der Farbe Schwarz annähert, die andere Textur einblenden... Dies wäre dann ideal für eine Sternenhimmeltextur die in den dunkel gewordenen prodzeduralen Sky eingeblendet wird.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...