至moodle下載processing-3.3.6-windows64.zip
解壓縮後執行如下
Bump Mapping 凹凸貼圖
https://www.openprocessing.org/sketch/249457
code來源
// Processing.jsでバンプマッピング
BumpMappedBox myBox;
void setup() {
size(200, 200, P3D);
myBox = new BumpMappedBox(100,
createTexture(),
createHeightMapImage());
}
void draw() {
background(0xff);
camera();
noStroke();
pushMatrix();
translate(.5 * width, .5 * height);
float baseAngle = radians(millis() * 0.015);
rotateX(baseAngle);
rotateZ(baseAngle);
rotateY(baseAngle);
myBox.render();
popMatrix();
}
PImage createTexture() {
int step = 0x20;
PImage tex = createImage(0x80, 0x80, RGB);
tex.loadPixels();
for(int i = 0; i < tex.width; i++) {
for(int j = 0; j < tex.height; j++) {
tex.set(i, j,
(floor(i / step) + floor(j / step)) % 2 == 0 ?
color(0xcc) : color(0xff));
}
}
tex.updatePixels();
return tex;
}
PImage createHeightMapImage() {
int step = 0x20;
PImage tex = createImage(0x80, 0x80, RGB);
tex.loadPixels();
for(int i = 0; i < tex.pixels.length; i++) {
tex.pixels[i] = color(0xfff - random(255));//與原code不同處
}
for(int i = step; i < tex.width -1; i += step) {
for(int j = 0; j < tex.height; j++) {
tex.pixels[i + j * tex.width] = 0xff << 0x16;
}
}
for(int i = 0; i < tex.width; i++) {
for(int j = step; j < tex.height; j += step) {
tex.pixels[i + j * tex.width] = 0xff << 0x16;
}
}
tex.updatePixels();
return tex;
}
// ----------------------------------------
interface Renderable {
void render();
}
// ----------------------------------------
abstract class RenderHelper implements Renderable {
private final int NUM_TEXTURE_COORDS_DEFAULT = 4;
protected final int DIFFUSE_COLOR = 0x7f;
protected final PVector LIGHT_DIRECTION = new PVector(0, 0, -1);
protected final PVector ZERO_VECTOR = new PVector(0, 0, 0);
protected PVector eyePoint = new PVector(.5 * width,
.5 * height,
.5 * height / tan(PI / 6.0));
protected PVector _origin = new PVector();
protected PVector _normal = new PVector();
protected PImage _originalTexture;
protected PVector[] _worldVertices;
protected PVector[] _localVertices;
protected PVector[] _originalTextureCoords;
private PImage _texture;
private boolean _isBack = false;
public abstract void render();
public void setEyePoint(PVector p) {
if(p != null) {
eyePoint.set(p);
} else {
setEyePoint(0, 0, 0);
}
}
public void setEyePoint(float x, float y, float z) {
eyePoint.set(x, y, z);
}
protected void initVertices(int numVertices) {
if(numVertices < 1) return;
_worldVertices = new PVector[numVertices];
_localVertices = new PVector[numVertices];
for(int i = 0; i < numVertices; i++) {
_worldVertices[i] = new PVector();
_localVertices[i] = new PVector();
}
}
protected void initTextureCoords() {
_originalTextureCoords = new PVector[NUM_TEXTURE_COORDS_DEFAULT];
for(int i = 0; i < _originalTextureCoords.length; i++) {
_originalTextureCoords[i] = new PVector(i < NUM_TEXTURE_COORDS_DEFAULT / 2 ? 0 : 1,
i % (NUM_TEXTURE_COORDS_DEFAULT - 1) == 0 ? 0 : 1);
}
}
protected void initTextureCoords(int numVertices) {
_originalTextureCoords = new PVector[numVertices];
for(int i = 0; i < numVertices; i++) {
_originalTextureCoords[i] = new PVector();
}
}
protected PVector[] updateWorldVertices(PVector[] localVertices, PVector[] destWorldVertices) {
for(int i = 0; i < destWorldVertices.length; i++) {
updateWorldVertex(localVertices[i], destWorldVertices[i]);
}
return destWorldVertices;
}
protected PVector[] updateWorldVertices() {
return updateWorldVertices(_localVertices, _worldVertices);
}
protected PVector updateWorldVertex(PVector localVertex, PVector destWorldVertex) {
destWorldVertex.set(
modelX(localVertex.x, localVertex.y, localVertex.z),
modelY(localVertex.x, localVertex.y, localVertex.z),
modelZ(localVertex.x, localVertex.y, localVertex.z));
return destWorldVertex;
}
protected PVector updateWorldVertex(PVector localVertex) {
return new PVector (
modelX(localVertex.x, localVertex.y, localVertex.z),
modelY(localVertex.x, localVertex.y, localVertex.z),
modelZ(localVertex.x, localVertex.y, localVertex.z));
}
protected PVector updateOrigin(PVector center) {
updateWorldVertex(center, _origin);
return _origin;
}
protected PVector updateOrigin() {
return updateOrigin(ZERO_VECTOR);
}
protected PVector updateNormalVector(PVector v1, PVector v2) {
_normal.set(v1.cross(v2));
_normal.normalize();
return _normal;
}
private PVector _ = new PVector();
protected int getDefaultTintColor() {
subVec(_origin, eyePoint, _);
_isBack = 0 < _normal.dot(_);
float arg = (_isBack ? 1.0 : -1.0) * _normal.dot(LIGHT_DIRECTION);
return (int)(arg * (0xff - DIFFUSE_COLOR) + DIFFUSE_COLOR);
}
protected void subVec(PVector p1, PVector p2, PVector dest) {
dest.set(p1.x - p2.x, p1.y - p2.y, p1.z - p2.z);
}
protected void renderWithoutShade(PVector[] worldVertices, PVector[] textureCoords) {
if(!checkArgsBeforeRender(_originalTexture,
worldVertices,
textureCoords)) return;
getDefaultTintColor();
if(_isBack) return;
if(!setupRenderTexture()) return;
_texture.resize(_texture.width, _texture.height);
renderMain(0xff, _texture, worldVertices, textureCoords);
}
protected void renderWithShade(PVector[] worldVertices, PVector[] textureCoords) {
if(!checkArgsBeforeRender(_originalTexture,
worldVertices,
textureCoords)) return;
int tintColor = getDefaultTintColor();
if(_isBack) return;
renderMain(tintColor, _originalTexture, worldVertices, textureCoords);
}
private boolean checkArgsBeforeRender(PImage originalTexture, PVector[] worldVertices, PVector[] textureCoords) {
if(_originalTexture == null || worldVertices == null || textureCoords == null) return false;
if(textureCoords.length < worldVertices.length) return false;
if(_originalTexture.get(0, 0) == 0) return false;
return true;
}
private boolean setupRenderTexture() {
// 毎回 createImage しないとうまくレンダリングされない...
_texture = createImage(_originalTexture.width, _originalTexture.height, RGB);
updateTexture(_originalTexture, _texture);
return !(_texture == null || _texture.get(0, 0) == 0);
}
protected void updateTexture(PImage originalTexture, PImage destUpdatedTexture) {
destUpdatedTexture.loadPixels();
for(int i = 0; i < originalTexture.pixels.length; i++) {
destUpdatedTexture.pixels[i] = originalTexture.pixels[i];
}
destUpdatedTexture.updatePixels();
}
private void renderMain(int tintColor, PImage textureImage, PVector[] worldVertices, PVector[] textureCoords) {
pushMatrix();
resetMatrix();
camera();
noLights();
beginShape();
textureMode(NORMAL);
texture(textureImage);
tint(tintColor);
for(int i = 0; i < worldVertices.length; i++) {
vertex(worldVertices[i].x, worldVertices[i].y, worldVertices[i].z,
textureCoords[i].x, textureCoords[i].y);
}
endShape(CLOSE);
popMatrix();
}
protected void renderWithShade() {
renderWithShade(_worldVertices, _originalTextureCoords);
}
protected void renderWithoutShade() {
renderWithoutShade(_worldVertices, _originalTextureCoords);
}
}
// ----------------------------------------
class BoxWithTexture extends RenderHelper {
protected final int NUM_VERTICES = 8;
protected final int NUM_PLANES = 6;
protected final int NUM_SIDE_PLANES = 4;
protected final int NUM_VERTICES_PER_PLANE = 4;
protected float _width;
protected float _height;
protected float _depth;
protected PVector[] _centers = new PVector[NUM_PLANES];
protected PVector[][] _surface = new PVector[NUM_PLANES][NUM_VERTICES_PER_PLANE];
public BoxWithTexture(float size, PImage tex) {
this(size, size, size, tex);
}
public BoxWithTexture(float w, float h, float d, PImage tex) {
_width = w;
_height = h;
_depth = d;
_originalTexture = tex;
setupSurface();
}
private void setupSurface() {
float halfWidth = .5 * _width;
float halfHeight = .5 * _height;
float halfDepth = .5 * _depth;
initTextureCoords();
initVertices(NUM_VERTICES);
for(int i = 0; i < NUM_VERTICES; i++) {
int j = i < NUM_VERTICES_PER_PLANE ?
i : i - NUM_VERTICES_PER_PLANE;
_localVertices[i].set(j % 3 == 0 ? -halfWidth : halfWidth,
i < 4 ? -halfHeight : halfHeight,
i % 4 < 2 ? -halfDepth : halfDepth);
}
setupSide(halfWidth, halfDepth);
setupTopAndBottom(halfHeight);
}
private void setupSide(float halfWidth, float halfDepth) {
for(int i = 0; i < NUM_SIDE_PLANES; i++) {
float _x = halfWidth * (i % 2 == 0 ? 0 : i < 2 ? 1 : -1);
float _z = halfDepth * (i % 2 != 0 ? 0 : i < 2 ? -1 : 1);
_centers[i] = new PVector(_x, 0, _z);
for(int j = 0; j < NUM_VERTICES_PER_PLANE; j++) {
int surplus = j % (NUM_VERTICES_PER_PLANE - 1);
int index = surplus != 0 ?
(i + surplus + (NUM_VERTICES_PER_PLANE - 1)) %
NUM_VERTICES_PER_PLANE +
NUM_VERTICES_PER_PLANE :
(i + (j < NUM_VERTICES_PER_PLANE / 2 ? 0 : 1)) %
NUM_VERTICES_PER_PLANE;
_surface[i][j] = _worldVertices[index];
}
}
}
private void setupTopAndBottom(float halfHeight) {
for(int i = NUM_SIDE_PLANES; i < _centers.length; i++) {
float _y = halfHeight * (i == NUM_SIDE_PLANES ? -1 : 1);
_centers[i] = new PVector(0, _y, 0);
for(int j = 0; j < NUM_VERTICES_PER_PLANE; j++) {
int index = i == NUM_SIDE_PLANES ? j : NUM_VERTICES - (j + 1);
_surface[i][j] = _worldVertices[index];
}
}
}
public void render() {
updateWorldVertices();
for(int i = 0; i < _surface.length; i++) {
updateOrigin(_centers[i]);
updateNormalVector(PVector.sub(_surface[i][1], _surface[i][0]),
PVector.sub(_surface[i][3], _surface[i][0]));
renderWithShade(_surface[i], _originalTextureCoords);
}
}
}
// ----------------------------------------
class BumpMappedPlane extends RenderHelper {
private final int NUM_VERTICES = 4;
private float _width;
private float _height;
private PImage _heightMap;
private PVector[][] _normalMap; // 法線マップ
public BumpMappedPlane(float w, float h, PImage tex, PImage hMap) {
_width = w;
_height = h;
_originalTexture = tex;
_heightMap = hMap;
float halfWidth = .5 * _width;
float halfHeight = .5 * _height;
initTextureCoords();
initVertices(NUM_VERTICES);
for(int i = 0; i < NUM_VERTICES; i++) {
_localVertices[i].set(i < 2 ? -halfWidth : halfWidth,
i % 3 == 0 ? -halfHeight : halfHeight, 0);
}
}
PVector _worldNormal = new PVector();
PImage _dummyTexture;
public void render() {
if(_originalTexture.get(0, 0) != 0) {
if (_normalMap == null) {
_normalMap = createNormalMap(_heightMap);
}
}
updateOrigin();
updateWorldVertices();
updateNormalVector(PVector.sub(_worldVertices[1], _worldVertices[0]),
PVector.sub(_worldVertices[3], _worldVertices[0]));
renderWithoutShade();
}
protected PVector zeroVec = new PVector();
protected void updateTexture(PImage originalTexture, PImage destUpdatedTexture) {
destUpdatedTexture.loadPixels();
int imgWidth = destUpdatedTexture.width;
for(int i = 0; i < _normalMap.length; i++) {
for(int j = 0; j < _normalMap[0].length; j++) {
updateWorldVertex(_normalMap[i][j], _worldNormal);
_worldNormal.sub(_origin);
float arg = _worldNormal.dot(LIGHT_DIRECTION);
float coef = (arg * (0xff - DIFFUSE_COLOR) / 0xff) + (DIFFUSE_COLOR / 0xff);
int originalColor = originalTexture.pixels[j * imgWidth + i];
int b = (int)(coef * (originalColor & 0xff));
int g = (int)(coef * (originalColor >> 0x8 & 0xff));
int r = (int)(coef * (originalColor >> 0x10 & 0xff));
destUpdatedTexture.pixels[j * imgWidth + i] = 0xff << 0x18 | r << 0x10 | g << 0x8 | b;
}
}
destUpdatedTexture.updatePixels();
}
private float dU(PImage heightMap, int i, int j) {
if(i < 1) return dU(heightMap, 1, j);
if(!(i < heightMap.width-1)) return dU(heightMap, heightMap.width - 2, j);
return .5 * (getHeight(heightMap, i+1,j) - getHeight(heightMap, i-1,j));
}
private float dV(PImage heightMap, int i, int j) {
if(j < 1) return dV(heightMap, i, 1);
if(!(j < heightMap.height-1)) return dV(heightMap, i, heightMap.height - 2);
return .5 * (getHeight(heightMap, i, j+1) - getHeight(heightMap, i,j-1));
}
private int getHeight(PImage heightMap, int i, int j) {
return 0xff & heightMap.pixels[i + j * heightMap.width];
}
private PVector[][] createNormalMap(PImage heightMapImage) {
int mapWidth = heightMapImage.width;
int mapHeight = heightMapImage.height;
PVector[][] normalMap = new PVector[mapWidth][mapHeight];
PVector v1 = new PVector();
PVector v2 = new PVector();
for(int i = 0; i < mapWidth; ++i) {
for(int j = 0; j < mapHeight; ++j) {
v1.set(1.0, 0, dU(heightMapImage, i, j));
v1.normalize();
v2.set(0, 1.0, dV(heightMapImage, i, j));
v2.normalize();
normalMap[i][j] = v1.cross(v2);
normalMap[i][j].normalize();
}
}
return normalMap;
}
}
// ----------------------------------------
class BumpMappedBox implements Renderable {
private BumpMappedPlane[] _surface = new BumpMappedPlane[6];
private float _size;
BumpMappedBox(float boxSize, PImage tex, PImage hMap) {
_size = boxSize;
for(int i = 0; i < 6; i++) {
_surface[i] = new BumpMappedPlane( _size, _size, tex, hMap);
}
}
void render() {
pushMatrix();
for(int i = 0; i < 4; i++) {
rotateY(i * HALF_PI);
pushMatrix();
translate(0, 0, -.5 * _size);
_surface[i].render();
popMatrix();
}
popMatrix();
pushMatrix();
rotateX(HALF_PI);
for(int i = 4; i < 6; i++) {
rotateX(i * PI);
pushMatrix();
translate(0, 0, -.5 * _size);
_surface[i].render();
popMatrix();
}
popMatrix();
}
}
執行結果
Environment Mapping 環境貼圖
下載一張圖片並匯入processing 3中
PImage img;
void setup(){
// setting window size
size(1280, 800);
// processing image load a image
img = loadImage("a.PNG");
}
void draw(){
// show image ( image, x, y, width, height)
image(img, mouseX, mouseY);//圖隨滑鼠移動
}
結果
3.簡易馬力歐遊戲
找瑪莉歐,問號方塊和普通磚塊的圖,存為mario, brick1, brick2
並複製以下程式碼貼上
int [][]map={{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,1,1,2,2,1,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1}};
PImage imgMario, imgBrick, imgBrick2;
void setup(){
size(800, 600);
imgMario=loadImage("mario.png");
imgBrick=loadImage("brick.png");
imgBrick2=loadImage("brick2.png");
}
float marioX=200, marioY=100, marioVX=0, marioVY=0;
boolean marioOnFloor=false;
void draw(){
background(255);
for(int x=0;x<14;x++){
for(int y=0;y<11;y++){
if(map[y][x]==1) image(imgBrick, x*50, y*50, 50,50);
if(map[y][x]==2) image(imgBrick2, x*50, y*50, 50,50);
}
}
image(imgMario, marioX, marioY, 50,50);
marioY += marioVY; marioX += marioVX;
marioVY += 0.98;
if(marioY>=500-50)
{marioY=500-50; marioVY=0; marioOnFloor=true;}
}
void keyPressed(){
if(keyCode==UP && marioOnFloor) {marioVY=-15; marioOnFloor=false;}
if(keyCode==RIGHT) marioVX=5;
if(keyCode==LEFT) marioVX=-5;
}
void keyReleased(){
if(keyCode==RIGHT || keyCode==LEFT) marioVX=0;
}
沒有留言:
張貼留言