10 - Shader Effekte

06 - Kreis

Selfhtml

Mit OpenGL kann man auch (halb)tranparente Elemente zeichen.
Dafür gibt es Alphablending. Der Transparent-Faktor wird mit dem vierten Wert im Vector angegeben. Dies ist auch im Shader der Fall.
Alphablending kann man auch auf Texturen anwenden, zB. um eine Baum zu zeichnen, oder auch nur eine Scheibe. Dazu mehr unter Texturen.


Neben einem Face mit 3 Werten, gibt es jetzt noch eines mit einem vierten, welcher dann den Aplhablending angibt.
type
  TFace3f = array[0..2] of TVector3f;
  TFace4f = array[0..2] of TVector4f;  // Mit Alpha
Beim Color sieht man auch den vierten Parameter. Wobei 0.0 voll Transparent ist. und 1.0 undurchsichtig.
Wen man nur den RGB-Wert betrachtet, wäre das Dreieck voll rot und das Rechteck grün.
const
  QuadVector: array[0..1] of TFace3f =
    (((-1.0, -1.0, 0.0), (-1.0, 1.0, 0.0), (1.0, 1.0, 0.0)),
    ((-1.0, -1.0, 0.0), (1.0, 1.0, 0.0), (1.0, -1.0, 0.0)));
Hier kommen zwie wichtige Zeilen hinzu, mit der Ersten wird Alphablending aktiviert und mit der zweiten gibt man die Art des Blinding an.
Bei glVertexAttribPointer(... bei der Farbe sieht man, das ein Vector 4 Werte anstelle 3 hat.
procedure TForm1.InitScene;
begin
  glClearColor(0.6, 0.6, 0.4, 1.0); // Hintergrundfarbe

  glEnable(GL_BLEND);                                  // Alphablending an
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);   // Sortierung der Primitiven von hinten nach vorne.

  glEnable(GL_DEPTH_TEST);
  glDepthFunc(GL_LESS);


  // --- Daten für Quadrat
  glBindVertexArray(VBQuad.VAO);

  // Vektor
  glBindBuffer(GL_ARRAY_BUFFER, VBQuad.VBOvert);
  glBufferData(GL_ARRAY_BUFFER, sizeof(QuadVector), @QuadVector, GL_STATIC_DRAW);
  glEnableVertexAttribArray(10);
  glVertexAttribPointer(10, 3, GL_FLOAT, False, 0, nil);


Die Shader sind sehr einfach gehalten. Man könnte mit Color.a direkt einen Alphawert zuordnen.
Da der Alpha-Kanal gebraucht wird, sieht man mehrfach vec4 anstelle vec3.

Vertex-Shader:
#version 330

layout (location = 10) in vec3 inPos;    // Vertex-Koordinaten

out vec2 PosXY;


void main(void)
{
  vec4 p = vec4(inPos, 1.0);  // Vektoren mit der Matrix multiplizieren.
  PosXY = p.xy;
  gl_Position = p;
}


Fragment-Shader:
#ifdef GL_ES
precision mediump float;
#endif

#extension GL_OES_standard_derivatives : disable

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

vec3 lightDir = normalize(vec3(sin(time * 1.5), 2.0, cos(time * 0.5)));

mat3 camera(vec3 ro, vec3 ta, vec3 up) {
	vec3 nz = normalize(ta - ro);
	vec3 nx = cross(nz, normalize(up));
	vec3 ny = cross(nx, nz);

	return mat3(nx, ny, nz);
}

float plane(vec3 p) {
	return p.y+2.;
}

float sphere(vec3 p, float r) {
	return length(p) - r;
}

float torus(vec3 p, vec2 t) {
	return length(vec2(length(p.xz) - t.x, p.y)) - t.y;
}

vec4 scene(vec3 p) {

	vec3 check = sin(p.x * 5.0) * sin(p.z * 5.0) > 0.0 ? vec3(0.7) : vec3(0.0);

	vec4 resP = vec4(check, plane(p - vec3(0.0, -1.0, 0.0)));
	vec4 resS = vec4(vec3(0.5, 0.1, 0.1), sphere(p - vec3(sin(time) * 2., cos(time) * 2. + 2.0, 0.0), 1.0));
	vec4 resT = vec4(vec3(0.1, 0.4, 0.5), torus(p - vec3(-2.0, 2.0, 0.0), vec2(2.0, 0.5)));

	vec4 res = resP.w < resS.w ? resP : resS;
	res = res.w < resT.w ? res : resT;

	return res;
}

vec3 normal(vec3 p) {
	float d = 0.0001;
	return normalize(vec3(
		scene(p + vec3(d, 0.0, 0.0)).w - scene(p + vec3(-d, 0.0, 0.0)).w,
		scene(p + vec3(0.0, d, 0.0)).w - scene(p + vec3(0.0, -d, 0.0)).w,
		scene(p + vec3(0.0, 0.0, d)).w - scene(p + vec3(0.0, 0.0, -d)).w
	));
}

float softshadow(vec3 ro, vec3 rd) {

	float v = 1.0;
	float t = 0.0;
	vec3 p = ro;
	for (int i = 0; i < 16; i++) {
		vec4 res = scene(p);
		float d = res.w;
		if (d < 0.001) {
			return 0.0;
		}
		v = min(v, 4.0 * d / t);
		t += d;
		p = ro + t * rd;
	}

	return v;
}

vec3 render(vec3 ro, vec3 rd) {


	vec3 color = vec3(0.8, 0.9, 1.0);

	float tmax = 30.0;

	float t = 0.0;
	float d = 0.0;
	vec3 p = ro;
	vec3 c;
	for(int i = 0; i < 64; i++) {
		vec4 res = scene(p);
		c = res.rgb;
		d = res.w;
		t += d;
		p = ro + t * rd;
		if (t > tmax) break;
	}

	if (t < tmax) {
		color = c;

		vec3 nor = normal(p);
		float dif = clamp(dot(nor, lightDir), 0.0, 1.0);
		color += vec3(0.3, 0.4, 0.5) * dif;

		vec3 ref = reflect(rd, nor);
		float spe = clamp(dot(ref, lightDir), 0.0, 1.0);
		color += vec3(4.0) * pow(spe, 30.0);

		float sf = softshadow(p + nor * 0.01, lightDir);
		color *= clamp(sf + 0.3, 0.0, 1.0);
	}


	color = mix(color, vec3(0.8, 0.9, 1.0), 1.0 - exp(-0.00005  * t * t * t));


	return color;

}

void main( void ) {

	vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / resolution;
	p.x *= resolution.x / resolution.y;

	vec3 ro = vec3(10.0 * cos(mouse.x * 6.0), mouse.y * 10., 10.0 * sin(mouse.x * 6.0));
	vec3 ta = vec3(0.0, 0.0, 0.0);

	vec3 rd = camera(ro, ta, vec3(0.0, 1.0, 0.0)) * normalize(vec3(p.xy, 2.0));

	vec3 col = render(ro, rd);

	gl_FragColor = vec4(col, 1.0);

}



zurück