shader ConeVolumeShadow

Aus DGL Wiki
Version vom 30. Januar 2010, 20:30 Uhr von Coolcat (Diskussion | Beiträge) (Die Seite wurde neu angelegt: „{{Offline}} =Shadername= Zurück zur Shadersammlung {|{{Prettytable_B1}} width=100% !width=60%|Beschreibung !width=20%|Autor !width=20%|Version |- |Kegelvolu…“)

(Unterschied) ← Nächstältere Version | Aktuelle Version (Unterschied) | Nächstjüngere Version → (Unterschied)
Wechseln zu: Navigation, Suche
Hinweis: Dieser Artikel wird gerade Offline bearbeitet!

Bitte haben Sie etwas Geduld und nehmen Sie keine Änderungen vor, bis der Artikel hochgeladen wurde.

(weitere Artikel)
WIP Offline.jpg

Shadername

Zurück zur Shadersammlung

Beschreibung Autor Version
Kegelvolumen-Schatten Coolcat 1.0

Bilder

shader ConeVolumeShadow1.jpg
shader ConeVolumeShadow2.jpg

Voraussetzungen

Nichts besonderes.

Funktionsweise

shader ConeVolumeSoftShadow.png

Code

Vertexshader

Der Vertexshader ist nichts besonderes. Er transformiert einfach nur die Vertexposition sowie die Normale und gibt die Daten weiter. Dieser Shader ist im wesentlichen aus UltimateConquest übernommen. Daher werden hier Vertexattribute und Matrixuniforms selbst definiert. Sofern man noch mit OpenGL 2.x arbeitet kann man aber problemlos die dort verfügbaren eingebauten Uniforms und Attribute benutzen.

uniform mat4 uModelViewProjection;
uniform mat4 uModelView;
uniform mat3 uNormalMatrix;

attribute vec3 aPosition;
attribute vec3 aNormal;
attribute vec2 aTexCoord;

varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vTexCoord;

void main() {
	gl_Position = uModelViewProjection * vec4(aPosition, 1.0);
	vPosition = (uModelView * vec4(aPosition, 1.0)).xyz;
	vNormal = normalize(uNormalMatrix * aNormal);
	vTexCoord = aTexCoord;
}

Fragmentshader

uniform sampler2D uTexture;

// the lightsource described by position and radius
uniform vec4 uLightsource;
vec3 lsPosition = uLightsource.xyz;
float lsRadius = uLightsource.w;

// each shadow volume is described by position (xyz) and radius (w) of the occluder packed into a single vec4
const int shadowMaxCount = 5;
uniform vec4 uShadows[shadowMaxCount];
uniform int uShadowCount;

varying vec3 vPosition;
varying vec3 vNormal;
varying vec2 vTexCoord;


const vec3 cAmbient = vec3(0.025,0.025,0.025);

// simple local diffuse per-pixel lighting
float diffuseFactor() {
	vec3 lightDir = normalize(lsPosition-vPosition);
	vec3 normal = normalize(vNormal);
	return max(dot(lightDir, normal), 0.0);
}

// process all shadow volumes
float shadowFactor() {
	float s = 1.0;
	// iterate all shadow volumes
	for (int i=0; i<uShadowCount; ++i) {
		// extract data
		vec4 occluder = uShadows[i];
		vec3 ocPosition = occluder.xyz;
		float ocRadius = occluder.w;

		// project fragment (vPosition) on the cone axis => F_
		vec3 nvLO = ocPosition - lsPosition;
		float dLO = length(nvLO);
		nvLO /= dLO;
		vec3 vLF = vPosition - lsPosition;
		float dLF_ = dot(vLF, nvLO);
		if (dLF_ < dLO) {
			// fragment before occluder => no shadow
			continue; 
		}
		vec3 F_ = lsPosition + dLF_ * nvLO;
		float rF = distance(F_, vPosition);

		// compute outer and inner radius at F_
		float rF_outer = (ocRadius + lsRadius) * (dLF_ / dLO) - lsRadius;
		if (rF >= rF_outer) {
			// outside the outer cone => no shadow
			continue;
		} 
		float rF_inner = (ocRadius - lsRadius) * (dLF_ / dLO) + lsRadius;
		if (rF_inner >= rF) {
			// inside the inner cone => full shadow
			return 0.0; 
		}
		else if (rF_inner >= 0.0 || rF >= -rF_inner) {
			// soft shadow, linear interpolation
			s *= (rF - rF_inner) / (rF_outer - rF_inner);
		}
		else {
			// light from both sides of the occluder
			s *= (-2.0*rF_inner) / (rF_outer - rF_inner);
		}
	}
	return s;
}

void main() {
	vec3 texcolor = texture2D(uTexture, vTexCoord).xyz;
	gl_FragColor.xyz = cAmbient * texcolor;
	float lightFactor = diffuseFactor();
	if (lightFactor > 0.004) {
		// don't compute shadows for fragments that are already dark from local lighting
		lightFactor *= shadowFactor();
	}
	gl_FragColor.xyz += texcolor * lightFactor;
	gl_FragColor.w = 1.0;
}