3D Oberflächen und Licht


Processing 2.0

Betrachtet man ein reales Objekt, z.B. einen einfärbigen Würfel, so stellt man fest, dass alle Seiten unterschiedliche Farbschattierungen aufweisen. Das liegt am Spiel zwischen Licht und Schatten. Dieses Spiel gilt es so gut, wie möglich zu immitieren, will man realitätsnahe 3D Darstellungen generieren.

Eins vorweg: Processing ist dafür nur bedingt gut geeignet. Nichts desto trotz werden wir uns hier mit den Grundlagen von Lichtern und Oberflächen beschäftigen.

Um die Effekte der Kombination aus verschieden Lichtquellen und Oberflächen zu demonstrieren habe ich das Programm lightsTesterDemo geschrieben. Die lightsTester Klasse kann auch in anderen Projekten verwendet werden.

LightsTester funktioniert leider derzeit nicht online, muss also heruntergeladen werden.

Lichtquellen

Generell müssen Lichtquellen in jedem draw() Durchlauf, und nicht in setup() aufgerufen werden.

lights();

Die einfachste Möglichkeit in Processing mit Licht zu arbeiten bietet die Funktion lights(). Sie generiert ein Kombination aus verschieden Lichtquellen mit default Werten.

ambientLight(rot, grün, blau);

Dient als Hintergrundbeleuchtung und wird in der Regel in Kombination mit anderen Lichtquellen eingesetzt. Es beleuchtet Objekte von allen Seiten gleich stark.

directionalLight(rot, grün, blau, x, y, z);

Erzeut paralleles Licht aus einer bestimmten Richtung. Trifft es auf eine Oberfläche, so entsteht Steulicht, welches wiederum auf andere Objekte wirkt. Es hat eine bestimmte Farbe und eine Richtung.

pointLight(rot, grün, blau, x, y, z); Funktioniert derzeit nicht (Processing 2.0b3)!!!

Generiert eine punktförmige Lichtquelle. Farbe und Position müssen als Parameter angegeben werden.

spotLight(rot, grün, blau, x, y, z, dx, dy, dz, winkel, fokus);

Eine Lichtquelle, die wie ein Scheinwerfer funktioniert. Neben der Farbe und der Position müssen hier noch die Abstrahlrichtung (winkel) und die Konzentration der Lichtstärke im Zentrum (fokus) angegeben werden. In lights können die Werte für winkel und fokus über den alpha Kanal des entsprechenden Color Pickers gesteuert werden.

lightSpecular(rot, grün, blau);

Legt die Farbe der Glanzlichter fest. Hat nur Einfluss auf die jenigen Elemente, die im Code danach erstellt werden. D.h. die Glanzlichter müssen vor den anderen Lichtern gesetzt werden.

Oberflächen

Die Effekte von Lichtquellen hängen von der Oberflächenbeschaffenheit der beleuchteten Objekte ab. Deshalb gibt es in Processing eine Reihe von Oberflächeneigenschaften, die in Kombination mit den verwendeten Lichtquellen benutzt werden können.

ambient(rot, grün, blau);

Legt den Reflexionsgrad der Oberfläche in Kombination mit ambientLight() fest. Z.B. ambient(255,128,0) reflektiert rot zur Gänze, grün zur Hälfte und blau gar nicht.

emissive(rot, grün, blau);

Objekte können selbst Licht emittieren. D.h. sie leuchten selbst in der hier definierten Farbe. Alledings nur dann, wenn irgendeine Lichtquelle vorhanden ist.

specular(rot, grün, blau);

Damit definiert man die Farbe der Glanzlichter.

shininess(float);

Legt die Glanzintensität einer Oberfläche fest.

lightFalloff(constant, linear, quadratic);

Dieser Parameter legt den Lichtabfall über die Entfernung zur Lichtquelle mit Werten zwischen 0 und 1 fest. Er wirkt allerdings nur auf point spot und ambient Lights.

Beispiel: lights

Mit dem Licht und Oberflächen Tool kannst du verschiedenste Licht und Oberflächeneffekte testen. Es funktioniert derzeit eider nur im Java Modus und muss deshalb als .zip Datei heruntergeladen werden.


