PImage checkPatternTexture; BoxWithTexture myBox; abstract class TextureRenderHelper { 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 _texture; protected PVector[] _worldVertices; protected PVector[] _localVertices; protected PVector[] _textureCoords; 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() { _textureCoords = new PVector[NUM_TEXTURE_COORDS_DEFAULT]; for(int i = 0; i < _textureCoords.length; i++) { _textureCoords[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) { _textureCoords = new PVector[numVertices]; for(int i = 0; i < numVertices; i++) { _textureCoords[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 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 getDefraultTintColor() { 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 renderWithShade(PVector[] worldVertices, PVector[] textureCoords) { if(_texture == null || worldVertices == null || textureCoords == null) return; if(textureCoords.length < worldVertices.length) return; if(_texture.get(0, 0) == 0) return; int tintColor = getDefraultTintColor(); if(_isBack) return; pushMatrix(); resetMatrix(); camera(); noLights(); beginShape(); textureMode(NORMAL); texture(_texture); 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, _textureCoords); } } class BoxWithTexture extends TextureRenderHelper { 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; _texture = 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], _textureCoords); } } } void setup() { size(200, 200, P3D); checkPatternTexture = createTexture(); myBox = new BoxWithTexture(100, 100, 100, checkPatternTexture); } void draw() { background(0xff); camera(); noStroke(); pushMatrix(); translate(.5 * width, .5 * height); float angle = radians(millis() * 0.015); rotateZ(angle); rotateX(angle); rotateY(angle); myBox.render(); popMatrix(); } PImage createTexture() { 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 / 0x20) + floor(j / 0x20)) % 2 == 0 ? color(0xcc) : color(0xff)); } } tex.updatePixels(); return tex; }
<canvas width="200px" height="200px"></canvas>
body { background-color: #fff; } </style> <script type="text/javascript"> window.addEventListener('load',function() { var scripts = document.body.getElementsByTagName('script'); var canvases = document.body.getElementsByTagName('canvas'); new Processing(canvases[0],scripts[0].text); }, false); // Here prevent javascript in body from throwing error </script> <style>