mirror of
https://github.com/smallmain/cocos-enhance-kit.git
synced 2025-10-08 23:25:22 +00:00
初始化
This commit is contained in:
573
engine/cocos2d/core/mesh/CCMesh.js
Normal file
573
engine/cocos2d/core/mesh/CCMesh.js
Normal file
@@ -0,0 +1,573 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
const renderer = require('../renderer');
|
||||
const EventTarget = require('../event/event-target');
|
||||
|
||||
import InputAssembler from '../../renderer/core/input-assembler';
|
||||
import gfx from '../../renderer/gfx';
|
||||
import { Primitive, VertexBundle, MeshData} from './mesh-data';
|
||||
|
||||
function applyColor (data, offset, value) {
|
||||
data[offset] = value._val;
|
||||
}
|
||||
|
||||
function applyVec2 (data, offset, value) {
|
||||
data[offset] = value.x;
|
||||
data[offset + 1] = value.y;
|
||||
}
|
||||
|
||||
function applyVec3 (data, offset, value) {
|
||||
data[offset] = value.x;
|
||||
data[offset + 1] = value.y;
|
||||
data[offset + 2] = value.z;
|
||||
}
|
||||
|
||||
const _compType2fn = {
|
||||
5120: 'getInt8',
|
||||
5121: 'getUint8',
|
||||
5122: 'getInt16',
|
||||
5123: 'getUint16',
|
||||
5124: 'getInt32',
|
||||
5125: 'getUint32',
|
||||
5126: 'getFloat32',
|
||||
};
|
||||
|
||||
const _compType2write = {
|
||||
5120: 'setInt8',
|
||||
5121: 'setUint8',
|
||||
5122: 'setInt16',
|
||||
5123: 'setUint16',
|
||||
5124: 'setInt32',
|
||||
5125: 'setUint32',
|
||||
5126: 'setFloat32',
|
||||
};
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView#Endianness
|
||||
const littleEndian = (function () {
|
||||
let buffer = new ArrayBuffer(2);
|
||||
new DataView(buffer).setInt16(0, 256, true);
|
||||
// Int16Array uses the platform's endianness.
|
||||
return new Int16Array(buffer)[0] === 256;
|
||||
})();
|
||||
|
||||
/**
|
||||
* @module cc
|
||||
*/
|
||||
/**
|
||||
* !#en Mesh Asset.
|
||||
* !#zh 网格资源。
|
||||
* @class Mesh
|
||||
* @extends Asset
|
||||
* @uses EventTarget
|
||||
*/
|
||||
let Mesh = cc.Class({
|
||||
name: 'cc.Mesh',
|
||||
extends: cc.Asset,
|
||||
mixins: [EventTarget],
|
||||
|
||||
properties: {
|
||||
_nativeAsset: {
|
||||
override: true,
|
||||
get () {
|
||||
return this._buffer;
|
||||
},
|
||||
set (bin) {
|
||||
this._buffer = ArrayBuffer.isView(bin) ? bin.buffer : bin;
|
||||
this.initWithBuffer();
|
||||
}
|
||||
},
|
||||
|
||||
_vertexBundles: {
|
||||
default: null,
|
||||
type: VertexBundle
|
||||
},
|
||||
_primitives: {
|
||||
default: null,
|
||||
Primitive
|
||||
},
|
||||
_minPos: cc.v3(),
|
||||
_maxPos: cc.v3(),
|
||||
|
||||
/**
|
||||
* !#en Get ir set the sub meshes.
|
||||
* !#zh 设置或者获取子网格。
|
||||
* @property {[InputAssembler]} subMeshes
|
||||
*/
|
||||
subMeshes: {
|
||||
get () {
|
||||
return this._subMeshes;
|
||||
},
|
||||
set (v) {
|
||||
this._subMeshes = v;
|
||||
}
|
||||
},
|
||||
|
||||
subDatas : {
|
||||
get () {
|
||||
return this._subDatas;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ctor () {
|
||||
this._subMeshes = [];
|
||||
this._subDatas = [];
|
||||
this.loaded = false;
|
||||
},
|
||||
|
||||
initWithBuffer () {
|
||||
this._subMeshes.length = 0;
|
||||
|
||||
let primitives = this._primitives;
|
||||
for (let i = 0; i < primitives.length; i++) {
|
||||
let primitive = primitives[i];
|
||||
|
||||
// ib
|
||||
let ibrange = primitive.data;
|
||||
let ibData = new Uint8Array(this._buffer, ibrange.offset, ibrange.length);
|
||||
|
||||
// vb
|
||||
let vertexBundle = this._vertexBundles[primitive.vertexBundleIndices[0]];
|
||||
let vbRange = vertexBundle.data;
|
||||
let gfxVFmt = new gfx.VertexFormat(vertexBundle.formats);
|
||||
// Mesh binary may have several data format, must use Uint8Array to store data.
|
||||
let vbData = new Uint8Array(this._buffer, vbRange.offset, vbRange.length);
|
||||
|
||||
let canBatch = this._canVertexFormatBatch(gfxVFmt);
|
||||
|
||||
let meshData = new MeshData();
|
||||
meshData.vData = vbData;
|
||||
meshData.iData = ibData;
|
||||
meshData.vfm = gfxVFmt;
|
||||
meshData.offset = vbRange.offset;
|
||||
meshData.canBatch = canBatch;
|
||||
this._subDatas.push(meshData);
|
||||
|
||||
if (CC_JSB && CC_NATIVERENDERER) {
|
||||
meshData.vDirty = true;
|
||||
this._subMeshes.push(new InputAssembler(null, null));
|
||||
} else {
|
||||
let vbBuffer = new gfx.VertexBuffer(
|
||||
renderer.device,
|
||||
gfxVFmt,
|
||||
gfx.USAGE_STATIC,
|
||||
vbData
|
||||
);
|
||||
|
||||
let ibBuffer = new gfx.IndexBuffer(
|
||||
renderer.device,
|
||||
primitive.indexUnit,
|
||||
gfx.USAGE_STATIC,
|
||||
ibData
|
||||
);
|
||||
|
||||
// create sub meshes
|
||||
this._subMeshes.push(new InputAssembler(vbBuffer, ibBuffer));
|
||||
}
|
||||
}
|
||||
this.loaded = true;
|
||||
this.emit('load');
|
||||
},
|
||||
|
||||
_canVertexFormatBatch (format) {
|
||||
let aPosition = format._attr2el[gfx.ATTR_POSITION];
|
||||
let canBatch = !aPosition ||
|
||||
(aPosition.type === gfx.ATTR_TYPE_FLOAT32 &&
|
||||
format._bytes % 4 === 0);
|
||||
return canBatch;
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Init vertex buffer according to the vertex format.
|
||||
* !#zh
|
||||
* 根据顶点格式初始化顶点内存。
|
||||
* @method init
|
||||
* @param {gfx.VertexFormat} vertexFormat - vertex format
|
||||
* @param {Number} vertexCount - how much vertex should be create in this buffer.
|
||||
* @param {Boolean} [dynamic] - whether or not to use dynamic buffer.
|
||||
* @param {Boolean} [index]
|
||||
*/
|
||||
init (vertexFormat, vertexCount, dynamic = false, index = 0) {
|
||||
let data = new Uint8Array(vertexFormat._bytes * vertexCount);
|
||||
let meshData = new MeshData();
|
||||
meshData.vData = data;
|
||||
meshData.vfm = vertexFormat;
|
||||
meshData.vDirty = true;
|
||||
meshData.canBatch = this._canVertexFormatBatch(vertexFormat);
|
||||
|
||||
if (!(CC_JSB && CC_NATIVERENDERER)) {
|
||||
let vb = new gfx.VertexBuffer(
|
||||
renderer.device,
|
||||
vertexFormat,
|
||||
dynamic ? gfx.USAGE_DYNAMIC : gfx.USAGE_STATIC,
|
||||
data,
|
||||
);
|
||||
|
||||
meshData.vb = vb;
|
||||
this._subMeshes[index] = new InputAssembler(meshData.vb);
|
||||
}
|
||||
|
||||
let oldSubData = this._subDatas[index];
|
||||
if (oldSubData) {
|
||||
if (oldSubData.vb) {
|
||||
oldSubData.vb.destroy();
|
||||
}
|
||||
if (oldSubData.ib) {
|
||||
oldSubData.ib.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
this._subDatas[index] = meshData;
|
||||
|
||||
this.loaded = true;
|
||||
this.emit('load');
|
||||
this.emit('init-format');
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Set the vertex values.
|
||||
* !#zh
|
||||
* 设置顶点数据
|
||||
* @method setVertices
|
||||
* @param {String} name - the attribute name, e.g. gfx.ATTR_POSITION
|
||||
* @param {[Vec2] | [Vec3] | [Color] | [Number] | Uint8Array | Float32Array} values - the vertex values
|
||||
*/
|
||||
setVertices (name, values, index) {
|
||||
index = index || 0;
|
||||
let subData = this._subDatas[index];
|
||||
|
||||
let el = subData.vfm.element(name);
|
||||
if (!el) {
|
||||
return cc.warn(`Cannot find ${name} attribute in vertex defines.`);
|
||||
}
|
||||
|
||||
// whether the values is expanded
|
||||
let isFlatMode = typeof values[0] === 'number';
|
||||
|
||||
let elNum = el.num;
|
||||
let verticesCount = isFlatMode ? ((values.length / elNum) | 0) : values.length;
|
||||
if (subData.vData.byteLength < verticesCount * el.stride) {
|
||||
subData.setVData(new Uint8Array(verticesCount * subData.vfm._bytes));
|
||||
}
|
||||
|
||||
let data;
|
||||
let bytes = 4;
|
||||
if (name === gfx.ATTR_COLOR) {
|
||||
if (!isFlatMode) {
|
||||
data = subData.getVData(Uint32Array);
|
||||
}
|
||||
else {
|
||||
data = subData.getVData();
|
||||
bytes = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
data = subData.getVData(Float32Array);
|
||||
}
|
||||
|
||||
let stride = el.stride / bytes;
|
||||
let offset = el.offset / bytes;
|
||||
|
||||
if (isFlatMode) {
|
||||
for (let i = 0, l = (values.length / elNum); i < l; i++) {
|
||||
let sOffset = i * elNum;
|
||||
let dOffset = i * stride + offset;
|
||||
for (let j = 0; j < elNum; j++) {
|
||||
data[dOffset + j] = values[sOffset + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
let applyFunc;
|
||||
if (name === gfx.ATTR_COLOR) {
|
||||
applyFunc = applyColor;
|
||||
}
|
||||
else {
|
||||
if (elNum === 2) {
|
||||
applyFunc = applyVec2;
|
||||
}
|
||||
else {
|
||||
applyFunc = applyVec3;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0, l = values.length; i < l; i++) {
|
||||
let v = values[i];
|
||||
let vOffset = i * stride + offset;
|
||||
applyFunc(data, vOffset, v);
|
||||
}
|
||||
}
|
||||
subData.vDirty = true;
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Set the sub mesh indices.
|
||||
* !#zh
|
||||
* 设置子网格索引。
|
||||
* @method setIndices
|
||||
* @param {[Number]|Uint16Array|Uint8Array} indices - the sub mesh indices.
|
||||
* @param {Number} [index] - sub mesh index.
|
||||
* @param {Boolean} [dynamic] - whether or not to use dynamic buffer.
|
||||
*/
|
||||
setIndices (indices, index, dynamic) {
|
||||
index = index || 0;
|
||||
|
||||
let iData = indices;
|
||||
if (indices instanceof Uint16Array) {
|
||||
iData = new Uint8Array(indices.buffer, indices.byteOffset, indices.byteLength);
|
||||
}
|
||||
else if (Array.isArray(indices)) {
|
||||
iData = new Uint16Array(indices);
|
||||
iData = new Uint8Array(iData.buffer, iData.byteOffset, iData.byteLength);
|
||||
}
|
||||
|
||||
let usage = dynamic ? gfx.USAGE_DYNAMIC : gfx.USAGE_STATIC;
|
||||
|
||||
let subData = this._subDatas[index];
|
||||
if (!subData.ib) {
|
||||
subData.iData = iData;
|
||||
if (!(CC_JSB && CC_NATIVERENDERER)) {
|
||||
let buffer = new gfx.IndexBuffer(
|
||||
renderer.device,
|
||||
gfx.INDEX_FMT_UINT16,
|
||||
usage,
|
||||
iData,
|
||||
iData.byteLength / gfx.IndexBuffer.BYTES_PER_INDEX[gfx.INDEX_FMT_UINT16]
|
||||
);
|
||||
|
||||
subData.ib = buffer;
|
||||
this._subMeshes[index]._indexBuffer = subData.ib;
|
||||
}
|
||||
}
|
||||
else {
|
||||
subData.iData = iData;
|
||||
subData.iDirty = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Set the sub mesh primitive type.
|
||||
* !#zh
|
||||
* 设置子网格绘制线条的方式。
|
||||
* @method setPrimitiveType
|
||||
* @param {Number} type
|
||||
* @param {Number} index
|
||||
*/
|
||||
setPrimitiveType (type, index) {
|
||||
index = index || 0;
|
||||
let subMesh = this._subMeshes[index];
|
||||
if (!subMesh) {
|
||||
cc.warn(`Do not have sub mesh at index ${index}`);
|
||||
return;
|
||||
}
|
||||
this._subMeshes[index]._primitiveType = type;
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Clear the buffer data.
|
||||
* !#zh
|
||||
* 清除网格创建的内存数据。
|
||||
* @method clear
|
||||
*/
|
||||
clear () {
|
||||
this._subMeshes.length = 0;
|
||||
|
||||
let subDatas = this._subDatas;
|
||||
for (let i = 0, len = subDatas.length; i < len; i++) {
|
||||
let vb = subDatas[i].vb;
|
||||
if (vb) {
|
||||
vb.destroy();
|
||||
}
|
||||
|
||||
let ib = subDatas[i].ib;
|
||||
if (ib) {
|
||||
ib.destroy();
|
||||
}
|
||||
}
|
||||
subDatas.length = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en Set mesh bounding box
|
||||
* !#zh 设置网格的包围盒
|
||||
* @method setBoundingBox
|
||||
* @param {Vec3} min
|
||||
* @param {Vec3} max
|
||||
*/
|
||||
setBoundingBox (min, max) {
|
||||
this._minPos = min;
|
||||
this._maxPos = max;
|
||||
},
|
||||
|
||||
destroy () {
|
||||
this.clear();
|
||||
},
|
||||
|
||||
_uploadData () {
|
||||
let subDatas = this._subDatas;
|
||||
for (let i = 0, len = subDatas.length; i < len; i++) {
|
||||
let subData = subDatas[i];
|
||||
|
||||
if (subData.vDirty) {
|
||||
let buffer = subData.vb, data = subData.vData;
|
||||
buffer.update(0, data);
|
||||
subData.vDirty = false;
|
||||
}
|
||||
|
||||
if (subData.iDirty) {
|
||||
let buffer = subData.ib, data = subData.iData;
|
||||
buffer.update(0, data);
|
||||
subData.iDirty = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_getAttrMeshData (subDataIndex, name) {
|
||||
let subData = this._subDatas[subDataIndex];
|
||||
if (!subData) return [];
|
||||
|
||||
let format = subData.vfm;
|
||||
let fmt = format.element(name);
|
||||
if (!fmt) return [];
|
||||
|
||||
if (!subData.attrDatas) {
|
||||
subData.attrDatas = {};
|
||||
}
|
||||
let attrDatas = subData.attrDatas;
|
||||
let data = attrDatas[name];
|
||||
if (data) {
|
||||
return data;
|
||||
}
|
||||
else {
|
||||
data = attrDatas[name] = [];
|
||||
}
|
||||
|
||||
let vbData = subData.vData;
|
||||
let dv = new DataView(vbData.buffer, vbData.byteOffset, vbData.byteLength);
|
||||
|
||||
let stride = fmt.stride;
|
||||
let eleOffset = fmt.offset;
|
||||
let eleNum = fmt.num;
|
||||
let eleByte = fmt.bytes / eleNum;
|
||||
let fn = _compType2fn[fmt.type];
|
||||
let vertexCount = vbData.byteLength / format._bytes;
|
||||
|
||||
for (let i = 0; i < vertexCount; i++) {
|
||||
let offset = i * stride + eleOffset;
|
||||
for (let j = 0; j < eleNum; j++) {
|
||||
let v = dv[fn](offset + j * eleByte, littleEndian);
|
||||
data.push(v);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en Read the specified attributes of the subgrid into the target buffer.
|
||||
* !#zh 读取子网格的指定属性到目标缓冲区中。
|
||||
* @param {Number} primitiveIndex The subgrid index.
|
||||
* @param {String} attributeName attribute name.
|
||||
* @param {ArrayBuffer} buffer The target buffer.
|
||||
* @param {Number} stride The byte interval between adjacent attributes in the target buffer.
|
||||
* @param {Number} offset The offset of the first attribute in the target buffer.
|
||||
* @returns {Boolean} If the specified sub-grid does not exist, the sub-grid does not exist, or the specified attribute cannot be read, return `false`, otherwise return` true`.
|
||||
* @method copyAttribute
|
||||
*/
|
||||
copyAttribute (primitiveIndex, attributeName, buffer, stride, offset) {
|
||||
let written = false;
|
||||
let subData = this._subDatas[primitiveIndex];
|
||||
|
||||
if (!subData) return written;
|
||||
|
||||
let format = subData.vfm;
|
||||
let fmt = format.element(attributeName);
|
||||
|
||||
if (!fmt) return written;
|
||||
|
||||
let writter = _compType2write[fmt.type];
|
||||
|
||||
if (!writter) return written;
|
||||
|
||||
let data = this._getAttrMeshData(primitiveIndex, attributeName);
|
||||
let vertexCount = subData.vData.byteLength / format._bytes;
|
||||
let eleByte = fmt.bytes / fmt.num;
|
||||
|
||||
if (data.length > 0) {
|
||||
const outputView = new DataView(buffer, offset);
|
||||
|
||||
let outputStride = stride;
|
||||
let num = fmt.num;
|
||||
|
||||
for (let i = 0; i < vertexCount; ++i) {
|
||||
let index = i * num;
|
||||
for (let j = 0; j < num; ++j) {
|
||||
const inputOffset = index + j;
|
||||
const outputOffset = outputStride * i + eleByte * j;
|
||||
|
||||
outputView[writter](outputOffset, data[inputOffset], littleEndian);
|
||||
}
|
||||
}
|
||||
|
||||
written = true;
|
||||
}
|
||||
|
||||
return written;
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en Read the index data of the subgrid into the target array.
|
||||
* !#zh 读取子网格的索引数据到目标数组中。
|
||||
* @param {Number} primitiveIndex The subgrid index.
|
||||
* @param {TypedArray} outputArray The target array.
|
||||
* @returns {Boolean} returns `false` if the specified sub-grid does not exist or the sub-grid does not have index data, otherwise returns` true`.
|
||||
* @method copyIndices
|
||||
*/
|
||||
copyIndices (primitiveIndex, outputArray) {
|
||||
let subData = this._subDatas[primitiveIndex];
|
||||
|
||||
if (!subData) return false;
|
||||
|
||||
const iData = subData.iData;
|
||||
const indexCount = iData.length / 2;
|
||||
|
||||
const dv = new DataView(iData.buffer, iData.byteOffset, iData.byteLength);
|
||||
const fn = _compType2fn[gfx.INDEX_FMT_UINT8];
|
||||
|
||||
for (let i = 0; i < indexCount; ++i) {
|
||||
outputArray[i] = dv[fn](i * 2);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
cc.Mesh = module.exports = Mesh;
|
482
engine/cocos2d/core/mesh/CCMeshRenderer.js
Normal file
482
engine/cocos2d/core/mesh/CCMeshRenderer.js
Normal file
@@ -0,0 +1,482 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
import gfx from '../../renderer/gfx';
|
||||
import InputAssembler from '../../renderer/core/input-assembler';
|
||||
import Aabb from '../geom-utils/aabb';
|
||||
import Vec3 from '../value-types/vec3';
|
||||
import Mat4 from '../value-types/mat4';
|
||||
import MaterialVariant from '../assets/material/material-variant';
|
||||
|
||||
const RenderComponent = require('../components/CCRenderComponent');
|
||||
const Mesh = require('./CCMesh');
|
||||
const RenderFlow = require('../renderer/render-flow');
|
||||
const Renderer = require('../renderer');
|
||||
const Material = require('../assets/material/CCMaterial');
|
||||
|
||||
|
||||
/**
|
||||
* !#en Shadow projection mode
|
||||
*
|
||||
* !#ch 阴影投射方式
|
||||
* @static
|
||||
* @enum MeshRenderer.ShadowCastingMode
|
||||
*/
|
||||
let ShadowCastingMode = cc.Enum({
|
||||
/**
|
||||
* !#en
|
||||
*
|
||||
* !#ch 关闭阴影投射
|
||||
* @property OFF
|
||||
* @readonly
|
||||
* @type {Number}
|
||||
*/
|
||||
OFF: 0,
|
||||
/**
|
||||
* !#en
|
||||
*
|
||||
* !#ch 开启阴影投射,当阴影光产生的时候
|
||||
* @property ON
|
||||
* @readonly
|
||||
* @type {Number}
|
||||
*/
|
||||
ON: 1,
|
||||
// /**
|
||||
// * !#en
|
||||
// *
|
||||
// * !#ch 可以从网格的任意一遍投射出阴影
|
||||
// * @property TWO_SIDED
|
||||
// * @readonly
|
||||
// * @type {Number}
|
||||
// */
|
||||
// TWO_SIDED: 2,
|
||||
// /**
|
||||
// * !#en
|
||||
// *
|
||||
// * !#ch 只显示阴影
|
||||
// * @property SHADOWS_ONLY
|
||||
// * @readonly
|
||||
// * @type {Number}
|
||||
// */
|
||||
// SHADOWS_ONLY: 3,
|
||||
});
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Mesh Renderer Component
|
||||
* !#zh
|
||||
* 网格渲染组件
|
||||
* @class MeshRenderer
|
||||
* @extends RenderComponent
|
||||
*/
|
||||
let MeshRenderer = cc.Class({
|
||||
name: 'cc.MeshRenderer',
|
||||
extends: RenderComponent,
|
||||
|
||||
editor: CC_EDITOR && {
|
||||
menu: 'i18n:MAIN_MENU.component.mesh/MeshRenderer',
|
||||
},
|
||||
|
||||
properties: {
|
||||
_mesh: {
|
||||
default: null,
|
||||
type: Mesh
|
||||
},
|
||||
|
||||
_receiveShadows: false,
|
||||
_shadowCastingMode: ShadowCastingMode.OFF,
|
||||
|
||||
_enableAutoBatch: false,
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* The mesh which the renderer uses.
|
||||
* !#zh
|
||||
* 设置使用的网格
|
||||
* @property {Mesh} mesh
|
||||
*/
|
||||
mesh: {
|
||||
get () {
|
||||
return this._mesh;
|
||||
},
|
||||
set (v) {
|
||||
if (this._mesh === v) return;
|
||||
this._setMesh(v);
|
||||
if (!v) {
|
||||
this.disableRender();
|
||||
return;
|
||||
}
|
||||
this.markForRender(true);
|
||||
this.node._renderFlag |= RenderFlow.FLAG_TRANSFORM;
|
||||
},
|
||||
type: Mesh,
|
||||
animatable: false
|
||||
},
|
||||
|
||||
textures: {
|
||||
default: [],
|
||||
type: cc.Texture2D,
|
||||
visible: false
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Whether the mesh should receive shadows.
|
||||
* !#zh
|
||||
* 网格是否接受光源投射的阴影
|
||||
* @property {Boolean} receiveShadows
|
||||
*/
|
||||
receiveShadows: {
|
||||
get () {
|
||||
return this._receiveShadows;
|
||||
},
|
||||
set (val) {
|
||||
this._receiveShadows = val;
|
||||
this._updateReceiveShadow();
|
||||
},
|
||||
animatable: false
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Shadow Casting Mode
|
||||
* !#zh
|
||||
* 网格投射阴影的模式
|
||||
* @property {ShadowCastingMode} shadowCastingMode
|
||||
*/
|
||||
shadowCastingMode: {
|
||||
get () {
|
||||
return this._shadowCastingMode;
|
||||
},
|
||||
set (val) {
|
||||
this._shadowCastingMode = val;
|
||||
this._updateCastShadow();
|
||||
},
|
||||
type: ShadowCastingMode,
|
||||
animatable: false
|
||||
},
|
||||
|
||||
/**
|
||||
* !#en
|
||||
* Enable auto merge mesh, only support when mesh's VertexFormat, PrimitiveType, materials are all the same
|
||||
* !#zh
|
||||
* 开启自动合并 mesh 功能,只有在网格的 顶点格式,PrimitiveType, 使用的材质 都一致的情况下才会有效
|
||||
* @property {Boolean} enableAutoBatch
|
||||
*/
|
||||
enableAutoBatch: {
|
||||
get () {
|
||||
return this._enableAutoBatch;
|
||||
},
|
||||
set (val) {
|
||||
this._enableAutoBatch = val;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
statics: {
|
||||
ShadowCastingMode: ShadowCastingMode
|
||||
},
|
||||
|
||||
ctor () {
|
||||
this._boundingBox = cc.geomUtils && new Aabb();
|
||||
|
||||
if (CC_DEBUG) {
|
||||
this._debugDatas = {
|
||||
wireFrame: [],
|
||||
normal: []
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
onEnable () {
|
||||
this._super();
|
||||
if (this._mesh && !this._mesh.loaded) {
|
||||
this.disableRender();
|
||||
this._mesh.once('load', () => {
|
||||
if (!this.isValid) return;
|
||||
this._setMesh(this._mesh);
|
||||
this.markForRender(true);
|
||||
});
|
||||
cc.assetManager.postLoadNative(this._mesh);
|
||||
}
|
||||
else {
|
||||
this._setMesh(this._mesh);
|
||||
}
|
||||
|
||||
this._updateRenderNode();
|
||||
this._updateMaterial();
|
||||
},
|
||||
|
||||
onDestroy () {
|
||||
this._setMesh(null);
|
||||
cc.pool.assembler.put(this._assembler);
|
||||
},
|
||||
|
||||
_updateRenderNode () {
|
||||
this._assembler.setRenderNode(this.node);
|
||||
},
|
||||
|
||||
_setMesh (mesh) {
|
||||
if (cc.geomUtils && mesh) {
|
||||
Aabb.fromPoints(this._boundingBox, mesh._minPos, mesh._maxPos);
|
||||
}
|
||||
|
||||
if (this._mesh) {
|
||||
this._mesh.off('init-format', this._updateMeshAttribute, this);
|
||||
}
|
||||
if (mesh) {
|
||||
mesh.on('init-format', this._updateMeshAttribute, this);
|
||||
}
|
||||
this._mesh = mesh;
|
||||
this._assembler && (this._assembler._worldDatas = {});
|
||||
this._updateMeshAttribute();
|
||||
},
|
||||
|
||||
_getDefaultMaterial () {
|
||||
return Material.getBuiltinMaterial('unlit');
|
||||
},
|
||||
|
||||
_validateRender () {
|
||||
let mesh = this._mesh;
|
||||
if (mesh && mesh._subDatas.length > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.disableRender();
|
||||
},
|
||||
|
||||
_updateMaterial () {
|
||||
// TODO: used to upgrade from 2.1, should be removed
|
||||
let textures = this.textures;
|
||||
if (textures && textures.length > 0) {
|
||||
let defaultMaterial = this._getDefaultMaterial();
|
||||
for (let i = 0; i < textures.length; i++) {
|
||||
let material = this._materials[i];
|
||||
if (material && material._uuid !== defaultMaterial._uuid) continue;
|
||||
if (!material) {
|
||||
material = MaterialVariant.create(defaultMaterial, this);
|
||||
this.setMaterial(i, material);
|
||||
}
|
||||
material.setProperty('diffuseTexture', textures[i]);
|
||||
}
|
||||
}
|
||||
|
||||
this._updateReceiveShadow();
|
||||
this._updateCastShadow();
|
||||
this._updateMeshAttribute();
|
||||
},
|
||||
|
||||
_updateReceiveShadow () {
|
||||
let materials = this.getMaterials();
|
||||
for (let i = 0; i < materials.length; i++) {
|
||||
materials[i].define('CC_USE_SHADOW_MAP', this._receiveShadows, undefined, true);
|
||||
}
|
||||
},
|
||||
|
||||
_updateCastShadow () {
|
||||
let materials = this.getMaterials();
|
||||
for (let i = 0; i < materials.length; i++) {
|
||||
materials[i].define('CC_CASTING_SHADOW', this._shadowCastingMode === ShadowCastingMode.ON, undefined, true);
|
||||
}
|
||||
},
|
||||
|
||||
_updateMeshAttribute () {
|
||||
let subDatas = this._mesh && this._mesh.subDatas;
|
||||
if (!subDatas) return;
|
||||
|
||||
let materials = this.getMaterials();
|
||||
for (let i = 0; i < materials.length; i++) {
|
||||
if (!subDatas[i]) break;
|
||||
let vfm = subDatas[i].vfm;
|
||||
let material = materials[i];
|
||||
material.define('CC_USE_ATTRIBUTE_COLOR', !!vfm.element(gfx.ATTR_COLOR), undefined, true);
|
||||
material.define('CC_USE_ATTRIBUTE_UV0', !!vfm.element(gfx.ATTR_UV0), undefined, true);
|
||||
material.define('CC_USE_ATTRIBUTE_NORMAL', !!vfm.element(gfx.ATTR_NORMAL), undefined, true);
|
||||
material.define('CC_USE_ATTRIBUTE_TANGENT', !!vfm.element(gfx.ATTR_TANGENT), undefined, true);
|
||||
}
|
||||
|
||||
if (CC_DEBUG) {
|
||||
for (let name in this._debugDatas) {
|
||||
this._debugDatas[name].length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (CC_JSB && CC_NATIVERENDERER) {
|
||||
this._assembler.updateMeshData(this);
|
||||
}
|
||||
},
|
||||
|
||||
_checkBacth () {
|
||||
},
|
||||
});
|
||||
|
||||
if (CC_DEBUG) {
|
||||
const BLACK_COLOR = cc.Color.BLACK;
|
||||
const RED_COLOR = cc.Color.RED;
|
||||
|
||||
let v3_tmp = [cc.v3(), cc.v3()];
|
||||
let mat4_tmp = cc.mat4();
|
||||
|
||||
let createDebugDataFns = {
|
||||
normal (comp, ia, subData, subIndex) {
|
||||
let oldVfm = subData.vfm;
|
||||
|
||||
let normalEle = oldVfm.element(gfx.ATTR_NORMAL);
|
||||
let posEle = oldVfm.element(gfx.ATTR_POSITION);
|
||||
let jointEle = oldVfm.element(gfx.ATTR_JOINTS);
|
||||
let weightEle = oldVfm.element(gfx.ATTR_WEIGHTS);
|
||||
|
||||
if (!normalEle || !posEle) {
|
||||
return;
|
||||
}
|
||||
|
||||
let indices = [];
|
||||
let vbData = [];
|
||||
|
||||
let lineLength = 100;
|
||||
Vec3.set(v3_tmp[0], 5, 0, 0);
|
||||
Mat4.invert(mat4_tmp, comp.node._worldMatrix);
|
||||
Vec3.transformMat4Normal(v3_tmp[0], v3_tmp[0], mat4_tmp);
|
||||
lineLength = v3_tmp[0].mag();
|
||||
|
||||
let mesh = comp.mesh;
|
||||
let posData = mesh._getAttrMeshData(subIndex, gfx.ATTR_POSITION);
|
||||
let normalData = mesh._getAttrMeshData(subIndex, gfx.ATTR_NORMAL);
|
||||
let jointData = mesh._getAttrMeshData(subIndex, gfx.ATTR_JOINTS);
|
||||
let weightData = mesh._getAttrMeshData(subIndex, gfx.ATTR_WEIGHTS);
|
||||
|
||||
let vertexCount = posData.length / posEle.num;
|
||||
|
||||
for (let i = 0; i < vertexCount; i++) {
|
||||
let normalIndex = i * normalEle.num;
|
||||
let posIndex = i * posEle.num;
|
||||
|
||||
Vec3.set(v3_tmp[0], normalData[normalIndex], normalData[normalIndex+1], normalData[normalIndex+2]);
|
||||
Vec3.set(v3_tmp[1], posData[posIndex], posData[posIndex+1], posData[posIndex+2]);
|
||||
Vec3.scaleAndAdd(v3_tmp[0], v3_tmp[1], v3_tmp[0], lineLength);
|
||||
|
||||
for (let lineIndex = 0; lineIndex < 2; lineIndex++) {
|
||||
vbData.push(v3_tmp[lineIndex].x, v3_tmp[lineIndex].y, v3_tmp[lineIndex].z);
|
||||
if (jointEle) {
|
||||
let jointIndex = i * jointEle.num;
|
||||
for (let j = 0; j < jointEle.num; j++) {
|
||||
vbData.push(jointData[jointIndex + j]);
|
||||
}
|
||||
}
|
||||
if (weightEle) {
|
||||
let weightIndex = i * weightEle.num;
|
||||
for (let j = 0; j < weightEle.num; j++) {
|
||||
vbData.push(weightData[weightIndex + j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
indices.push(i*2, i*2+1);
|
||||
}
|
||||
|
||||
let formatOpts = [
|
||||
{ name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 3 },
|
||||
];
|
||||
if (jointEle) {
|
||||
formatOpts.push({ name: gfx.ATTR_JOINTS, type: gfx.ATTR_TYPE_FLOAT32, num: jointEle.num })
|
||||
}
|
||||
if (weightEle) {
|
||||
formatOpts.push({ name: gfx.ATTR_WEIGHTS, type: gfx.ATTR_TYPE_FLOAT32, num: weightEle.num })
|
||||
}
|
||||
let gfxVFmt = new gfx.VertexFormat(formatOpts);
|
||||
|
||||
let vb = new gfx.VertexBuffer(
|
||||
Renderer.device,
|
||||
gfxVFmt,
|
||||
gfx.USAGE_STATIC,
|
||||
new Float32Array(vbData)
|
||||
);
|
||||
|
||||
let ibData = new Uint16Array(indices);
|
||||
let ib = new gfx.IndexBuffer(
|
||||
Renderer.device,
|
||||
gfx.INDEX_FMT_UINT16,
|
||||
gfx.USAGE_STATIC,
|
||||
ibData,
|
||||
ibData.length
|
||||
);
|
||||
|
||||
let m = MaterialVariant.createWithBuiltin('unlit');
|
||||
m.setProperty('diffuseColor', RED_COLOR);
|
||||
|
||||
return {
|
||||
material: m,
|
||||
ia: new InputAssembler(vb, ib, gfx.PT_LINES)
|
||||
};
|
||||
},
|
||||
|
||||
wireFrame (comp, ia, subData) {
|
||||
let oldIbData = subData.getIData(Uint16Array);
|
||||
let m = MaterialVariant.createWithBuiltin('unlit');
|
||||
m.setProperty('diffuseColor', BLACK_COLOR);
|
||||
|
||||
let indices = [];
|
||||
for (let i = 0; i < oldIbData.length; i+=3) {
|
||||
let a = oldIbData[ i + 0 ];
|
||||
let b = oldIbData[ i + 1 ];
|
||||
let c = oldIbData[ i + 2 ];
|
||||
indices.push(a, b, b, c, c, a);
|
||||
}
|
||||
|
||||
let ibData = new Uint16Array(indices);
|
||||
let ib = new gfx.IndexBuffer(
|
||||
Renderer.device,
|
||||
gfx.INDEX_FMT_UINT16,
|
||||
gfx.USAGE_STATIC,
|
||||
ibData,
|
||||
ibData.length
|
||||
);
|
||||
|
||||
return {
|
||||
material: m,
|
||||
ia: new InputAssembler(ia._vertexBuffer, ib, gfx.PT_LINES)
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let _proto = MeshRenderer.prototype;
|
||||
_proto._updateDebugDatas = function () {
|
||||
let debugDatas = this._debugDatas;
|
||||
let subMeshes = this._mesh.subMeshes;
|
||||
let subDatas = this._mesh._subDatas;
|
||||
for (let name in debugDatas) {
|
||||
let debugData = debugDatas[name];
|
||||
if (debugData.length === subMeshes.length) continue;
|
||||
if (!cc.macro['SHOW_MESH_' + name.toUpperCase()]) continue;
|
||||
|
||||
debugData.length = subMeshes.length;
|
||||
for (let i = 0; i < subMeshes.length; i++) {
|
||||
debugData[i] = createDebugDataFns[name](this, subMeshes[i], subDatas[i], i);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
cc.MeshRenderer = module.exports = MeshRenderer;
|
5
engine/cocos2d/core/mesh/index.js
Normal file
5
engine/cocos2d/core/mesh/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
require('./CCMesh');
|
||||
if (!CC_EDITOR || !Editor.isMainProcess) {
|
||||
require('./CCMeshRenderer');
|
||||
require('./mesh-renderer');
|
||||
}
|
179
engine/cocos2d/core/mesh/mesh-data.js
Normal file
179
engine/cocos2d/core/mesh/mesh-data.js
Normal file
@@ -0,0 +1,179 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
import gfx from '../../renderer/gfx';
|
||||
|
||||
/**
|
||||
* The class BufferRange denotes a range of the buffer.
|
||||
* @class BufferRange
|
||||
*/
|
||||
export let BufferRange = cc.Class({
|
||||
name: 'cc.BufferRange',
|
||||
|
||||
properties: {
|
||||
/**
|
||||
* The offset of the range.
|
||||
* @property {Number} offset
|
||||
*/
|
||||
offset: 0,
|
||||
/**
|
||||
* The length of the range.
|
||||
* @property {Number} length
|
||||
*/
|
||||
length: 0
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @class VertexFormat
|
||||
*/
|
||||
export let VertexFormat = cc.Class({
|
||||
name: 'cc.mesh.VertexFormat',
|
||||
|
||||
properties: {
|
||||
name: '',
|
||||
type: -1,
|
||||
num: -1,
|
||||
normalize: false
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* A vertex bundle describes a serials of vertex attributes.
|
||||
* These vertex attributes occupy a range of the buffer and
|
||||
* are interleaved, no padding bytes, in the range.
|
||||
*/
|
||||
export let VertexBundle = cc.Class({
|
||||
name: 'cc.mesh.VertexBundle',
|
||||
properties: {
|
||||
/**
|
||||
* The data range of this bundle.
|
||||
* This range of data is essentially mapped to a GPU vertex buffer.
|
||||
* @property {BufferRange} data
|
||||
*/
|
||||
data: {
|
||||
default: null,
|
||||
type: BufferRange
|
||||
},
|
||||
/**
|
||||
* The attribute formats.
|
||||
* @property {VertexFormat} formats
|
||||
*/
|
||||
formats: {
|
||||
default: [],
|
||||
type: VertexFormat
|
||||
},
|
||||
/**
|
||||
* The bundle's vertices count.
|
||||
*/
|
||||
verticesCount: 0,
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* A primitive is a geometry constituted with a list of
|
||||
* same topology primitive graphic(such as points, lines or triangles).
|
||||
*/
|
||||
export let Primitive = cc.Class({
|
||||
name: 'cc.mesh.Primitive',
|
||||
properties: {
|
||||
/**
|
||||
* The vertex bundle that the primitive use.
|
||||
* @property {[Number]} vertexBundleIndices
|
||||
*/
|
||||
vertexBundleIndices: {
|
||||
default: [],
|
||||
type: cc.Float
|
||||
},
|
||||
/**
|
||||
* The data range of the primitive.
|
||||
* This range of data is essentially mapped to a GPU indices buffer.
|
||||
* @property {BufferRange} data
|
||||
*/
|
||||
data: {
|
||||
default: null,
|
||||
type: BufferRange
|
||||
},
|
||||
/**
|
||||
* The type of this primitive's indices.
|
||||
* @property {Number} indexUnit
|
||||
*/
|
||||
indexUnit: gfx.INDEX_FMT_UINT16,
|
||||
/**
|
||||
* The primitive's topology.
|
||||
* @property {Number} topology
|
||||
*/
|
||||
topology: gfx.PT_TRIANGLES
|
||||
}
|
||||
});
|
||||
|
||||
export function MeshData () {
|
||||
this.vData = null; // Uint8Array;
|
||||
this.float32VData = null;
|
||||
this.uint32VData = null;
|
||||
this.iData = null; // Uint8Array;
|
||||
this.uint16IData = null;
|
||||
this.vfm = null;
|
||||
this.offset = 0;
|
||||
|
||||
this.vb = null;
|
||||
this.ib = null;
|
||||
this.vDirty = false;
|
||||
this.iDirty = false;
|
||||
|
||||
this.enable = true;
|
||||
}
|
||||
|
||||
MeshData.prototype.setVData = function (data) {
|
||||
this.vData = data;
|
||||
this.float32VData = null;
|
||||
this.uint32VData = null;
|
||||
}
|
||||
|
||||
MeshData.prototype.getVData = function (format) {
|
||||
if (format === Float32Array) {
|
||||
if (!this.float32VData) {
|
||||
this.float32VData = new Float32Array(this.vData.buffer, this.vData.byteOffset, this.vData.byteLength / 4);
|
||||
}
|
||||
return this.float32VData;
|
||||
}
|
||||
else if (format === Uint32Array) {
|
||||
if (!this.uint32VData) {
|
||||
this.uint32VData = new Uint32Array(this.vData.buffer, this.vData.byteOffset, this.vData.byteLength / 4);
|
||||
}
|
||||
return this.uint32VData;
|
||||
}
|
||||
return this.vData;
|
||||
}
|
||||
|
||||
MeshData.prototype.getIData = function (format) {
|
||||
if (format === Uint16Array) {
|
||||
if (!this.uint16IData) {
|
||||
this.uint16IData = new Uint16Array(this.iData.buffer, this.iData.byteOffset, this.iData.byteLength / 2);
|
||||
}
|
||||
return this.uint16IData;
|
||||
}
|
||||
return this.iData;
|
||||
}
|
181
engine/cocos2d/core/mesh/mesh-renderer.js
Normal file
181
engine/cocos2d/core/mesh/mesh-renderer.js
Normal file
@@ -0,0 +1,181 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos.com
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated engine source code (the "Software"), a limited,
|
||||
worldwide, royalty-free, non-assignable, revocable and non-exclusive license
|
||||
to use Cocos Creator solely to develop games on your target platforms. You shall
|
||||
not use Cocos Creator software for developing other software or tools that's
|
||||
used for developing games. You are not granted to publish, distribute,
|
||||
sublicense, and/or sell copies of Cocos Creator.
|
||||
|
||||
The software or tools in this License Agreement are licensed, not sold.
|
||||
Xiamen Yaji Software Co., Ltd. reserves all rights not expressly granted to you.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
|
||||
import Assembler from '../renderer/assembler';
|
||||
import gfx from '../../renderer/gfx';
|
||||
import Vec3 from '../value-types/vec3';
|
||||
|
||||
const MeshRenderer = require('./CCMeshRenderer');
|
||||
|
||||
let _tmp_vec3 = new Vec3();
|
||||
|
||||
export default class MeshRendererAssembler extends Assembler {
|
||||
init (renderComp) {
|
||||
super.init(renderComp);
|
||||
|
||||
this._worldDatas = {};
|
||||
this._renderNode = null;
|
||||
}
|
||||
|
||||
setRenderNode (node) {
|
||||
this._renderNode = node;
|
||||
}
|
||||
|
||||
fillBuffers (comp, renderer) {
|
||||
if (!comp.mesh) return;
|
||||
|
||||
comp.mesh._uploadData();
|
||||
|
||||
// update culling mask
|
||||
let isCullingMaskSame = renderer.cullingMask === comp.node._cullingMask;
|
||||
|
||||
let enableAutoBatch = comp.enableAutoBatch;
|
||||
|
||||
let materials = comp._materials;
|
||||
let submeshes = comp.mesh._subMeshes;
|
||||
let subDatas = comp.mesh.subDatas;
|
||||
for (let i = 0; i < submeshes.length; i++) {
|
||||
let ia = submeshes[i];
|
||||
let meshData = subDatas[i];
|
||||
|
||||
let material = materials[i] || materials[0];
|
||||
|
||||
if (!enableAutoBatch || !meshData.canBatch || ia._primitiveType !== gfx.PT_TRIANGLES) {
|
||||
renderer._flush();
|
||||
|
||||
renderer.material = material;
|
||||
renderer.cullingMask = comp.node._cullingMask;
|
||||
renderer.node = this._renderNode;
|
||||
|
||||
renderer._flushIA(ia);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isCullingMaskSame ||
|
||||
material.getHash() !== renderer.material.getHash()) {
|
||||
renderer._flush();
|
||||
}
|
||||
|
||||
renderer.material = material;
|
||||
renderer.cullingMask = comp.node._cullingMask;
|
||||
renderer.node = renderer._dummyNode;
|
||||
|
||||
this._fillBuffer(comp, meshData, renderer, i);
|
||||
}
|
||||
|
||||
if (CC_DEBUG &&
|
||||
(cc.macro.SHOW_MESH_WIREFRAME || cc.macro.SHOW_MESH_NORMAL) &&
|
||||
!(comp.node._cullingMask & (1<<cc.Node.BuiltinGroupIndex.DEBUG))) {
|
||||
renderer._flush();
|
||||
renderer.node = this._renderNode;
|
||||
comp._updateDebugDatas();
|
||||
|
||||
if (cc.macro.SHOW_MESH_WIREFRAME) {
|
||||
this._drawDebugDatas(comp, renderer, 'wireFrame');
|
||||
}
|
||||
if (cc.macro.SHOW_MESH_NORMAL) {
|
||||
this._drawDebugDatas(comp, renderer, 'normal');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_fillBuffer (comp, meshData, renderer, dataIndex) {
|
||||
let vData = meshData.getVData(Float32Array);
|
||||
|
||||
let vtxFormat = meshData.vfm;
|
||||
let vertexCount = (vData.byteLength / vtxFormat._bytes) | 0;
|
||||
|
||||
let indices = meshData.getIData(Uint16Array);
|
||||
let indicesCount = indices.length;
|
||||
|
||||
let buffer = renderer.getBuffer('mesh', vtxFormat);
|
||||
let offsetInfo = buffer.request(vertexCount, indicesCount);
|
||||
|
||||
// buffer data may be realloc, need get reference after request.
|
||||
let indiceOffset = offsetInfo.indiceOffset,
|
||||
vertexOffset = offsetInfo.byteOffset >> 2,
|
||||
vertexId = offsetInfo.vertexOffset,
|
||||
vbuf = buffer._vData,
|
||||
ibuf = buffer._iData;
|
||||
|
||||
if (renderer.worldMatDirty || !this._worldDatas[dataIndex]) {
|
||||
this._updateWorldVertices(dataIndex, vertexCount, vData, vtxFormat, comp.node._worldMatrix);
|
||||
}
|
||||
|
||||
vbuf.set(this._worldDatas[dataIndex], vertexOffset);
|
||||
|
||||
for (let i = 0; i < indicesCount; i++) {
|
||||
ibuf[indiceOffset + i] = vertexId + indices[i];
|
||||
}
|
||||
}
|
||||
|
||||
_updateWorldVertices (dataIndex, vertexCount, local, vtxFormat, wolrdMatrix) {
|
||||
let world = this._worldDatas[dataIndex];
|
||||
if (!world) {
|
||||
world = this._worldDatas[dataIndex] = new Float32Array(local.length);
|
||||
world.set(local);
|
||||
}
|
||||
|
||||
let floatCount = vtxFormat._bytes / 4;
|
||||
|
||||
let elements = vtxFormat._elements;
|
||||
for (let i = 0, n = elements.length; i < n; i++) {
|
||||
let element = elements[i];
|
||||
let attrOffset = element.offset / 4;
|
||||
|
||||
if (element.name === gfx.ATTR_POSITION || element.name === gfx.ATTR_NORMAL) {
|
||||
let transformMat4 = element.name === gfx.ATTR_NORMAL ? Vec3.transformMat4Normal : Vec3.transformMat4;
|
||||
for (let j = 0; j < vertexCount; j++) {
|
||||
let offset = j * floatCount + attrOffset;
|
||||
|
||||
_tmp_vec3.x = local[offset];
|
||||
_tmp_vec3.y = local[offset + 1];
|
||||
_tmp_vec3.z = local[offset + 2];
|
||||
|
||||
transformMat4(_tmp_vec3, _tmp_vec3, wolrdMatrix);
|
||||
|
||||
world[offset] = _tmp_vec3.x;
|
||||
world[offset + 1] = _tmp_vec3.y;
|
||||
world[offset + 2] = _tmp_vec3.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_drawDebugDatas (comp, renderer, name) {
|
||||
let debugDatas = comp._debugDatas[name];
|
||||
if (!debugDatas) return;
|
||||
for (let i = 0; i < debugDatas.length; i++) {
|
||||
let debugData = debugDatas[i];
|
||||
if (!debugData) continue;
|
||||
let material = debugData.material;
|
||||
renderer.material = material;
|
||||
renderer._flushIA(debugData.ia);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assembler.register(MeshRenderer, MeshRendererAssembler);
|
Reference in New Issue
Block a user