// Bewege die Maus, um die Position der Lichtquelle zu ändern

//GUI Library ControlP5
import controlP5.*;
ControlP5 controlP5;
ColorPicker cplamb, cpldir, cplpoi, cpambient, cpfill, cplspt, cplspc, cpemissive, cpspecular;
CheckBox checkbox;

public int R, G, B=128;
public int shininess, falloff=0;
int mode = 0;
int [] heights = new int [25];
boolean lightsOn, ambientOn, directionalOn, pointOn, spotOn, specOn =false;

void setup() {
size(800, 800, P3D);
smooth(1);
createControlP5();

for (int i=0;i< heights.length;i++) {
heights[i]=(int) random(100, 255);
}
}

void draw() {
background(0);

// Kontrolle über die Lichter
controlP5.draw();

ambient(cpambient.getColorValue());
emissive(cpemissive.getColorValue());
specular(cpspecular.getColorValue());
shininess(shininess);
lightFalloff(0, 0, falloff);

if (specOn) {
lightSpecular(red(cplspc.getColorValue()), green(cplspc.getColorValue()), blue(cplspc.getColorValue()));
}
if (lightsOn) lights();
if (ambientOn) {
ambientLight(red(cplamb.getColorValue()), green(cplamb.getColorValue()), blue(cplamb.getColorValue()),
map(mouseX, 0, width, 1, -1), -1, map(mouseY, 0, height, 1, -1));
}
if (directionalOn) directionalLight(red(cpldir.getColorValue()), green(cpldir.getColorValue()), blue(cpldir.getColorValue()),
map(mouseX, 0, width, 1, -1), 1, map(mouseY, height, 0, -1, 1));

if (pointOn) pointLight(red(cplpoi.getColorValue()), green(cplpoi.getColorValue()), blue(cplpoi.getColorValue()),
0, 100, 0);

if (spotOn) {
spotLight(red(cplspt.getColorValue()), green(cplspt.getColorValue()), blue(cplspt.getColorValue()),
map(mouseX, 0, width, 0, width), -1000, map(mouseY, 0, height, 0, height*2),
0, 1, -1, map(alpha(cplspt.getColorValue()),0,255,0,PI), map(alpha(cplspt.getColorValue()),0,255,255,0));
}

fill(cpfill.getColorValue());
drawBlocks();
}

void drawBlocks() {

// Betrachtungsperspektive ändern
translate(100, height/2, -500);
rotateX(PI/3);

//Zeichne Blocks
for (int i=0;i<5;i++) {
for (int j=0;j<5;j++) {
pushMatrix();
translate(120*i, 120*j, heights[i*5+j]/2);
//box(50, 50, heights[i*5+j]*1.2);
sphere(heights[i*5+j]/2);
popMatrix();
}
}
}

