void PUBillboardChain::render( Renderer* renderer, const Mat4 &transform, ParticleSystem3D* particleSystem ) { auto camera = Camera::getVisitingCamera(); auto cameraMat = camera->getNodeToWorldTransform(); if (!_chainSegmentList.empty()) { updateVertexBuffer(cameraMat); updateIndexBuffer(); if (!_vertices.empty() && !_indices.empty()) { GLuint texId = this->getTextureName(); _stateBlock->setBlendFunc(particleSystem->getBlendFunc()); _meshCommand->init(0, texId, _glProgramState, _stateBlock, _vertexBuffer->getVBO(), _indexBuffer->getVBO(), GL_TRIANGLES, GL_UNSIGNED_SHORT, _indices.size(), transform, Node::FLAGS_RENDER_AS_3D); _meshCommand->setSkipBatching(true); _meshCommand->setTransparent(true); _glProgramState->setUniformVec4("u_color", Vec4(1,1,1,1)); renderer->addCommand(_meshCommand); } } }
wyRect wyNode::getBoundingBoxRelativeToWorld() { wyRect r = { 0, 0, m_width, m_height }; wyAffineTransform t = getNodeToWorldTransform(); return wyaTransformRect(t, r); }
const AABB& Sprite3D::getAABB() const { Mat4 nodeToWorldTransform(getNodeToWorldTransform()); // If nodeToWorldTransform matrix isn't changed, we don't need to transform aabb. if (memcmp(_nodeToWorldTransform.m, nodeToWorldTransform.m, sizeof(Mat4)) == 0 && !_aabbDirty) { return _aabb; } else { _aabb.reset(); if (_meshes.size()) { Mat4 transform(nodeToWorldTransform); for (const auto& it : _meshes) { if (it->isVisible()) _aabb.merge(it->getAABB()); } _aabb.transform(transform); _nodeToWorldTransform = nodeToWorldTransform; _aabbDirty = false; } } return _aabb; }
float Camera::getDepthInView(const Mat4& transform) const { Mat4 camWorldMat = getNodeToWorldTransform(); const Mat4 &viewMat = camWorldMat.getInversed(); float depth = -(viewMat.m[2] * transform.m[12] + viewMat.m[6] * transform.m[13] + viewMat.m[10] * transform.m[14] + viewMat.m[14]); return depth; }
void Skybox::onDraw(const Mat4& transform, uint32_t flags) { auto camera = Camera::getVisitingCamera(); Mat4 cameraModelMat = camera->getNodeToWorldTransform(); auto state = getGLProgramState(); state->apply(transform); Vec4 color(_displayedColor.r / 255.f, _displayedColor.g / 255.f, _displayedColor.b / 255.f, 1.f); state->setUniformVec4("u_color", color); cameraModelMat.m[12] = cameraModelMat.m[13] = cameraModelMat.m[14] = 0; state->setUniformMat4("u_cameraRot", cameraModelMat); glEnable(GL_DEPTH_TEST); StateBlock::_defaultState->setDepthTest(true); glDepthFunc(GL_LEQUAL); StateBlock::_defaultState->setDepthFunction(DEPTH_LEQUAL); glEnable(GL_CULL_FACE); StateBlock::_defaultState->setCullFace(true); glCullFace(GL_BACK); StateBlock::_defaultState->setCullFaceSide(CULL_FACE_SIDE_BACK); glDisable(GL_BLEND); StateBlock::_defaultState->setBlend(false); if (Configuration::getInstance()->supportsShareableVAO()) { GL::bindVAO(_vao); } else { GL::enableVertexAttribs(GL::VERTEX_ATTRIB_FLAG_POSITION); glBindBuffer(GL_ARRAY_BUFFER, _vertexBuffer); glVertexAttribPointer(GLProgram::VERTEX_ATTRIB_POSITION, 3, GL_FLOAT, GL_FALSE, sizeof(Vec3), nullptr); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer); } glDrawElements(GL_TRIANGLES, (GLsizei)36, GL_UNSIGNED_BYTE, nullptr); if (Configuration::getInstance()->supportsShareableVAO()) { GL::bindVAO(0); } else { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, 8); CHECK_GL_ERROR_DEBUG(); }
void Hero::_armEventHandler(cocos2d::EventCustom* event) { const auto eventObject = (dragonBones::EventObject*)event->getUserData(); if (eventObject->type == dragonBones::EventObject::COMPLETE) { _isAttacking = false; _hitCount = 0; const auto animationName = "ready_" + _weaponName; _armArmature->getAnimation().fadeIn(animationName); } else if (eventObject->type == dragonBones::EventObject::FRAME_EVENT) { if (eventObject->name == "ready") { _isAttacking = false; _hitCount++; } else if (eventObject->name == "fire") { const auto display = (dragonBones::CCArmatureDisplay*)(eventObject->armature->getDisplay()); const auto firePointBone = eventObject->armature->getBone("bow"); const auto transform = display->getNodeToWorldTransform(); cocos2d::Vec3 localPoint(firePointBone->global.x, -firePointBone->global.y, 0.f); cocos2d::Vec2 globalPoint; transform.transformPoint(&localPoint); globalPoint.set(localPoint.x, localPoint.y); auto radian = 0.f; if (_faceDir > 0) { radian = firePointBone->global.getRotation() + display->getRotation() * dragonBones::ANGLE_TO_RADIAN; } else { radian = dragonBones::PI - (firePointBone->global.getRotation() + display->getRotation() * dragonBones::ANGLE_TO_RADIAN); } switch (_weaponsLevel[_weaponIndex]) { case 0: _fire(globalPoint, radian); break; case 1: _fire(globalPoint, radian + 3.f * dragonBones::ANGLE_TO_RADIAN); _fire(globalPoint, radian - 3.f * dragonBones::ANGLE_TO_RADIAN); break; case 2: _fire(globalPoint, radian + 6.f * dragonBones::ANGLE_TO_RADIAN); _fire(globalPoint, radian); _fire(globalPoint, radian - 6.f * dragonBones::ANGLE_TO_RADIAN); break; } } } }
Vec2 Node::convertToWorldSpace(const Vec2& nodePoint) const { Mat4 tmp = getNodeToWorldTransform(); Vec3 vec3(nodePoint.x, nodePoint.y, 0); Vec3 ret; tmp.transformPoint(vec3,&ret); return Vec2(ret.x, ret.y); }
Point Node::convertToWorldSpace(const Point& nodePoint) const { kmMat4 tmp = getNodeToWorldTransform(); kmVec3 vec3 = {nodePoint.x, nodePoint.y, 0}; kmVec3 ret; kmVec3Transform(&ret, &vec3, &tmp); return Point(ret.x, ret.y); }
Vec3 BillboardParticleSystem::convertToWorldSpace3D(const Vec3& nodePoint) const { Mat4 tmp = getNodeToWorldTransform(); Vec3 vec3(nodePoint.x, nodePoint.y, nodePoint.z); Vec3 ret; tmp.transformPoint(vec3,&ret); return Vec3(ret.x, ret.y,ret.z); }
cocos2d::Vec3 PUParticleSystem3D::getDerivedPosition() { //if (_parentParticleSystem && _parentParticleSystem->isKeepLocal()) return Vec3::ZERO; //if (_keepLocal) return Vec3::ZERO; if (_isMarkedForEmission){ return Vec3(_position.x, _position.y, _positionZ); }else{ Mat4 mat = getNodeToWorldTransform(); return Vec3(mat.m[12], mat.m[13], mat.m[14]); } }
const Mat4& Camera::getViewMatrix() const { Mat4 viewInv(getNodeToWorldTransform()); static int count = sizeof(float) * 16; if (memcmp(viewInv.m, _viewInv.m, count) != 0) { _viewProjectionDirty = true; _viewInv = viewInv; _view = viewInv.getInversed(); } return _view; }
cocos2d::Quaternion PUParticleSystem3D::getDerivedOrientation() { //if (_parentParticleSystem && _parentParticleSystem->isKeepLocal()) return Quaternion(); //if (_keepLocal) return Quaternion(); if (_isMarkedForEmission){ return getRotationQuat(); }else{ Quaternion q; Mat4 mat = getNodeToWorldTransform(); mat.decompose(nullptr, &q, nullptr); return q; } }
cocos2d::Vec3 PUParticleSystem3D::getDerivedScale() { //if (_parentParticleSystem && _parentParticleSystem->isKeepLocal()) return Vec3::ONE; //if (_keepLocal) return Vec3::ONE; if (_isMarkedForEmission){ return Vec3(_scaleX, _scaleY, _scaleZ); }else{ Vec3 s; Mat4 mat = getNodeToWorldTransform(); mat.decompose(&s, nullptr, nullptr); return s; } }
Mat4 AttachNode::getNodeToWorldTransform() const { Mat4 mat; auto parent = getParent(); if (parent) { mat = parent->getNodeToWorldTransform() * _attachBone->getWorldMat(); } else { mat = _attachBone->getWorldMat(); } return mat; }
void Gun::emitProjectile() { GAFAnimatedObject* model = m_projectile->createObjectAndRun(true); model->setPosition(m_projectileOffset); Mat4 transform = getNodeToWorldTransform(); Node* container = Node::create(); container->setPosition(m_emissionPoint); addChild(container); Projectile* p = Projectile::create(model, m_projectileDamage, m_projectileSpeed, container); removeChild(container); Director::getInstance()->getRunningScene()->addChild(p); }
void Mecha::_frameEventHandler(cocos2d::EventCustom* event) { const auto eventObject = (dragonBones::EventObject*)event->getUserData(); if (eventObject->name == "onFire") { const auto display = (dragonBones::CCArmatureDisplay*)eventObject->armature->getDisplay(); const auto firePointBone = eventObject->armature->getBone("firePoint"); const auto transform = display->getNodeToWorldTransform(); cocos2d::Vec3 localPoint(firePointBone->global.x, -firePointBone->global.y, 0.f); cocos2d::Vec2 globalPoint; transform.transformPoint(&localPoint); globalPoint.set(localPoint.x, localPoint.y); _fire(globalPoint); } }
void Player::update(float dt) { Rect rect = m_model->realBoundingBoxForCurrentFrame(); Vec3 scale, pos; Quaternion rot; getNodeToWorldTransform().decompose(&scale, &rot, &pos); do { Node* level = Director::getInstance()->getRunningScene()->getChildByTag(1); if (level == nullptr) { break; } Vec2 position = level->getPosition(); if (m_state == EWalkLeft) { position += dt * m_speed * Vec2(scale.x, 0); } else if (m_state == EWalkRight) { position += dt * m_speed * Vec2(-scale.x, 0); } else { break; } level->setPosition(position); } while (0); Size boxSize(rect.size.width * scale.x, rect.size.height * scale.y); Vec2 boxPos(rect.origin.x * scale.x + boxSize.width / 2, rect.origin.y * scale.y + boxSize.height / 2); auto body = PhysicsBody::createBox(boxSize, PHYSICSBODY_MATERIAL_DEFAULT); body->setPositionOffset(boxPos); setPhysicsBody(body); body->setContactTestBitmask(0x2); }
void PUSphereRender::render( Renderer* renderer, const Mat4 &transform, ParticleSystem3D* particleSystem ) { //batch and generate draw const ParticlePool &particlePool = particleSystem->getParticlePool(); if (!_isVisible || particlePool.empty()) return; auto camera = Camera::getVisitingCamera(); auto cameraMat = camera->getNodeToWorldTransform(); Vec3 backward(cameraMat.m[8], cameraMat.m[9], cameraMat.m[10]); unsigned int vertexCount = (_numberOfRings + 1) * (_numberOfSegments + 1); unsigned int indexCount = 6 * _numberOfRings * (_numberOfSegments + 1); if (_vertexBuffer == nullptr && _indexBuffer == nullptr) { GLsizei stride = sizeof(VertexInfo); _vertexBuffer = VertexBuffer::create(stride, vertexCount * particleSystem->getParticleQuota()); if (_vertexBuffer == nullptr) { CCLOG("PUSphereRender::render create vertex buffer failed"); return; } _vertexBuffer->retain(); _vertices.resize(vertexCount * particleSystem->getParticleQuota()); _indexBuffer = IndexBuffer::create(IndexBuffer::IndexType::INDEX_TYPE_SHORT_16, indexCount * particleSystem->getParticleQuota()); if (_indexBuffer == nullptr) { CCLOG("PUSphereRender::render create index buffer failed"); return; } _indexBuffer->retain(); _indices.resize(indexCount * particleSystem->getParticleQuota()); buildBuffers(particleSystem->getParticleQuota()); } unsigned int vertexindex = 0; unsigned int index = 0; Mat4 mat; Mat4 rotMat; Mat4 sclMat; Mat4 texRot; Vec3 val; for (auto iter : particlePool.getActiveDataList()) { auto particle = static_cast<PUParticle3D *>(iter); float radius = particle->width * 0.5f; Mat4::createRotation(particle->orientation, &rotMat); Mat4::createScale(radius, radius, radius, &sclMat); Mat4::createRotation(backward, particle->zRotation, &texRot); mat = rotMat * sclMat; mat.m[12] = particle->position.x; mat.m[13] = particle->position.y; mat.m[14] = particle->position.z; for (unsigned int i = 0; i < vertexCount; ++i) { val = texRot * Vec3(_vertexTemplate[vertexindex + i].uv.x, _vertexTemplate[vertexindex + i].uv.y, 0.0f); mat.transformPoint(_vertexTemplate[vertexindex + i].position, &_vertices[vertexindex + i].position); _vertices[vertexindex + i].color = particle->color; _vertices[vertexindex + i].uv.x = val.x; _vertices[vertexindex + i].uv.y = val.y; } vertexindex += vertexCount; index += indexCount; } if (!_vertices.empty() && !_indices.empty()) { _vertexBuffer->updateVertices(&_vertices[0], vertexindex/* * sizeof(_posuvcolors[0])*/, 0); _indexBuffer->updateIndices(&_indices[0], index/* * sizeof(unsigned short)*/, 0); GLuint texId = (_texture ? _texture->getName() : 0); _stateBlock->setBlendFunc(particleSystem->getBlendFunc()); _meshCommand->init( 0, texId, _glProgramState, _stateBlock, _vertexBuffer->getVBO(), _indexBuffer->getVBO(), GL_TRIANGLES, GL_UNSIGNED_SHORT, index, transform, Node::FLAGS_RENDER_AS_3D); _meshCommand->setSkipBatching(true); _meshCommand->setTransparent(true); _glProgramState->setUniformVec4("u_color", Vec4(1,1,1,1)); renderer->addCommand(_meshCommand); } }
wyAffineTransform wyNode::getWorldToNodeTransform() { wyAffineTransform t = getNodeToWorldTransform(); wyaInverse(&t); return t; }
wyPoint wyNode::nodeToWorldSpace(wyPoint p) { wyAffineTransform t = getNodeToWorldTransform(); return wyaTransformPoint(t, p); }
void BillboardParticleSystem::update(float dt) { if(_camera) { const Mat4& cameraViewMatrix = _camera->getViewMatrix().getInversed(); cameraViewMatrix.getRightVector(&_cameraRight); cameraViewMatrix.getUpVector(&_cameraUp); } const Mat4& WorldMat = getNodeToWorldTransform(); Quaternion rotation;; WorldMat.getRotation(&rotation); Mat4 roaMat; Mat4::createRotation(rotation,&roaMat); CC_PROFILER_START_CATEGORY(kProfilerCategoryParticles , "CCParticleSystem - update"); if (_isActive && _emissionRate) { float rate = 1.0f / _emissionRate; //issue #1201, prevent bursts of particles, due to too high emitCounter if (_particleCount < _totalParticles) { _emitCounter += dt; } while (_particleCount < _totalParticles && _emitCounter > rate) { this->addParticle(); _emitCounter -= rate; } _elapsed += dt; if (_duration != -1 && _duration < _elapsed) { this->stopSystem(); } } _particleIdx = 0; Vec3 currentPosition = Vec3::ZERO; if (_positionType == PositionType::FREE) { currentPosition = this->convertToWorldSpace3D(Vec3::ZERO); } else if (_positionType == PositionType::RELATIVE) { currentPosition.x = _position.x; currentPosition.y = _position.y; currentPosition.z = _positionZ; } { while (_particleIdx < _particleCount) { sBillboardParticle *p = &_particles[_particleIdx]; // life p->timeToLive -= dt; if (p->timeToLive > 0) { // Mode A: gravity, direction, tangential accel & radial accel if (_emitterMode == Mode::GRAVITY) { Vec2 tmp, radial, tangential; radial = Vec2::ZERO; // radial acceleration if (p->pos.x || p->pos.y) { radial = p->pos.getNormalized(); } tangential = radial; radial = radial * p->modeA.radialAccel; // tangential acceleration float newy = tangential.x; tangential.x = -tangential.y; tangential.y = newy; tangential = tangential * p->modeA.tangentialAccel; // (gravity + radial + tangential) * dt tmp = radial + tangential + modeA.gravity; tmp = tmp * dt; p->modeA.dir = p->modeA.dir + tmp; // this is cocos2d-x v3.0 // if (_configName.length()>0 && _yCoordFlipped != -1) // this is cocos2d-x v3.0 tmp = p->modeA.dir * dt * _yCoordFlipped; p->pos = p->pos + tmp; } // Mode B: radius movement else { // Update the angle and radius of the particle. p->modeB.angle += p->modeB.degreesPerSecond * dt; p->modeB.radius += p->modeB.deltaRadius * dt; p->pos.x = - cosf(p->modeB.angle) * p->modeB.radius; p->pos.y = - sinf(p->modeB.angle) * p->modeB.radius; p->pos.y *= _yCoordFlipped; } // color p->color.r += (p->deltaColor.r * dt); p->color.g += (p->deltaColor.g * dt); p->color.b += (p->deltaColor.b * dt); p->color.a += (p->deltaColor.a * dt); // size p->size += (p->deltaSize * dt); p->size = MAX( 0, p->size ); // angle p->rotation += (p->deltaRotation * dt); // // update values in quad // Vec3 newPos; Vec3 parPos(p->pos.x,p->pos.y,0); roaMat.transformVector(&parPos); if (_positionType == PositionType::FREE) { Vec3 diff = convertToNodeSpace3D(currentPosition) - convertToNodeSpace3D(p->startPos); //newPos.x = p->pos.x - diff.x; //newPos.y = p->pos.y - diff.y; //newPos.z = - diff.z; newPos = parPos-diff; } else if(_positionType == PositionType::RELATIVE) { Vec3 diff = currentPosition - p->startPos; newPos.x = p->pos.x - diff.x; newPos.y = p->pos.y - diff.y; newPos.z = - diff.z; } else { newPos.x = p->pos.x; newPos.y = p->pos.y; newPos.z = 0; } updateQuadWithParticle(p, newPos); //updateParticleImp(self, updateParticleSel, p, newPos); // update particle counter ++_particleIdx; } else { // life < 0 int currentIndex = p->atlasIndex; if( _particleIdx != _particleCount-1 ) { _particles[_particleIdx] = _particles[_particleCount-1]; } --_particleCount; if( _particleCount == 0 && _isAutoRemoveOnFinish ) { this->unscheduleUpdate(); _parent->removeChild(this, true); return; } } } //while _transformSystemDirty = false; } // only update gl buffer when visible if (_visible) { postStep(); } CC_PROFILER_STOP_CATEGORY(kProfilerCategoryParticles , "BillboardParticleSystem - update"); }
void BillBoard::draw(Renderer *renderer, const Mat4 &transform, uint32_t flags) { auto camera = Camera::getVisitingCamera(); const Mat4& camWorldMat = camera->getNodeToWorldTransform(); if (memcmp(_camWorldMat.m, camWorldMat.m, sizeof(float) * 16) != 0 || memcmp(_mvTransform.m, transform.m, sizeof(float) * 16) != 0 || _modeDirty) { Vec3 anchorPoint(_anchorPointInPoints.x , _anchorPointInPoints.y , 0.0f); Mat4 localToWorld = transform; localToWorld.translate(anchorPoint); Vec3 camDir; switch (_mode) { case Mode::VIEW_POINT_ORIENTED: camDir = Vec3(localToWorld.m[12] - camWorldMat.m[12], localToWorld.m[13] - camWorldMat.m[13], localToWorld.m[14] - camWorldMat.m[14]); break; case Mode::VIEW_PLANE_ORIENTED: camWorldMat.transformVector(Vec3(0.0f, 0.0f, -1.0f), &camDir); break; default: CCASSERT(false, "invalid billboard mode"); break; } _modeDirty = false; if (camDir.length() < MATH_TOLERANCE) { camDir.set(camWorldMat.m[8], camWorldMat.m[9], camWorldMat.m[10]); } camDir.normalize(); Quaternion rotationQuaternion; this->getNodeToWorldTransform().getRotation(&rotationQuaternion); // fetch the rotation angle of z float rotationZ = atan2(2*(rotationQuaternion.w*rotationQuaternion.z + rotationQuaternion.x*rotationQuaternion.y), (1 - 2* (rotationQuaternion.y*rotationQuaternion.y + rotationQuaternion.z *rotationQuaternion.z))); Mat4 rotationMatrix; rotationMatrix.setIdentity(); rotationMatrix.rotateZ(rotationZ); Vec3 upAxis = Vec3(rotationMatrix.m[4],rotationMatrix.m[5],rotationMatrix.m[6]); Vec3 x, y; camWorldMat.transformVector(upAxis, &y); Vec3::cross(camDir, y, &x); x.normalize(); Vec3::cross(x, camDir, &y); y.normalize(); float xlen = sqrtf(localToWorld.m[0] * localToWorld.m[0] + localToWorld.m[1] * localToWorld.m[1] + localToWorld.m[2] * localToWorld.m[2]); float ylen = sqrtf(localToWorld.m[4] * localToWorld.m[4] + localToWorld.m[5] * localToWorld.m[5] + localToWorld.m[6] * localToWorld.m[6]); float zlen = sqrtf(localToWorld.m[8] * localToWorld.m[8] + localToWorld.m[9] * localToWorld.m[9] + localToWorld.m[10] * localToWorld.m[10]); _billboardTransform.m[0] = x.x * xlen; _billboardTransform.m[1] = x.y * xlen; _billboardTransform.m[2] = x.z * xlen; _billboardTransform.m[4] = y.x * ylen; _billboardTransform.m[5] = y.y * ylen; _billboardTransform.m[6] = y.z * ylen; _billboardTransform.m[8] = -camDir.x * zlen; _billboardTransform.m[9] = -camDir.y * zlen; _billboardTransform.m[10] = -camDir.z * zlen; _billboardTransform.m[12] = localToWorld.m[12]; _billboardTransform.m[13] = localToWorld.m[13]; _billboardTransform.m[14] = localToWorld.m[14]; _billboardTransform.translate(-anchorPoint); const Mat4 &viewMat = camWorldMat.getInversed(); _zDepthInView = -(viewMat.m[2] * _billboardTransform.m[12] + viewMat.m[6] * _billboardTransform.m[13] + viewMat.m[10] * _billboardTransform.m[14] + viewMat.m[14]); _mvTransform = transform; _camWorldMat = camWorldMat; } //FIXME: frustum culling here { _quadCommand.init(_zDepthInView, _texture->getName(), getGLProgramState(), _blendFunc, &_quad, 1, _billboardTransform); _quadCommand.setTransparent(true); renderer->addCommand(&_quadCommand); } }
Mat4 Node::getWorldToNodeTransform() const { return getNodeToWorldTransform().getInversed(); }
void PUParticle3DBoxRender::render( Renderer* renderer, const Mat4 &transform, ParticleSystem3D* particleSystem ) { //batch and generate draw const ParticlePool &particlePool = particleSystem->getParticlePool(); if (!_isVisible || particlePool.empty()) return; auto camera = Camera::getVisitingCamera(); auto cameraMat = camera->getNodeToWorldTransform(); Vec3 backward(cameraMat.m[8], cameraMat.m[9], cameraMat.m[10]); if (_vertexBuffer == nullptr && _indexBuffer == nullptr) { GLsizei stride = sizeof(VertexInfo); _vertexBuffer = VertexBuffer::create(stride, 8 * particleSystem->getParticleQuota()); if (_vertexBuffer == nullptr) { CCLOG("PUParticle3DBoxRender::render create vertex buffer failed"); return; } _vertexBuffer->retain(); _vertices.resize(8 * particleSystem->getParticleQuota()); _indexBuffer = IndexBuffer::create(IndexBuffer::IndexType::INDEX_TYPE_SHORT_16, 36 * particleSystem->getParticleQuota()); if (_indexBuffer == nullptr) { CCLOG("PUParticle3DBoxRender::render create index buffer failed"); return; } _indexBuffer->retain(); _indices.resize(36 * particleSystem->getParticleQuota()); reBuildIndices(particleSystem->getParticleQuota()); } unsigned int vertexindex = 0; unsigned int index = 0; Mat4 texRot; Vec3 val; for (auto iter : particlePool.getActiveDataList()) { auto particle = static_cast<PUParticle3D *>(iter); float halfHeight = particle->height * 0.5f; float halfWidth = particle->width * 0.5f; float halfDepth = particle->depth * 0.5f; Mat4::createRotation(backward, particle->zRotation, &texRot); val = texRot * Vec3(0.0f, 0.75f, 0.0); _vertices[vertexindex + 0].position = particle->position + Vec3(-halfWidth, -halfHeight, halfDepth); _vertices[vertexindex + 0].color = particle->color; _vertices[vertexindex + 0].uv.x = val.x; _vertices[vertexindex + 0].uv.y = val.y; val = texRot * Vec3(0.0f, 0.25f, 0.0); _vertices[vertexindex + 1].position = particle->position + Vec3(halfWidth, -halfHeight, halfDepth); _vertices[vertexindex + 1].color = particle->color; _vertices[vertexindex + 1].uv.x = val.x; _vertices[vertexindex + 1].uv.y = val.y; val = texRot * Vec3(0.5f, 0.25f, 0.0); _vertices[vertexindex + 2].position = particle->position + Vec3(halfWidth, halfHeight, halfDepth); _vertices[vertexindex + 2].color = particle->color; _vertices[vertexindex + 2].uv.x = val.x; _vertices[vertexindex + 2].uv.y = val.y; val = texRot * Vec3(0.5f, 0.75f, 0.0); _vertices[vertexindex + 3].position = particle->position + Vec3(-halfWidth, halfHeight, halfDepth); _vertices[vertexindex + 3].color = particle->color; _vertices[vertexindex + 3].uv.x = val.x; _vertices[vertexindex + 3].uv.y = val.y; val = texRot * Vec3(0.0f, 0.0f, 0.0); _vertices[vertexindex + 4].position = particle->position + Vec3(halfWidth, -halfHeight, -halfDepth); _vertices[vertexindex + 4].color = particle->color; _vertices[vertexindex + 4].uv.x = val.x; _vertices[vertexindex + 4].uv.y = val.y; val = texRot * Vec3(0.0f, 1.0f, 0.0); _vertices[vertexindex + 5].position = particle->position + Vec3(-halfWidth, -halfHeight, -halfDepth); _vertices[vertexindex + 5].color = particle->color; _vertices[vertexindex + 5].uv.x = val.x; _vertices[vertexindex + 5].uv.y = val.y; val = texRot * Vec3(0.5f, 1.0f, 0.0); _vertices[vertexindex + 6].position = particle->position + Vec3(-halfWidth, halfHeight, -halfDepth); _vertices[vertexindex + 6].color = particle->color; _vertices[vertexindex + 6].uv.x = val.x; _vertices[vertexindex + 6].uv.y = val.y; val = texRot * Vec3(0.5f, 0.0f, 0.0); _vertices[vertexindex + 7].position = particle->position + Vec3(halfWidth, halfHeight, -halfDepth); _vertices[vertexindex + 7].color = particle->color; _vertices[vertexindex + 7].uv.x = val.x; _vertices[vertexindex + 7].uv.y = val.y; vertexindex += 8; index += 36; } if (!_vertices.empty() && !_indices.empty()) { _vertexBuffer->updateVertices(&_vertices[0], vertexindex/* * sizeof(_posuvcolors[0])*/, 0); _indexBuffer->updateIndices(&_indices[0], index/* * sizeof(unsigned short)*/, 0); GLuint texId = (_texture ? _texture->getName() : 0); _stateBlock->setBlendFunc(_particleSystem->getBlendFunc()); _meshCommand->init(0, texId, _glProgramState, _stateBlock, _vertexBuffer->getVBO(), _indexBuffer->getVBO(), GL_TRIANGLES, GL_UNSIGNED_SHORT, index, transform, Node::FLAGS_RENDER_AS_3D); _meshCommand->setSkipBatching(true); _meshCommand->setTransparent(true); _glProgramState->setUniformVec4("u_color", Vec4(1,1,1,1)); renderer->addCommand(_meshCommand); } }
void MeshCommand::setLightUniforms() { Director *director = Director::getInstance(); auto scene = director->getRunningScene(); const auto& conf = Configuration::getInstance(); int maxDirLight = conf->getMaxSupportDirLightInShader(); int maxPointLight = conf->getMaxSupportPointLightInShader(); int maxSpotLight = conf->getMaxSupportSpotLightInShader(); auto &lights = scene->getLights(); auto glProgram = _glProgramState->getGLProgram(); if (_glProgramState->getVertexAttribsFlags() & (1 << GLProgram::VERTEX_ATTRIB_NORMAL)) { resetLightUniformValues(); GLint enabledDirLightNum = 0; GLint enabledPointLightNum = 0; GLint enabledSpotLightNum = 0; Vec3 ambientColor; for (const auto& light : lights) { bool useLight = light->isEnabled() && ((unsigned int)light->getLightFlag() & _lightMask); if (useLight) { float intensity = light->getIntensity(); switch (light->getLightType()) { case LightType::DIRECTIONAL: { if(enabledDirLightNum < maxDirLight) { auto dirLight = static_cast<DirectionLight *>(light); Vec3 dir = dirLight->getDirectionInWorld(); dir.normalize(); const Color3B &col = dirLight->getDisplayedColor(); s_dirLightUniformColorValues[enabledDirLightNum] = Vec3(col.r / 255.0f * intensity, col.g / 255.0f * intensity, col.b / 255.0f * intensity); s_dirLightUniformDirValues[enabledDirLightNum] = dir; ++enabledDirLightNum; } } break; case LightType::POINT: { if(enabledPointLightNum < maxPointLight) { auto pointLight = static_cast<PointLight *>(light); Mat4 mat= pointLight->getNodeToWorldTransform(); const Color3B &col = pointLight->getDisplayedColor(); s_pointLightUniformColorValues[enabledPointLightNum] = Vec3(col.r / 255.0f * intensity, col.g / 255.0f * intensity, col.b / 255.0f * intensity); s_pointLightUniformPositionValues[enabledPointLightNum] = Vec3(mat.m[12], mat.m[13], mat.m[14]); s_pointLightUniformRangeInverseValues[enabledPointLightNum] = 1.0f / pointLight->getRange(); ++enabledPointLightNum; } } break; case LightType::SPOT: { if(enabledSpotLightNum < maxSpotLight) { auto spotLight = static_cast<SpotLight *>(light); Vec3 dir = spotLight->getDirectionInWorld(); dir.normalize(); Mat4 mat= light->getNodeToWorldTransform(); const Color3B &col = spotLight->getDisplayedColor(); s_spotLightUniformColorValues[enabledSpotLightNum] = Vec3(col.r / 255.0f * intensity, col.g / 255.0f * intensity, col.b / 255.0f * intensity); s_spotLightUniformPositionValues[enabledSpotLightNum] = Vec3(mat.m[12], mat.m[13], mat.m[14]); s_spotLightUniformDirValues[enabledSpotLightNum] = dir; s_spotLightUniformInnerAngleCosValues[enabledSpotLightNum] = spotLight->getCosInnerAngle(); s_spotLightUniformOuterAngleCosValues[enabledSpotLightNum] = spotLight->getCosOuterAngle(); s_spotLightUniformRangeInverseValues[enabledSpotLightNum] = 1.0f / spotLight->getRange(); ++enabledSpotLightNum; } } break; case LightType::AMBIENT: { auto ambLight = static_cast<AmbientLight *>(light); const Color3B &col = ambLight->getDisplayedColor(); ambientColor += Vec3(col.r / 255.0f * intensity, col.g / 255.0f * intensity, col.b / 255.0f * intensity); } break; default: break; } } } if (0 < maxDirLight) { glProgram->setUniformLocationWith3fv((GLint)glProgram->getUniformLocationForName(s_dirLightUniformColorName), (GLfloat*)(&s_dirLightUniformColorValues[0]), (unsigned int)s_dirLightUniformColorValues.size()); glProgram->setUniformLocationWith3fv((GLint)glProgram->getUniformLocationForName(s_dirLightUniformDirName), (GLfloat*)(&s_dirLightUniformDirValues[0]), (unsigned int)s_dirLightUniformDirValues.size()); } if (0 < maxPointLight) { glProgram->setUniformLocationWith3fv((GLint)glProgram->getUniformLocationForName(s_pointLightUniformColorName), (GLfloat*)(&s_pointLightUniformColorValues[0]), (unsigned int)s_pointLightUniformColorValues.size()); glProgram->setUniformLocationWith3fv((GLint)glProgram->getUniformLocationForName(s_pointLightUniformPositionName), (GLfloat*)(&s_pointLightUniformPositionValues[0]), (unsigned int)s_pointLightUniformPositionValues.size()); glProgram->setUniformLocationWith1fv((GLint)glProgram->getUniformLocationForName(s_pointLightUniformRangeInverseName), (GLfloat*)(&s_pointLightUniformRangeInverseValues[0]), (unsigned int)s_pointLightUniformRangeInverseValues.size()); } if (0 < maxSpotLight) { glProgram->setUniformLocationWith3fv((GLint)glProgram->getUniformLocationForName(s_spotLightUniformColorName), (GLfloat*)(&s_spotLightUniformColorValues[0]), (unsigned int)s_spotLightUniformColorValues.size()); glProgram->setUniformLocationWith3fv((GLint)glProgram->getUniformLocationForName(s_spotLightUniformPositionName), (GLfloat*)(&s_spotLightUniformPositionValues[0]), (unsigned int)s_spotLightUniformPositionValues.size()); glProgram->setUniformLocationWith3fv((GLint)glProgram->getUniformLocationForName(s_spotLightUniformDirName), (GLfloat*)(&s_spotLightUniformDirValues[0]), (unsigned int)s_spotLightUniformDirValues.size()); glProgram->setUniformLocationWith1fv((GLint)glProgram->getUniformLocationForName(s_spotLightUniformInnerAngleCosName), (GLfloat*)(&s_spotLightUniformInnerAngleCosValues[0]), (unsigned int)s_spotLightUniformInnerAngleCosValues.size()); glProgram->setUniformLocationWith1fv((GLint)glProgram->getUniformLocationForName(s_spotLightUniformOuterAngleCosName), (GLfloat*)(&s_spotLightUniformOuterAngleCosValues[0]), (unsigned int)s_spotLightUniformOuterAngleCosValues.size()); glProgram->setUniformLocationWith1fv((GLint)glProgram->getUniformLocationForName(s_spotLightUniformRangeInverseName), (GLfloat*)(&s_spotLightUniformRangeInverseValues[0]), (unsigned int)s_spotLightUniformRangeInverseValues.size()); } glProgram->setUniformLocationWith3f(glProgram->getUniformLocationForName(s_ambientLightUniformColorName), ambientColor.x, ambientColor.y, ambientColor.z); } else // normal does not exist { Vec3 ambient(0.0f, 0.0f, 0.0f); bool hasAmbient; for (const auto& light : lights) { if (light->getLightType() == LightType::AMBIENT) { bool useLight = light->isEnabled() && ((unsigned int)light->getLightFlag() & _lightMask); if (useLight) { hasAmbient = true; const Color3B &col = light->getDisplayedColor(); ambient.x += col.r * light->getIntensity(); ambient.y += col.g * light->getIntensity(); ambient.z += col.b * light->getIntensity(); } } } if (hasAmbient) { ambient.x /= 255.f; ambient.y /= 255.f; ambient.z /= 255.f; } glProgram->setUniformLocationWith4f(glProgram->getUniformLocationForName("u_color"), _displayColor.x * ambient.x, _displayColor.y * ambient.y, _displayColor.z * ambient.z, _displayColor.w); } }
void PUParticle3DQuadRender::render(Renderer* renderer, const Mat4 &transform, ParticleSystem3D* particleSystem) { //batch and generate draw const ParticlePool &particlePool = particleSystem->getParticlePool(); if (!_isVisible || particlePool.empty()) return; if (_vertexBuffer == nullptr) { GLsizei stride = sizeof(VertexInfo); _vertexBuffer = VertexBuffer::create(stride, 4 * particleSystem->getParticleQuota()); if (_vertexBuffer == nullptr) { CCLOG("PUParticle3DQuadRender::render create vertex buffer failed"); return; } _vertexBuffer->retain(); } if (_indexBuffer == nullptr) { _indexBuffer = IndexBuffer::create(IndexBuffer::IndexType::INDEX_TYPE_SHORT_16, 6 * particleSystem->getParticleQuota()); if (_indexBuffer == nullptr) { CCLOG("PUParticle3DQuadRender::render create index buffer failed"); return; } _indexBuffer->retain(); } const ParticlePool::PoolList &activeParticleList = particlePool.getActiveDataList(); if (_vertices.size() < activeParticleList.size() * 4) { _vertices.resize(activeParticleList.size() * 4); _indices.resize(activeParticleList.size() * 6); } auto camera = Camera::getVisitingCamera(); auto cameraMat = camera->getNodeToWorldTransform(); //for (auto iter : activeParticleList){ // iter->depthInView = -(viewMat.m[2] * iter->positionInWorld.x + viewMat.m[6] * iter->positionInWorld.y + viewMat.m[10] * iter->positionInWorld.z + viewMat.m[14]); //} //std::sort(activeParticleList.begin(), activeParticleList.end(), compareParticle3D); Vec3 right(cameraMat.m[0], cameraMat.m[1], cameraMat.m[2]); Vec3 up(cameraMat.m[4], cameraMat.m[5], cameraMat.m[6]); Vec3 backward(cameraMat.m[8], cameraMat.m[9], cameraMat.m[10]); Mat4 pRotMat; Vec3 position; //particle position int vertexindex = 0; int index = 0; int offsetX,offsetY; getOriginOffset(offsetX, offsetY); if (_type == PERPENDICULAR_COMMON) { up = _commonUp; up.normalize(); Vec3::cross(up, _commonDir, &right); right.normalize(); backward = _commonDir; } else if (_type == ORIENTED_COMMON) { up = _commonDir; up.normalize(); Vec3::cross(up, backward, &right); right.normalize(); } for (auto iter : activeParticleList) { auto particle = static_cast<PUParticle3D *>(iter); determineUVCoords(particle); if (_type == ORIENTED_SELF) { Vec3 direction = particle->direction; //transform.transformVector(particle->direction, &direction); up = direction; up.normalize(); Vec3::cross(direction, backward, &right); right.normalize(); } else if (_type == PERPENDICULAR_SELF) { Vec3 direction = particle->direction; //transform.transformVector(particle->direction, &direction); direction.normalize(); //up = PUUtil::perpendicular(direction); //up.normalize(); Vec3::cross(_commonUp, direction, &right); right.normalize(); Vec3::cross(direction, right, &up); up.normalize(); backward = direction; } else if (_type == ORIENTED_SHAPE) { up.set(particle->orientation.x, particle->orientation.y, particle->orientation.z); up.normalize(); Vec3::cross(up, backward, &right); right.normalize(); } Vec3 halfwidth = particle->width * 0.5f * right; Vec3 halfheight = particle->height * 0.5f * up; Vec3 offset = halfwidth * offsetX + halfheight * offsetY; //transform.transformPoint(particle->position, &position); position = particle->position; if (_rotateType == TEXTURE_COORDS) { float costheta = cosf(-particle->zRotation); float sintheta = sinf(-particle->zRotation); Vec2 texOffset = 0.5f * (particle->lb_uv + particle->rt_uv); Vec2 val; val.set((particle->lb_uv.x - texOffset.x), (particle->lb_uv.y - texOffset.y)); val.set(val.x * costheta - val.y * sintheta, val.x * sintheta + val.y * costheta); fillVertex(vertexindex, (position + (-halfwidth - halfheight + offset)), particle->color, val + texOffset); val.set(particle->rt_uv.x - texOffset.x, particle->lb_uv.y - texOffset.y); val.set(val.x * costheta - val.y * sintheta, val.x * sintheta + val.y * costheta); fillVertex(vertexindex + 1, (position + (halfwidth - halfheight + offset)), particle->color, val + texOffset); val.set(particle->lb_uv.x - texOffset.x, particle->rt_uv.y - texOffset.y); val.set(val.x * costheta - val.y * sintheta, val.x * sintheta + val.y * costheta); fillVertex(vertexindex + 2, (position + (-halfwidth + halfheight + offset)), particle->color, val + texOffset); val.set(particle->rt_uv.x - texOffset.x, particle->rt_uv.y - texOffset.y); val.set(val.x * costheta - val.y * sintheta, val.x * sintheta + val.y * costheta); fillVertex(vertexindex + 3, (position + (halfwidth + halfheight + offset)), particle->color, val + texOffset); } else { Mat4::createRotation(backward, -particle->zRotation, &pRotMat); fillVertex(vertexindex , (position + pRotMat * (- halfwidth - halfheight + offset)), particle->color, particle->lb_uv); fillVertex(vertexindex + 1, (position + pRotMat * (halfwidth - halfheight + offset)), particle->color, Vec2(particle->rt_uv.x, particle->lb_uv.y)); fillVertex(vertexindex + 2, (position + pRotMat * (-halfwidth + halfheight + offset)), particle->color, Vec2(particle->lb_uv.x, particle->rt_uv.y)); fillVertex(vertexindex + 3, (position + pRotMat * (halfwidth + halfheight + offset)), particle->color, particle->rt_uv); } fillTriangle(index, vertexindex, vertexindex + 1, vertexindex + 3); fillTriangle(index + 3, vertexindex, vertexindex + 3, vertexindex + 2); //_posuvcolors[vertexindex].position = (position + (- halfwidth - halfheight + halfwidth * offsetX + halfheight * offsetY)); //_posuvcolors[vertexindex].color = particle->color; //_posuvcolors[vertexindex].uv.set(val.x + texOffset.x, val.y + texOffset.y); //val.set(particle->rt_uv.x - texOffset.x, particle->lb_uv.y - texOffset.y); //val.set(val.x * costheta - val.y * sintheta, val.x * sintheta + val.y * costheta); //_posuvcolors[vertexindex + 1].position = (position + (halfwidth - halfheight + halfwidth * offsetX + halfheight * offsetY)); //_posuvcolors[vertexindex + 1].color = particle->color; //_posuvcolors[vertexindex + 1].uv.set(val.x + texOffset.x, val.y + texOffset.y); // //val.set(particle->lb_uv.x - texOffset.x, particle->rt_uv.y - texOffset.y); //val.set(val.x * costheta - val.y * sintheta, val.x * sintheta + val.y * costheta); //_posuvcolors[vertexindex + 2].position = (position + (- halfwidth + halfheight + halfwidth * offsetX + halfheight * offsetY)); //_posuvcolors[vertexindex + 2].color = particle->color; //_posuvcolors[vertexindex + 2].uv.set(val.x + texOffset.x, val.y + texOffset.y); // //val.set(particle->rt_uv.x - texOffset.x, particle->rt_uv.y - texOffset.y); //val.set(val.x * costheta - val.y * sintheta, val.x * sintheta + val.y * costheta); //_posuvcolors[vertexindex + 3].position = (position + (halfwidth + halfheight + halfwidth * offsetX + halfheight * offsetY)); //_posuvcolors[vertexindex + 3].color = particle->color; //_posuvcolors[vertexindex + 3].uv.set(val.x + texOffset.x, val.y + texOffset.y); // // //_indexData[index] = vertexindex; //_indexData[index + 1] = vertexindex + 1; //_indexData[index + 2] = vertexindex + 3; //_indexData[index + 3] = vertexindex; //_indexData[index + 4] = vertexindex + 3; //_indexData[index + 5] = vertexindex + 2; index += 6; vertexindex += 4; } _vertices.erase(_vertices.begin() + vertexindex, _vertices.end()); _indices.erase(_indices.begin() + index, _indices.end()); if (!_vertices.empty() && !_indices.empty()) { _vertexBuffer->updateVertices(&_vertices[0], vertexindex/* * sizeof(_posuvcolors[0])*/, 0); _indexBuffer->updateIndices(&_indices[0], index/* * sizeof(unsigned short)*/, 0); _stateBlock->setBlendFunc(particleSystem->getBlendFunc()); GLuint texId = (_texture ? _texture->getName() : 0); _meshCommand->init(0, texId, _glProgramState, _stateBlock, _vertexBuffer->getVBO(), _indexBuffer->getVBO(), GL_TRIANGLES, GL_UNSIGNED_SHORT, index, transform, Node::FLAGS_RENDER_AS_3D); _meshCommand->setSkipBatching(true); _meshCommand->setTransparent(true); _glProgramState->setUniformVec4("u_color", Vec4(1,1,1,1)); renderer->addCommand(_meshCommand); } }
Vec3 DirectionLight::getDirectionInWorld() const { Mat4 mat = getNodeToWorldTransform(); return Vec3(-mat.m[8], -mat.m[9], -mat.m[10]); }
bool BillBoard::calculateBillbaordTransform() { //Get camera world position auto camera = Camera::getVisitingCamera(); const Mat4& camWorldMat = camera->getNodeToWorldTransform(); //TODO: use math lib to calculate math lib Make it easier to read and maintain if (memcmp(_camWorldMat.m, camWorldMat.m, sizeof(float) * 16) != 0 || memcmp(_mvTransform.m, _modelViewTransform.m, sizeof(float) * 16) != 0 || _modeDirty || true) { //Rotate based on anchor point Vec3 anchorPoint(_anchorPointInPoints.x , _anchorPointInPoints.y , 0.0f); Mat4 localToWorld = _modelViewTransform; localToWorld.translate(anchorPoint); //Decide billboard mode Vec3 camDir; switch (_mode) { case Mode::VIEW_POINT_ORIENTED: camDir.set(localToWorld.m[12] - camWorldMat.m[12], localToWorld.m[13] - camWorldMat.m[13], localToWorld.m[14] - camWorldMat.m[14]); break; case Mode::VIEW_PLANE_ORIENTED: camWorldMat.transformVector(Vec3(0.0f, 0.0f, -1.0f), &camDir); break; default: CCASSERT(false, "invalid billboard mode"); break; } _modeDirty = false; if (camDir.length() < MATH_TOLERANCE) { camDir.set(camWorldMat.m[8], camWorldMat.m[9], camWorldMat.m[10]); } camDir.normalize(); Quaternion rotationQuaternion; this->getNodeToWorldTransform().getRotation(&rotationQuaternion); Mat4 rotationMatrix; rotationMatrix.setIdentity(); Vec3 upAxis(rotationMatrix.m[4],rotationMatrix.m[5],rotationMatrix.m[6]); Vec3 x, y; camWorldMat.transformVector(upAxis, &y); Vec3::cross(camDir, y, &x); x.normalize(); Vec3::cross(x, camDir, &y); y.normalize(); float xlen = sqrtf(localToWorld.m[0] * localToWorld.m[0] + localToWorld.m[1] * localToWorld.m[1] + localToWorld.m[2] * localToWorld.m[2]); float ylen = sqrtf(localToWorld.m[4] * localToWorld.m[4] + localToWorld.m[5] * localToWorld.m[5] + localToWorld.m[6] * localToWorld.m[6]); float zlen = sqrtf(localToWorld.m[8] * localToWorld.m[8] + localToWorld.m[9] * localToWorld.m[9] + localToWorld.m[10] * localToWorld.m[10]); Mat4 billboardTransform; billboardTransform.m[0] = x.x * xlen; billboardTransform.m[1] = x.y * xlen; billboardTransform.m[2] = x.z * xlen; billboardTransform.m[4] = y.x * ylen; billboardTransform.m[5] = y.y * ylen; billboardTransform.m[6] = y.z * ylen; billboardTransform.m[8] = -camDir.x * zlen; billboardTransform.m[9] = -camDir.y * zlen; billboardTransform.m[10] = -camDir.z * zlen; billboardTransform.m[12] = localToWorld.m[12]; billboardTransform.m[13] = localToWorld.m[13]; billboardTransform.m[14] = localToWorld.m[14]; billboardTransform.translate(-anchorPoint); _mvTransform = _modelViewTransform = billboardTransform; _camWorldMat = camWorldMat; return true; } return false; }