<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/gl-matrix@3.0.0/gl-matrix.js"></script>
<script src="https://cdn.jsdelivr.net/npm/stats.js@0.17.0/build/stats.min.js"></script>
</head>
<body>
<!--
1.设置three.js渲染器
2.设置摄像机camera
3.设置场景scene
4.设置光源light
5.设置物体object
-->
<script>
function inherits(childCtor, parentCtor) {
childCtor.prototype = Object.create(parentCtor.prototype);
childCtor.prototype.constructor = childCtor;
}
function makeFrustum(left, right, bottom, top, near, far) {
var m, x, y, a, b, c, d;
m = glMatrix.mat4.create();
x = 2 * near / (right - left);
y = 2 * near / (top - bottom);
a = (right + left) / (right - left);
b = (top + bottom) / (top - bottom);
c = - (far + near) / (far - near);
d = - 2 * far * near / (far - near);
m.n11 = x; m.n13 = a;
m.n22 = y; m.n23 = b;
m.n33 = c; m.n34 = d;
m.n43 = - 1; m.n44 = 0;
return m;
};
function makePerspective(fov, aspect, near, far) {
var ymax, ymin, xmin, xmax;
ymax = near * Math.tan(fov * Math.PI / 360);
ymin = - ymax;
xmin = ymin * aspect;
xmax = ymax * aspect;
return makeFrustum(xmin, xmax, ymin, ymax, near, far);
};
/*
摄像机:(从外面观看房间内部)
*生成具有给定边界的透视投影矩阵。
*为far传递空/未定义/无值将生成无限投影矩阵。
*
out MAT4 mat4 frustum矩阵将被写入
@param {number} fovy 数 垂直的视野在弧度
@param {number} aspect 数 宽高比。通常视口宽度/高度
@param {number} near 数 在截头体附近
@param {number} far 数 截头锥体的远端,可以是null或无穷大
*/
function Camera(fov, aspect, near, far) {
this.position = glMatrix.vec3.fromValues(0, 0, 0);
this.target = { position: glMatrix.vec3.fromValues(0, 0, 0) };
//透视投影矩阵
this.projectionMatrix = glMatrix.mat4.perspective([], fov, aspect, near, far);
// this.projectionMatrix=makePerspective(fov,aspect,near,far)
this.up = glMatrix.vec3.fromValues(0, 1, 0);
this.matrix = glMatrix.mat4.create();
this.autoUpdateMatrix = true;
this.updateMatrix = function () {
this.matrix = glMatrix.mat4.lookAt(this.matrix, this.position, this.target.position, this.up)
// this.matrix.lookAt( this.position, this.target.position, this.up );
};
}
/*
场景:(房间)
*/
function Scene() {
this.objects = [];
this.add = function (object) {
this.objects.push(object);
};
}
/*
光源:(房间里面的光)
*/
function Light() {
}
function Color(hex) {
var _r, _g, _b, _a;
this.cssRgba = "rgba(0, 0, 0, 1)";
var _hex;
this.updateHex = function () {
_hex = (Math.floor(_a * 255) << 24) | (_r << 16) | (_g << 8) | _b;
}
this.updateRGBA = function () {
_r = _hex >> 16 & 0xff;
_g = _hex >> 8 & 0xff;
_b = _hex & 0xff;
_a = (_hex >> 24 & 0xff) / 255;
};
this.setRGBA = function (r, g, b, a) {
_r = r;
_g = g;
_b = b;
_a = a;
this.updateHex();
this.updateStyleString();
}
this.setHex = function (hex) {
_hex = hex;
this.updateRGBA();
this.updateStyleString();
};
this.updateStyleString = function () {
this.cssRgba = 'rgba(' + _r + ',' + _g + ',' + _b + ',' + _a + ')';
};
this.setHex(hex);
}
function FaceColorFillMaterial() {
}
function ColorFillMaterial(hex, opacity) {
this.color = new Color((opacity >= 0 ? (opacity * 0xff) << 24 : 0xff000000) | hex);
};
function ColorStrokeMaterial(lineWidth, hex, opacity) {
this.lineWidth = lineWidth;
ColorFillMaterial.call(this, hex, opacity)
}
function BitmapUVMappingMaterial() {
}
/*
几何
*/
function Geometry() {
this.vertices = [];// 顶点
this.faces = []; // 面
this.uvs = [];
this.computeNormals = function () {
var v, f, vA, vB, vC, cb, ab, normal;
for (v = 0; v < this.vertices.length; v++) {
this.vertices[v].normal.set(0, 0, 0);
}
for (f = 0; f < this.faces.length; f++) {
vA = this.vertices[this.faces[f].a];
vB = this.vertices[this.faces[f].b];
vC = this.vertices[this.faces[f].c];
cb = new THREE.Vector3();
ab = new THREE.Vector3();
normal = new THREE.Vector3();
cb.sub(vC.position, vB.position);
ab.sub(vA.position, vB.position);
cb.cross(ab);
if (!cb.isZero()) {
cb.normalize();
}
this.faces[f].normal = cb;
vA.normal.addSelf(normal);
vB.normal.addSelf(normal);
vC.normal.addSelf(normal);
if (this.faces[f] instanceof THREE.Face4) {
this.vertices[this.faces[f].d].normal.addSelf(normal);
}
}
};
}
/*
@material 材料
*/
function Object3D(material) {
this.position = glMatrix.vec3.create();
this.rotation = glMatrix.vec3.create();
this.scale = glMatrix.vec3.fromValues(1, 1, 1);
this.matrix = glMatrix.mat4.create();
this.screen = glMatrix.vec3.create();
this.material = material instanceof Array ? material : [material];
this.overdraw = false;
this.autoUpdateMatrix = true;
this.updateMatrix = function () {
glMatrix.mat4.identity(this.matrix);
glMatrix.mat4.mul(this.matrix, this.matrix, glMatrix.mat4.translate([],glMatrix.mat4.create(),this.position));
glMatrix.mat4.mul(this.matrix, this.matrix, glMatrix.mat4.rotateX([], glMatrix.mat4.create(), this.rotation[0]));
glMatrix.mat4.mul(this.matrix, this.matrix, glMatrix.mat4.rotateY([], glMatrix.mat4.create(), this.rotation[1]));
glMatrix.mat4.mul(this.matrix, this.matrix, glMatrix.mat4.rotateZ([], glMatrix.mat4.create(), this.rotation[2]));
glMatrix.mat4.mul(this.matrix, this.matrix, glMatrix.mat4.scale([], glMatrix.mat4.create(), glMatrix.vec3.fromValues(this.scale[0], this.scale[1], this.scale[2])));
};
}
function Mesh(geometry, material) {
Object3D.call(this, material);
this.geometry = geometry;
this.doubleSided = false;
};
inherits(Mesh, Object3D);
function Vertex(position, normal) {
this.position = position || glMatrix.vec3.create();
this.normal = normal || glMatrix.vec3.create();
this.screen = glMatrix.vec3.create();
this.__visible = true;
}
function Face3(a, b, c, normal, color) {
this.a = a;
this.b = b;
this.c = c;
this.normal = normal || glMatrix.vec3.create();
this.screen = glMatrix.vec3.create();
this.color = color || new Color(0x000000);
};
function Face4(a, b, c, d, normal, color) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.normal = normal || glMatrix.vec3.create();
this.screen = glMatrix.vec3.create();
this.color = color || new Color(0x000000);
};
function RenderableFace3() {
this.v1 = glMatrix.vec2.create();
this.v2 = glMatrix.vec2.create();
this.v3 = glMatrix.vec2.create();
this.z = null;
this.color = null;
this.material = null;
}
function RenderableFace4() {
this.v1 = glMatrix.vec2.create();
this.v2 = glMatrix.vec2.create();
this.v3 = glMatrix.vec2.create();
this.v4 = glMatrix.vec2.create();
this.z = null;
this.color = null;
this.material = null;
}
function Renderer() {
var vector4 = new glMatrix.vec4.create();
var matrix = new glMatrix.mat4.create();
var face4Pool = [], face3Pool = [];
this.renderList = null;
function painterSort(a, b) {
return b.z - a.z;
}
// 投影
this.project = function (scene, camera) {
this.renderList = [];
if (camera.autoUpdateMatrix) {
camera.updateMatrix();
}
var objects = scene.objects, len = objects.length;
var mesh, vertex, face;
var i, j, verticesLength, facesLength;
var v1, v2, v3, v4, face4count = 0, face3count = 0;
for (i = 0; i < len; i++) {
object = objects[i];
if (object.autoUpdateMatrix) {
object.updateMatrix();
}
if (object instanceof Mesh) {
glMatrix.mat4.multiply(matrix, camera.matrix, object.matrix);
verticesLength = object.geometry.vertices.length;
for (j = 0; j < verticesLength; j++) {
vertex = object.geometry.vertices[j];
glMatrix.vec3.copy(vertex.screen, vertex.position)
glMatrix.vec3.transformMat4(vertex.screen, vertex.screen, matrix)
glMatrix.vec3.transformMat4(vertex.screen, vertex.screen, camera.projectionMatrix)
vertex.__visible = vertex.screen[2] > 0 && vertex.screen[2] < 1;
// console.log(vertex.screen[2])
//console.log(vertex.screen[2] )
}
facesLength = object.geometry.faces.length;
for (j = 0; j < facesLength; j++) {
face = object.geometry.faces[j];
// TODO: Use normals for culling... maybe not?
if (face instanceof Face3) {
v1 = object.geometry.vertices[face.a];
v2 = object.geometry.vertices[face.b];
v3 = object.geometry.vertices[face.c];
if (v1.__visible && v2.__visible && v3.__visible && (object.doubleSided ||
(v3.screen[0] - v1.screen[0]) * (v2.screen[1] - v1.screen[1]) -
(v3.screen[1] - v1.screen[1]) * (v2.screen[0] - v1.screen[0]) > 0)) {
face.screen[2] = Math.max(v1.screen[2], Math.max(v2.screen[2], v3.screen[2]));
if (!face3Pool[face3count]) {
face3Pool[face3count] = new RenderableFace3();
}
glMatrix.vec2.copy(face3Pool[face3count].v1, v1.screen);
glMatrix.vec2.copy(face3Pool[face3count].v2, v2.screen)
glMatrix.vec2.copy(face3Pool[face3count].v3, v3.screen);
face3Pool[face3count].z = face.screen[2];
// face3Pool[face3count].v1.x = v1.screen.x;
// face3Pool[face3count].v1.y = v1.screen.y;
// face3Pool[face3count].v2.x = v2.screen.x;
// face3Pool[face3count].v2.y = v2.screen.y;
// face3Pool[face3count].v3.x = v3.screen.x;
// face3Pool[face3count].v3.y = v3.screen.y;
// face3Pool[face3count].z = face.screen.z;
face3Pool[face3count].material = object.material;
face3Pool[face3count].overdraw = object.overdraw;
face3Pool[face3count].uvs = object.geometry.uvs[j];
face3Pool[face3count].color = face.color;
this.renderList.push(face3Pool[face3count]);
face3count++;
}
}
else if (face instanceof Face4) {
v1 = object.geometry.vertices[face.a];
v2 = object.geometry.vertices[face.b];
v3 = object.geometry.vertices[face.c];
v4 = object.geometry.vertices[face.d];
if (v1.__visible && v2.__visible && v3.__visible && v4.__visible && (object.doubleSided ||
((v4.screen[0] - v1.screen[0]) * (v2.screen[1] - v1.screen[1]) -
(v4.screen[1] - v1.screen[1]) * (v2.screen[0] - v1.screen[0]) > 0 ||
(v2.screen[0] - v3.screen[0]) * (v4.screen[1] - v3.screen[1]) -
(v2.screen[1] - v3.screen[1]) * (v4.screen[0] - v3.screen[0]) > 0))) {
// console.log('vertices')
face.screen[2] = Math.max(v1.screen[2], Math.max(v2.screen[2], Math.max(v3.screen[2], v4.screen[2])));
if (!face4Pool[face4count]) {
face4Pool[face4count] = new RenderableFace4();
}
glMatrix.vec2.copy(face4Pool[face4count].v1, v1.screen);
glMatrix.vec2.copy(face4Pool[face4count].v2, v2.screen)
glMatrix.vec2.copy(face4Pool[face4count].v3, v3.screen);
glMatrix.vec2.copy(face4Pool[face4count].v4, v4.screen);
face4Pool[face4count].z = face.screen[2];
// face4Pool[face4count].v1[0] = v1.screen[0];
// face4Pool[face4count].v1[1] = v1.screen[1];
// face4Pool[face4count].v2[0] = v2.screen[0];
// face4Pool[face4count].v2[1] = v2.screen[1];
// face4Pool[face4count].v3[0] = v3.screen[0];
// face4Pool[face4count].v3.y = v3.screen[1];
// face4Pool[face4count].v4.x = v4.screen[0];
// face4Pool[face4count].v4.y = v4.screen[1];
// face4Pool[face4count].z = face.screen[2];
face4Pool[face4count].material = object.material;
face4Pool[face4count].overdraw = object.overdraw;
face4Pool[face4count].uvs = object.geometry.uvs[j];
face4Pool[face4count].color = face.color;
this.renderList.push(face4Pool[face4count]);
face4count++;
}
}
}
}
}
this.renderList.sort(painterSort)
}
}
function Rectangle(x1, y1, x2, y2) {
var _x1 = x1, _y1 = y1,
_x2 = x2, _y2 = y2,
_width = _x2 - _x1, _height = _y2 - _y1,
_isEmpty = false;
function resize() {
_width = _x2 - _x1;
_height = _y2 - _y1;
}
this.getX = function () {
return _x1;
};
this.getY = function () {
return _y1;
};
this.getWidth = function () {
return _width;
};
this.getHeight = function () {
return _height;
};
this.getX1 = function () {
return _x1;
};
this.getY1 = function () {
return _y1;
};
this.getX2 = function () {
return _x2;
};
this.getY2 = function () {
return _y2;
};
this.set = function (x1, y1, x2, y2) {
_isEmpty = false;
_x1 = x1; _y1 = y1;
_x2 = x2; _y2 = y2;
resize();
};
this.addPoint = function (x, y) {
if (_isEmpty) {
_isEmpty = false;
_x1 = x; _y1 = y;
_x2 = x; _y2 = y;
} else {
_x1 = Math.min(_x1, x);
_y1 = Math.min(_y1, y);
_x2 = Math.max(_x2, x);
_y2 = Math.max(_y2, y);
}
resize();
};
this.addRectangle = function (r) {
if (_isEmpty) {
_isEmpty = false;
_x1 = r.getX1(); _y1 = r.getY1();
_x2 = r.getX2(); _y2 = r.getY2();
} else {
_x1 = Math.min(_x1, r.getX1());
_y1 = Math.min(_y1, r.getY1());
_x2 = Math.max(_x2, r.getX2());
_y2 = Math.max(_y2, r.getY2());
}
resize();
};
this.inflate = function (v) {
_x1 -= v; _y1 -= v;
_x2 += v; _y2 += v;
resize();
};
this.minSelf = function (r) {
_x1 = Math.max(_x1, r.getX1());
_y1 = Math.max(_y1, r.getY1());
_x2 = Math.min(_x2, r.getX2());
_y2 = Math.min(_y2, r.getY2());
resize();
};
/*
this.containsPoint = function (x, y) {
return x > _x1 && x < _x2 && y > _y1 && y < _y2;
}
*/
this.instersects = function (r) {
return Math.min(_x2, r.getX2()) - Math.max(_x1, r.getX1()) > 0 && Math.min(_y2, r.getY2()) - Math.max(_y1, r.getY1()) > 0;
};
this.empty = function () {
_isEmpty = true;
_x1 = 0; _y1 = 0;
_x2 = 0; _y2 = 0;
resize();
};
};
function SVGRenderer() {
this.render = function (scene, camera) {
}
}
function CanvasRenderer() {
Renderer.call(this);
var _viewport = document.createElement("canvas"),
_context = _viewport.getContext("2d"),
_width, _height, _widthHalf, _heightHalf, _widthHeightHalf = glMatrix.vec2.create();
_clipRect = new Rectangle(),
_clearRect = new Rectangle(0, 0, 0, 0),
_bboxRect = new Rectangle(),
_vector2 = glMatrix.vec2.create();
this.domElement = _viewport;
this.autoClear = true;
this.setSize = function (width, height) {
_width = width; _height = height;
_widthHalf = _width / 2; _heightHalf = _height / 2;
_viewport.width = _width;
_viewport.height = _height;
_context.setTransform(1, 0, 0, 1, _widthHalf, _heightHalf);
_clipRect.set(- _widthHalf, - _heightHalf, _widthHalf, _heightHalf);
glMatrix.vec2.set(_widthHeightHalf, _widthHalf, _heightHalf)
};
this.clear = function () {
_clearRect.inflate(1);
_clearRect.minSelf(_clipRect);
_context.clearRect(_clearRect.getX(), _clearRect.getY(), _clearRect.getWidth(), _clearRect.getHeight());
_clearRect.empty();
};
this.render = function (scene, camera) {
this.project(scene, camera);
if (this.autoClear) {
this.clear();
}
var element, materialLength, elementsLength = this.renderList.length;
var v1x, v2x, v3x, v4x, v1y, v2y, v3y, v4y;
var i;
for (i = 0; i < elementsLength; i++) {
element = this.renderList[i];
materialLength = element.material.length;
_bboxRect.empty();
_context.beginPath();
if (element instanceof RenderableFace3) {
glMatrix.vec2.mul(element.v1, element.v1, _widthHeightHalf);
glMatrix.vec2.mul(element.v2, element.v2, _widthHeightHalf)
glMatrix.vec2.mul(element.v3, element.v3, _widthHeightHalf)
// element.v1.x *= _widthHalf; element.v1.y *= _heightHalf;
// element.v2.x *= _widthHalf; element.v2.y *= _heightHalf;
// element.v3.x *= _widthHalf; element.v3.y *= _heightHalf;
if (element.overdraw) {
expand(element.v1, element.v2);
expand(element.v2, element.v3);
expand(element.v3, element.v1);
}
v1x = element.v1[0]; v1y = element.v1[1];
v2x = element.v2[0]; v2y = element.v2[1];
v3x = element.v3[0]; v3y = element.v3[1];
// v1x = element.v1.x; v1y = element.v1.y;
// v2x = element.v2.x; v2y = element.v2.y;
// v3x = element.v3.x; v3y = element.v3.y;
_bboxRect.addPoint(v1x, v1y);
_bboxRect.addPoint(v2x, v2y);
_bboxRect.addPoint(v3x, v3y);
if (!_clipRect.instersects(_bboxRect)) {
continue;
}
_context.moveTo(v1x, v1y);
_context.lineTo(v2x, v2y);
_context.lineTo(v3x, v3y);
_context.lineTo(v1x, v1y);
}
else if (element instanceof RenderableFace4) {
glMatrix.vec2.mul(element.v1, element.v1, _widthHeightHalf);
glMatrix.vec2.mul(element.v2, element.v2, _widthHeightHalf)
glMatrix.vec2.mul(element.v3, element.v3, _widthHeightHalf)
glMatrix.vec2.mul(element.v4, element.v4, _widthHeightHalf)
// element.v1.x *= _widthHalf; element.v1.y *= _heightHalf;
// element.v2.x *= _widthHalf; element.v2.y *= _heightHalf;
// element.v3.x *= _widthHalf; element.v3.y *= _heightHalf;
// element.v4.x *= _widthHalf; element.v4.y *= _heightHalf;
if (element.overdraw) {
expand(element.v1, element.v2);
expand(element.v2, element.v3);
expand(element.v3, element.v4);
expand(element.v4, element.v1);
}
v1x = element.v1[0]; v1y = element.v1[1];
v2x = element.v2[0]; v2y = element.v2[1];
v3x = element.v3[0]; v3y = element.v3[1];
v4x = element.v4[0]; v4y = element.v4[1];
_bboxRect.addPoint(v1x, v1y);
_bboxRect.addPoint(v2x, v2y);
_bboxRect.addPoint(v3x, v3y);
_bboxRect.addPoint(v4x, v4y);
if (!_clipRect.instersects(_bboxRect)) {
continue;
}
_context.moveTo(v1x, v1y);
_context.lineTo(v2x, v2y);
_context.lineTo(v3x, v3y);
_context.lineTo(v4x, v4y);
_context.lineTo(v1x, v1y);
}
_context.closePath();
for (j = 0; j < materialLength; j++) {
material = element.material[j];
if (material instanceof ColorFillMaterial) {
_context.fillStyle = material.color.cssRgba;
_context.fill();
} else if (material instanceof FaceColorFillMaterial) {
_context.fillStyle = element.color.cssRgba;
_context.fill();
} else if (material instanceof ColorStrokeMaterial) {
_context.lineWidth = material.lineWidth;
_context.lineJoin = "round";
_context.lineCap = "round";
_context.strokeStyle = material.color.__styleString;
_context.stroke();
_bboxRect.inflate(_context.lineWidth);
} else if (material instanceof BitmapUVMappingMaterial) {
bitmap = material.bitmap;
bitmapWidth = bitmap.width;
bitmapHeight = bitmap.height;
uv1.copy(element.uvs[0]); uv2.copy(element.uvs[1]); uv3.copy(element.uvs[2]);
suv1.copy(uv1); suv2.copy(uv2); suv3.copy(uv3);
suv1.x *= bitmapWidth; suv1.y *= bitmapHeight;
suv2.x *= bitmapWidth; suv2.y *= bitmapHeight;
suv3.x *= bitmapWidth; suv3.y *= bitmapHeight;
if (element.overdraw) {
expand(suv1, suv2);
expand(suv2, suv3);
expand(suv3, suv1);
suv1.x = (uv1.x === 0) ? 1 : (uv1.x === 1) ? suv1.x - 1 : suv1.x;
suv1.y = (uv1.y === 0) ? 1 : (uv1.y === 1) ? suv1.y - 1 : suv1.y;
suv2.x = (uv2.x === 0) ? 1 : (uv2.x === 1) ? suv2.x - 1 : suv2.x;
suv2.y = (uv2.y === 0) ? 1 : (uv2.y === 1) ? suv2.y - 1 : suv2.y;
suv3.x = (uv3.x === 0) ? 1 : (uv3.x === 1) ? suv3.x - 1 : suv3.x;
suv3.y = (uv3.y === 0) ? 1 : (uv3.y === 1) ? suv3.y - 1 : suv3.y;
}
suv1x = suv1.x; suv1y = suv1.y;
suv2x = suv2.x; suv2y = suv2.y;
suv3x = suv3.x; suv3y = suv3.y;
// Textured triangle drawing by Thatcher Ulrich.
// http://tulrich.com/geekstuff/canvas/jsgl.js
_context.save();
_context.clip();
denom = suv1x * (suv3y - suv2y) - suv2x * suv3y + suv3x * suv2y + (suv2x - suv3x) * suv1y;
m11 = - (suv1y * (v3x - v2x) - suv2y * v3x + suv3y * v2x + (suv2y - suv3y) * v1x) / denom;
m12 = (suv2y * v3y + suv1y * (v2y - v3y) - suv3y * v2y + (suv3y - suv2y) * v1y) / denom;
m21 = (suv1x * (v3x - v2x) - suv2x * v3x + suv3x * v2x + (suv2x - suv3x) * v1x) / denom;
m22 = - (suv2x * v3y + suv1x * (v2y - v3y) - suv3x * v2y + (suv3x - suv2x) * v1y) / denom;
dx = (suv1x * (suv3y * v2x - suv2y * v3x) + suv1y * (suv2x * v3x - suv3x * v2x) + (suv3x * suv2y - suv2x * suv3y) * v1x) / denom;
dy = (suv1x * (suv3y * v2y - suv2y * v3y) + suv1y * (suv2x * v3y - suv3x * v2y) + (suv3x * suv2y - suv2x * suv3y) * v1y) / denom;
_context.transform(m11, m12, m21, m22, dx, dy);
_context.drawImage(bitmap, 0, 0);
_context.restore();
}
_clearRect.addRectangle(_bboxRect);
}
}
}
function expand(a, b) {
glMatrix.vec2.sub(_vector2, b, a)
glMatrix.vec2.normalize$4(_vector2, _vector2);
glMatrix.vec2.add(b, b, _vector2);
glMatrix.vec2.sub(a, a, _vector2);
}
}
inherits(CanvasRenderer, Renderer)
var Cube = function (width, height, depth) {
Geometry.call(this);
var scope = this,
width_half = width / 2,
height_half = height / 2,
depth_half = depth / 2;
v(width_half, height_half, -depth_half);
v(width_half, -height_half, -depth_half);
v(-width_half, -height_half, -depth_half);
v(-width_half, height_half, -depth_half);
v(width_half, height_half, depth_half);
v(width_half, -height_half, depth_half);
v(-width_half, -height_half, depth_half);
v(-width_half, height_half, depth_half);
f4(0, 1, 2, 3);
f4(4, 7, 6, 5);
f4(0, 4, 5, 1);
f4(1, 5, 6, 2);
f4(2, 6, 7, 3);
f4(4, 0, 3, 7);
// 添加顶点
function v(x, y, z) {
scope.vertices.push(new Vertex(new glMatrix.vec3.fromValues(x, y, z)));
}
// 添加面
function f4(a, b, c, d) {
scope.faces.push(new Face4(a, b, c, d));
}
}
inherits(Cube, Geometry);
var Plane = function (width, height, segments_width, segments_height) {
Geometry.call(this);
var scope = this,
width_half = width / 2,
height_half = height / 2,
gridX = segments_width || 1,
gridY = segments_height || 1,
gridX1 = gridX + 1,
gridY1 = gridY + 1,
segment_width = width / gridX,
segment_height = height / gridY;
for (var iy = 0; iy < gridY1; iy++) {
for (var ix = 0; ix < gridX1; ix++) {
var x = ix * segment_width - width_half;
var y = iy * segment_height - height_half;
this.vertices.push(new Vertex(new glMatrix.vec3.fromValues(x, - y, 0)));
}
}
for (iy = 0; iy < gridY; iy++) {
for (ix = 0; ix < gridX; ix++) {
var a = ix + gridX1 * iy;
var b = ix + gridX1 * (iy + 1);
var c = (ix + 1) + gridX1 * iy;
this.faces.push(new Face3(a, b, c));
this.uvs.push([
glMatrix.vec2.fromValues(ix / gridX, iy / gridY),
glMatrix.vec2.fromValues(ix / gridX, (iy + 1) / gridY),
glMatrix.vec2.fromValues((ix + 1) / gridX, iy / gridY)
]);
a = (ix + 1) + gridX1 * (iy + 1);
b = (ix + 1) + gridX1 * iy;
c = ix + gridX1 * (iy + 1);
this.faces.push(new Face3(a, b, c));
this.uvs.push([
glMatrix.vec2.fromValues((ix + 1) / gridX, (iy + 1) / gridY),
glMatrix.vec2.fromValues((ix + 1) / gridX, iy / gridY),
glMatrix.vec2.fromValues(ix / gridX, (iy + 1) / gridY)
]);
}
}
}
inherits(Plane, Geometry)
function show() {
var width = window.innerWidth;
var height = window.innerWidth;
var renderer = new CanvasRenderer();
var camera = new Camera(70 / 180 * Math.PI, width / height, 0.0001, 10000);
camera.position[1] = 150;
camera.position[2] = 500;
camera.target.position[1] = 150;
var scene = new Scene();
var cubeGeometry = new Cube(200, 200, 200);//创建立方体(正方体)
for (var i = 0; i < cubeGeometry.faces.length; i++) {
cubeGeometry.faces[i].color.setRGBA(Math.floor(Math.random() * 128), Math.floor(Math.random() * 128 + 128), Math.floor(Math.random() * 128 + 128), 255);
}
var cube = new Mesh(cubeGeometry, new FaceColorFillMaterial(0xff0000, 1));
cube.position[1] = 150;
scene.add(cube);
var plane = new Mesh(new Plane(200, 200), new ColorFillMaterial(0xdddddd, 1));
plane.rotation[0] = -90 * (Math.PI / 180);
plane.position[1]=300;
scene.add(plane);
renderer.setSize(width, height);
d3.select('body').append('div').append(function () {
return renderer.domElement;
})
// renderer.render(scene, camera);
var targetRotation = 0;
var targetRotationOnMouseDown = 0;
var mouseX = 0;
var mouseXOnMouseDown = 0;
var windowHalfX = width / 2;
var windowHalfY = height / 2;
var stats = new Stats();
stats.showPanel(0); // 0: fps, 1: ms, 2: mb, 3+: custom
stats.domElement.style.position = 'fixed';
stats.domElement.style.top = '0px';
document.body.appendChild(stats.domElement);
document.addEventListener('mousedown', onDocumentMouseDown, false);
document.addEventListener('touchstart', onDocumentTouchStart, false);
document.addEventListener('touchmove', onDocumentTouchMove, false);
function onDocumentMouseDown(event) {
event.preventDefault();
document.addEventListener('mousemove', onDocumentMouseMove, false);
document.addEventListener('mouseup', onDocumentMouseUp, false);
document.addEventListener('mouseout', onDocumentMouseOut, false);
mouseXOnMouseDown = event.clientX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
}
function onDocumentMouseUp(event) {
document.removeEventListener('mousemove', onDocumentMouseMove, false);
document.removeEventListener('mouseup', onDocumentMouseUp, false);
document.removeEventListener('mouseout', onDocumentMouseOut, false);
}
function onDocumentMouseOut(event) {
document.removeEventListener('mousemove', onDocumentMouseMove, false);
document.removeEventListener('mouseup', onDocumentMouseUp, false);
document.removeEventListener('mouseout', onDocumentMouseOut, false);
}
function onDocumentTouchStart(event) {
if (event.touches.length == 1) {
event.preventDefault();
mouseXOnMouseDown = event.touches[0].pageX - windowHalfX;
targetRotationOnMouseDown = targetRotation;
}
}
function onDocumentTouchMove(event) {
if (event.touches.length == 1) {
event.preventDefault();
mouseX = event.touches[0].pageX - windowHalfX;
targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.05;
}
}
//
function loop() {
// cube.rotation[1] += 0.1;
plane.rotation[2] = cube.rotation[1] += (targetRotation - cube.rotation[1]) * 0.05;
renderer.render(scene, camera);
stats.update();
}
d3.timer(loop)
}
show();
</script>
</body>
</html>