void createControlP5() {

// Steuerelemente erstellen
controlP5 = new ControlP5(this);

//Checkboxes erstellen
checkbox = controlP5.addCheckBox("lcheckBox", 10, 10);
checkbox.setColorForeground(color(120));
checkbox.setColorActive(color(255));
checkbox.setColorLabel(color(255));
checkbox.setItemsPerRow(8);
checkbox.setSpacingColumn(119);
checkbox.addItem("lights()", 0);
checkbox.addItem("ambientLight()", 0);
checkbox.addItem("directionalLight()", 0);
checkbox.addItem("pointLight()", 0);
checkbox.addItem("spotLight()", 0);
checkbox.addItem("lightSpecular()", 0);

//Colorpicker erstellen
ControlGroup fillColor = controlP5.addGroup("fill Color", 10, 40);
fillColor.activateEvent(false);
fillColor.close();
cpfill = controlP5.addColorPicker("fillpicker", 0, 0, 128, 0);
cpfill.setGroup(fillColor);

ControlGroup ambLightCol = controlP5.addGroup("ambientLight Color", 140, 40);
ambLightCol.activateEvent(false);
ambLightCol.close();
cplamb = controlP5.addColorPicker("amblpicker", 0, 0, 128, 0);
cplamb.setGroup(ambLightCol);
cplamb.setArrayValue(new float[] {
100, 100, 100, 255
}
);

ControlGroup dirLightCol = controlP5.addGroup("directionalLight Color", 270, 40);
dirLightCol.activateEvent(false);
dirLightCol.close();
cpldir = controlP5.addColorPicker("dirlpicker", 0, 0, 128, 0);
cpldir.setGroup(dirLightCol);
cpldir.setArrayValue(new float[] {
100, 100, 100, 255
}
);

ControlGroup poiLightCol = controlP5.addGroup("pointLight Color", 400, 40);
poiLightCol.activateEvent(false);
poiLightCol.close();
cplpoi = controlP5.addColorPicker("poilpicker", 0, 0, 128, 0);
cplpoi.setGroup(poiLightCol);
cplpoi.setArrayValue(new float[] {
100, 100, 100, 255
}
);

ControlGroup sptLightCol = controlP5.addGroup("spotLight Color", 530, 40);
sptLightCol.activateEvent(false);
sptLightCol.close();
cplspt = controlP5.addColorPicker("spotlpicker", 0, 0, 128, 0);
cplspt.setGroup(sptLightCol);
cplspt.setArrayValue(new float[] {
100, 100, 100, 100
}
);

ControlGroup lightSpecCol = controlP5.addGroup("lightSpec Color", 660, 40);
lightSpecCol.activateEvent(false);
lightSpecCol.close();
cplspc = controlP5.addColorPicker("speclpicker", 0, 0, 128, 0);
cplspc.setGroup(lightSpecCol);
cplspc.setArrayValue(new float[] {
100, 100, 100, 255
}
);

ControlGroup surfaceCol = controlP5.addGroup("ambient Color", 10, 120);
surfaceCol.activateEvent(false);
surfaceCol.close();
cpambient = controlP5.addColorPicker("ambpicker", 0, 0, 128, 0);
cpambient.setGroup(surfaceCol);
cpambient.setArrayValue(new float[] {
100, 100, 100, 255
}
);

ControlGroup emissiveCol = controlP5.addGroup("emissive Color", 140, 120);
emissiveCol.activateEvent(false);
emissiveCol.close();
cpemissive = controlP5.addColorPicker("emipicker", 0, 0, 128, 0);
cpemissive.setGroup(emissiveCol);
cpemissive.setArrayValue(new float[] {
100, 100, 100, 255
}
);

ControlGroup specularCol = controlP5.addGroup("specular Color", 270, 120);
specularCol.activateEvent(false);
specularCol.close();
cpspecular = controlP5.addColorPicker("specpicker", 0, 0, 128, 0);
cpspecular.setGroup(specularCol);
cpspecular.setArrayValue(new float[] {
100, 100, 100, 255
}
);

//Slider erstellen
controlP5.begin(10, 150);
controlP5.addSlider("shininess", 0, 255, 0, 400, 110, 128, 10);
controlP5.addSlider("falloff", 0, 1, 0, 595, 110, 128, 10);
controlP5.end();
}

// Aktion Radio Button
void controlEvent(ControlEvent theEvent) {
if (theEvent.isGroup()) {
//print("got an event from "+theEvent.group().name()+"\t");
for (int i=0;i<theEvent.group().arrayValue().length;i++) {
int n = (int)theEvent.group().arrayValue()[i];
print(n);
if (i==0) {
if (n==1)  lightsOn=true;
else lightsOn=false;
}
if (i==1) {
if (n==1)  ambientOn=true;
else ambientOn=false;
}
if (i==2) {
if (n==1)  directionalOn=true;
else directionalOn=false;
}
if (i==3) {
if (n==1)  pointOn=true;
else pointOn=false;
}
if (i==4) {
if (n==1)  spotOn=true;
else spotOn=false;
}
if (i==5) {
if (n==1)  specOn=true;
else specOn=false;
}
}
}
}

Advertisements

3 Kommentare

  1. Pingback: Processing – Über dieses Weblog « processing – tutorial

  2. Pingback: The Hunt « processing – tutorial

  3. Pingback: 3 D Basics « processing – tutorial

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: