mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-05-15 13:20:39 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into fixCrashRedux
Conflicts: interface/src/Application.cpp
This commit is contained in:
commit
6ac9b737d2
24 changed files with 1033 additions and 683 deletions
87
examples/dropStuffNearMe.js
Normal file
87
examples/dropStuffNearMe.js
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
//
|
||||||
|
// Created by Philip Rosedale on January 9, 2016
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
// Puts a bunch of entities in front of you, with various adjustable properties for testing.
|
||||||
|
//
|
||||||
|
// Note that when creating things quickly, the entity server will ignore data if we send updates too quickly.
|
||||||
|
// like Internet MTU, these rates are set by th domain operator, so in this script there is a RATE_PER_SECOND
|
||||||
|
// variable letting you set this speed. If entities are missing from the grid after a relog, this number
|
||||||
|
// being too high may be the reason.
|
||||||
|
|
||||||
|
var SIZE = 0.5;
|
||||||
|
var TYPE = "Box"; // Right now this can be "Box" or "Model" or "Sphere"
|
||||||
|
var MODEL_URL = "http://s3.amazonaws.com/hifi-public/models/content/basketball2.fbx";
|
||||||
|
var MODEL_DIMENSION = { x: 0.3, y: 0.3, z: 0.3 };
|
||||||
|
|
||||||
|
var RATE_PER_SECOND = 1000; // The entity server will drop data if we create things too fast.
|
||||||
|
var SCRIPT_INTERVAL = 100;
|
||||||
|
var LIFETIME = 90;
|
||||||
|
|
||||||
|
var NUMBER_TO_CREATE = 300;
|
||||||
|
|
||||||
|
var GRAVITY = { x: 0, y: -9.8, z: 0 };
|
||||||
|
var VELOCITY = { x: 0.0, y: 0, z: 0 };
|
||||||
|
var ANGULAR_VELOCITY = { x: 1, y: 1, z: 1 };
|
||||||
|
|
||||||
|
var DAMPING = 0.5;
|
||||||
|
var ANGULAR_DAMPING = 0.5;
|
||||||
|
|
||||||
|
var collidable = true;
|
||||||
|
var gravity = true;
|
||||||
|
|
||||||
|
|
||||||
|
var x = 0;
|
||||||
|
var z = 0;
|
||||||
|
var totalCreated = 0;
|
||||||
|
|
||||||
|
var RANGE = 10;
|
||||||
|
var HOW_FAR_IN_FRONT_OF_ME = 3 * RANGE;
|
||||||
|
|
||||||
|
|
||||||
|
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(HOW_FAR_IN_FRONT_OF_ME, Quat.getFront(Camera.orientation)));
|
||||||
|
|
||||||
|
|
||||||
|
function randomVector(range) {
|
||||||
|
return {
|
||||||
|
x: (Math.random() - 0.5) * range.x,
|
||||||
|
y: (Math.random() - 0.5) * range.y,
|
||||||
|
z: (Math.random() - 0.5) * range.z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Vec3.print("Center: ", center);
|
||||||
|
|
||||||
|
Script.setInterval(function () {
|
||||||
|
if (!Entities.serversExist() || !Entities.canRez() || (totalCreated > NUMBER_TO_CREATE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var numToCreate = RATE_PER_SECOND * (SCRIPT_INTERVAL / 1000.0);
|
||||||
|
for (var i = 0; (i < numToCreate) && (totalCreated < NUMBER_TO_CREATE); i++) {
|
||||||
|
var position = Vec3.sum(center, randomVector({ x: RANGE, y: RANGE, z: RANGE }));
|
||||||
|
|
||||||
|
Vec3.print("Position: ", position);
|
||||||
|
Entities.addEntity({
|
||||||
|
type: TYPE,
|
||||||
|
modelURL: MODEL_URL,
|
||||||
|
name: "gridTest",
|
||||||
|
position: position,
|
||||||
|
dimensions: (TYPE == "Model") ? MODEL_DIMENSION : { x: SIZE, y: SIZE, z: SIZE },
|
||||||
|
color: { red: Math.random() * 255, green: Math.random() * 255, blue: Math.random() * 255 },
|
||||||
|
velocity: VELOCITY,
|
||||||
|
angularVelocity: Vec3.multiply(Math.random(), ANGULAR_VELOCITY),
|
||||||
|
damping: DAMPING,
|
||||||
|
angularDamping: ANGULAR_DAMPING,
|
||||||
|
gravity: (gravity ? GRAVITY : { x: 0, y: 0, z: 0}),
|
||||||
|
collisionsWillMove: collidable,
|
||||||
|
lifetime: LIFETIME
|
||||||
|
});
|
||||||
|
|
||||||
|
totalCreated++;
|
||||||
|
}
|
||||||
|
}, SCRIPT_INTERVAL);
|
||||||
|
|
102
examples/example/ui/energyBar.js
Normal file
102
examples/example/ui/energyBar.js
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
// energyBar.js
|
||||||
|
// examples/ui
|
||||||
|
//
|
||||||
|
// Created by Eric Levin on 1/4/15
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// This script adds an energy bar overlay which displays the amount of energy a user has left for grabbing and moving objects
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
Script.include("../../libraries/utils.js");
|
||||||
|
var energyColor = {red: 0, green: 200, blue: 0};
|
||||||
|
var lowEnergyColor = {red: 255, green: 0, blue: 0};
|
||||||
|
var totalWidth = 200;
|
||||||
|
var paddingRight = 50;
|
||||||
|
var xPosition = Window.innerWidth - totalWidth - paddingRight;
|
||||||
|
var lowEnergyThreshold = 0.3;
|
||||||
|
var currentEnergy = 1.0;
|
||||||
|
var energyLossRate = 0.003;
|
||||||
|
var energyChargeRate = 0.003;
|
||||||
|
var isGrabbing = false;
|
||||||
|
var refractoryPeriod = 2000;
|
||||||
|
|
||||||
|
var lastAvatarVelocity = MyAvatar.getVelocity();
|
||||||
|
var lastAvatarPosition = MyAvatar.position;
|
||||||
|
|
||||||
|
var background = Overlays.addOverlay("text", {
|
||||||
|
x: xPosition,
|
||||||
|
y: 20,
|
||||||
|
width: totalWidth,
|
||||||
|
height: 10,
|
||||||
|
backgroundColor: {red: 184, green: 181, blue: 178}
|
||||||
|
})
|
||||||
|
|
||||||
|
var bar = Overlays.addOverlay("text", {
|
||||||
|
x: xPosition,
|
||||||
|
y: 20,
|
||||||
|
width: totalWidth,
|
||||||
|
height: 10,
|
||||||
|
backgroundColor: energyColor
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// Takes an energy value between 0 and 1 and sets energy bar width appropriately
|
||||||
|
function setEnergy(energy) {
|
||||||
|
energy = clamp(energy, 0, 1);
|
||||||
|
var barWidth = totalWidth * energy;
|
||||||
|
var color = energy <= lowEnergyThreshold ? lowEnergyColor: energyColor;
|
||||||
|
Overlays.editOverlay(bar, { width: barWidth, backgroundColor: color});
|
||||||
|
}
|
||||||
|
|
||||||
|
function avatarAccelerationEnergy() {
|
||||||
|
var AVATAR_MOVEMENT_ENERGY_CONSTANT = 0.001;
|
||||||
|
var velocity = MyAvatar.getVelocity();
|
||||||
|
var dV = Math.abs(Vec3.length(velocity) - Vec3.length(lastAvatarVelocity));
|
||||||
|
var dE = Vec3.length(lastAvatarVelocity) * dV * AVATAR_MOVEMENT_ENERGY_CONSTANT;
|
||||||
|
lastAvatarVelocity = velocity;
|
||||||
|
return dE;
|
||||||
|
}
|
||||||
|
|
||||||
|
function teleported() {
|
||||||
|
var MAX_AVATAR_MOVEMENT_PER_FRAME = 30.0;
|
||||||
|
var position = MyAvatar.position;
|
||||||
|
var dP = Vec3.length(Vec3.subtract(position, lastAvatarPosition));
|
||||||
|
lastAvatarPosition = position;
|
||||||
|
return (dP > MAX_AVATAR_MOVEMENT_PER_FRAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
function audioEnergy() {
|
||||||
|
var AUDIO_ENERGY_CONSTANT = 0.000001;
|
||||||
|
return MyAvatar.audioLoudness * AUDIO_ENERGY_CONSTANT;
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
// refill energy
|
||||||
|
currentEnergy += energyChargeRate;
|
||||||
|
|
||||||
|
// Avatar acceleration
|
||||||
|
currentEnergy -= avatarAccelerationEnergy();
|
||||||
|
|
||||||
|
// Teleport cost
|
||||||
|
if (teleported()) {
|
||||||
|
currentEnergy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Making sounds
|
||||||
|
currentEnergy -= audioEnergy();
|
||||||
|
|
||||||
|
|
||||||
|
currentEnergy = clamp(currentEnergy, 0, 1);
|
||||||
|
setEnergy(currentEnergy);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup() {
|
||||||
|
Overlays.deleteOverlay(background);
|
||||||
|
Overlays.deleteOverlay(bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
Script.update.connect(update);
|
||||||
|
Script.scriptEnding.connect(cleanup);
|
|
@ -297,3 +297,8 @@ calculateHandSizeRatio = function() {
|
||||||
var handSizeRatio = centerHandPoint/standardCenterHandPoint;
|
var handSizeRatio = centerHandPoint/standardCenterHandPoint;
|
||||||
return handSizeRatio;
|
return handSizeRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clamp = function(val, min, max){
|
||||||
|
return Math.max(min, Math.min(max, val))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -448,8 +448,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
|
|
||||||
_bookmarks = new Bookmarks(); // Before setting up the menu
|
_bookmarks = new Bookmarks(); // Before setting up the menu
|
||||||
|
|
||||||
_renderEngine->addTask(make_shared<RenderDeferredTask>());
|
_runningScriptsWidget = new RunningScriptsWidget(_window);
|
||||||
_renderEngine->registerScene(_main3DScene);
|
|
||||||
|
|
||||||
// start the nodeThread so its event loop is running
|
// start the nodeThread so its event loop is running
|
||||||
QThread* nodeThread = new QThread(this);
|
QThread* nodeThread = new QThread(this);
|
||||||
|
@ -615,7 +614,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
OffscreenUi::warning(nullptr, "Error Loading Script", filename + " failed to load.");
|
OffscreenUi::warning(nullptr, "Error Loading Script", filename + " failed to load.");
|
||||||
}, Qt::QueuedConnection);
|
}, Qt::QueuedConnection);
|
||||||
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WSADATA WsaData;
|
WSADATA WsaData;
|
||||||
int wsaresult = WSAStartup(MAKEWORD(2, 2), &WsaData);
|
int wsaresult = WSAStartup(MAKEWORD(2, 2), &WsaData);
|
||||||
|
@ -678,6 +676,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
||||||
_offscreenContext->makeCurrent();
|
_offscreenContext->makeCurrent();
|
||||||
initializeGL();
|
initializeGL();
|
||||||
|
|
||||||
|
// Start rendering
|
||||||
|
_renderEngine->addTask(make_shared<RenderDeferredTask>());
|
||||||
|
_renderEngine->registerScene(_main3DScene);
|
||||||
|
|
||||||
_toolWindow = new ToolWindow();
|
_toolWindow = new ToolWindow();
|
||||||
_toolWindow->setWindowFlags((_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint) & ~Qt::WindowMinimizeButtonHint);
|
_toolWindow->setWindowFlags((_toolWindow->windowFlags() | Qt::WindowStaysOnTopHint) & ~Qt::WindowMinimizeButtonHint);
|
||||||
|
|
|
@ -48,7 +48,7 @@ public:
|
||||||
|
|
||||||
// setters for lens attributes
|
// setters for lens attributes
|
||||||
void setProjection(const glm::mat4 & projection);
|
void setProjection(const glm::mat4 & projection);
|
||||||
void getFocalLength(float focalLength) { _focalLength = focalLength; }
|
void setFocalLength(float focalLength) { _focalLength = focalLength; }
|
||||||
|
|
||||||
// getters for lens attributes
|
// getters for lens attributes
|
||||||
const glm::mat4& getProjection() const { return _projection; }
|
const glm::mat4& getProjection() const { return _projection; }
|
||||||
|
|
|
@ -70,7 +70,7 @@ uniform SphericalHarmonics ambientSphere;
|
||||||
<@include model/Light.slh@>
|
<@include model/Light.slh@>
|
||||||
|
|
||||||
<@func declareEvalAmbientGlobalColor()@>
|
<@func declareEvalAmbientGlobalColor()@>
|
||||||
vec3 evalAmbienGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) {
|
vec3 evalAmbientGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) {
|
||||||
|
|
||||||
// Need the light now
|
// Need the light now
|
||||||
Light light = getLight();
|
Light light = getLight();
|
||||||
|
@ -93,7 +93,7 @@ vec3 evalAmbienGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi
|
||||||
|
|
||||||
<$declareSphericalHarmonics()$>
|
<$declareSphericalHarmonics()$>
|
||||||
|
|
||||||
vec3 evalAmbienSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) {
|
vec3 evalAmbientSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss) {
|
||||||
// Need the light now
|
// Need the light now
|
||||||
Light light = getLight();
|
Light light = getLight();
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,8 @@
|
||||||
#include "model/Stage.h"
|
#include "model/Stage.h"
|
||||||
#include "model/Geometry.h"
|
#include "model/Geometry.h"
|
||||||
|
|
||||||
|
#include "render/ShapePipeline.h"
|
||||||
|
|
||||||
class RenderArgs;
|
class RenderArgs;
|
||||||
class SimpleProgramKey;
|
class SimpleProgramKey;
|
||||||
struct LightLocations;
|
struct LightLocations;
|
||||||
|
@ -30,7 +32,7 @@ class DeferredLightingEffect : public Dependency {
|
||||||
SINGLETON_DEPENDENCY
|
SINGLETON_DEPENDENCY
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const int NORMAL_FITTING_MAP_SLOT = 10;
|
static const int NORMAL_FITTING_MAP_SLOT = render::ShapePipeline::Slot::NORMAL_FITTING_MAP;
|
||||||
static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2;
|
static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
|
@ -14,30 +14,36 @@
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
|
||||||
#include "DeferredLightingEffect.h"
|
#include "DeferredLightingEffect.h"
|
||||||
|
|
||||||
#include "Model.h"
|
#include "Model.h"
|
||||||
|
|
||||||
namespace render {
|
using namespace render;
|
||||||
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
|
|
||||||
if (payload) {
|
|
||||||
return payload->getKey();
|
|
||||||
}
|
|
||||||
// Return opaque for lack of a better idea
|
|
||||||
return ItemKey::Builder::opaqueShape();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) {
|
namespace render {
|
||||||
if (payload) {
|
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
|
||||||
return payload->getBound();
|
if (payload) {
|
||||||
}
|
return payload->getKey();
|
||||||
return render::Item::Bound();
|
|
||||||
}
|
|
||||||
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) {
|
|
||||||
return payload->render(args);
|
|
||||||
}
|
}
|
||||||
|
return ItemKey::Builder::opaqueShape(); // for lack of a better idea
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace render;
|
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) {
|
||||||
|
if (payload) {
|
||||||
|
return payload->getBound();
|
||||||
|
}
|
||||||
|
return Item::Bound();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload) {
|
||||||
|
if (payload) {
|
||||||
|
return payload->getShapeKey();
|
||||||
|
}
|
||||||
|
return ShapeKey::Builder::invalid();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) {
|
||||||
|
return payload->render(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) {
|
MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) {
|
||||||
|
|
||||||
|
@ -69,7 +75,7 @@ void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) {
|
||||||
_drawMaterial = drawMaterial;
|
_drawMaterial = drawMaterial;
|
||||||
}
|
}
|
||||||
|
|
||||||
render::ItemKey MeshPartPayload::getKey() const {
|
ItemKey MeshPartPayload::getKey() const {
|
||||||
ItemKey::Builder builder;
|
ItemKey::Builder builder;
|
||||||
builder.withTypeShape();
|
builder.withTypeShape();
|
||||||
|
|
||||||
|
@ -83,10 +89,32 @@ render::ItemKey MeshPartPayload::getKey() const {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
render::Item::Bound MeshPartPayload::getBound() const {
|
Item::Bound MeshPartPayload::getBound() const {
|
||||||
return _worldBound;
|
return _worldBound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShapeKey MeshPartPayload::getShapeKey() const {
|
||||||
|
model::MaterialKey drawMaterialKey;
|
||||||
|
if (_drawMaterial) {
|
||||||
|
drawMaterialKey = _drawMaterial->getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapeKey::Builder builder;
|
||||||
|
if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap()) {
|
||||||
|
builder.withTranslucent();
|
||||||
|
}
|
||||||
|
if (drawMaterialKey.isNormalMap()) {
|
||||||
|
builder.withTangents();
|
||||||
|
}
|
||||||
|
if (drawMaterialKey.isGlossMap()) {
|
||||||
|
builder.withSpecular();
|
||||||
|
}
|
||||||
|
if (drawMaterialKey.isLightmapMap()) {
|
||||||
|
builder.withLightmap();
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
||||||
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
|
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
|
||||||
}
|
}
|
||||||
|
@ -104,14 +132,14 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const {
|
||||||
if (!_drawMaterial) {
|
if (!_drawMaterial) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto textureCache = DependencyManager::get<TextureCache>();
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
|
|
||||||
batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer());
|
batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_GPU, _drawMaterial->getSchemaBuffer());
|
||||||
|
|
||||||
auto materialKey = _drawMaterial->getKey();
|
auto materialKey = _drawMaterial->getKey();
|
||||||
auto textureMaps = _drawMaterial->getTextureMaps();
|
auto textureMaps = _drawMaterial->getTextureMaps();
|
||||||
|
@ -121,44 +149,44 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio
|
||||||
if (materialKey.isDiffuseMap()) {
|
if (materialKey.isDiffuseMap()) {
|
||||||
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
|
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
|
||||||
if (diffuseMap && diffuseMap->isDefined()) {
|
if (diffuseMap && diffuseMap->isDefined()) {
|
||||||
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
|
batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, diffuseMap->getTextureView());
|
||||||
|
|
||||||
if (!diffuseMap->getTextureTransform().isIdentity()) {
|
if (!diffuseMap->getTextureTransform().isIdentity()) {
|
||||||
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
|
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getGrayTexture());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getWhiteTexture());
|
batch.setResourceTexture(ShapePipeline::Slot::DIFFUSE_MAP, textureCache->getWhiteTexture());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normal map
|
// Normal map
|
||||||
if (materialKey.isNormalMap()) {
|
if (materialKey.isNormalMap()) {
|
||||||
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
|
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
|
||||||
if (normalMap && normalMap->isDefined()) {
|
if (normalMap && normalMap->isDefined()) {
|
||||||
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView());
|
batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, normalMap->getTextureView());
|
||||||
|
|
||||||
// texcoord are assumed to be the same has diffuse
|
// texcoord are assumed to be the same has diffuse
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture());
|
batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, textureCache->getBlueTexture());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr);
|
batch.setResourceTexture(ShapePipeline::Slot::NORMAL_MAP, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that
|
// TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that
|
||||||
if (materialKey.isGlossMap()) {
|
if (materialKey.isGlossMap()) {
|
||||||
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
|
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
|
||||||
if (specularMap && specularMap->isDefined()) {
|
if (specularMap && specularMap->isDefined()) {
|
||||||
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, specularMap->getTextureView());
|
batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, specularMap->getTextureView());
|
||||||
|
|
||||||
// texcoord are assumed to be the same has diffuse
|
// texcoord are assumed to be the same has diffuse
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture());
|
batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, textureCache->getBlackTexture());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, nullptr);
|
batch.setResourceTexture(ShapePipeline::Slot::SPECULAR_MAP, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too
|
// TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too
|
||||||
|
@ -166,7 +194,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio
|
||||||
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
|
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
|
||||||
|
|
||||||
if (lightmapMap && lightmapMap->isDefined()) {
|
if (lightmapMap && lightmapMap->isDefined()) {
|
||||||
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView());
|
batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, lightmapMap->getTextureView());
|
||||||
|
|
||||||
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
|
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
|
||||||
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
|
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
|
||||||
|
@ -175,10 +203,10 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio
|
||||||
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
|
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture());
|
batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, textureCache->getGrayTexture());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr);
|
batch.setResourceTexture(ShapePipeline::Slot::LIGHTMAP_MAP, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Texcoord transforms ?
|
// Texcoord transforms ?
|
||||||
|
@ -187,7 +215,7 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locatio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const {
|
||||||
batch.setModelTransform(_drawTransform);
|
batch.setModelTransform(_drawTransform);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,29 +223,12 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati
|
||||||
void MeshPartPayload::render(RenderArgs* args) const {
|
void MeshPartPayload::render(RenderArgs* args) const {
|
||||||
PerformanceTimer perfTimer("MeshPartPayload::render");
|
PerformanceTimer perfTimer("MeshPartPayload::render");
|
||||||
|
|
||||||
|
|
||||||
gpu::Batch& batch = *(args->_batch);
|
gpu::Batch& batch = *(args->_batch);
|
||||||
auto mode = args->_renderMode;
|
|
||||||
|
|
||||||
model::MaterialKey drawMaterialKey;
|
ShapeKey key = getShapeKey();
|
||||||
if (_drawMaterial) {
|
|
||||||
drawMaterialKey = _drawMaterial->getKey();
|
|
||||||
}
|
|
||||||
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
|
|
||||||
|
|
||||||
bool hasTangents = drawMaterialKey.isNormalMap();
|
|
||||||
bool hasSpecular = drawMaterialKey.isGlossMap();
|
|
||||||
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
|
||||||
bool isSkinned = false;
|
|
||||||
bool wireframe = false;
|
|
||||||
if (wireframe) {
|
|
||||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelRender::Locations* locations = nullptr;
|
|
||||||
ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
|
||||||
args, locations);
|
|
||||||
|
|
||||||
|
auto locations = args->_pipeline->locations;
|
||||||
|
assert(locations);
|
||||||
|
|
||||||
// Bind the model transform and the skinCLusterMatrices if needed
|
// Bind the model transform and the skinCLusterMatrices if needed
|
||||||
bindTransform(batch, locations);
|
bindTransform(batch, locations);
|
||||||
|
@ -230,7 +241,7 @@ void MeshPartPayload::render(RenderArgs* args) const {
|
||||||
|
|
||||||
|
|
||||||
// TODO: We should be able to do that just in the renderTransparentJob
|
// TODO: We should be able to do that just in the renderTransparentJob
|
||||||
if (translucentMesh && locations->lightBufferUnit >= 0) {
|
if (key.isTranslucent() && locations->lightBufferUnit >= 0) {
|
||||||
PerformanceTimer perfTimer("DLE->setupTransparent()");
|
PerformanceTimer perfTimer("DLE->setupTransparent()");
|
||||||
|
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
|
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
|
||||||
|
@ -251,29 +262,32 @@ void MeshPartPayload::render(RenderArgs* args) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) {
|
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) {
|
||||||
if (payload) {
|
if (payload) {
|
||||||
return payload->getKey();
|
return payload->getKey();
|
||||||
}
|
|
||||||
// Return opaque for lack of a better idea
|
|
||||||
return ItemKey::Builder::opaqueShape();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) {
|
|
||||||
if (payload) {
|
|
||||||
return payload->getBound();
|
|
||||||
}
|
|
||||||
return render::Item::Bound();
|
|
||||||
}
|
|
||||||
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
|
|
||||||
return payload->render(args);
|
|
||||||
}
|
}
|
||||||
|
return ItemKey::Builder::opaqueShape(); // for lack of a better idea
|
||||||
}
|
}
|
||||||
|
|
||||||
using namespace render;
|
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) {
|
||||||
|
if (payload) {
|
||||||
|
return payload->getBound();
|
||||||
|
}
|
||||||
|
return Item::Bound();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) {
|
||||||
|
if (payload) {
|
||||||
|
return payload->getShapeKey();
|
||||||
|
}
|
||||||
|
return ShapeKey::Builder::invalid();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
|
||||||
|
return payload->render(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
|
ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
|
||||||
_model(model),
|
_model(model),
|
||||||
|
@ -310,7 +324,7 @@ void ModelMeshPartPayload::notifyLocationChanged() {
|
||||||
_model->_needsUpdateClusterMatrices = true;
|
_model->_needsUpdateClusterMatrices = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
render::ItemKey ModelMeshPartPayload::getKey() const {
|
ItemKey ModelMeshPartPayload::getKey() const {
|
||||||
ItemKey::Builder builder;
|
ItemKey::Builder builder;
|
||||||
builder.withTypeShape();
|
builder.withTypeShape();
|
||||||
|
|
||||||
|
@ -332,12 +346,79 @@ render::ItemKey ModelMeshPartPayload::getKey() const {
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
render::Item::Bound ModelMeshPartPayload::getBound() const {
|
Item::Bound ModelMeshPartPayload::getBound() const {
|
||||||
// NOTE: we can't cache this bounds because we need to handle the case of a moving
|
// NOTE: we can't cache this bounds because we need to handle the case of a moving
|
||||||
// entity or mesh part.
|
// entity or mesh part.
|
||||||
return _model->getPartBounds(_meshIndex, _partIndex, _transform.getTranslation(), _transform.getRotation());
|
return _model->getPartBounds(_meshIndex, _partIndex, _transform.getTranslation(), _transform.getRotation());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
||||||
|
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
|
||||||
|
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
|
||||||
|
|
||||||
|
// guard against partially loaded meshes
|
||||||
|
if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size()) {
|
||||||
|
return ShapeKey::Builder::invalid();
|
||||||
|
}
|
||||||
|
|
||||||
|
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
|
||||||
|
|
||||||
|
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
|
||||||
|
// to false to rebuild out mesh groups.
|
||||||
|
if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) {
|
||||||
|
_model->_meshGroupsKnown = false; // regenerate these lists next time around.
|
||||||
|
_model->_readyWhenAdded = false; // in case any of our users are using scenes
|
||||||
|
_model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
|
||||||
|
return ShapeKey::Builder::invalid();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int vertexCount = mesh.vertices.size();
|
||||||
|
if (vertexCount == 0) {
|
||||||
|
// sanity check
|
||||||
|
return ShapeKey::Builder::invalid(); // FIXME
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
model::MaterialKey drawMaterialKey;
|
||||||
|
if (_drawMaterial) {
|
||||||
|
drawMaterialKey = _drawMaterial->getKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
|
||||||
|
bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty();
|
||||||
|
bool hasSpecular = drawMaterialKey.isGlossMap();
|
||||||
|
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
||||||
|
|
||||||
|
bool isSkinned = _isSkinned;
|
||||||
|
bool wireframe = _model->isWireframe();
|
||||||
|
|
||||||
|
if (wireframe) {
|
||||||
|
isTranslucent = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ShapeKey::Builder builder;
|
||||||
|
if (isTranslucent) {
|
||||||
|
builder.withTranslucent();
|
||||||
|
}
|
||||||
|
if (hasTangents) {
|
||||||
|
builder.withTangents();
|
||||||
|
}
|
||||||
|
if (hasSpecular) {
|
||||||
|
builder.withSpecular();
|
||||||
|
}
|
||||||
|
if (hasLightmap) {
|
||||||
|
builder.withLightmap();
|
||||||
|
}
|
||||||
|
if (isSkinned) {
|
||||||
|
builder.withSkinned();
|
||||||
|
}
|
||||||
|
if (wireframe) {
|
||||||
|
builder.withWireframe();
|
||||||
|
}
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||||
if (!_isBlendShaped) {
|
if (!_isBlendShaped) {
|
||||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||||
|
@ -361,16 +442,16 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations) const {
|
||||||
// Still relying on the raw data from the model
|
// Still relying on the raw data from the model
|
||||||
const Model::MeshState& state = _model->_meshStates.at(_meshIndex);
|
const Model::MeshState& state = _model->_meshStates.at(_meshIndex);
|
||||||
|
|
||||||
Transform transform;
|
Transform transform;
|
||||||
if (state.clusterBuffer) {
|
if (state.clusterBuffer) {
|
||||||
if (_model->_cauterizeBones) {
|
if (_model->_cauterizeBones) {
|
||||||
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.cauterizedClusterBuffer);
|
batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.cauterizedClusterBuffer);
|
||||||
} else {
|
} else {
|
||||||
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer);
|
batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.clusterBuffer);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_model->_cauterizeBones) {
|
if (_model->_cauterizeBones) {
|
||||||
|
@ -387,54 +468,18 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::L
|
||||||
|
|
||||||
void ModelMeshPartPayload::render(RenderArgs* args) const {
|
void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
|
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
|
||||||
|
|
||||||
if (!_model->_readyWhenAdded || !_model->_isVisible) {
|
if (!_model->_readyWhenAdded || !_model->_isVisible) {
|
||||||
return; // bail asap
|
return; // bail asap
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::Batch& batch = *(args->_batch);
|
gpu::Batch& batch = *(args->_batch);
|
||||||
auto mode = args->_renderMode;
|
|
||||||
|
|
||||||
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
|
ShapeKey key = getShapeKey();
|
||||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
|
if (!key.isValid()) {
|
||||||
|
|
||||||
// guard against partially loaded meshes
|
|
||||||
if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size() ) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Back to model to update the cluster matrices right now
|
|
||||||
_model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation());
|
|
||||||
|
|
||||||
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
|
|
||||||
|
|
||||||
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
|
|
||||||
// to false to rebuild out mesh groups.
|
|
||||||
if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) {
|
|
||||||
_model->_meshGroupsKnown = false; // regenerate these lists next time around.
|
|
||||||
_model->_readyWhenAdded = false; // in case any of our users are using scenes
|
|
||||||
_model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
|
|
||||||
return; // FIXME!
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int vertexCount = mesh.vertices.size();
|
|
||||||
if (vertexCount == 0) {
|
|
||||||
// sanity check
|
|
||||||
return; // FIXME!
|
|
||||||
}
|
|
||||||
|
|
||||||
model::MaterialKey drawMaterialKey;
|
|
||||||
if (_drawMaterial) {
|
|
||||||
drawMaterialKey = _drawMaterial->getKey();
|
|
||||||
}
|
|
||||||
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
|
|
||||||
|
|
||||||
bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty();
|
|
||||||
bool hasSpecular = drawMaterialKey.isGlossMap();
|
|
||||||
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
|
||||||
bool isSkinned = _isSkinned;
|
|
||||||
bool wireframe = _model->isWireframe();
|
|
||||||
|
|
||||||
// render the part bounding box
|
// render the part bounding box
|
||||||
#ifdef DEBUG_BOUNDING_PARTS
|
#ifdef DEBUG_BOUNDING_PARTS
|
||||||
{
|
{
|
||||||
|
@ -458,19 +503,11 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
}
|
}
|
||||||
#endif //def DEBUG_BOUNDING_PARTS
|
#endif //def DEBUG_BOUNDING_PARTS
|
||||||
|
|
||||||
if (wireframe) {
|
auto locations = args->_pipeline->locations;
|
||||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
assert(locations);
|
||||||
}
|
|
||||||
|
|
||||||
ModelRender::Locations* locations = nullptr;
|
|
||||||
ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
|
||||||
args, locations);
|
|
||||||
|
|
||||||
if (!locations) { // the pipeline could not be found
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bind the model transform and the skinCLusterMatrices if needed
|
// Bind the model transform and the skinCLusterMatrices if needed
|
||||||
|
_model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation());
|
||||||
bindTransform(batch, locations);
|
bindTransform(batch, locations);
|
||||||
|
|
||||||
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||||
|
@ -481,7 +518,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
||||||
|
|
||||||
|
|
||||||
// TODO: We should be able to do that just in the renderTransparentJob
|
// TODO: We should be able to do that just in the renderTransparentJob
|
||||||
if (translucentMesh && locations->lightBufferUnit >= 0) {
|
if (key.isTranslucent() && locations->lightBufferUnit >= 0) {
|
||||||
PerformanceTimer perfTimer("DLE->setupTransparent()");
|
PerformanceTimer perfTimer("DLE->setupTransparent()");
|
||||||
|
|
||||||
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
|
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
|
||||||
|
|
|
@ -15,11 +15,10 @@
|
||||||
#include <gpu/Batch.h>
|
#include <gpu/Batch.h>
|
||||||
|
|
||||||
#include <render/Scene.h>
|
#include <render/Scene.h>
|
||||||
|
#include <render/ShapePipeline.h>
|
||||||
|
|
||||||
#include <model/Geometry.h>
|
#include <model/Geometry.h>
|
||||||
|
|
||||||
#include "ModelRender.h"
|
|
||||||
|
|
||||||
class Model;
|
class Model;
|
||||||
|
|
||||||
class MeshPartPayload {
|
class MeshPartPayload {
|
||||||
|
@ -40,13 +39,14 @@ public:
|
||||||
// Render Item interface
|
// Render Item interface
|
||||||
virtual render::ItemKey getKey() const;
|
virtual render::ItemKey getKey() const;
|
||||||
virtual render::Item::Bound getBound() const;
|
virtual render::Item::Bound getBound() const;
|
||||||
|
virtual render::ShapeKey getShapeKey() const; // shape interface
|
||||||
virtual void render(RenderArgs* args) const;
|
virtual void render(RenderArgs* args) const;
|
||||||
|
|
||||||
// ModelMeshPartPayload functions to perform render
|
// ModelMeshPartPayload functions to perform render
|
||||||
void drawCall(gpu::Batch& batch) const;
|
void drawCall(gpu::Batch& batch) const;
|
||||||
virtual void bindMesh(gpu::Batch& batch) const;
|
virtual void bindMesh(gpu::Batch& batch) const;
|
||||||
virtual void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const;
|
||||||
virtual void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const;
|
||||||
|
|
||||||
// Payload resource cached values
|
// Payload resource cached values
|
||||||
model::MeshPointer _drawMesh;
|
model::MeshPointer _drawMesh;
|
||||||
|
@ -67,10 +67,10 @@ public:
|
||||||
namespace render {
|
namespace render {
|
||||||
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload);
|
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload);
|
||||||
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
|
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
|
||||||
|
template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload);
|
||||||
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
|
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class ModelMeshPartPayload : public MeshPartPayload {
|
class ModelMeshPartPayload : public MeshPartPayload {
|
||||||
public:
|
public:
|
||||||
ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
||||||
|
@ -83,11 +83,12 @@ public:
|
||||||
// Render Item interface
|
// Render Item interface
|
||||||
render::ItemKey getKey() const override;
|
render::ItemKey getKey() const override;
|
||||||
render::Item::Bound getBound() const override;
|
render::Item::Bound getBound() const override;
|
||||||
|
render::ShapeKey getShapeKey() const override; // shape interface
|
||||||
void render(RenderArgs* args) const override;
|
void render(RenderArgs* args) const override;
|
||||||
|
|
||||||
// ModelMeshPartPayload functions to perform render
|
// ModelMeshPartPayload functions to perform render
|
||||||
void bindMesh(gpu::Batch& batch) const override;
|
void bindMesh(gpu::Batch& batch) const override;
|
||||||
void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const override;
|
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations) const override;
|
||||||
|
|
||||||
|
|
||||||
void initCache();
|
void initCache();
|
||||||
|
|
|
@ -22,8 +22,8 @@
|
||||||
#include <ViewFrustum.h>
|
#include <ViewFrustum.h>
|
||||||
|
|
||||||
#include "AbstractViewStateInterface.h"
|
#include "AbstractViewStateInterface.h"
|
||||||
#include "Model.h"
|
|
||||||
#include "MeshPartPayload.h"
|
#include "MeshPartPayload.h"
|
||||||
|
#include "Model.h"
|
||||||
|
|
||||||
#include "RenderUtilsLogging.h"
|
#include "RenderUtilsLogging.h"
|
||||||
|
|
||||||
|
@ -35,6 +35,8 @@ static int vec3VectorTypeId = qRegisterMetaType<QVector<glm::vec3> >();
|
||||||
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
|
float Model::FAKE_DIMENSION_PLACEHOLDER = -1.0f;
|
||||||
#define HTTP_INVALID_COM "http://invalid.com"
|
#define HTTP_INVALID_COM "http://invalid.com"
|
||||||
|
|
||||||
|
model::MaterialPointer Model::_collisionHullMaterial;
|
||||||
|
|
||||||
Model::Model(RigPointer rig, QObject* parent) :
|
Model::Model(RigPointer rig, QObject* parent) :
|
||||||
QObject(parent),
|
QObject(parent),
|
||||||
_translation(0.0f),
|
_translation(0.0f),
|
||||||
|
@ -1193,8 +1195,13 @@ void Model::segregateMeshGroups() {
|
||||||
int totalParts = mesh.parts.size();
|
int totalParts = mesh.parts.size();
|
||||||
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
|
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
|
||||||
if (showingCollisionHull) {
|
if (showingCollisionHull) {
|
||||||
_renderItemsSet << std::make_shared<MeshPartPayload>(networkMesh._mesh, partIndex, ModelRender::getCollisionHullMaterial(), transform, offset);
|
if (!_collisionHullMaterial) {
|
||||||
|
_collisionHullMaterial = std::make_shared<model::Material>();
|
||||||
|
_collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f));
|
||||||
|
_collisionHullMaterial->setMetallic(0.02f);
|
||||||
|
_collisionHullMaterial->setGloss(1.0f);
|
||||||
|
}
|
||||||
|
_renderItemsSet << std::make_shared<MeshPartPayload>(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset);
|
||||||
} else {
|
} else {
|
||||||
_renderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
|
_renderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
|
||||||
}
|
}
|
||||||
|
|
|
@ -347,6 +347,7 @@ protected:
|
||||||
void recalculateMeshBoxes(bool pickAgainstTriangles = false);
|
void recalculateMeshBoxes(bool pickAgainstTriangles = false);
|
||||||
|
|
||||||
void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes
|
void segregateMeshGroups(); // used to calculate our list of translucent vs opaque meshes
|
||||||
|
static model::MaterialPointer _collisionHullMaterial;
|
||||||
|
|
||||||
bool _meshGroupsKnown;
|
bool _meshGroupsKnown;
|
||||||
bool _isWireframe;
|
bool _isWireframe;
|
||||||
|
|
|
@ -1,284 +0,0 @@
|
||||||
//
|
|
||||||
// ModelRender.cpp
|
|
||||||
// interface/src/renderer
|
|
||||||
//
|
|
||||||
// Created by Sam Gateau on 10/3/15.
|
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#include "ModelRender.h"
|
|
||||||
|
|
||||||
#include <model-networking/TextureCache.h>
|
|
||||||
|
|
||||||
#include <PerfStat.h>
|
|
||||||
|
|
||||||
#include "DeferredLightingEffect.h"
|
|
||||||
|
|
||||||
#include "model_vert.h"
|
|
||||||
#include "model_shadow_vert.h"
|
|
||||||
#include "model_normal_map_vert.h"
|
|
||||||
#include "model_lightmap_vert.h"
|
|
||||||
#include "model_lightmap_normal_map_vert.h"
|
|
||||||
#include "skin_model_vert.h"
|
|
||||||
#include "skin_model_shadow_vert.h"
|
|
||||||
#include "skin_model_normal_map_vert.h"
|
|
||||||
|
|
||||||
#include "model_frag.h"
|
|
||||||
#include "model_shadow_frag.h"
|
|
||||||
#include "model_normal_map_frag.h"
|
|
||||||
#include "model_normal_specular_map_frag.h"
|
|
||||||
#include "model_specular_map_frag.h"
|
|
||||||
#include "model_lightmap_frag.h"
|
|
||||||
#include "model_lightmap_normal_map_frag.h"
|
|
||||||
#include "model_lightmap_normal_specular_map_frag.h"
|
|
||||||
#include "model_lightmap_specular_map_frag.h"
|
|
||||||
#include "model_translucent_frag.h"
|
|
||||||
|
|
||||||
ModelRender::RenderPipelineLib ModelRender::_renderPipelineLib;
|
|
||||||
|
|
||||||
const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib() {
|
|
||||||
if (_renderPipelineLib.empty()) {
|
|
||||||
// Vertex shaders
|
|
||||||
auto modelVertex = gpu::Shader::createVertex(std::string(model_vert));
|
|
||||||
auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert));
|
|
||||||
auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert));
|
|
||||||
auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert));
|
|
||||||
auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
|
|
||||||
auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert));
|
|
||||||
auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert));
|
|
||||||
auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert));
|
|
||||||
|
|
||||||
// Pixel shaders
|
|
||||||
auto modelPixel = gpu::Shader::createPixel(std::string(model_frag));
|
|
||||||
auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag));
|
|
||||||
auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag));
|
|
||||||
auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag));
|
|
||||||
auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag));
|
|
||||||
auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
|
|
||||||
auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag));
|
|
||||||
auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag));
|
|
||||||
auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag));
|
|
||||||
auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag));
|
|
||||||
|
|
||||||
// Fill the renderPipelineLib
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(0),
|
|
||||||
modelVertex, modelPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_TANGENTS),
|
|
||||||
modelNormalMapVertex, modelNormalMapPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_SPECULAR),
|
|
||||||
modelVertex, modelSpecularMapPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR),
|
|
||||||
modelNormalMapVertex, modelNormalSpecularMapPixel);
|
|
||||||
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_TRANSLUCENT),
|
|
||||||
modelVertex, modelTranslucentPixel);
|
|
||||||
// FIXME Ignore lightmap for translucents meshpart
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_TRANSLUCENT | RenderKey::HAS_LIGHTMAP),
|
|
||||||
modelVertex, modelTranslucentPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT),
|
|
||||||
modelNormalMapVertex, modelTranslucentPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
|
|
||||||
modelVertex, modelTranslucentPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
|
|
||||||
modelNormalMapVertex, modelTranslucentPixel);
|
|
||||||
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_LIGHTMAP),
|
|
||||||
modelLightmapVertex, modelLightmapPixel);
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS),
|
|
||||||
modelLightmapNormalMapVertex, modelLightmapNormalMapPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_SPECULAR),
|
|
||||||
modelLightmapVertex, modelLightmapSpecularMapPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::HAS_LIGHTMAP | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR),
|
|
||||||
modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel);
|
|
||||||
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_SKINNED),
|
|
||||||
skinModelVertex, modelPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS),
|
|
||||||
skinModelNormalMapVertex, modelNormalMapPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR),
|
|
||||||
skinModelVertex, modelSpecularMapPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR),
|
|
||||||
skinModelNormalMapVertex, modelNormalSpecularMapPixel);
|
|
||||||
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_TRANSLUCENT),
|
|
||||||
skinModelVertex, modelTranslucentPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::IS_TRANSLUCENT),
|
|
||||||
skinModelNormalMapVertex, modelTranslucentPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
|
|
||||||
skinModelVertex, modelTranslucentPixel);
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_SKINNED | RenderKey::HAS_TANGENTS | RenderKey::HAS_SPECULAR | RenderKey::IS_TRANSLUCENT),
|
|
||||||
skinModelNormalMapVertex, modelTranslucentPixel);
|
|
||||||
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW),
|
|
||||||
modelShadowVertex, modelShadowPixel);
|
|
||||||
|
|
||||||
|
|
||||||
_renderPipelineLib.addRenderPipeline(
|
|
||||||
RenderKey(RenderKey::IS_SKINNED | RenderKey::IS_DEPTH_ONLY | RenderKey::IS_SHADOW),
|
|
||||||
skinModelShadowVertex, modelShadowPixel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return _renderPipelineLib;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey key,
|
|
||||||
gpu::ShaderPointer& vertexShader,
|
|
||||||
gpu::ShaderPointer& pixelShader) {
|
|
||||||
|
|
||||||
gpu::Shader::BindingSet slotBindings;
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), ModelRender::SKINNING_GPU_SLOT));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), ModelRender::MATERIAL_GPU_SLOT));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), ModelRender::DIFFUSE_MAP_SLOT));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), ModelRender::NORMAL_MAP_SLOT));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), ModelRender::SPECULAR_MAP_SLOT));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), ModelRender::LIGHTMAP_MAP_SLOT));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), ModelRender::LIGHT_BUFFER_SLOT));
|
|
||||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), DeferredLightingEffect::NORMAL_FITTING_MAP_SLOT));
|
|
||||||
|
|
||||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
|
|
||||||
gpu::Shader::makeProgram(*program, slotBindings);
|
|
||||||
|
|
||||||
|
|
||||||
auto locations = std::make_shared<Locations>();
|
|
||||||
initLocations(program, *locations);
|
|
||||||
|
|
||||||
|
|
||||||
auto state = std::make_shared<gpu::State>();
|
|
||||||
|
|
||||||
// Backface on shadow
|
|
||||||
if (key.isShadow()) {
|
|
||||||
state->setCullMode(gpu::State::CULL_FRONT);
|
|
||||||
state->setDepthBias(1.0f);
|
|
||||||
state->setDepthBiasSlopeScale(4.0f);
|
|
||||||
} else {
|
|
||||||
state->setCullMode(gpu::State::CULL_BACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Z test depends if transparent or not
|
|
||||||
state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL);
|
|
||||||
|
|
||||||
// Blend on transparent
|
|
||||||
state->setBlendFunction(key.isTranslucent(),
|
|
||||||
gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, // For transparent only, this keep the highlight intensity
|
|
||||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
|
||||||
|
|
||||||
// Good to go add the brand new pipeline
|
|
||||||
auto pipeline = gpu::Pipeline::create(program, state);
|
|
||||||
insert(value_type(key.getRaw(), RenderPipeline(pipeline, locations)));
|
|
||||||
|
|
||||||
|
|
||||||
if (!key.isWireFrame()) {
|
|
||||||
|
|
||||||
RenderKey wireframeKey(key.getRaw() | RenderKey::IS_WIREFRAME);
|
|
||||||
auto wireframeState = std::make_shared<gpu::State>(state->getValues());
|
|
||||||
|
|
||||||
wireframeState->setFillMode(gpu::State::FILL_LINE);
|
|
||||||
|
|
||||||
// create a new RenderPipeline with the same shader side and the wireframe state
|
|
||||||
auto wireframePipeline = gpu::Pipeline::create(program, wireframeState);
|
|
||||||
insert(value_type(wireframeKey.getRaw(), RenderPipeline(wireframePipeline, locations)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program, ModelRender::Locations& locations) {
|
|
||||||
locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices");
|
|
||||||
locations.emissiveParams = program->getUniforms().findLocation("emissiveParams");
|
|
||||||
locations.normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
|
|
||||||
locations.diffuseTextureUnit = program->getTextures().findLocation("diffuseMap");
|
|
||||||
locations.normalTextureUnit = program->getTextures().findLocation("normalMap");
|
|
||||||
locations.specularTextureUnit = program->getTextures().findLocation("specularMap");
|
|
||||||
locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
|
|
||||||
locations.skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer");
|
|
||||||
locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer");
|
|
||||||
locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent,
|
|
||||||
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args,
|
|
||||||
Locations*& locations) {
|
|
||||||
|
|
||||||
PerformanceTimer perfTimer("Model::pickPrograms");
|
|
||||||
getRenderPipelineLib();
|
|
||||||
|
|
||||||
RenderKey key(mode, translucent, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe);
|
|
||||||
auto pipeline = _renderPipelineLib.find(key.getRaw());
|
|
||||||
if (pipeline == _renderPipelineLib.end()) {
|
|
||||||
qDebug() << "No good, couldn't find a pipeline from the key ?" << key.getRaw();
|
|
||||||
locations = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::ShaderPointer program = (*pipeline).second._pipeline->getProgram();
|
|
||||||
locations = (*pipeline).second._locations.get();
|
|
||||||
|
|
||||||
|
|
||||||
// Setup the One pipeline
|
|
||||||
batch.setPipeline((*pipeline).second._pipeline);
|
|
||||||
|
|
||||||
if ((locations->normalFittingMapUnit > -1)) {
|
|
||||||
batch.setResourceTexture(locations->normalFittingMapUnit,
|
|
||||||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
model::MaterialPointer ModelRender::_collisionHullMaterial;
|
|
||||||
|
|
||||||
model::MaterialPointer ModelRender::getCollisionHullMaterial() {
|
|
||||||
if (!_collisionHullMaterial) {
|
|
||||||
_collisionHullMaterial = std::make_shared<model::Material>();
|
|
||||||
_collisionHullMaterial->setDiffuse(glm::vec3(1.0f, 0.5f, 0.0f));
|
|
||||||
_collisionHullMaterial->setMetallic(0.02f);
|
|
||||||
_collisionHullMaterial->setGloss(1.0f);
|
|
||||||
}
|
|
||||||
return _collisionHullMaterial;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,157 +0,0 @@
|
||||||
//
|
|
||||||
// ModelRender.h
|
|
||||||
// interface/src/renderer
|
|
||||||
//
|
|
||||||
// Created by Sam Gateau on 10/3/15.
|
|
||||||
// Copyright 2015 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef hifi_ModelRender_h
|
|
||||||
#define hifi_ModelRender_h
|
|
||||||
|
|
||||||
#include <gpu/Batch.h>
|
|
||||||
|
|
||||||
#include <render/Scene.h>
|
|
||||||
|
|
||||||
class ModelRender {
|
|
||||||
public:
|
|
||||||
|
|
||||||
static const int SKINNING_GPU_SLOT = 2;
|
|
||||||
static const int MATERIAL_GPU_SLOT = 3;
|
|
||||||
static const int DIFFUSE_MAP_SLOT = 0;
|
|
||||||
static const int NORMAL_MAP_SLOT = 1;
|
|
||||||
static const int SPECULAR_MAP_SLOT = 2;
|
|
||||||
static const int LIGHTMAP_MAP_SLOT = 3;
|
|
||||||
static const int LIGHT_BUFFER_SLOT = 4;
|
|
||||||
|
|
||||||
class Locations {
|
|
||||||
public:
|
|
||||||
int texcoordMatrices;
|
|
||||||
int diffuseTextureUnit;
|
|
||||||
int normalTextureUnit;
|
|
||||||
int specularTextureUnit;
|
|
||||||
int emissiveTextureUnit;
|
|
||||||
int emissiveParams;
|
|
||||||
int normalFittingMapUnit;
|
|
||||||
int skinClusterBufferUnit;
|
|
||||||
int materialBufferUnit;
|
|
||||||
int lightBufferUnit;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, bool translucent,
|
|
||||||
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args,
|
|
||||||
Locations*& locations);
|
|
||||||
|
|
||||||
class RenderKey {
|
|
||||||
public:
|
|
||||||
enum FlagBit {
|
|
||||||
IS_TRANSLUCENT_FLAG = 0,
|
|
||||||
HAS_LIGHTMAP_FLAG,
|
|
||||||
HAS_TANGENTS_FLAG,
|
|
||||||
HAS_SPECULAR_FLAG,
|
|
||||||
HAS_EMISSIVE_FLAG,
|
|
||||||
IS_SKINNED_FLAG,
|
|
||||||
IS_STEREO_FLAG,
|
|
||||||
IS_DEPTH_ONLY_FLAG,
|
|
||||||
IS_SHADOW_FLAG,
|
|
||||||
IS_WIREFRAME_FLAG,
|
|
||||||
|
|
||||||
NUM_FLAGS,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Flag {
|
|
||||||
IS_TRANSLUCENT = (1 << IS_TRANSLUCENT_FLAG),
|
|
||||||
HAS_LIGHTMAP = (1 << HAS_LIGHTMAP_FLAG),
|
|
||||||
HAS_TANGENTS = (1 << HAS_TANGENTS_FLAG),
|
|
||||||
HAS_SPECULAR = (1 << HAS_SPECULAR_FLAG),
|
|
||||||
HAS_EMISSIVE = (1 << HAS_EMISSIVE_FLAG),
|
|
||||||
IS_SKINNED = (1 << IS_SKINNED_FLAG),
|
|
||||||
IS_STEREO = (1 << IS_STEREO_FLAG),
|
|
||||||
IS_DEPTH_ONLY = (1 << IS_DEPTH_ONLY_FLAG),
|
|
||||||
IS_SHADOW = (1 << IS_SHADOW_FLAG),
|
|
||||||
IS_WIREFRAME = (1 << IS_WIREFRAME_FLAG),
|
|
||||||
};
|
|
||||||
typedef unsigned short Flags;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool isFlag(short flagNum) const { return bool((_flags & flagNum) != 0); }
|
|
||||||
|
|
||||||
bool isTranslucent() const { return isFlag(IS_TRANSLUCENT); }
|
|
||||||
bool hasLightmap() const { return isFlag(HAS_LIGHTMAP); }
|
|
||||||
bool hasTangents() const { return isFlag(HAS_TANGENTS); }
|
|
||||||
bool hasSpecular() const { return isFlag(HAS_SPECULAR); }
|
|
||||||
bool hasEmissive() const { return isFlag(HAS_EMISSIVE); }
|
|
||||||
bool isSkinned() const { return isFlag(IS_SKINNED); }
|
|
||||||
bool isStereo() const { return isFlag(IS_STEREO); }
|
|
||||||
bool isDepthOnly() const { return isFlag(IS_DEPTH_ONLY); }
|
|
||||||
bool isShadow() const { return isFlag(IS_SHADOW); } // = depth only but with back facing
|
|
||||||
bool isWireFrame() const { return isFlag(IS_WIREFRAME); }
|
|
||||||
|
|
||||||
Flags _flags = 0;
|
|
||||||
short _spare = 0;
|
|
||||||
|
|
||||||
int getRaw() { return *reinterpret_cast<int*>(this); }
|
|
||||||
|
|
||||||
|
|
||||||
RenderKey(
|
|
||||||
bool translucent, bool hasLightmap,
|
|
||||||
bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) :
|
|
||||||
RenderKey((translucent ? IS_TRANSLUCENT : 0)
|
|
||||||
| (hasLightmap ? HAS_LIGHTMAP : 0)
|
|
||||||
| (hasTangents ? HAS_TANGENTS : 0)
|
|
||||||
| (hasSpecular ? HAS_SPECULAR : 0)
|
|
||||||
| (isSkinned ? IS_SKINNED : 0)
|
|
||||||
| (isWireframe ? IS_WIREFRAME : 0)
|
|
||||||
) {}
|
|
||||||
|
|
||||||
RenderKey(RenderArgs::RenderMode mode,
|
|
||||||
bool translucent, bool hasLightmap,
|
|
||||||
bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe) :
|
|
||||||
RenderKey(((translucent && (mode != RenderArgs::SHADOW_RENDER_MODE)) ? IS_TRANSLUCENT : 0)
|
|
||||||
| (hasLightmap && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_LIGHTMAP : 0) // Lightmap, tangents and specular don't matter for depthOnly
|
|
||||||
| (hasTangents && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_TANGENTS : 0)
|
|
||||||
| (hasSpecular && (mode != RenderArgs::SHADOW_RENDER_MODE) ? HAS_SPECULAR : 0)
|
|
||||||
| (isSkinned ? IS_SKINNED : 0)
|
|
||||||
| (isWireframe ? IS_WIREFRAME : 0)
|
|
||||||
| ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_DEPTH_ONLY : 0)
|
|
||||||
| ((mode == RenderArgs::SHADOW_RENDER_MODE) ? IS_SHADOW : 0)
|
|
||||||
) {}
|
|
||||||
|
|
||||||
RenderKey(int bitmask) : _flags(bitmask) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class RenderPipeline {
|
|
||||||
public:
|
|
||||||
gpu::PipelinePointer _pipeline;
|
|
||||||
std::shared_ptr<Locations> _locations;
|
|
||||||
RenderPipeline(gpu::PipelinePointer pipeline, std::shared_ptr<Locations> locations) :
|
|
||||||
_pipeline(pipeline), _locations(locations) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef std::unordered_map<int, RenderPipeline> BaseRenderPipelineMap;
|
|
||||||
class RenderPipelineLib : public BaseRenderPipelineMap {
|
|
||||||
public:
|
|
||||||
typedef RenderKey Key;
|
|
||||||
|
|
||||||
|
|
||||||
void addRenderPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader);
|
|
||||||
|
|
||||||
void initLocations(gpu::ShaderPointer& program, Locations& locations);
|
|
||||||
};
|
|
||||||
static RenderPipelineLib _renderPipelineLib;
|
|
||||||
|
|
||||||
static const RenderPipelineLib& getRenderPipelineLib();
|
|
||||||
|
|
||||||
// Collision hull Material
|
|
||||||
static model::MaterialPointer _collisionHullMaterial;
|
|
||||||
|
|
||||||
static model::MaterialPointer getCollisionHullMaterial();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // hifi_ModelRender_h
|
|
|
@ -9,7 +9,6 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
#include "RenderDeferredTask.h"
|
|
||||||
|
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
|
@ -29,6 +28,28 @@
|
||||||
#include "AmbientOcclusionEffect.h"
|
#include "AmbientOcclusionEffect.h"
|
||||||
#include "AntialiasingEffect.h"
|
#include "AntialiasingEffect.h"
|
||||||
|
|
||||||
|
#include "RenderDeferredTask.h"
|
||||||
|
|
||||||
|
#include "model_vert.h"
|
||||||
|
#include "model_shadow_vert.h"
|
||||||
|
#include "model_normal_map_vert.h"
|
||||||
|
#include "model_lightmap_vert.h"
|
||||||
|
#include "model_lightmap_normal_map_vert.h"
|
||||||
|
#include "skin_model_vert.h"
|
||||||
|
#include "skin_model_shadow_vert.h"
|
||||||
|
#include "skin_model_normal_map_vert.h"
|
||||||
|
|
||||||
|
#include "model_frag.h"
|
||||||
|
#include "model_shadow_frag.h"
|
||||||
|
#include "model_normal_map_frag.h"
|
||||||
|
#include "model_normal_specular_map_frag.h"
|
||||||
|
#include "model_specular_map_frag.h"
|
||||||
|
#include "model_lightmap_frag.h"
|
||||||
|
#include "model_lightmap_normal_map_frag.h"
|
||||||
|
#include "model_lightmap_normal_specular_map_frag.h"
|
||||||
|
#include "model_lightmap_specular_map_frag.h"
|
||||||
|
#include "model_translucent_frag.h"
|
||||||
|
|
||||||
#include "overlay3D_vert.h"
|
#include "overlay3D_vert.h"
|
||||||
#include "overlay3D_frag.h"
|
#include "overlay3D_frag.h"
|
||||||
|
|
||||||
|
@ -36,6 +57,7 @@
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
|
void initDeferredPipelines(render::ShapePlumber& plumber);
|
||||||
|
|
||||||
void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
void PrepareDeferred::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||||
DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->getArgs());
|
DependencyManager::get<DeferredLightingEffect>()->prepare(renderContext->getArgs());
|
||||||
|
@ -51,11 +73,15 @@ void ToneMappingDeferred::run(const SceneContextPointer& sceneContext, const Ren
|
||||||
}
|
}
|
||||||
|
|
||||||
RenderDeferredTask::RenderDeferredTask() : Task() {
|
RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
|
// Prepare the ShapePipelines
|
||||||
|
ShapePlumberPointer shapePlumber = std::make_shared<ShapePlumber>();
|
||||||
|
initDeferredPipelines(*shapePlumber);
|
||||||
|
|
||||||
// CPU only, create the list of renderedOpaques items
|
// CPU only, create the list of renderedOpaques items
|
||||||
addJob<FetchItems>("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) {
|
addJob<FetchItems>("FetchOpaque", FetchItems([](const RenderContextPointer& context, int count) {
|
||||||
context->getItemsConfig().opaque.numFeed = count;
|
context->getItemsConfig().opaque.numFeed = count;
|
||||||
}));
|
}));
|
||||||
addJob<CullItemsOpaque>("CullOpaque", _jobs.back().getOutput());
|
addJob<CullItems<RenderDetails::OPAQUE_ITEM>>("CullOpaque", _jobs.back().getOutput());
|
||||||
addJob<DepthSortItems>("DepthSortOpaque", _jobs.back().getOutput());
|
addJob<DepthSortItems>("DepthSortOpaque", _jobs.back().getOutput());
|
||||||
auto& renderedOpaques = _jobs.back().getOutput();
|
auto& renderedOpaques = _jobs.back().getOutput();
|
||||||
|
|
||||||
|
@ -66,7 +92,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
context->getItemsConfig().transparent.numFeed = count;
|
context->getItemsConfig().transparent.numFeed = count;
|
||||||
}
|
}
|
||||||
));
|
));
|
||||||
addJob<CullItemsTransparent>("CullTransparent", _jobs.back().getOutput());
|
addJob<CullItems<RenderDetails::TRANSLUCENT_ITEM>>("CullTransparent", _jobs.back().getOutput());
|
||||||
addJob<DepthSortItems>("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false));
|
addJob<DepthSortItems>("DepthSortTransparent", _jobs.back().getOutput(), DepthSortItems(false));
|
||||||
auto& renderedTransparents = _jobs.back().getOutput();
|
auto& renderedTransparents = _jobs.back().getOutput();
|
||||||
|
|
||||||
|
@ -74,7 +100,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
addJob<PrepareDeferred>("PrepareDeferred");
|
addJob<PrepareDeferred>("PrepareDeferred");
|
||||||
|
|
||||||
// Render opaque objects in DeferredBuffer
|
// Render opaque objects in DeferredBuffer
|
||||||
addJob<DrawOpaqueDeferred>("DrawOpaqueDeferred", renderedOpaques);
|
addJob<DrawOpaqueDeferred>("DrawOpaqueDeferred", renderedOpaques, shapePlumber);
|
||||||
|
|
||||||
// Once opaque is all rendered create stencil background
|
// Once opaque is all rendered create stencil background
|
||||||
addJob<DrawStencilDeferred>("DrawOpaqueStencil");
|
addJob<DrawStencilDeferred>("DrawOpaqueStencil");
|
||||||
|
@ -99,7 +125,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
_antialiasingJobIndex = (int)_jobs.size() - 1;
|
_antialiasingJobIndex = (int)_jobs.size() - 1;
|
||||||
|
|
||||||
// Render transparent objects forward in LigthingBuffer
|
// Render transparent objects forward in LigthingBuffer
|
||||||
addJob<DrawTransparentDeferred>("TransparentDeferred", renderedTransparents);
|
addJob<DrawTransparentDeferred>("DrawTransparentDeferred", renderedTransparents, shapePlumber);
|
||||||
|
|
||||||
// Lighting Buffer ready for tone mapping
|
// Lighting Buffer ready for tone mapping
|
||||||
addJob<ToneMappingDeferred>("ToneMapping");
|
addJob<ToneMappingDeferred>("ToneMapping");
|
||||||
|
@ -120,7 +146,7 @@ RenderDeferredTask::RenderDeferredTask() : Task() {
|
||||||
_drawStatusJobIndex = (int)_jobs.size() - 1;
|
_drawStatusJobIndex = (int)_jobs.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
addJob<DrawOverlay3D>("DrawOverlay3D");
|
addJob<DrawOverlay3D>("DrawOverlay3D", shapePlumber);
|
||||||
|
|
||||||
addJob<HitEffect>("HitEffect");
|
addJob<HitEffect>("HitEffect");
|
||||||
_jobs.back().setEnabled(false);
|
_jobs.back().setEnabled(false);
|
||||||
|
@ -173,7 +199,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend
|
||||||
assert(renderContext->getArgs()->_viewFrustum);
|
assert(renderContext->getArgs()->_viewFrustum);
|
||||||
|
|
||||||
RenderArgs* args = renderContext->getArgs();
|
RenderArgs* args = renderContext->getArgs();
|
||||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
batch.setViewportTransform(args->_viewport);
|
batch.setViewportTransform(args->_viewport);
|
||||||
batch.setStateScissorRect(args->_viewport);
|
batch.setStateScissorRect(args->_viewport);
|
||||||
args->_batch = &batch;
|
args->_batch = &batch;
|
||||||
|
@ -189,7 +215,7 @@ void DrawOpaqueDeferred::run(const SceneContextPointer& sceneContext, const Rend
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
|
|
||||||
renderItems(sceneContext, renderContext, inItems, opaque.maxDrawn);
|
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, opaque.maxDrawn);
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -199,7 +225,7 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const
|
||||||
assert(renderContext->getArgs()->_viewFrustum);
|
assert(renderContext->getArgs()->_viewFrustum);
|
||||||
|
|
||||||
RenderArgs* args = renderContext->getArgs();
|
RenderArgs* args = renderContext->getArgs();
|
||||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
batch.setViewportTransform(args->_viewport);
|
batch.setViewportTransform(args->_viewport);
|
||||||
batch.setStateScissorRect(args->_viewport);
|
batch.setStateScissorRect(args->_viewport);
|
||||||
args->_batch = &batch;
|
args->_batch = &batch;
|
||||||
|
@ -215,11 +241,12 @@ void DrawTransparentDeferred::run(const SceneContextPointer& sceneContext, const
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
|
|
||||||
renderItems(sceneContext, renderContext, inItems, transparent.maxDrawn);
|
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, transparent.maxDrawn);
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Move this to the shapePlumber
|
||||||
gpu::PipelinePointer DrawOverlay3D::_opaquePipeline;
|
gpu::PipelinePointer DrawOverlay3D::_opaquePipeline;
|
||||||
const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() {
|
const gpu::PipelinePointer& DrawOverlay3D::getOpaquePipeline() {
|
||||||
if (!_opaquePipeline) {
|
if (!_opaquePipeline) {
|
||||||
|
@ -272,7 +299,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the items
|
// Render the items
|
||||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||||
args->_batch = &batch;
|
args->_batch = &batch;
|
||||||
args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture();
|
args->_whiteTexture = DependencyManager::get<TextureCache>()->getWhiteTexture();
|
||||||
|
|
||||||
|
@ -288,7 +315,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon
|
||||||
|
|
||||||
batch.setPipeline(getOpaquePipeline());
|
batch.setPipeline(getOpaquePipeline());
|
||||||
batch.setResourceTexture(0, args->_whiteTexture);
|
batch.setResourceTexture(0, args->_whiteTexture);
|
||||||
renderItems(sceneContext, renderContext, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn);
|
renderShapes(sceneContext, renderContext, _shapePlumber, inItems, renderContext->getItemsConfig().overlay3D.maxDrawn);
|
||||||
});
|
});
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
args->_whiteTexture.reset();
|
args->_whiteTexture.reset();
|
||||||
|
@ -377,8 +404,7 @@ void DrawBackgroundDeferred::run(const SceneContextPointer& sceneContext, const
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
|
|
||||||
renderItems(sceneContext, renderContext, inItems);
|
renderLights(sceneContext, renderContext, inItems);
|
||||||
|
|
||||||
});
|
});
|
||||||
args->_batch = nullptr;
|
args->_batch = nullptr;
|
||||||
}
|
}
|
||||||
|
@ -482,3 +508,165 @@ int RenderDeferredTask::getToneMappingToneCurve() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pipelineBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
|
||||||
|
if (pipeline.locations->normalFittingMapUnit > -1) {
|
||||||
|
batch.setResourceTexture(pipeline.locations->normalFittingMapUnit,
|
||||||
|
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initDeferredPipelines(render::ShapePlumber& plumber) {
|
||||||
|
using Key = render::ShapeKey;
|
||||||
|
using ShaderPointer = gpu::ShaderPointer;
|
||||||
|
|
||||||
|
auto addPipeline = [&plumber](const Key& key, const ShaderPointer& vertexShader, const ShaderPointer& pixelShader) {
|
||||||
|
auto state = std::make_shared<gpu::State>();
|
||||||
|
|
||||||
|
// Cull backface
|
||||||
|
state->setCullMode(gpu::State::CULL_BACK);
|
||||||
|
|
||||||
|
// Z test depends on transparency
|
||||||
|
state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL);
|
||||||
|
|
||||||
|
// Blend if transparent
|
||||||
|
state->setBlendFunction(key.isTranslucent(),
|
||||||
|
// For transparency, keep the highlight intensity
|
||||||
|
gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||||
|
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||||
|
|
||||||
|
ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
|
||||||
|
plumber.addPipeline(key, program, state, &pipelineBatchSetter);
|
||||||
|
|
||||||
|
// Add a wireframe version
|
||||||
|
if (!key.isWireFrame()) {
|
||||||
|
auto wireFrameKey = Key::Builder(key).withWireframe();
|
||||||
|
auto wireFrameState = std::make_shared<gpu::State>(state->getValues());
|
||||||
|
|
||||||
|
wireFrameState->setFillMode(gpu::State::FILL_LINE);
|
||||||
|
|
||||||
|
plumber.addPipeline(wireFrameKey, program, wireFrameState, &pipelineBatchSetter);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Vertex shaders
|
||||||
|
auto modelVertex = gpu::Shader::createVertex(std::string(model_vert));
|
||||||
|
auto modelNormalMapVertex = gpu::Shader::createVertex(std::string(model_normal_map_vert));
|
||||||
|
auto modelLightmapVertex = gpu::Shader::createVertex(std::string(model_lightmap_vert));
|
||||||
|
auto modelLightmapNormalMapVertex = gpu::Shader::createVertex(std::string(model_lightmap_normal_map_vert));
|
||||||
|
auto modelShadowVertex = gpu::Shader::createVertex(std::string(model_shadow_vert));
|
||||||
|
auto skinModelVertex = gpu::Shader::createVertex(std::string(skin_model_vert));
|
||||||
|
auto skinModelNormalMapVertex = gpu::Shader::createVertex(std::string(skin_model_normal_map_vert));
|
||||||
|
auto skinModelShadowVertex = gpu::Shader::createVertex(std::string(skin_model_shadow_vert));
|
||||||
|
|
||||||
|
// Pixel shaders
|
||||||
|
auto modelPixel = gpu::Shader::createPixel(std::string(model_frag));
|
||||||
|
auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag));
|
||||||
|
auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag));
|
||||||
|
auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag));
|
||||||
|
auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag));
|
||||||
|
auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
|
||||||
|
auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag));
|
||||||
|
auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag));
|
||||||
|
auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag));
|
||||||
|
auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag));
|
||||||
|
|
||||||
|
// Fill the pipelineLib
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder(),
|
||||||
|
modelVertex, modelPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withTangents(),
|
||||||
|
modelNormalMapVertex, modelNormalMapPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSpecular(),
|
||||||
|
modelVertex, modelSpecularMapPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withTangents().withSpecular(),
|
||||||
|
modelNormalMapVertex, modelNormalSpecularMapPixel);
|
||||||
|
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withTranslucent(),
|
||||||
|
modelVertex, modelTranslucentPixel);
|
||||||
|
// FIXME Ignore lightmap for translucents meshpart
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withTranslucent().withLightmap(),
|
||||||
|
modelVertex, modelTranslucentPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withTangents().withTranslucent(),
|
||||||
|
modelNormalMapVertex, modelTranslucentPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSpecular().withTranslucent(),
|
||||||
|
modelVertex, modelTranslucentPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withTangents().withSpecular().withTranslucent(),
|
||||||
|
modelNormalMapVertex, modelTranslucentPixel);
|
||||||
|
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withLightmap(),
|
||||||
|
modelLightmapVertex, modelLightmapPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withLightmap().withTangents(),
|
||||||
|
modelLightmapNormalMapVertex, modelLightmapNormalMapPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withLightmap().withSpecular(),
|
||||||
|
modelLightmapVertex, modelLightmapSpecularMapPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withLightmap().withTangents().withSpecular(),
|
||||||
|
modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel);
|
||||||
|
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSkinned(),
|
||||||
|
skinModelVertex, modelPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSkinned().withTangents(),
|
||||||
|
skinModelNormalMapVertex, modelNormalMapPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSkinned().withSpecular(),
|
||||||
|
skinModelVertex, modelSpecularMapPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSkinned().withTangents().withSpecular(),
|
||||||
|
skinModelNormalMapVertex, modelNormalSpecularMapPixel);
|
||||||
|
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSkinned().withTranslucent(),
|
||||||
|
skinModelVertex, modelTranslucentPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSkinned().withTangents().withTranslucent(),
|
||||||
|
skinModelNormalMapVertex, modelTranslucentPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSkinned().withSpecular().withTranslucent(),
|
||||||
|
skinModelVertex, modelTranslucentPixel);
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSkinned().withTangents().withSpecular().withTranslucent(),
|
||||||
|
skinModelNormalMapVertex, modelTranslucentPixel);
|
||||||
|
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withDepthOnly(),
|
||||||
|
modelShadowVertex, modelShadowPixel);
|
||||||
|
|
||||||
|
|
||||||
|
addPipeline(
|
||||||
|
Key::Builder().withSkinned().withDepthOnly(),
|
||||||
|
skinModelShadowVertex, modelShadowPixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,26 +51,36 @@ public:
|
||||||
|
|
||||||
class DrawOpaqueDeferred {
|
class DrawOpaqueDeferred {
|
||||||
public:
|
public:
|
||||||
|
DrawOpaqueDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
|
||||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
|
||||||
|
|
||||||
using JobModel = render::Task::Job::ModelI<DrawOpaqueDeferred, render::ItemIDsBounds>;
|
using JobModel = render::Task::Job::ModelI<DrawOpaqueDeferred, render::ItemIDsBounds>;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
render::ShapePlumberPointer _shapePlumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawTransparentDeferred {
|
class DrawTransparentDeferred {
|
||||||
public:
|
public:
|
||||||
|
DrawTransparentDeferred(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
|
||||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const render::ItemIDsBounds& inItems);
|
||||||
|
|
||||||
using JobModel = render::Task::Job::ModelI<DrawTransparentDeferred, render::ItemIDsBounds>;
|
using JobModel = render::Task::Job::ModelI<DrawTransparentDeferred, render::ItemIDsBounds>;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
render::ShapePlumberPointer _shapePlumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawStencilDeferred {
|
class DrawStencilDeferred {
|
||||||
static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
|
|
||||||
public:
|
public:
|
||||||
static const gpu::PipelinePointer& getOpaquePipeline();
|
static const gpu::PipelinePointer& getOpaquePipeline();
|
||||||
|
|
||||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||||
|
|
||||||
using JobModel = render::Task::Job::Model<DrawStencilDeferred>;
|
using JobModel = render::Task::Job::Model<DrawStencilDeferred>;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawBackgroundDeferred {
|
class DrawBackgroundDeferred {
|
||||||
|
@ -81,13 +91,17 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawOverlay3D {
|
class DrawOverlay3D {
|
||||||
static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
|
|
||||||
public:
|
public:
|
||||||
|
DrawOverlay3D(render::ShapePlumberPointer shapePlumber) : _shapePlumber{ shapePlumber } {}
|
||||||
static const gpu::PipelinePointer& getOpaquePipeline();
|
static const gpu::PipelinePointer& getOpaquePipeline();
|
||||||
|
|
||||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||||
|
|
||||||
using JobModel = render::Task::Job::Model<DrawOverlay3D>;
|
using JobModel = render::Task::Job::Model<DrawOverlay3D>;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static gpu::PipelinePointer _opaquePipeline; //lazy evaluation hence mutable
|
||||||
|
render::ShapePlumberPointer _shapePlumber;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Blit {
|
class Blit {
|
||||||
|
|
|
@ -36,7 +36,7 @@ void main(void) {
|
||||||
frag.specularVal.xyz);
|
frag.specularVal.xyz);
|
||||||
_fragColor = vec4(color, 1.0);
|
_fragColor = vec4(color, 1.0);
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbienSphereGlobalColor(
|
vec3 color = evalAmbientSphereGlobalColor(
|
||||||
deferredTransform.viewInverse,
|
deferredTransform.viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
|
|
|
@ -37,7 +37,7 @@ void main(void) {
|
||||||
frag.specularVal.xyz);
|
frag.specularVal.xyz);
|
||||||
_fragColor = vec4(color, 1.0);
|
_fragColor = vec4(color, 1.0);
|
||||||
} else {
|
} else {
|
||||||
vec3 color = evalAmbienGlobalColor(
|
vec3 color = evalAmbientGlobalColor(
|
||||||
deferredTransform.viewInverse,
|
deferredTransform.viewInverse,
|
||||||
1.0,
|
1.0,
|
||||||
frag.position.xyz,
|
frag.position.xyz,
|
||||||
|
|
|
@ -65,13 +65,17 @@ void render::cullItems(const SceneContextPointer& sceneContext, const RenderCont
|
||||||
|
|
||||||
void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) {
|
void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, ItemIDsBounds& outItems) {
|
||||||
auto& scene = sceneContext->_scene;
|
auto& scene = sceneContext->_scene;
|
||||||
auto& items = scene->getMasterBucket().at(_filter);
|
|
||||||
|
|
||||||
outItems.clear();
|
outItems.clear();
|
||||||
outItems.reserve(items.size());
|
|
||||||
for (auto id : items) {
|
const auto& bucket = scene->getMasterBucket();
|
||||||
auto& item = scene->getItem(id);
|
const auto& items = bucket.find(_filter);
|
||||||
outItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
|
if (items != bucket.end()) {
|
||||||
|
outItems.reserve(items->second.size());
|
||||||
|
for (auto& id : items->second) {
|
||||||
|
auto& item = scene->getItem(id);
|
||||||
|
outItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_probeNumItems) {
|
if (_probeNumItems) {
|
||||||
|
@ -79,34 +83,6 @@ void FetchItems::run(const SceneContextPointer& sceneContext, const RenderContex
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CullItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
|
|
||||||
|
|
||||||
outItems.clear();
|
|
||||||
outItems.reserve(inItems.size());
|
|
||||||
RenderArgs* args = renderContext->getArgs();
|
|
||||||
args->_details.pointTo(RenderDetails::OTHER_ITEM);
|
|
||||||
cullItems(sceneContext, renderContext, inItems, outItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CullItemsOpaque::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
|
|
||||||
|
|
||||||
outItems.clear();
|
|
||||||
outItems.reserve(inItems.size());
|
|
||||||
RenderArgs* args = renderContext->getArgs();
|
|
||||||
args->_details.pointTo(RenderDetails::OPAQUE_ITEM);
|
|
||||||
cullItems(sceneContext, renderContext, inItems, outItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CullItemsTransparent::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
|
|
||||||
|
|
||||||
outItems.clear();
|
|
||||||
outItems.reserve(inItems.size());
|
|
||||||
RenderArgs* args = renderContext->getArgs();
|
|
||||||
args->_details.pointTo(RenderDetails::TRANSLUCENT_ITEM);
|
|
||||||
cullItems(sceneContext, renderContext, inItems, outItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct ItemBound {
|
struct ItemBound {
|
||||||
float _centerDepth = 0.0f;
|
float _centerDepth = 0.0f;
|
||||||
float _nearDepth = 0.0f;
|
float _nearDepth = 0.0f;
|
||||||
|
@ -177,29 +153,40 @@ void DepthSortItems::run(const SceneContextPointer& sceneContext, const RenderCo
|
||||||
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems);
|
depthSortItems(sceneContext, renderContext, _frontToBack, inItems, outItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
void render::renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems) {
|
void render::renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems) {
|
||||||
auto& scene = sceneContext->_scene;
|
auto& scene = sceneContext->_scene;
|
||||||
RenderArgs* args = renderContext->getArgs();
|
RenderArgs* args = renderContext->getArgs();
|
||||||
// render
|
|
||||||
if ((maxDrawnItems < 0) || (maxDrawnItems > (int) inItems.size())) {
|
for (const auto& itemDetails : inItems) {
|
||||||
for (auto itemDetails : inItems) {
|
auto& item = scene->getItem(itemDetails.id);
|
||||||
auto item = scene->getItem(itemDetails.id);
|
item.render(args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, const Item& item) {
|
||||||
|
assert(item.getKey().isShape());
|
||||||
|
const auto& key = item.getShapeKey();
|
||||||
|
if (key.isValid() && !key.hasOwnPipeline()) {
|
||||||
|
args->_pipeline = shapeContext->pickPipeline(args, key);
|
||||||
|
if (args->_pipeline) {
|
||||||
item.render(args);
|
item.render(args);
|
||||||
}
|
}
|
||||||
|
} else if (key.hasOwnPipeline()) {
|
||||||
|
item.render(args);
|
||||||
} else {
|
} else {
|
||||||
int numItems = 0;
|
qDebug() << "Item could not be rendered: invalid key ?" << key;
|
||||||
for (auto itemDetails : inItems) {
|
}
|
||||||
auto item = scene->getItem(itemDetails.id);
|
}
|
||||||
if (numItems + 1 >= maxDrawnItems) {
|
|
||||||
item.render(args);
|
void render::renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext,
|
||||||
return;
|
const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems) {
|
||||||
}
|
auto& scene = sceneContext->_scene;
|
||||||
item.render(args);
|
RenderArgs* args = renderContext->getArgs();
|
||||||
numItems++;
|
|
||||||
if (numItems >= maxDrawnItems) {
|
auto numItemsToDraw = glm::max((int)inItems.size(), maxDrawnItems);
|
||||||
return;
|
for (auto i = 0; i < numItemsToDraw; ++i) {
|
||||||
}
|
auto& item = scene->getItem(inItems[i].id);
|
||||||
}
|
renderShape(args, shapeContext, item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,7 +198,6 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext
|
||||||
auto& scene = sceneContext->_scene;
|
auto& scene = sceneContext->_scene;
|
||||||
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::light());
|
auto& items = scene->getMasterBucket().at(ItemFilter::Builder::light());
|
||||||
|
|
||||||
|
|
||||||
ItemIDsBounds inItems;
|
ItemIDsBounds inItems;
|
||||||
inItems.reserve(items.size());
|
inItems.reserve(items.size());
|
||||||
for (auto id : items) {
|
for (auto id : items) {
|
||||||
|
@ -219,15 +205,16 @@ void DrawLight::run(const SceneContextPointer& sceneContext, const RenderContext
|
||||||
inItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
|
inItems.emplace_back(ItemIDAndBounds(id, item.getBound()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RenderArgs* args = renderContext->getArgs();
|
||||||
|
|
||||||
ItemIDsBounds culledItems;
|
ItemIDsBounds culledItems;
|
||||||
culledItems.reserve(inItems.size());
|
culledItems.reserve(inItems.size());
|
||||||
RenderArgs* args = renderContext->getArgs();
|
|
||||||
args->_details.pointTo(RenderDetails::OTHER_ITEM);
|
args->_details.pointTo(RenderDetails::OTHER_ITEM);
|
||||||
cullItems(sceneContext, renderContext, inItems, culledItems);
|
cullItems(sceneContext, renderContext, inItems, culledItems);
|
||||||
|
|
||||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||||
args->_batch = &batch;
|
args->_batch = &batch;
|
||||||
renderItems(sceneContext, renderContext, culledItems);
|
renderLights(sceneContext, renderContext, culledItems);
|
||||||
|
args->_batch = nullptr;
|
||||||
});
|
});
|
||||||
args->_batch = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define hifi_render_DrawTask_h
|
#define hifi_render_DrawTask_h
|
||||||
|
|
||||||
#include "Engine.h"
|
#include "Engine.h"
|
||||||
|
#include "ShapePipeline.h"
|
||||||
#include "gpu/Batch.h"
|
#include "gpu/Batch.h"
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,7 +21,8 @@ namespace render {
|
||||||
|
|
||||||
void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems);
|
void cullItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outITems);
|
||||||
void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems);
|
void depthSortItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, bool frontToBack, const ItemIDsBounds& inItems, ItemIDsBounds& outITems);
|
||||||
void renderItems(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1);
|
void renderLights(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems);
|
||||||
|
void renderShapes(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ShapePlumberPointer& shapeContext, const ItemIDsBounds& inItems, int maxDrawnItems = -1);
|
||||||
|
|
||||||
|
|
||||||
class FetchItems {
|
class FetchItems {
|
||||||
|
@ -37,22 +39,17 @@ public:
|
||||||
using JobModel = Task::Job::ModelO<FetchItems, ItemIDsBounds>;
|
using JobModel = Task::Job::ModelO<FetchItems, ItemIDsBounds>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<RenderDetails::Type T = RenderDetails::Type::OTHER_ITEM>
|
||||||
class CullItems {
|
class CullItems {
|
||||||
public:
|
public:
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
|
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems) {
|
||||||
using JobModel = Task::Job::ModelIO<CullItems, ItemIDsBounds, ItemIDsBounds>;
|
outItems.clear();
|
||||||
};
|
outItems.reserve(inItems.size());
|
||||||
|
renderContext->getArgs()->_details.pointTo(T);
|
||||||
|
render::cullItems(sceneContext, renderContext, inItems, outItems);
|
||||||
|
}
|
||||||
|
|
||||||
class CullItemsOpaque {
|
using JobModel = Task::Job::ModelIO<CullItems<T>, ItemIDsBounds, ItemIDsBounds>;
|
||||||
public:
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
|
|
||||||
using JobModel = Task::Job::ModelIO<CullItemsOpaque, ItemIDsBounds, ItemIDsBounds>;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CullItemsTransparent {
|
|
||||||
public:
|
|
||||||
void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemIDsBounds& inItems, ItemIDsBounds& outItems);
|
|
||||||
using JobModel = Task::Job::ModelIO<CullItemsTransparent, ItemIDsBounds, ItemIDsBounds>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DepthSortItems {
|
class DepthSortItems {
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <RenderArgs.h>
|
#include <RenderArgs.h>
|
||||||
|
|
||||||
#include "model/Material.h"
|
#include "model/Material.h"
|
||||||
|
#include "ShapePipeline.h"
|
||||||
|
|
||||||
namespace render {
|
namespace render {
|
||||||
|
|
||||||
|
@ -82,6 +83,9 @@ public:
|
||||||
};
|
};
|
||||||
ItemKey(const Builder& builder) : ItemKey(builder._flags) {}
|
ItemKey(const Builder& builder) : ItemKey(builder._flags) {}
|
||||||
|
|
||||||
|
bool isShape() const { return _flags[TYPE_SHAPE]; }
|
||||||
|
bool isLight() const { return _flags[TYPE_LIGHT]; }
|
||||||
|
|
||||||
bool isOpaque() const { return !_flags[TRANSLUCENT]; }
|
bool isOpaque() const { return !_flags[TRANSLUCENT]; }
|
||||||
bool isTransparent() const { return _flags[TRANSLUCENT]; }
|
bool isTransparent() const { return _flags[TRANSLUCENT]; }
|
||||||
|
|
||||||
|
@ -264,7 +268,7 @@ public:
|
||||||
|
|
||||||
virtual void render(RenderArgs* args) = 0;
|
virtual void render(RenderArgs* args) = 0;
|
||||||
|
|
||||||
virtual const model::MaterialKey getMaterialKey() const = 0;
|
virtual const ShapeKey getShapeKey() const = 0;
|
||||||
|
|
||||||
~PayloadInterface() {}
|
~PayloadInterface() {}
|
||||||
|
|
||||||
|
@ -301,10 +305,10 @@ public:
|
||||||
int getLayer() const { return _payload->getLayer(); }
|
int getLayer() const { return _payload->getLayer(); }
|
||||||
|
|
||||||
// Render call for the item
|
// Render call for the item
|
||||||
void render(RenderArgs* args) { _payload->render(args); }
|
void render(RenderArgs* args) const { _payload->render(args); }
|
||||||
|
|
||||||
// Shape Type Interface
|
// Shape Type Interface
|
||||||
const model::MaterialKey getMaterialKey() const { return _payload->getMaterialKey(); }
|
const ShapeKey getShapeKey() const { return _payload->getShapeKey(); }
|
||||||
|
|
||||||
// Access the status
|
// Access the status
|
||||||
const StatusPointer& getStatus() const { return _payload->getStatus(); }
|
const StatusPointer& getStatus() const { return _payload->getStatus(); }
|
||||||
|
@ -346,7 +350,10 @@ template <class T> int payloadGetLayer(const std::shared_ptr<T>& payloadData) {
|
||||||
template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { }
|
template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { }
|
||||||
|
|
||||||
// Shape type interface
|
// Shape type interface
|
||||||
template <class T> const model::MaterialKey shapeGetMaterialKey(const std::shared_ptr<T>& payloadData) { return model::MaterialKey(); }
|
// This allows shapes to characterize their pipeline via a ShapeKey, to be picked with a subclass of Shape.
|
||||||
|
// When creating a new shape payload you need to create a specialized version, or the ShapeKey will be ownPipeline,
|
||||||
|
// implying that the shape will setup its own pipeline without the use of the ShapeKey.
|
||||||
|
template <class T> const ShapeKey shapeGetShapeKey(const std::shared_ptr<T>& payloadData) { return ShapeKey::Builder::ownPipeline(); }
|
||||||
|
|
||||||
template <class T> class Payload : public Item::PayloadInterface {
|
template <class T> class Payload : public Item::PayloadInterface {
|
||||||
public:
|
public:
|
||||||
|
@ -364,7 +371,7 @@ public:
|
||||||
virtual void render(RenderArgs* args) { payloadRender<T>(_data, args); }
|
virtual void render(RenderArgs* args) { payloadRender<T>(_data, args); }
|
||||||
|
|
||||||
// Shape Type interface
|
// Shape Type interface
|
||||||
virtual const model::MaterialKey getMaterialKey() const { return shapeGetMaterialKey<T>(_data); }
|
virtual const ShapeKey getShapeKey() const { return shapeGetShapeKey<T>(_data); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DataPointer _data;
|
DataPointer _data;
|
||||||
|
|
100
libraries/render/src/render/ShapePipeline.cpp
Normal file
100
libraries/render/src/render/ShapePipeline.cpp
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
//
|
||||||
|
// ShapePipeline.cpp
|
||||||
|
// render/src/render
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 12/31/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "DependencyManager.h"
|
||||||
|
|
||||||
|
#include "ShapePipeline.h"
|
||||||
|
|
||||||
|
#include <PerfStat.h>
|
||||||
|
|
||||||
|
using namespace render;
|
||||||
|
|
||||||
|
ShapeKey::Filter::Builder::Builder() {
|
||||||
|
_mask.set(OWN_PIPELINE);
|
||||||
|
_mask.set(INVALID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) {
|
||||||
|
// Iterate over all keys
|
||||||
|
if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) {
|
||||||
|
addPipelineHelper(filter, key, bit + 1, pipeline);
|
||||||
|
if (!filter._mask[bit]) {
|
||||||
|
// Toggle bits set as insignificant in filter._mask
|
||||||
|
key._flags.flip(bit);
|
||||||
|
addPipelineHelper(filter, key, bit + 1, pipeline);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Add the brand new pipeline and cache its location in the lib
|
||||||
|
_pipelineMap.insert(PipelineMap::value_type(key, pipeline));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||||
|
BatchSetter batchSetter) {
|
||||||
|
addPipeline(Filter{key}, program, state, batchSetter);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||||
|
BatchSetter batchSetter) {
|
||||||
|
gpu::Shader::BindingSet slotBindings;
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_GPU));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_GPU));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), Slot::DIFFUSE_MAP));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::NORMAL_MAP));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Slot::SPECULAR_MAP));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Slot::LIGHTMAP_MAP));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Slot::LIGHT_BUFFER));
|
||||||
|
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Slot::NORMAL_FITTING_MAP));
|
||||||
|
|
||||||
|
gpu::Shader::makeProgram(*program, slotBindings);
|
||||||
|
|
||||||
|
auto locations = std::make_shared<Locations>();
|
||||||
|
locations->texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices");
|
||||||
|
locations->emissiveParams = program->getUniforms().findLocation("emissiveParams");
|
||||||
|
locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
|
||||||
|
locations->diffuseTextureUnit = program->getTextures().findLocation("diffuseMap");
|
||||||
|
locations->normalTextureUnit = program->getTextures().findLocation("normalMap");
|
||||||
|
locations->specularTextureUnit = program->getTextures().findLocation("specularMap");
|
||||||
|
locations->emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
|
||||||
|
locations->skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer");
|
||||||
|
locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer");
|
||||||
|
locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
|
||||||
|
|
||||||
|
ShapeKey key{filter._flags};
|
||||||
|
auto gpuPipeline = gpu::Pipeline::create(program, state);
|
||||||
|
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter);
|
||||||
|
addPipelineHelper(filter, key, 0, shapePipeline);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Key& key) const {
|
||||||
|
assert(!_pipelineMap.empty());
|
||||||
|
assert(args);
|
||||||
|
assert(args->_batch);
|
||||||
|
|
||||||
|
PerformanceTimer perfTimer("ShapePlumber::pickPipeline");
|
||||||
|
|
||||||
|
const auto& pipelineIterator = _pipelineMap.find(key);
|
||||||
|
if (pipelineIterator == _pipelineMap.end()) {
|
||||||
|
qDebug() << "Couldn't find a pipeline from ShapeKey ?" << key;
|
||||||
|
return PipelinePointer(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
PipelinePointer shapePipeline(pipelineIterator->second);
|
||||||
|
auto& batch = args->_batch;
|
||||||
|
|
||||||
|
// Run the pipeline's BatchSetter on the passed in batch
|
||||||
|
shapePipeline->batchSetter(*shapePipeline, *batch);
|
||||||
|
|
||||||
|
// Setup the one pipeline (to rule them all)
|
||||||
|
batch->setPipeline(shapePipeline->pipeline);
|
||||||
|
|
||||||
|
return shapePipeline;
|
||||||
|
}
|
249
libraries/render/src/render/ShapePipeline.h
Normal file
249
libraries/render/src/render/ShapePipeline.h
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
//
|
||||||
|
// ShapePipeline.h
|
||||||
|
// render/src/render
|
||||||
|
//
|
||||||
|
// Created by Zach Pomerantz on 12/31/15.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_render_ShapePipeline_h
|
||||||
|
#define hifi_render_ShapePipeline_h
|
||||||
|
|
||||||
|
#include <gpu/Batch.h>
|
||||||
|
#include <RenderArgs.h>
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
|
||||||
|
class ShapeKey {
|
||||||
|
public:
|
||||||
|
enum FlagBit {
|
||||||
|
TRANSLUCENT = 0,
|
||||||
|
LIGHTMAP,
|
||||||
|
TANGENTS,
|
||||||
|
SPECULAR,
|
||||||
|
EMISSIVE,
|
||||||
|
SKINNED,
|
||||||
|
STEREO,
|
||||||
|
DEPTH_ONLY,
|
||||||
|
WIREFRAME,
|
||||||
|
|
||||||
|
OWN_PIPELINE,
|
||||||
|
INVALID,
|
||||||
|
|
||||||
|
NUM_FLAGS, // Not a valid flag
|
||||||
|
};
|
||||||
|
using Flags = std::bitset<NUM_FLAGS>;
|
||||||
|
|
||||||
|
Flags _flags;
|
||||||
|
|
||||||
|
ShapeKey() : _flags{0} {}
|
||||||
|
ShapeKey(const Flags& flags) : _flags{flags} {}
|
||||||
|
|
||||||
|
class Builder {
|
||||||
|
public:
|
||||||
|
Builder() {}
|
||||||
|
Builder(ShapeKey key) : _flags{key._flags} {}
|
||||||
|
|
||||||
|
ShapeKey build() const { return ShapeKey{_flags}; }
|
||||||
|
|
||||||
|
Builder& withTranslucent() { _flags.set(TRANSLUCENT); return (*this); }
|
||||||
|
Builder& withLightmap() { _flags.set(LIGHTMAP); return (*this); }
|
||||||
|
Builder& withTangents() { _flags.set(TANGENTS); return (*this); }
|
||||||
|
Builder& withSpecular() { _flags.set(SPECULAR); return (*this); }
|
||||||
|
Builder& withEmissive() { _flags.set(EMISSIVE); return (*this); }
|
||||||
|
Builder& withSkinned() { _flags.set(SKINNED); return (*this); }
|
||||||
|
Builder& withStereo() { _flags.set(STEREO); return (*this); }
|
||||||
|
Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); }
|
||||||
|
Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); }
|
||||||
|
|
||||||
|
Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); }
|
||||||
|
Builder& invalidate() { _flags.set(INVALID); return (*this); }
|
||||||
|
|
||||||
|
static const ShapeKey ownPipeline() { return Builder().withOwnPipeline(); }
|
||||||
|
static const ShapeKey invalid() { return Builder().invalidate(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class ShapeKey;
|
||||||
|
Flags _flags{0};
|
||||||
|
};
|
||||||
|
ShapeKey(const Builder& builder) : ShapeKey{builder._flags} {}
|
||||||
|
|
||||||
|
class Filter {
|
||||||
|
public:
|
||||||
|
Filter(Flags flags, Flags mask) : _flags{flags}, _mask{mask} {}
|
||||||
|
Filter(const ShapeKey& key) : _flags{ key._flags } { _mask.set(); }
|
||||||
|
|
||||||
|
// Build a standard filter (will always exclude OWN_PIPELINE, INVALID)
|
||||||
|
class Builder {
|
||||||
|
public:
|
||||||
|
Builder();
|
||||||
|
|
||||||
|
Filter build() const { return Filter(_flags, _mask); }
|
||||||
|
|
||||||
|
Builder& withOpaque() { _flags.reset(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
|
||||||
|
Builder& withTranslucent() { _flags.set(TRANSLUCENT); _mask.set(TRANSLUCENT); return (*this); }
|
||||||
|
|
||||||
|
Builder& withLightmap() { _flags.reset(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); }
|
||||||
|
Builder& withoutLightmap() { _flags.set(LIGHTMAP); _mask.set(LIGHTMAP); return (*this); }
|
||||||
|
|
||||||
|
Builder& withTangents() { _flags.reset(TANGENTS); _mask.set(TANGENTS); return (*this); }
|
||||||
|
Builder& withoutTangents() { _flags.set(TANGENTS); _mask.set(TANGENTS); return (*this); }
|
||||||
|
|
||||||
|
Builder& withSpecular() { _flags.reset(SPECULAR); _mask.set(SPECULAR); return (*this); }
|
||||||
|
Builder& withoutSpecular() { _flags.set(SPECULAR); _mask.set(SPECULAR); return (*this); }
|
||||||
|
|
||||||
|
Builder& withEmissive() { _flags.reset(EMISSIVE); _mask.set(EMISSIVE); return (*this); }
|
||||||
|
Builder& withoutEmissive() { _flags.set(EMISSIVE); _mask.set(EMISSIVE); return (*this); }
|
||||||
|
|
||||||
|
Builder& withSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||||
|
Builder& withoutSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||||
|
|
||||||
|
Builder& withStereo() { _flags.reset(STEREO); _mask.set(STEREO); return (*this); }
|
||||||
|
Builder& withoutStereo() { _flags.set(STEREO); _mask.set(STEREO); return (*this); }
|
||||||
|
|
||||||
|
Builder& withDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
||||||
|
Builder& withoutDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); }
|
||||||
|
|
||||||
|
Builder& withWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME); return (*this); }
|
||||||
|
Builder& withoutWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME); return (*this); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class Filter;
|
||||||
|
Flags _flags{0};
|
||||||
|
Flags _mask{0};
|
||||||
|
};
|
||||||
|
Filter(const Filter::Builder& builder) : Filter(builder._flags, builder._mask) {}
|
||||||
|
protected:
|
||||||
|
friend class ShapePlumber;
|
||||||
|
Flags _flags{0};
|
||||||
|
Flags _mask{0};
|
||||||
|
};
|
||||||
|
|
||||||
|
bool hasLightmap() const { return _flags[LIGHTMAP]; }
|
||||||
|
bool hasTangents() const { return _flags[TANGENTS]; }
|
||||||
|
bool hasSpecular() const { return _flags[SPECULAR]; }
|
||||||
|
bool hasEmissive() const { return _flags[EMISSIVE]; }
|
||||||
|
bool isTranslucent() const { return _flags[TRANSLUCENT]; }
|
||||||
|
bool isSkinned() const { return _flags[SKINNED]; }
|
||||||
|
bool isStereo() const { return _flags[STEREO]; }
|
||||||
|
bool isDepthOnly() const { return _flags[DEPTH_ONLY]; }
|
||||||
|
bool isWireFrame() const { return _flags[WIREFRAME]; }
|
||||||
|
|
||||||
|
bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; }
|
||||||
|
bool isValid() const { return !_flags[INVALID]; }
|
||||||
|
|
||||||
|
// Hasher for use in unordered_maps
|
||||||
|
class Hash {
|
||||||
|
public:
|
||||||
|
size_t operator() (const ShapeKey& key) const {
|
||||||
|
return std::hash<ShapeKey::Flags>()(key._flags);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Comparator for use in unordered_maps
|
||||||
|
class KeyEqual {
|
||||||
|
public:
|
||||||
|
bool operator()(const ShapeKey& lhs, const ShapeKey& rhs) const { return lhs._flags == rhs._flags; }
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) {
|
||||||
|
if (renderKey.isValid()) {
|
||||||
|
if (renderKey.hasOwnPipeline()) {
|
||||||
|
debug << "[ShapeKey: OWN_PIPELINE]";
|
||||||
|
} else {
|
||||||
|
debug << "[ShapeKey:"
|
||||||
|
<< "hasLightmap:" << renderKey.hasLightmap()
|
||||||
|
<< "hasTangents:" << renderKey.hasTangents()
|
||||||
|
<< "hasSpecular:" << renderKey.hasSpecular()
|
||||||
|
<< "hasEmissive:" << renderKey.hasEmissive()
|
||||||
|
<< "isTranslucent:" << renderKey.isTranslucent()
|
||||||
|
<< "isSkinned:" << renderKey.isSkinned()
|
||||||
|
<< "isStereo:" << renderKey.isStereo()
|
||||||
|
<< "isDepthOnly:" << renderKey.isDepthOnly()
|
||||||
|
<< "isWireFrame:" << renderKey.isWireFrame()
|
||||||
|
<< "]";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug << "[ShapeKey: INVALID]";
|
||||||
|
}
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rendering abstraction over gpu::Pipeline and map locations
|
||||||
|
// Meta-information (pipeline and locations) to render a shape
|
||||||
|
class ShapePipeline {
|
||||||
|
public:
|
||||||
|
class Slot {
|
||||||
|
public:
|
||||||
|
static const int SKINNING_GPU = 2;
|
||||||
|
static const int MATERIAL_GPU = 3;
|
||||||
|
static const int DIFFUSE_MAP = 0;
|
||||||
|
static const int NORMAL_MAP = 1;
|
||||||
|
static const int SPECULAR_MAP = 2;
|
||||||
|
static const int LIGHTMAP_MAP = 3;
|
||||||
|
static const int LIGHT_BUFFER = 4;
|
||||||
|
static const int NORMAL_FITTING_MAP = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Locations {
|
||||||
|
public:
|
||||||
|
int texcoordMatrices;
|
||||||
|
int diffuseTextureUnit;
|
||||||
|
int normalTextureUnit;
|
||||||
|
int specularTextureUnit;
|
||||||
|
int emissiveTextureUnit;
|
||||||
|
int emissiveParams;
|
||||||
|
int normalFittingMapUnit;
|
||||||
|
int skinClusterBufferUnit;
|
||||||
|
int materialBufferUnit;
|
||||||
|
int lightBufferUnit;
|
||||||
|
};
|
||||||
|
using LocationsPointer = std::shared_ptr<Locations>;
|
||||||
|
|
||||||
|
using BatchSetter = std::function<void(const ShapePipeline&, gpu::Batch&)>;
|
||||||
|
|
||||||
|
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) :
|
||||||
|
pipeline(pipeline), locations(locations), batchSetter(batchSetter) {}
|
||||||
|
|
||||||
|
gpu::PipelinePointer pipeline;
|
||||||
|
std::shared_ptr<Locations> locations;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
friend class ShapePlumber;
|
||||||
|
|
||||||
|
BatchSetter batchSetter;
|
||||||
|
};
|
||||||
|
using ShapePipelinePointer = std::shared_ptr<ShapePipeline>;
|
||||||
|
|
||||||
|
class ShapePlumber {
|
||||||
|
public:
|
||||||
|
using Key = ShapeKey;
|
||||||
|
using Filter = Key::Filter;
|
||||||
|
using Pipeline = ShapePipeline;
|
||||||
|
using PipelinePointer = ShapePipelinePointer;
|
||||||
|
using PipelineMap = std::unordered_map<ShapeKey, PipelinePointer, ShapeKey::Hash, ShapeKey::KeyEqual>;
|
||||||
|
using Slot = Pipeline::Slot;
|
||||||
|
using Locations = Pipeline::Locations;
|
||||||
|
using LocationsPointer = Pipeline::LocationsPointer;
|
||||||
|
using BatchSetter = Pipeline::BatchSetter;
|
||||||
|
|
||||||
|
void addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||||
|
BatchSetter batchSetter = nullptr);
|
||||||
|
void addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||||
|
BatchSetter batchSetter = nullptr);
|
||||||
|
|
||||||
|
const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline);
|
||||||
|
PipelineMap _pipelineMap;
|
||||||
|
};
|
||||||
|
using ShapePlumberPointer = std::shared_ptr<ShapePlumber>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // hifi_render_ShapePipeline_h
|
|
@ -20,6 +20,7 @@
|
||||||
class AABox;
|
class AABox;
|
||||||
class OctreeRenderer;
|
class OctreeRenderer;
|
||||||
class ViewFrustum;
|
class ViewFrustum;
|
||||||
|
|
||||||
namespace gpu {
|
namespace gpu {
|
||||||
class Batch;
|
class Batch;
|
||||||
class Context;
|
class Context;
|
||||||
|
@ -27,6 +28,10 @@ class Texture;
|
||||||
class Framebuffer;
|
class Framebuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
class ShapePipeline;
|
||||||
|
}
|
||||||
|
|
||||||
class RenderDetails {
|
class RenderDetails {
|
||||||
public:
|
public:
|
||||||
enum Type {
|
enum Type {
|
||||||
|
@ -103,6 +108,7 @@ public:
|
||||||
|
|
||||||
std::shared_ptr<gpu::Context> _context = nullptr;
|
std::shared_ptr<gpu::Context> _context = nullptr;
|
||||||
std::shared_ptr<gpu::Framebuffer> _blitFramebuffer = nullptr;
|
std::shared_ptr<gpu::Framebuffer> _blitFramebuffer = nullptr;
|
||||||
|
std::shared_ptr<render::ShapePipeline> _pipeline = nullptr;
|
||||||
OctreeRenderer* _renderer = nullptr;
|
OctreeRenderer* _renderer = nullptr;
|
||||||
ViewFrustum* _viewFrustum = nullptr;
|
ViewFrustum* _viewFrustum = nullptr;
|
||||||
glm::ivec4 _viewport{ 0, 0, 1, 1 };
|
glm::ivec4 _viewport{ 0, 0, 1, 1 };
|
||||||
|
|
|
@ -3,5 +3,5 @@ AUTOSCRIBE_SHADER_LIB(gpu model render-utils)
|
||||||
# This is not a testcase -- just set it up as a regular hifi project
|
# This is not a testcase -- just set it up as a regular hifi project
|
||||||
setup_hifi_project(Quick Gui OpenGL Script Widgets)
|
setup_hifi_project(Quick Gui OpenGL Script Widgets)
|
||||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||||
link_hifi_libraries(networking gl gpu procedural shared fbx model model-networking animation script-engine render-utils )
|
link_hifi_libraries(networking gl gpu procedural shared fbx model model-networking animation script-engine render render-utils )
|
||||||
package_libraries_for_deployment()
|
package_libraries_for_deployment()
|
Loading…
Reference in a new issue