void RenderableLightEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableLightEntityItem::render"); assert(getType() == EntityTypes::Light); glm::vec3 position = getPosition(); glm::vec3 dimensions = getDimensions(); glm::quat rotation = getRotation(); float largestDiameter = glm::max(dimensions.x, dimensions.y, dimensions.z); glm::vec3 color = toGlm(getXColor()); float intensity = getIntensity(); float exponent = getExponent(); float cutoff = glm::radians(getCutoff()); if (_isSpotlight) { DependencyManager::get<DeferredLightingEffect>()->addSpotLight(position, largestDiameter / 2.0f, color, intensity, rotation, exponent, cutoff); } else { DependencyManager::get<DeferredLightingEffect>()->addPointLight(position, largestDiameter / 2.0f, color, intensity); } #ifdef WANT_DEBUG Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; batch.setModelTransform(getTransformToCenter()); DependencyManager::get<GeometryCache>()->renderWireSphere(batch, 0.5f, 15, 15, glm::vec4(color, 1.0f)); #endif };
void RenderableBoxEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableBoxEntityItem::render"); Q_ASSERT(getType() == EntityTypes::Box); Q_ASSERT(args->_batch); if (!_procedural) { _procedural.reset(new Procedural(this->getUserData())); _procedural->_vertexSource = simple_vert; _procedural->_fragmentSource = simple_frag; _procedural->_state->setCullMode(gpu::State::CULL_NONE); _procedural->_state->setDepthTest(true, true, gpu::LESS_EQUAL); _procedural->_state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } gpu::Batch& batch = *args->_batch; glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha()); if (_procedural->ready()) { batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well _procedural->prepare(batch, this->getDimensions()); auto color = _procedural->getColor(cubeColor); batch._glColor4f(color.r, color.g, color.b, color.a); DependencyManager::get<GeometryCache>()->renderCube(batch); } else { DependencyManager::get<DeferredLightingEffect>()->renderSolidCubeInstance(batch, getTransformToCenter(), cubeColor); } RenderableDebugableEntityItem::render(this, args); };
EntityItemProperties SphereEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class properties.setColor(getXColor()); properties.setGlowLevel(getGlowLevel()); return properties; }
void RenderablePolyLineEntityItem::update(const quint64& now) { PolyLineUniforms uniforms; uniforms.color = toGlm(getXColor()); memcpy(&_uniformBuffer.edit<PolyLineUniforms>(), &uniforms, sizeof(PolyLineUniforms)); if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) { updateVertices(); updateGeometry(); } }
void RenderableShapeEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableShapeEntityItem::render"); //Q_ASSERT(getType() == EntityTypes::Shape); Q_ASSERT(args->_batch); checkFading(); if (!_procedural) { _procedural.reset(new Procedural(getUserData())); _procedural->_vertexSource = simple_vert; _procedural->_fragmentSource = simple_frag; _procedural->_opaqueState->setCullMode(gpu::State::CULL_NONE); _procedural->_opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL); PrepareStencil::testMaskDrawShape(*_procedural->_opaqueState); _procedural->_opaqueState->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } gpu::Batch& batch = *args->_batch; glm::vec4 color(toGlm(getXColor()), getLocalRenderAlpha()); bool success; Transform modelTransform = getTransformToCenter(success); if (!success) { return; } if (_shape == entity::Sphere) { modelTransform.postScale(SPHERE_ENTITY_SCALE); } batch.setModelTransform(modelTransform); // use a transform with scale, rotation, registration point and translation if (_procedural->ready()) { _procedural->prepare(batch, getPosition(), getDimensions(), getOrientation()); auto outColor = _procedural->getColor(color); outColor.a *= _procedural->isFading() ? Interpolate::calculateFadeRatio(_procedural->getFadeStartTime()) : 1.0f; batch._glColor4f(outColor.r, outColor.g, outColor.b, outColor.a); if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { DependencyManager::get<GeometryCache>()->renderWireShape(batch, MAPPING[_shape]); } else { DependencyManager::get<GeometryCache>()->renderShape(batch, MAPPING[_shape]); } } else { // FIXME, support instanced multi-shape rendering using multidraw indirect color.a *= _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) : 1.0f; auto geometryCache = DependencyManager::get<GeometryCache>(); auto pipeline = color.a < 1.0f ? geometryCache->getTransparentShapePipeline() : geometryCache->getOpaqueShapePipeline(); if (render::ShapeKey(args->_globalShapeKey).isWireframe()) { geometryCache->renderWireShapeInstance(args, batch, MAPPING[_shape], color, pipeline); } else { geometryCache->renderSolidShapeInstance(args, batch, MAPPING[_shape], color, pipeline); } } static const auto triCount = DependencyManager::get<GeometryCache>()->getShapeTriangleCount(MAPPING[_shape]); args->_details._trianglesRendered += (int)triCount; }
EntityItemProperties BoxEntityItem::getProperties() const { EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class properties._color = getXColor(); properties._colorChanged = false; properties._glowLevel = getGlowLevel(); properties._glowLevelChanged = false; return properties; }
void RenderableLineEntityItem::updateGeometry() { auto geometryCache = DependencyManager::get<GeometryCache>(); if (_lineVerticesID == GeometryCache::UNKNOWN_ID) { _lineVerticesID = geometryCache ->allocateID(); } if (_pointsChanged) { glm::vec4 lineColor(toGlm(getXColor()), getLocalRenderAlpha()); geometryCache->updateVertices(_lineVerticesID, getLinePoints(), lineColor); _pointsChanged = false; } }
void RenderableParticleEffectEntityItem::updateQuads(RenderArgs* args, bool textured) { float particleRadius = getParticleRadius(); glm::vec4 particleColor(toGlm(getXColor()), getLocalRenderAlpha()); glm::vec3 upOffset = args->_viewFrustum->getUp() * particleRadius; glm::vec3 rightOffset = args->_viewFrustum->getRight() * particleRadius; QVector<glm::vec3> vertices; QVector<glm::vec3> positions; QVector<glm::vec2> textureCoords; vertices.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE); if (textured) { textureCoords.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE); } positions.reserve(getLivingParticleCount()); for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { positions.append(_particlePositions[i]); if (textured) { textureCoords.append(glm::vec2(0, 1)); textureCoords.append(glm::vec2(1, 1)); textureCoords.append(glm::vec2(1, 0)); textureCoords.append(glm::vec2(0, 0)); } } // sort particles back to front ::zSortAxis = args->_viewFrustum->getDirection(); qSort(positions.begin(), positions.end(), zSort); for (int i = 0; i < positions.size(); i++) { glm::vec3 pos = (textured) ? positions[i] : _particlePositions[i]; // generate corners of quad aligned to face the camera. vertices.append(pos + rightOffset + upOffset); vertices.append(pos - rightOffset + upOffset); vertices.append(pos - rightOffset - upOffset); vertices.append(pos + rightOffset - upOffset); } if (textured) { DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, textureCoords, particleColor); } else { DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, particleColor); } }
EntityItemProperties LineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties._color = getXColor(); properties._colorChanged = false; COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineWidth, getLineWidth); COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints); return properties; }
void RenderableLineEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableLineEntityItem::render"); assert(getType() == EntityTypes::Line); glm::vec3 position = getPosition(); glm::vec3 dimensions = getDimensions(); glm::quat rotation = getRotation(); glm::vec4 lineColor(toGlm(getXColor()), getLocalRenderAlpha()); glPushMatrix(); glTranslatef(position.x, position.y, position.z); glm::vec3 axis = glm::axis(rotation); glRotatef(glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); glm::vec3 p1 = {0.0f, 0.0f, 0.0f}; glm::vec3& p2 = dimensions; DependencyManager::get<DeferredLightingEffect>()->renderLine(p1, p2, lineColor, lineColor); glPopMatrix(); RenderableDebugableEntityItem::render(this, args); };
EntityItemProperties PolyLineEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { QWriteLocker lock(&_quadReadWriteLock); EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties._color = getXColor(); properties._colorChanged = false; COPY_ENTITY_PROPERTY_TO_PROPERTIES(lineWidth, getLineWidth); COPY_ENTITY_PROPERTY_TO_PROPERTIES(linePoints, getLinePoints); COPY_ENTITY_PROPERTY_TO_PROPERTIES(normals, getNormals); COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeColors, getStrokeColors); COPY_ENTITY_PROPERTY_TO_PROPERTIES(strokeWidths, getStrokeWidths); COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures); COPY_ENTITY_PROPERTY_TO_PROPERTIES(isUVModeStretch, getIsUVModeStretch); return properties; }
void RenderableBoxEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableBoxEntityItem::render"); Q_ASSERT(getType() == EntityTypes::Box); Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; batch.setModelTransform(getTransformToCenter()); // we want to include the scale as well if (!_procedural) { _procedural.reset(new ProceduralInfo(this)); } if (_procedural->ready()) { _procedural->prepare(batch); DependencyManager::get<GeometryCache>()->renderUnitCube(batch); } else { glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha()); DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(batch, 1.0f, cubeColor); } RenderableDebugableEntityItem::render(this, args); };
void RenderableLightEntityItem::updateRenderItemFromEntity(LightPayload& lightPayload) { auto entity = this; lightPayload.setVisible(entity->getVisible()); auto light = lightPayload.editLight(); light->setPosition(entity->getPosition()); light->setOrientation(entity->getRotation()); bool success; lightPayload.editBound() = entity->getAABox(success); if (!success) { lightPayload.editBound() = render::Item::Bound(); } glm::vec3 dimensions = entity->getDimensions(); float largestDiameter = glm::compMax(dimensions); light->setMaximumRadius(largestDiameter / 2.0f); light->setColor(toGlm(entity->getXColor())); float intensity = entity->getIntensity();//* entity->getFadingRatio(); light->setIntensity(intensity); light->setFalloffRadius(entity->getFalloffRadius()); float exponent = entity->getExponent(); float cutoff = glm::radians(entity->getCutoff()); if (!entity->getIsSpotlight()) { light->setType(model::Light::POINT); } else { light->setType(model::Light::SPOT); light->setSpotAngle(cutoff); light->setSpotExponent(exponent); } }
void RenderableBoxEntityItem::render(RenderArgs* args) { PerformanceTimer perfTimer("RenderableBoxEntityItem::render"); Q_ASSERT(getType() == EntityTypes::Box); Q_ASSERT(args->_batch); if (!_procedural) { _procedural.reset(new Procedural(this->getUserData())); _procedural->_vertexSource = simple_vert; _procedural->_fragmentSource = simple_frag; _procedural->_state->setCullMode(gpu::State::CULL_NONE); _procedural->_state->setDepthTest(true, true, gpu::LESS_EQUAL); _procedural->_state->setBlendFunction(false, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); } gpu::Batch& batch = *args->_batch; glm::vec4 cubeColor(toGlm(getXColor()), getLocalRenderAlpha()); bool success; auto transToCenter = getTransformToCenter(success); if (!success) { return; } batch.setModelTransform(transToCenter); // we want to include the scale as well if (_procedural->ready()) { _procedural->prepare(batch, getPosition(), getDimensions()); auto color = _procedural->getColor(cubeColor); batch._glColor4f(color.r, color.g, color.b, color.a); DependencyManager::get<GeometryCache>()->renderCube(batch); } else { DependencyManager::get<GeometryCache>()->renderSolidCubeInstance(batch, cubeColor); } static const auto triCount = DependencyManager::get<GeometryCache>()->getCubeTriangleCount(); args->_details._trianglesRendered += (int)triCount; }
EntityItemProperties ShapeEntityItem::getProperties(EntityPropertyFlags desiredProperties) const { EntityItemProperties properties = EntityItem::getProperties(desiredProperties); // get the properties from our base class properties.setColor(getXColor()); properties.setShape(entity::stringFromShape(getShape())); return properties; }
void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particleMinBound = glm::vec3(-1.0f, -1.0f, -1.0f); _particleMaxBound = glm::vec3(1.0f, 1.0f, 1.0f); // update particles between head and tail for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { _particleLifetimes[i] -= deltaTime; // if particle has died. if (_particleLifetimes[i] <= 0.0f || _lifespan == 0.0f) { // move head forward _particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles; } else { float age = 1.0f - _particleLifetimes[i] / _lifespan; // 0.0 .. 1.0 updateRadius(i, age); updateColor(i, age); updateAlpha(i, age); integrateParticle(i, deltaTime); extendBounds(_particlePositions[i]); } } // emit new particles, but only if we are emmitting if (getIsEmitting() && _emitRate > 0.0f && _lifespan > 0.0f && _polarStart <= _polarFinish) { float timeLeftInFrame = deltaTime; while (_timeUntilNextEmit < timeLeftInFrame) { timeLeftInFrame -= _timeUntilNextEmit; _timeUntilNextEmit = 1.0f / _emitRate; // emit a new particle at tail index. quint32 i = _particleTailIndex; _particleLifetimes[i] = _lifespan; // Radius if (_radiusSpread == 0.0f) { _radiusStarts[i] = getRadiusStart(); _radiusMiddles[i] =_particleRadius; _radiusFinishes[i] = getRadiusFinish(); } else { float spreadMultiplier; if (_particleRadius > 0.0f) { spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _radiusSpread / _particleRadius; } else { spreadMultiplier = 1.0f; } _radiusStarts[i] = glm::clamp(spreadMultiplier * getRadiusStart(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); _radiusMiddles[i] = glm::clamp(spreadMultiplier * _particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); _radiusFinishes[i] = glm::clamp(spreadMultiplier * getRadiusFinish(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); } updateRadius(i, 0.0f); // Position, velocity, and acceleration if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { // Emit along z-axis from position _particlePositions[i] = getPosition(); _particleVelocities[i] = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Z_AXIS); _particleAccelerations[i] = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } else { // Emit around point or from ellipsoid // - Distribute directions evenly around point // - Distribute points relatively evenly over ellipsoid surface // - Distribute points relatively evenly within ellipsoid volume float elevationMinZ = sin(PI_OVER_TWO - _polarFinish); float elevationMaxZ = sin(PI_OVER_TWO - _polarStart); float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat()); float azimuth; if (_azimuthFinish >= _azimuthStart) { azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat(); } else { azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat(); } glm::vec3 emitDirection; if (_emitDimensions == glm::vec3()) { // Point emitDirection = glm::quat(glm::vec3(PI_OVER_TWO - elevation, 0.0f, azimuth)) * Z_AXIS; _particlePositions[i] = getPosition(); } else { // Ellipsoid float radiusScale = 1.0f; if (_emitRadiusStart < 1.0f) { float emitRadiusStart = glm::max(_emitRadiusStart, EPSILON); // Avoid math complications at center float randRadius = emitRadiusStart + randFloatInRange(0.0f, MAXIMUM_EMIT_RADIUS_START - emitRadiusStart); radiusScale = 1.0f - std::pow(1.0f - randRadius, 3.0f); } glm::vec3 radiuses = radiusScale * 0.5f * _emitDimensions; float x = radiuses.x * glm::cos(elevation) * glm::cos(azimuth); float y = radiuses.y * glm::cos(elevation) * glm::sin(azimuth); float z = radiuses.z * glm::sin(elevation); glm::vec3 emitPosition = glm::vec3(x, y, z); emitDirection = glm::normalize(glm::vec3( radiuses.x > 0.0f ? x / (radiuses.x * radiuses.x) : 0.0f, radiuses.y > 0.0f ? y / (radiuses.y * radiuses.y) : 0.0f, radiuses.z > 0.0f ? z / (radiuses.z * radiuses.z) : 0.0f )); _particlePositions[i] = getPosition() + _emitOrientation * emitPosition; } _particleVelocities[i] = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); _particleAccelerations[i] = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } integrateParticle(i, timeLeftInFrame); extendBounds(_particlePositions[i]); // Color if (_colorSpread == xColor{ 0, 0, 0 }) { _colorStarts[i] = getColorStart(); _colorMiddles[i] = getXColor(); _colorFinishes[i] = getColorFinish(); } else { xColor startColor = getColorStart(); xColor middleColor = getXColor(); xColor finishColor = getColorFinish(); float spread = randFloatInRange(-1.0f, 1.0f); float spreadMultiplierRed = middleColor.red > 0 ? 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red : 1.0f; float spreadMultiplierGreen = middleColor.green > 0 ? 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green : 1.0f; float spreadMultiplierBlue = middleColor.blue > 0 ? 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue : 1.0f; _colorStarts[i].red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f); _colorStarts[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f); _colorStarts[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f); _colorMiddles[i].red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f); _colorMiddles[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f); _colorMiddles[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f); _colorFinishes[i].red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f); _colorFinishes[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f); _colorFinishes[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f); } updateColor(i, 0.0f); // Alpha if (_alphaSpread == 0.0f) { _alphaStarts[i] = getAlphaStart(); _alphaMiddles[i] = _alpha; _alphaFinishes[i] = getAlphaFinish(); } else { float spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _alphaSpread / _alpha; _alphaStarts[i] = spreadMultiplier * getAlphaStart(); _alphaMiddles[i] = spreadMultiplier * _alpha; _alphaFinishes[i] = spreadMultiplier * getAlphaFinish(); } updateAlpha(i, 0.0f); _particleTailIndex = (_particleTailIndex + 1) % _maxParticles; // overflow! move head forward by one. // because the case of head == tail indicates an empty array, not a full one. // This can drop an existing older particle, but this is by design, newer particles are a higher priority. if (_particleTailIndex == _particleHeadIndex) { _particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles; } } _timeUntilNextEmit -= timeLeftInFrame; } }