wip finish adding material entity

This commit is contained in:
SamGondelman 2018-01-17 15:56:18 -08:00
parent 134a026d8a
commit d7f4b033e8
35 changed files with 1291 additions and 219 deletions

View file

@ -133,6 +133,17 @@ TabView {
editTabView.currentIndex = 4
}
}
NewEntityButton {
icon: "icons/create-icons/94-model-01.svg"
text: "MATERIAL"
onClicked: {
editRoot.sendToScript({
method: "newEntityButtonClicked", params: { buttonName: "newMaterialButton" }
});
editTabView.currentIndex = 2
}
}
}
HifiControls.Button {

View file

@ -0,0 +1,174 @@
//
// NewMaterialDialog.qml
// qml/hifi
//
// Created by Sam Gondelman on 1/17/18
// Copyright 2018 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
//
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Dialogs 1.2 as OriginalDialogs
import "../../styles-uit"
import "../../controls-uit"
import "../dialogs"
Rectangle {
id: newMaterialDialog
// width: parent.width
// height: parent.height
HifiConstants { id: hifi }
color: hifi.colors.baseGray;
signal sendToScript(var message);
property bool keyboardEnabled: false
property bool punctuationMode: false
property bool keyboardRasied: false
function errorMessageBox(message) {
return desktop.messageBox({
icon: hifi.icons.warning,
defaultButton: OriginalDialogs.StandardButton.Ok,
title: "Error",
text: message
});
}
Item {
id: column1
anchors.rightMargin: 10
anchors.leftMargin: 10
anchors.bottomMargin: 10
anchors.topMargin: 10
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: keyboard.top
Text {
id: text1
text: qsTr("Material URL")
color: "#ffffff"
font.pixelSize: 12
}
TextInput {
id: materialURL
height: 20
text: qsTr("")
color: "white"
anchors.top: text1.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
font.pixelSize: 12
onAccepted: {
newMaterialDialog.keyboardEnabled = false;
}
MouseArea {
anchors.fill: parent
onClicked: {
newMaterialDialog.keyboardEnabled = HMD.active
parent.focus = true;
parent.forceActiveFocus();
materialURL.cursorPosition = materialURL.positionAt(mouseX, mouseY, TextInput.CursorBetweenCharaters);
}
}
}
Rectangle {
id: textInputBox
color: "white"
anchors.fill: materialURL
opacity: 0.1
}
Row {
id: row1
height: 400
spacing: 30
anchors.top: materialURL.bottom
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 0
anchors.right: parent.right
anchors.rightMargin: 0
Column {
id: column3
height: 400
spacing: 10
Text {
id: text3
text: qsTr("Material Mode")
color: "#ffffff"
font.pixelSize: 12
}
ComboBox {
id: materialMode
property var materialArray: ["UV space material",
"3D projected material"]
width: 200
z: 100
transformOrigin: Item.Center
model: materialArray
}
Row {
id: row3
width: 200
height: 400
spacing: 5
anchors.horizontalCenter: column3.horizontalCenter
anchors.horizontalCenterOffset: -20
Button {
id: button1
text: qsTr("Add")
z: -1
onClicked: {
newMaterialDialog.sendToScript({
method: "newMaterialDialogAdd",
params: {
textInput: materialURL.text,
comboBox: materialMode.currentIndex
}
});
}
}
Button {
id: button2
z: -1
text: qsTr("Cancel")
onClicked: {
newMaterialDialog.sendToScript({method: "newMaterialDialogCancel"})
}
}
}
}
}
}
Keyboard {
id: keyboard
raised: parent.keyboardEnabled
numeric: parent.punctuationMode
anchors {
bottom: parent.bottom
left: parent.left
right: parent.right
}
}
}

View file

@ -25,6 +25,7 @@
#include "RenderableTextEntityItem.h"
#include "RenderableWebEntityItem.h"
#include "RenderableZoneEntityItem.h"
#include "RenderableMaterialEntityItem.h"
using namespace render;
@ -247,6 +248,10 @@ EntityRenderer::Pointer EntityRenderer::addToScene(EntityTreeRenderer& renderer,
result = make_renderer<ZoneEntityRenderer>(entity);
break;
case Type::Material:
result = make_renderer<MaterialEntityRenderer>(entity);
break;
default:
break;
}
@ -388,4 +393,4 @@ void EntityRenderer::onAddToScene(const EntityItemPointer& entity) {
void EntityRenderer::onRemoveFromScene(const EntityItemPointer& entity) {
entity->deregisterChangeHandler(_changeHandlerId);
QObject::disconnect(this, &EntityRenderer::requestRenderUpdate, this, nullptr);
}
}

View file

@ -59,7 +59,6 @@ protected:
virtual void onAddToScene(const EntityItemPointer& entity);
virtual void onRemoveFromScene(const EntityItemPointer& entity);
protected:
EntityRenderer(const EntityItemPointer& entity);
~EntityRenderer();

View file

@ -0,0 +1,238 @@
//
// Created by Sam Gondelman on 1/18/2018
// Copyright 2018 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 "RenderableMaterialEntityItem.h"
using namespace render;
using namespace render::entities;
bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const {
if (entity->getMaterial() != _drawMaterial) {
return true;
}
return false;
}
void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) {
withWriteLock([&] {
_drawMaterial = entity->getMaterial();
_renderTransform = getModelTransform();
const float MATERIAL_ENTITY_SCALE = 0.5f;
_renderTransform.postScale(MATERIAL_ENTITY_SCALE);
_renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
});
}
ItemKey MaterialEntityRenderer::getKey() {
ItemKey::Builder builder;
builder.withTypeShape();
if (!_visible) {
builder.withInvisible();
}
if (_drawMaterial) {
auto matKey = _drawMaterial->getKey();
if (matKey.isTranslucent()) {
builder.withTransparent();
}
}
return builder.build();
}
ShapeKey MaterialEntityRenderer::getShapeKey() {
graphics::MaterialKey drawMaterialKey;
if (_drawMaterial) {
drawMaterialKey = _drawMaterial->getKey();
}
bool isTranslucent = drawMaterialKey.isTranslucent();
bool hasTangents = drawMaterialKey.isNormalMap();
bool hasSpecular = drawMaterialKey.isMetallicMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
bool isUnlit = drawMaterialKey.isUnlit();
ShapeKey::Builder builder;
builder.withMaterial();
if (isTranslucent) {
builder.withTranslucent();
}
if (hasTangents) {
builder.withTangents();
}
if (hasSpecular) {
builder.withSpecular();
}
if (hasLightmap) {
builder.withLightmap();
}
if (isUnlit) {
builder.withUnlit();
}
return builder.build();
}
glm::vec3 MaterialEntityRenderer::getVertexPos(float phi, float theta) {
return glm::vec3(glm::sin(theta) * glm::cos(phi), glm::cos(theta), glm::sin(theta) * glm::sin(phi));
}
glm::vec3 MaterialEntityRenderer::getTangent(float phi, float theta) {
return glm::vec3(-glm::cos(theta) * glm::cos(phi), 0, -glm::cos(theta) * glm::sin(phi));
}
void MaterialEntityRenderer::addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv) {
buffer.push_back(pos.x); buffer.push_back(pos.y); buffer.push_back(pos.z);
buffer.push_back(tan.x); buffer.push_back(tan.y); buffer.push_back(tan.z);
buffer.push_back(uv.x); buffer.push_back(uv.y);
}
void MaterialEntityRenderer::addTriangleFan(std::vector<float>& buffer, int stack, int step) {
float v1 = ((float)stack) / STACKS;
float theta1 = v1 * M_PI;
glm::vec3 tip = getVertexPos(0, theta1);
float v2 = ((float)(stack + step)) / STACKS;
float theta2 = v2 * M_PI;
for (int i = 0; i < SLICES; i++) {
float u1 = ((float)i) / SLICES;
float u2 = ((float)(i + step)) / SLICES;
float phi1 = u1 * M_PI_TIMES_2;
float phi2 = u2 * M_PI_TIMES_2;
/* (flipped for negative step)
p1
/ \
/ \
/ \
p3 ------ p2
*/
glm::vec3 pos2 = getVertexPos(phi2, theta2);
glm::vec3 pos3 = getVertexPos(phi1, theta2);
glm::vec3 tan1 = getTangent(0, theta1);
glm::vec3 tan2 = getTangent(phi2, theta2);
glm::vec3 tan3 = getTangent(phi1, theta2);
glm::vec2 uv1 = glm::vec2((u1 + u2) / 2.0f, v1);
glm::vec2 uv2 = glm::vec2(u2, v2);
glm::vec2 uv3 = glm::vec2(u1, v2);
addVertex(buffer, tip, tan1, uv1);
addVertex(buffer, pos2, tan2, uv2);
addVertex(buffer, pos3, tan3, uv3);
_numVertices += 3;
}
}
int MaterialEntityRenderer::_numVertices = 0;
std::shared_ptr<gpu::Stream::Format> MaterialEntityRenderer::_streamFormat = nullptr;
std::shared_ptr<gpu::BufferStream> MaterialEntityRenderer::_stream = nullptr;
std::shared_ptr<gpu::Buffer> MaterialEntityRenderer::_verticesBuffer = nullptr;
void MaterialEntityRenderer::generateMesh() {
_streamFormat = std::make_shared<gpu::Stream::Format>();
_stream = std::make_shared<gpu::BufferStream>();
_verticesBuffer = std::make_shared<gpu::Buffer>();
const int NUM_POS_COORDS = 3;
const int NUM_TANGENT_COORDS = 3;
const int VERTEX_TANGENT_OFFSET = NUM_POS_COORDS * sizeof(float);
const int VERTEX_TEXCOORD_OFFSET = VERTEX_TANGENT_OFFSET + NUM_TANGENT_COORDS * sizeof(float);
_streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
_streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0);
_streamFormat->setAttribute(gpu::Stream::TANGENT, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_TANGENT_OFFSET);
_streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET);
_stream->addBuffer(_verticesBuffer, 0, _streamFormat->getChannels().at(0)._stride);
std::vector<float> vertexBuffer;
// Top
addTriangleFan(vertexBuffer, 0, 1);
// Middle section
for (int j = 1; j < STACKS - 1; j++) {
float v1 = ((float)j) / STACKS;
float v2 = ((float)(j + 1)) / STACKS;
float theta1 = v1 * M_PI;
float theta2 = v2 * M_PI;
for (int i = 0; i < SLICES; i++) {
float u1 = ((float)i) / SLICES;
float u2 = ((float)(i + 1)) / SLICES;
float phi1 = u1 * M_PI_TIMES_2;
float phi2 = u2 * M_PI_TIMES_2;
/*
p2 ---- p3
| / |
| / |
| / |
p1 ---- p4
*/
glm::vec3 pos1 = getVertexPos(phi1, theta2);
glm::vec3 pos2 = getVertexPos(phi1, theta1);
glm::vec3 pos3 = getVertexPos(phi2, theta1);
glm::vec3 pos4 = getVertexPos(phi2, theta2);
glm::vec3 tan1 = getTangent(phi1, theta2);
glm::vec3 tan2 = getTangent(phi1, theta1);
glm::vec3 tan3 = getTangent(phi2, theta1);
glm::vec3 tan4 = getTangent(phi2, theta2);
glm::vec2 uv1 = glm::vec2(u1, v2);
glm::vec2 uv2 = glm::vec2(u1, v1);
glm::vec2 uv3 = glm::vec2(u2, v1);
glm::vec2 uv4 = glm::vec2(u2, v2);
addVertex(vertexBuffer, pos1, tan1, uv1);
addVertex(vertexBuffer, pos2, tan2, uv2);
addVertex(vertexBuffer, pos3, tan3, uv3);
addVertex(vertexBuffer, pos3, tan3, uv3);
addVertex(vertexBuffer, pos4, tan4, uv4);
addVertex(vertexBuffer, pos1, tan1, uv1);
_numVertices += 6;
}
}
// Bottom
addTriangleFan(vertexBuffer, STACKS, -1);
_verticesBuffer->append(vertexBuffer.size() * sizeof(float), (gpu::Byte*) vertexBuffer.data());
}
void MaterialEntityRenderer::doRender(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableMaterialEntityItem::render");
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
batch.setModelTransform(_renderTransform);
// bind the material
args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing);
args->_details._materialSwitches++;
// Draw!
if (_numVertices == 0) {
generateMesh();
}
batch.setInputFormat(_streamFormat);
batch.setInputStream(0, *_stream);
batch.draw(gpu::TRIANGLES, _numVertices, 0);
const int NUM_VERTICES_PER_TRIANGLE = 3;
args->_details._trianglesRendered += _numVertices / NUM_VERTICES_PER_TRIANGLE;
}

View file

@ -0,0 +1,54 @@
//
// Created by Sam Gondelman on 1/18/2018
// Copyright 2018 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_RenderableMaterialEntityItem_h
#define hifi_RenderableMaterialEntityItem_h
#include "RenderableEntityItem.h"
#include <MaterialEntityItem.h>
class NetworkMaterial;
namespace render { namespace entities {
class MaterialEntityRenderer : public TypedEntityRenderer<MaterialEntityItem> {
using Parent = TypedEntityRenderer<MaterialEntityItem>;
using Pointer = std::shared_ptr<MaterialEntityRenderer>;
public:
MaterialEntityRenderer(const EntityItemPointer& entity) : Parent(entity) {}
private:
virtual bool needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const override;
virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override;
virtual void doRender(RenderArgs* args) override;
ItemKey getKey() override;
ShapeKey getShapeKey() override;
Transform _renderTransform;
std::shared_ptr<NetworkMaterial> _drawMaterial;
static int _numVertices;
static std::shared_ptr<gpu::Stream::Format> _streamFormat;
static std::shared_ptr<gpu::BufferStream> _stream;
static std::shared_ptr<gpu::Buffer> _verticesBuffer;
void generateMesh();
void addTriangleFan(std::vector<float>& buffer, int stack, int step);
static glm::vec3 getVertexPos(float phi, float theta);
static glm::vec3 getTangent(float phi, float theta);
static void addVertex(std::vector<float>& buffer, const glm::vec3& pos, const glm::vec3& tan, const glm::vec2 uv);
const int SLICES = 15;
const int STACKS = 9;
const float M_PI_TIMES_2 = 2.0f * M_PI;
};
} }
#endif // hifi_RenderableMaterialEntityItem_h

View file

@ -115,6 +115,17 @@ void buildStringToShapeTypeLookup() {
addShapeType(SHAPE_TYPE_STATIC_MESH);
}
QHash<QString, MaterialMode> stringToMaterialModeLookup;
void addMaterialMode(MaterialMode mode) {
stringToMaterialModeLookup[MaterialModeHelpers::getNameForMaterialMode(mode)] = mode;
}
void buildStringToMaterialModeLookup() {
addMaterialMode(UV);
addMaterialMode(PROJECTED);
}
QString getCollisionGroupAsString(uint8_t group) {
switch (group) {
case USER_COLLISION_GROUP_DYNAMIC:
@ -259,6 +270,21 @@ void EntityItemProperties::setSkyboxModeFromString(const QString& skyboxMode) {
}
}
QString EntityItemProperties::getMaterialModeAsString() const {
return MaterialModeHelpers::getNameForMaterialMode(_materialMode);
}
void EntityItemProperties::setMaterialModeFromString(const QString& materialMode) {
if (stringToMaterialModeLookup.empty()) {
buildStringToMaterialModeLookup();
}
auto materialModeItr = stringToMaterialModeLookup.find(materialMode.toLower());
if (materialModeItr != stringToMaterialModeLookup.end()) {
_materialMode = materialModeItr.value();
_materialModeChanged = true;
}
}
EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
EntityPropertyFlags changedProperties;
@ -329,7 +355,6 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread);
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_URL, materialURL);
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_TYPE, materialMode);
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_BLEND_FACTOR, blendFactor);
@ -635,7 +660,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
// Materials
if (_type == EntityTypes::Material) {
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_URL, materialURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_TYPE, materialMode);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(PROP_MATERIAL_TYPE, materialMode, getMaterialModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_BLEND_FACTOR, blendFactor);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_MATERIAL_PRIORITY, priority);
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARENT_SHAPE_ID, shapeID);
@ -776,7 +801,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish);
COPY_PROPERTY_FROM_QSCRIPTVALUE(relayParentJoints, bool, setRelayParentJoints);
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialURL, QString, setMaterialURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMode, MaterialMode, setMaterialMode);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(materialMode, MaterialMode, setMaterialMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(blendFactor, float, setBlendFactor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(priority, int, setPriority);
COPY_PROPERTY_FROM_QSCRIPTVALUE(shapeID, int, setShapeID);
@ -1135,6 +1160,13 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
ADD_PROPERTY_TO_MAP(PROP_RADIUS_START, RadiusStart, radiusStart, float);
ADD_PROPERTY_TO_MAP(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_URL, MaterialURL, materialURL, QString);
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_TYPE, MaterialMode, materialMode, MaterialMode);
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BLEND_FACTOR, BlendFactor, blendFactor, float);
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_PRIORITY, Priority, priority, uint32_t);
ADD_PROPERTY_TO_MAP(PROP_PARENT_SHAPE_ID, ShapeID, shapeID, uint32_t);
ADD_PROPERTY_TO_MAP(PROP_MATERIAL_BOUNDS, MaterialBounds, materialBounds, glmVec4);
// Certifiable Properties
ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString);
ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString);
@ -2067,6 +2099,13 @@ void EntityItemProperties::markAllChanged() {
//_alphaStartChanged = true;
//_alphaFinishChanged = true;
_materialURLChanged = true;
_materialModeChanged = true;
_blendFactorChanged = true;
_priorityChanged = true;
_shapeIDChanged = true;
_materialBoundsChanged = true;
// Certifiable Properties
_itemNameChanged = true;
_itemDescriptionChanged = true;
@ -2390,6 +2429,24 @@ QList<QString> EntityItemProperties::listChangedProperties() {
if (radiusFinishChanged()) {
out += "radiusFinish";
}
if (materialURLChanged()) {
out += "materialURL";
}
if (materialModeChanged()) {
out += "materialMode";
}
if (blendFactorChanged()) {
out += "blendFactor";
}
if (priorityChanged()) {
out += "priority";
}
if (shapeIDChanged()) {
out += "shapeID";
}
if (materialBoundsChanged()) {
out += "materialBounds";
}
// Certifiable Properties
if (itemNameChanged()) {

View file

@ -242,6 +242,29 @@ inline glmVec3 glmVec3_convertFromScriptValue(const QScriptValue& v, bool& isVal
return glm::vec3(0);
}
inline glmVec4 glmVec4_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = false; /// assume it can't be converted
QScriptValue x = v.property("x");
QScriptValue y = v.property("y");
QScriptValue z = v.property("z");
QScriptValue w = v.property("w");
if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
glm::vec4 newValue(0);
newValue.x = x.toVariant().toFloat();
newValue.y = y.toVariant().toFloat();
newValue.z = z.toVariant().toFloat();
newValue.w = w.toVariant().toFloat();
isValid = !glm::isnan(newValue.x) &&
!glm::isnan(newValue.y) &&
!glm::isnan(newValue.z) &&
!glm::isnan(newValue.w);
if (isValid) {
return newValue;
}
}
return glm::vec4(0);
}
inline AACube AACube_convertFromScriptValue(const QScriptValue& v, bool& isValid) {
isValid = true;
AACube result;

View file

@ -10,6 +10,9 @@
#include "EntityItemProperties.h"
#include "QJsonDocument"
#include "QJsonArray"
EntityItemPointer MaterialEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
Pointer entity(new MaterialEntityItem(entityID), [](EntityItem* ptr) { ptr->deleteLater(); });
entity->setProperties(properties);
@ -34,7 +37,7 @@ EntityItemProperties MaterialEntityItem::getProperties(EntityPropertyFlags desir
bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) {
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialURL, setMaterialURL);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(materialMode, setMaterialMode);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(blendFactor, setBlendFactor);
@ -55,6 +58,139 @@ bool MaterialEntityItem::setProperties(const EntityItemProperties& properties) {
return somethingChanged;
}
bool MaterialEntityItem::parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB) {
if (array.isArray()) {
QJsonArray colorArray = array.toArray();
if (colorArray.size() >= 3 && colorArray[0].isDouble() && colorArray[1].isDouble() && colorArray[2].isDouble()) {
isSRGB = true;
if (colorArray.size() >= 4) {
if (colorArray[3].isBool()) {
isSRGB = colorArray[3].toBool();
}
}
color = glm::vec3(colorArray[0].toDouble(), colorArray[1].toDouble(), colorArray[2].toDouble());
return true;
}
}
return false;
}
void MaterialEntityItem::parseJSONMaterial(const QJsonObject& materialJSON) {
QString name = "";
std::shared_ptr<NetworkMaterial> material = std::make_shared<NetworkMaterial>();
for (auto& key : materialJSON.keys()) {
if (key == "name") {
auto nameJSON = materialJSON.value(key);
if (nameJSON.isString()) {
name = nameJSON.toString();
}
} else if (key == "emissive") {
glm::vec3 color;
bool isSRGB;
bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB);
if (valid) {
material->setEmissive(color, isSRGB);
}
} else if (key == "opacity") {
auto value = materialJSON.value(key);
if (value.isDouble()) {
material->setOpacity(value.toDouble());
}
} else if (key == "albedo") {
glm::vec3 color;
bool isSRGB;
bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB);
if (valid) {
material->setAlbedo(color, isSRGB);
}
} else if (key == "roughness") {
auto value = materialJSON.value(key);
if (value.isDouble()) {
material->setRoughness(value.toDouble());
}
} else if (key == "fresnel") {
glm::vec3 color;
bool isSRGB;
bool valid = parseJSONColor(materialJSON.value(key), color, isSRGB);
if (valid) {
material->setFresnel(color, isSRGB);
}
} else if (key == "metallic") {
auto value = materialJSON.value(key);
if (value.isDouble()) {
material->setMetallic(value.toDouble());
}
} else if (key == "scattering") {
auto value = materialJSON.value(key);
if (value.isDouble()) {
material->setScattering(value.toDouble());
}
} else if (key == "emissiveMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setEmissiveMap(value.toString());
}
} else if (key == "albedoMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
bool useAlphaChannel = false;
auto opacityMap = materialJSON.find("opacityMap");
if (opacityMap != materialJSON.end() && opacityMap->isString() && opacityMap->toString() == value.toString()) {
useAlphaChannel = true;
}
material->setAlbedoMap(value.toString(), useAlphaChannel);
}
} else if (key == "roughnessMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setRoughnessMap(value.toString(), false);
}
} else if (key == "glossMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setRoughnessMap(value.toString(), true);
}
} else if (key == "metallicMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setMetallicMap(value.toString(), false);
}
} else if (key == "specularMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setMetallicMap(value.toString(), true);
}
} else if (key == "normalMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setNormalMap(value.toString(), false);
}
} else if (key == "bumpMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setNormalMap(value.toString(), true);
}
} else if (key == "occlusionMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setOcclusionMap(value.toString());
}
} else if (key == "scatteringMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setScatteringMap(value.toString());
}
} else if (key == "lightMap") {
auto value = materialJSON.value(key);
if (value.isString()) {
material->setLightmapMap(value.toString());
}
}
}
_materials[name] = material;
_materialNames.push_back(name);
}
int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
ReadBitstreamToTreeParams& args,
EntityPropertyFlags& propertyFlags, bool overwriteLocalData,
@ -66,8 +202,8 @@ int MaterialEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* da
READ_ENTITY_PROPERTY(PROP_MATERIAL_URL, QString, setMaterialURL);
READ_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, MaterialMode, setMaterialMode);
READ_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, float, setBlendFactor);
READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, int, setPriority);
READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, int, setShapeID);
READ_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, uint32_t, setPriority);
READ_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, uint32_t, setShapeID);
READ_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, glm::vec4, setMaterialBounds);
return bytesRead;
@ -96,25 +232,82 @@ void MaterialEntityItem::appendSubclassData(OctreePacketData* packetData, Encode
bool successPropertyFits = true;
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_URL, getMaterialURL());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, getMaterialMode());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_TYPE, (uint32_t)getMaterialMode());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BLEND_FACTOR, getBlendFactor());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, getPriority());
APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, getShapeID());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_PRIORITY, (uint32_t)getPriority());
APPEND_ENTITY_PROPERTY(PROP_PARENT_SHAPE_ID, (uint32_t)getShapeID());
APPEND_ENTITY_PROPERTY(PROP_MATERIAL_BOUNDS, getMaterialBounds());
}
void MaterialEntityItem::debugDump() const {
quint64 now = usecTimestampNow();
qCDebug(entities) << "MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " name:" << _name;
qCDebug(entities) << " url:" << _materialURL;
qCDebug(entities) << " material type:" << _materialMode;
qCDebug(entities) << " blend factor:" << _blendFactor;
qCDebug(entities) << " priority:" << _priority;
qCDebug(entities) << " parent shape ID:" << _shapeID;
qCDebug(entities) << " material bounds:" << _materialBounds;
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << "SHAPE EntityItem Ptr:" << this;
qCDebug(entities) << " MATERIAL EntityItem id:" << getEntityItemID() << "---------------------------------------------";
qCDebug(entities) << " name:" << _name;
qCDebug(entities) << " material json:" << _materialURL;
qCDebug(entities) << " current material name:" << _currentMaterialName;
qCDebug(entities) << " material type:" << _materialMode;
qCDebug(entities) << " blend factor:" << _blendFactor;
qCDebug(entities) << " priority:" << _priority;
qCDebug(entities) << " parent shape ID:" << _shapeID;
qCDebug(entities) << " material bounds:" << _materialBounds;
qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition());
qCDebug(entities) << " dimensions:" << debugTreeVector(getScaledDimensions());
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
qCDebug(entities) << "MATERIAL EntityItem Ptr:" << this;
}
void MaterialEntityItem::setUnscaledDimensions(const glm::vec3& value) {
EntityItem::setUnscaledDimensions(ENTITY_ITEM_DEFAULT_DIMENSIONS);
}
std::shared_ptr<NetworkMaterial> MaterialEntityItem::getMaterial() const {
auto material = _materials.find(_currentMaterialName);
if (material != _materials.end()) {
return material.value();
} else {
return nullptr;
}
}
void MaterialEntityItem::setMaterialURL(const QString& materialURLString) {
if (materialURLString.startsWith("userData")) {
QJsonDocument materialJSON = QJsonDocument::fromJson(getUserData().toUtf8());
_materials.clear();
_materialNames.clear();
if (!materialJSON.isNull()) {
if (materialJSON.isArray()) {
QJsonArray materials = materialJSON.array();
for (auto& material : materials) {
if (!material.isNull() && material.isObject()) {
parseJSONMaterial(material.toObject());
}
}
} else if (materialJSON.isObject()) {
parseJSONMaterial(materialJSON.object());
}
}
}
_materialURL = materialURLString;
// TODO: if URL ends with ?string, set _currentMaterialName = string
// Since our JSON changed, the current name might not be valid anymore, so we need to update
setCurrentMaterialName(_currentMaterialName);
}
void MaterialEntityItem::setCurrentMaterialName(const QString& currentMaterialName) {
auto material = _materials.find(currentMaterialName);
if (material != _materials.end()) {
_currentMaterialName = currentMaterialName;
} else if (_materialNames.size() > 0) {
setCurrentMaterialName(_materialNames[0]);
}
}
void MaterialEntityItem::setUserData(const QString& userData) {
EntityItem::setUserData(userData);
if (_materialURL.startsWith("userData")) {
// Trigger material update when user data changes
setMaterialURL(_materialURL);
}
}

View file

@ -46,25 +46,34 @@ public:
void debugDump() const override;
const QString& getMaterialURL() { return _materialURL; }
void setMaterialURL(const QString& materialURL) { _materialURL = materialURL; }
virtual void setUnscaledDimensions(const glm::vec3& value) override;
MaterialMode getMaterialType() { return _materialMode; }
void setMaterialMode(MaterialMode mode);
QString getMaterialURL() const { return _materialURL; }
void setMaterialURL(const QString& materialURLString);
float getBlendFactor() { return _blendFactor; }
QString getCurrentMaterialName() const { return _currentMaterialName; }
void setCurrentMaterialName(const QString& currentMaterialName);
MaterialMode getMaterialMode() const { return _materialMode; }
void setMaterialMode(MaterialMode mode) { _materialMode = mode; }
float getBlendFactor() const { return _blendFactor; }
void setBlendFactor(float blendFactor) { _blendFactor = blendFactor; }
int getPriority() { return _priority; }
int getPriority() const { return _priority; }
void setPriority(int priority) { _priority = priority; }
int getShapeID() { return _shapeID; }
int getShapeID() const { return _shapeID; }
void setShapeID(int shapeID) { _shapeID = shapeID; }
const glm::vec4& getMaterialBounds() { return _materialBounds; }
glm::vec4 getMaterialBounds() const { return _materialBounds; }
void setMaterialBounds(const glm::vec4& materialBounds) { _materialBounds = materialBounds; }
protected:
std::shared_ptr<NetworkMaterial> getMaterial() const;
void setUserData(const QString& userData) override;
private:
QString _materialURL;
MaterialMode _materialMode { UV };
float _blendFactor { 1.0f };
@ -72,7 +81,12 @@ protected:
int _shapeID { 0 };
glm::vec4 _materialBounds { 0, 0, 1, 1 };
//NetworkMaterial _material;
QHash<QString, std::shared_ptr<NetworkMaterial>> _materials;
std::vector<QString> _materialNames;
QString _currentMaterialName;
void parseJSONMaterial(const QJsonObject& materialJSON);
static bool parseJSONColor(const QJsonValue& array, glm::vec3& color, bool& isSRGB);
};

View file

@ -221,4 +221,4 @@ bool Material::calculateMaterialInfo() const {
_hasCalculatedTextureInfo = allTextures;
}
return _hasCalculatedTextureInfo;
}
}

View file

@ -425,7 +425,7 @@ bool Geometry::areTexturesLoaded() const {
return true;
}
const std::shared_ptr<const NetworkMaterial> Geometry::getShapeMaterial(int partID) const {
const std::shared_ptr<NetworkMaterial> Geometry::getShapeMaterial(int partID) const {
if ((partID >= 0) && (partID < (int)_meshParts->size())) {
int materialID = _meshParts->at(partID)->materialID;
if ((materialID >= 0) && (materialID < (int)_materials.size())) {
@ -491,6 +491,15 @@ void GeometryResourceWatcher::resourceRefreshed() {
// _instance.reset();
}
NetworkMaterial::NetworkMaterial(const NetworkMaterial& m) :
Material(m),
_textures(m._textures),
_albedoTransform(m._albedoTransform),
_lightmapParams(m._lightmapParams),
_lightmapTransform(m._lightmapTransform),
_isOriginal(m._isOriginal)
{}
const QString NetworkMaterial::NO_TEXTURE = QString();
const QString& NetworkMaterial::getTextureName(MapChannel channel) {
@ -532,19 +541,85 @@ graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& baseUrl
}
graphics::TextureMapPointer NetworkMaterial::fetchTextureMap(const QUrl& url, image::TextureUsage::Type type, MapChannel channel) {
const auto texture = DependencyManager::get<TextureCache>()->getTexture(url, type);
_textures[channel].texture = texture;
auto textureCache = DependencyManager::get<TextureCache>();
if (textureCache) {
auto texture = textureCache->getTexture(url, type);
_textures[channel].texture = texture;
auto map = std::make_shared<graphics::TextureMap>();
map->setTextureSource(texture->_textureSource);
auto map = std::make_shared<graphics::TextureMap>();
if (texture) {
map->setTextureSource(texture->_textureSource);
emit textureFinished();
}
return map;
return map;
}
return nullptr;
}
void NetworkMaterial::setAlbedoMap(const QString& url, bool useAlphaChannel) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
if (map) {
map->setUseAlphaChannel(useAlphaChannel);
setTextureMap(MapChannel::ALBEDO_MAP, map);
}
}
void NetworkMaterial::setNormalMap(const QString& url, bool isBumpmap) {
auto map = fetchTextureMap(QUrl(url), isBumpmap ? image::TextureUsage::BUMP_TEXTURE : image::TextureUsage::NORMAL_TEXTURE, MapChannel::NORMAL_MAP);
if (map) {
setTextureMap(MapChannel::NORMAL_MAP, map);
}
}
void NetworkMaterial::setRoughnessMap(const QString& url, bool isGloss) {
auto map = fetchTextureMap(QUrl(url), isGloss ? image::TextureUsage::GLOSS_TEXTURE : image::TextureUsage::ROUGHNESS_TEXTURE, MapChannel::ROUGHNESS_MAP);
if (map) {
setTextureMap(MapChannel::ROUGHNESS_MAP, map);
}
}
void NetworkMaterial::setMetallicMap(const QString& url, bool isSpecular) {
auto map = fetchTextureMap(QUrl(url), isSpecular ? image::TextureUsage::SPECULAR_TEXTURE : image::TextureUsage::METALLIC_TEXTURE, MapChannel::METALLIC_MAP);
if (map) {
setTextureMap(MapChannel::METALLIC_MAP, map);
}
}
void NetworkMaterial::setOcclusionMap(const QString& url) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::OCCLUSION_TEXTURE, MapChannel::OCCLUSION_MAP);
if (map) {
setTextureMap(MapChannel::OCCLUSION_MAP, map);
}
}
void NetworkMaterial::setEmissiveMap(const QString& url) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::EMISSIVE_TEXTURE, MapChannel::EMISSIVE_MAP);
if (map) {
setTextureMap(MapChannel::EMISSIVE_MAP, map);
}
}
void NetworkMaterial::setScatteringMap(const QString& url) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::SCATTERING_TEXTURE, MapChannel::SCATTERING_MAP);
if (map) {
setTextureMap(MapChannel::SCATTERING_MAP, map);
}
}
void NetworkMaterial::setLightmapMap(const QString& url) {
auto map = fetchTextureMap(QUrl(url), image::TextureUsage::LIGHTMAP_TEXTURE, MapChannel::LIGHTMAP_MAP);
if (map) {
//map->setTextureTransform(_lightmapTransform);
//map->setLightmapOffsetScale(_lightmapParams.x, _lightmapParams.y);
setTextureMap(MapChannel::LIGHTMAP_MAP, map);
}
}
NetworkMaterial::NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl) :
graphics::Material(*material._material)
graphics::Material(*material._material),
_textures(MapChannel::NUM_MAP_CHANNELS)
{
_textures = Textures(MapChannel::NUM_MAP_CHANNELS);
if (!material.albedoTexture.filename.isEmpty()) {
auto map = fetchTextureMap(textureBaseUrl, material.albedoTexture, image::TextureUsage::ALBEDO_TEXTURE, MapChannel::ALBEDO_MAP);
_albedoTransform = material.albedoTexture.transform;

View file

@ -48,7 +48,7 @@ public:
const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; }
const GeometryMeshes& getMeshes() const { return *_meshes; }
const std::shared_ptr<const NetworkMaterial> getShapeMaterial(int shapeID) const;
const std::shared_ptr<NetworkMaterial> getShapeMaterial(int shapeID) const;
const QVariantMap getTextures() const;
void setTextures(const QVariantMap& textureMap);
@ -131,7 +131,6 @@ private:
Geometry::Pointer& _geometryRef;
};
/// Stores cached model geometries.
class ModelCache : public ResourceCache, public Dependency {
Q_OBJECT
@ -157,11 +156,26 @@ private:
virtual ~ModelCache() = default;
};
class NetworkMaterial : public graphics::Material {
class NetworkMaterial : public QObject, public graphics::Material {
Q_OBJECT
public:
using MapChannel = graphics::Material::MapChannel;
NetworkMaterial() : _textures(MapChannel::NUM_MAP_CHANNELS) {}
NetworkMaterial(const FBXMaterial& material, const QUrl& textureBaseUrl);
NetworkMaterial(const NetworkMaterial& material);
void setAlbedoMap(const QString& url, bool useAlphaChannel);
void setNormalMap(const QString& url, bool isBumpmap);
void setRoughnessMap(const QString& url, bool isGloss);
void setMetallicMap(const QString& url, bool isSpecular);
void setOcclusionMap(const QString& url);
void setEmissiveMap(const QString& url);
void setScatteringMap(const QString& url);
void setLightmapMap(const QString& url);
signals:
void textureFinished();
protected:
friend class Geometry;

View file

@ -275,6 +275,8 @@ QSharedPointer<Resource> TextureCache::createResource(const QUrl& url, const QSh
return QSharedPointer<Resource>(texture, &Resource::deleter);
}
int networkTexturePointerMetaTypeId = qRegisterMetaType<QWeakPointer<NetworkTexture>>();
NetworkTexture::NetworkTexture(const QUrl& url) :
Resource(url),
_type(),

View file

@ -163,7 +163,6 @@ public:
NetworkTexturePointer getTexture(const QUrl& url, image::TextureUsage::Type type = image::TextureUsage::DEFAULT_TEXTURE,
const QByteArray& content = QByteArray(), int maxNumPixels = ABSOLUTE_MAX_TEXTURE_NUM_PIXELS);
gpu::TexturePointer getTextureByHash(const std::string& hash);
gpu::TexturePointer cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture);

View file

@ -340,14 +340,6 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
return resource;
}
if (QThread::currentThread() != thread()) {
qCDebug(networking) << "Fetching asynchronously:" << url;
QMetaObject::invokeMethod(this, "getResource",
Q_ARG(QUrl, url), Q_ARG(QUrl, fallback));
// Cannot use extra parameter as it might be freed before the invocation
return QSharedPointer<Resource>();
}
if (!url.isValid() && !url.isEmpty() && fallback.isValid()) {
return getResource(fallback, QUrl());
}
@ -358,6 +350,7 @@ QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl&
extra);
resource->setSelf(resource);
resource->setCache(this);
resource->moveToThread(qApp->thread());
connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize);
{
QWriteLocker locker(&_resourcesLock);

View file

@ -30,7 +30,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
case PacketType::EntityEdit:
case PacketType::EntityData:
case PacketType::EntityPhysics:
return static_cast<PacketVersion>(EntityVersion::SoftEntities);
return static_cast<PacketVersion>(EntityVersion::MaterialEntities);
case PacketType::EntityQuery:
return static_cast<PacketVersion>(EntityQueryPacketVersion::RemovedJurisdictions);

View file

@ -206,7 +206,8 @@ enum class EntityVersion : PacketVersion {
OwnershipChallengeFix,
ZoneLightInheritModes = 82,
ZoneStageRemoved,
SoftEntities
SoftEntities,
MaterialEntities
};
enum class EntityScriptCallMethodVersion : PacketVersion {

View file

@ -33,6 +33,8 @@
#include <NLPacket.h>
#include <udt/PacketHeaders.h>
#include "MaterialMode.h"
#include "OctreeConstants.h"
#include "OctreeElement.h"
@ -249,6 +251,7 @@ public:
static int unpackDataFromBytes(const unsigned char* dataBytes, float& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec3& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::vec4& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, bool& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, quint64& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, uint32_t& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
@ -257,6 +260,7 @@ public:
static int unpackDataFromBytes(const unsigned char* dataBytes, rgbColor& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, glm::quat& result) { int bytes = unpackOrientationQuatFromBytes(dataBytes, result); return bytes; }
static int unpackDataFromBytes(const unsigned char* dataBytes, ShapeType& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, MaterialMode& result) { memcpy(&result, dataBytes, sizeof(result)); return sizeof(result); }
static int unpackDataFromBytes(const unsigned char* dataBytes, QString& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, QUuid& result);
static int unpackDataFromBytes(const unsigned char* dataBytes, xColor& result);

View file

@ -38,7 +38,7 @@ void CauterizedMeshPartPayload::updateTransformForCauterizedMesh(const Transform
_cauterizedTransform = renderTransform;
}
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
bool useCauterizedMesh = (renderMode != RenderArgs::RenderMode::SHADOW_RENDER_MODE && renderMode != RenderArgs::RenderMode::SECONDARY_CAMERA_RENDER_MODE) && _enableCauterization;
if (useCauterizedMesh) {
if (_cauterizedClusterBuffer) {
@ -46,7 +46,7 @@ void CauterizedMeshPartPayload::bindTransform(gpu::Batch& batch, const render::S
}
batch.setModelTransform(_cauterizedTransform);
} else {
ModelMeshPartPayload::bindTransform(batch, locations, renderMode);
ModelMeshPartPayload::bindTransform(batch, renderMode);
}
}

View file

@ -25,7 +25,7 @@ public:
void updateTransformForCauterizedMesh(const Transform& renderTransform);
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
void setEnableCauterization(bool enableCauterization) { _enableCauterization = enableCauterization; }

View file

@ -1318,7 +1318,6 @@ void GeometryCache::renderUnitQuad(gpu::Batch& batch, const glm::vec4& color, in
renderQuad(batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, color, id);
}
void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, const glm::vec2& maxCorner,
const glm::vec2& texCoordMinCorner, const glm::vec2& texCoordMaxCorner,
const glm::vec4& color, int id) {

View file

@ -125,126 +125,7 @@ void MeshPartPayload::bindMesh(gpu::Batch& batch) {
batch.setInputStream(0, _drawMesh->getVertexStream());
}
void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool enableTextures) const {
if (!_drawMaterial) {
return;
}
auto textureCache = DependencyManager::get<TextureCache>();
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, _drawMaterial->getSchemaBuffer());
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, _drawMaterial->getTexMapArrayBuffer());
const auto& materialKey = _drawMaterial->getKey();
const auto& textureMaps = _drawMaterial->getTextureMaps();
int numUnlit = 0;
if (materialKey.isUnlit()) {
numUnlit++;
}
if (!enableTextures) {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
return;
}
// Albedo
if (materialKey.isAlbedoMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView());
} else {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture());
}
}
// Roughness map
if (materialKey.isRoughnessMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
}
}
// Normal map
if (materialKey.isNormalMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
}
}
// Metallic map
if (materialKey.isMetallicMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
}
}
// Occlusion map
if (materialKey.isOcclusionMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
}
}
// Scattering map
if (materialKey.isScatteringMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
}
}
// Emissive / Lightmap
if (materialKey.isLightmapMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture());
}
} else if (materialKey.isEmissiveMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
}
}
}
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
void MeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
batch.setModelTransform(_drawTransform);
}
@ -252,23 +133,21 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::Loca
void MeshPartPayload::render(RenderArgs* args) {
PerformanceTimer perfTimer("MeshPartPayload::render");
if (!args) {
return;
}
gpu::Batch& batch = *(args->_batch);
auto locations = args->_shapePipeline->locations;
assert(locations);
// Bind the model transform and the skinCLusterMatrices if needed
bindTransform(batch, locations, args->_renderMode);
bindTransform(batch, args->_renderMode);
//Bind the index buffer and vertex buffer and Blend shapes if needed
bindMesh(batch);
// apply material properties
bindMaterial(batch, locations, args->_enableTexturing);
if (args) {
args->_details._materialSwitches++;
}
args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing);
args->_details._materialSwitches++;
// Draw!
{
@ -276,10 +155,8 @@ void MeshPartPayload::render(RenderArgs* args) {
drawCall(batch);
}
if (args) {
const int INDICES_PER_TRIANGLE = 3;
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
}
const int INDICES_PER_TRIANGLE = 3;
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
}
namespace render {
@ -500,7 +377,7 @@ void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) {
}
}
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const {
void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const {
if (_clusterBuffer) {
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::SKINNING, _clusterBuffer);
}
@ -515,17 +392,14 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
}
gpu::Batch& batch = *(args->_batch);
auto locations = args->_shapePipeline->locations;
assert(locations);
bindTransform(batch, locations, args->_renderMode);
bindTransform(batch, args->_renderMode);
//Bind the index buffer and vertex buffer and Blend shapes if needed
bindMesh(batch);
// apply material properties
bindMaterial(batch, locations, args->_enableTexturing);
args->_shapePipeline->bindMaterial(_drawMaterial, batch, args->_enableTexturing);
args->_details._materialSwitches++;
// Draw!

View file

@ -17,7 +17,6 @@
#include <gpu/Batch.h>
#include <render/Scene.h>
#include <render/ShapePipeline.h>
#include <graphics/Geometry.h>
@ -49,8 +48,7 @@ public:
// ModelMeshPartPayload functions to perform render
void drawCall(gpu::Batch& batch) const;
virtual void bindMesh(gpu::Batch& batch);
virtual void bindMaterial(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, bool enableTextures) const;
virtual void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const;
virtual void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const;
// Payload resource cached values
Transform _drawTransform;
@ -63,7 +61,7 @@ public:
mutable graphics::Box _worldBound;
std::shared_ptr<const graphics::Mesh> _drawMesh;
std::shared_ptr<const graphics::Material> _drawMaterial;
std::shared_ptr<graphics::Material> _drawMaterial;
graphics::Mesh::Part _drawPart;
size_t getVerticesCount() const { return _drawMesh ? _drawMesh->getNumVertices() : 0; }
@ -109,7 +107,7 @@ public:
// ModelMeshPartPayload functions to perform render
void bindMesh(gpu::Batch& batch) override;
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
void bindTransform(gpu::Batch& batch, RenderArgs::RenderMode renderMode) const override;
void computeAdjustedLocalBound(const std::vector<TransformType>& clusterTransforms);

View file

@ -2,7 +2,9 @@ set(TARGET_NAME render)
AUTOSCRIBE_SHADER_LIB(gpu graphics)
setup_hifi_library()
# render needs octree only for getAccuracyAngle(float, int)
link_hifi_libraries(shared ktx gpu graphics octree)
# render needs octree only for getAccuracyAngle(float, int), and model-networking for TextureCache
link_hifi_libraries(shared ktx gpu graphics octree model-networking)
include_hifi_library_headers(networking)
include_hifi_library_headers(image)
target_nsight()

View file

@ -15,6 +15,8 @@
#include <PerfStat.h>
#include <model-networking/TextureCache.h>
using namespace render;
ShapePipeline::CustomFactoryMap ShapePipeline::_globalCustomFactoryMap;
@ -157,3 +159,122 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke
return shapePipeline;
}
void ShapePipeline::bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) const {
if (!material) {
return;
}
auto textureCache = DependencyManager::get<TextureCache>();
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::MATERIAL, material->getSchemaBuffer());
batch.setUniformBuffer(ShapePipeline::Slot::BUFFER::TEXMAPARRAY, material->getTexMapArrayBuffer());
const auto& materialKey = material->getKey();
const auto& textureMaps = material->getTextureMaps();
int numUnlit = 0;
if (materialKey.isUnlit()) {
numUnlit++;
}
if (!enableTextures) {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
return;
}
// Albedo
if (materialKey.isAlbedoMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::ALBEDO_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, itr->second->getTextureView());
} else {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO, textureCache->getGrayTexture());
}
}
// Roughness map
if (materialKey.isRoughnessMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::ROUGHNESS_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::ROUGHNESS, textureCache->getWhiteTexture());
}
}
// Normal map
if (materialKey.isNormalMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::NORMAL_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::NORMAL, textureCache->getBlueTexture());
}
}
// Metallic map
if (materialKey.isMetallicMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::METALLIC_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::METALLIC, textureCache->getBlackTexture());
}
}
// Occlusion map
if (materialKey.isOcclusionMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::OCCLUSION_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::OCCLUSION, textureCache->getWhiteTexture());
}
}
// Scattering map
if (materialKey.isScatteringMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::SCATTERING_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, itr->second->getTextureView());
// texcoord are assumed to be the same has albedo
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::SCATTERING, textureCache->getWhiteTexture());
}
}
// Emissive / Lightmap
if (materialKey.isLightmapMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::LIGHTMAP_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getGrayTexture());
}
} else if (materialKey.isEmissiveMap()) {
auto itr = textureMaps.find(graphics::MaterialKey::EMISSIVE_MAP);
if (itr != textureMaps.end() && itr->second->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, itr->second->getTextureView());
} else {
batch.setResourceTexture(ShapePipeline::Slot::MAP::EMISSIVE_LIGHTMAP, textureCache->getBlackTexture());
}
}
}

View file

@ -18,6 +18,8 @@
#include "Args.h"
#include <graphics/Material.h>
namespace render {
class Item;
class ShapePlumber;
@ -294,6 +296,8 @@ public:
void prepareShapeItem(Args* args, const ShapeKey& key, const Item& shape);
void bindMaterial(graphics::MaterialPointer material, gpu::Batch& batch, bool enableTextures) const;
protected:
friend class ShapePlumber;

View file

@ -0,0 +1,24 @@
//
// Created by Sam Gondelman on 1/17/2018
// Copyright 2018 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 "MaterialMode.h"
const char* materialModeNames[] = {
"uv",
"projected"
};
static const size_t MATERIAL_MODE_NAMES = (sizeof(materialModeNames) / sizeof((materialModeNames)[0]));
QString MaterialModeHelpers::getNameForMaterialMode(MaterialMode mode) {
if (((int)mode <= 0) || ((int)mode >= (int)MATERIAL_MODE_NAMES)) {
mode = (MaterialMode)0;
}
return materialModeNames[(int)mode];
}

View file

@ -9,10 +9,17 @@
#ifndef hifi_MaterialMode_h
#define hifi_MaterialMode_h
#include "QString"
enum MaterialMode {
UV = 0,
PROJECTED
};
class MaterialModeHelpers {
public:
static QString getNameForMaterialMode(MaterialMode mode);
};
#endif // hifi_MaterialMode_h

View file

@ -11,7 +11,8 @@ var toolBar = (function() {
newTextButton,
newWebButton,
newZoneButton,
newParticleButton
newParticleButton,
newMaterialButton
var toolIconUrl = Script.resolvePath("../../system/assets/images/tools/");
@ -89,6 +90,13 @@ var toolBar = (function() {
visible: false
});
newMaterialButton = toolBar.addButton({
objectName: "newMaterialButton",
imageURL: toolIconUrl + "model-01.svg",
alpha: 0.9,
visible: false
});
that.setActive(false);
newModelButton.clicked();
}
@ -109,8 +117,8 @@ var toolBar = (function() {
newTextButton.writeProperty('visible', doShow);
newWebButton.writeProperty('visible', doShow);
newZoneButton.writeProperty('visible', doShow);
newModelButton.writeProperty('visible', doShow);
newParticleButton.writeProperty('visible', doShow);
newMaterialButton.writeProperty('visible', doShow);
};
initialize();

View file

@ -251,7 +251,7 @@ var toolBar = (function () {
// Align entity with Avatar orientation.
properties.rotation = MyAvatar.orientation;
var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web"];
var PRE_ADJUST_ENTITY_TYPES = ["Box", "Sphere", "Shape", "Text", "Web", "Material"];
if (PRE_ADJUST_ENTITY_TYPES.indexOf(properties.type) !== -1) {
// Adjust position of entity per bounding box prior to creating it.
@ -354,6 +354,9 @@ var toolBar = (function () {
var SHAPE_TYPE_SPHERE = 5;
var DYNAMIC_DEFAULT = false;
var MATERIAL_MODE_UV = 0;
var MATERIAL_MODE_PROJECTED = 1;
function handleNewModelDialogResult(result) {
if (result) {
var url = result.textInput;
@ -394,6 +397,28 @@ var toolBar = (function () {
}
}
function handleNewMaterialDialogResult(result) {
if (result) {
var json = result.textInput;
var materialMode;
switch (result.comboBox) {
case MATERIAL_MODE_PROJECTED:
materialMode = "projected";
break;
default:
shapeType = "uv";
}
if (json) {
createNewEntity({
type: "Material",
materialURL: json,
materialMode: materialMode
});
}
}
}
function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml.
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.popFromStack();
@ -404,6 +429,9 @@ var toolBar = (function () {
case "newEntityButtonClicked":
buttonHandlers[message.params.buttonName]();
break;
case "newMaterialDialogAdd":
handleNewMaterialDialogResult(message.params);
break;
}
}
@ -614,6 +642,17 @@ var toolBar = (function () {
});
});
addButton("newMaterialButton", "model-01.svg", function () {
var MATERIAL_MODES = [];
MATERIAL_MODES[MATERIAL_MODE_UV] = "UV space material";
MATERIAL_MODES[MATERIAL_MODE_PROJECTED] = "3D projected material";
var MATERIAL_MODE_DEFAULT = MATERIAL_MODE_UV;
// tablet version of new material dialog
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
tablet.pushOntoStack("NewMaterialDialog.qml");
});
that.setActive(false);
}
@ -1983,7 +2022,7 @@ var PropertiesTool = function (opts) {
);
}
Entities.editEntity(selectionManager.selections[0], data.properties);
if (data.properties.name !== undefined || data.properties.modelURL !== undefined ||
if (data.properties.name !== undefined || data.properties.modelURL !== undefined || data.properties.materialURL !== undefined ||
data.properties.visible !== undefined || data.properties.locked !== undefined) {
entityListTool.sendUpdate();
}
@ -1994,7 +2033,7 @@ var PropertiesTool = function (opts) {
parentSelectedEntities();
} else if (data.type === 'unparent') {
unparentSelectedEntities();
} else if (data.type === 'saveUserData'){
} else if (data.type === 'saveUserData') {
//the event bridge and json parsing handle our avatar id string differently.
var actualID = data.id.split('"')[1];
Entities.editEntity(actualID, data.properties);

View file

@ -448,7 +448,7 @@ input[type=checkbox]:checked + label:hover {
border: 1.5pt solid black;
}
.shape-section, .light-section, .model-section, .web-section, .hyperlink-section, .text-section, .zone-section {
.shape-section, .light-section, .model-section, .web-section, .hyperlink-section, .text-section, .zone-section, .material-section {
display: table;
}
@ -570,6 +570,7 @@ hr {
.physical-group[collapsed="true"] ~ .physical-group,
.behavior-group[collapsed="true"] ~ .behavior-group,
.model-group[collapsed="true"] ~ .model-group,
.material-group[collapsed="true"] ~ .material-group,
.light-group[collapsed="true"] ~ .light-group {
display: none !important;
}
@ -1386,7 +1387,7 @@ input#reset-to-natural-dimensions {
}
#static-userdata{
#static-userdata {
display: none;
z-index: 99;
position: absolute;
@ -1397,7 +1398,7 @@ input#reset-to-natural-dimensions {
background-color: #2e2e2e;
}
#userdata-saved{
#userdata-saved {
margin-top:5px;
font-size:16px;
display:none;
@ -1454,6 +1455,9 @@ input#reset-to-natural-dimensions {
order: 6;
}
#properties-list.ShapeMenu #material,
#properties-list.BoxMenu #material,
#properties-list.SphereMenu #material,
#properties-list.ShapeMenu #light,
#properties-list.BoxMenu #light,
#properties-list.SphereMenu #light,
@ -1490,6 +1494,7 @@ input#reset-to-natural-dimensions {
}
/* items to hide */
#properties-list.ParticleEffectMenu #material,
#properties-list.ParticleEffectMenu #base-color-section,
#properties-list.ParticleEffectMenu #hyperlink,
#properties-list.ParticleEffectMenu #light,
@ -1524,6 +1529,7 @@ input#reset-to-natural-dimensions {
order: 7;
}
/* sections to hide */
#properties-list.LightMenu #material,
#properties-list.LightMenu #model,
#properties-list.LightMenu #zone,
#properties-list.LightMenu #text,
@ -1560,6 +1566,7 @@ input#reset-to-natural-dimensions {
order: 7;
}
/* sections to hide */
#properties-list.ModelMenu #material,
#properties-list.ModelMenu #light,
#properties-list.ModelMenu #zone,
#properties-list.ModelMenu #text,
@ -1596,6 +1603,7 @@ input#reset-to-natural-dimensions {
order: 7;
}
/* sections to hide */
#properties-list.ZoneMenu #material,
#properties-list.ZoneMenu #light,
#properties-list.ZoneMenu #model,
#properties-list.ZoneMenu #text,
@ -1632,6 +1640,7 @@ input#reset-to-natural-dimensions {
order: 7;
}
/* sections to hide */
#properties-list.WebMenu #material,
#properties-list.WebMenu #light,
#properties-list.WebMenu #model,
#properties-list.WebMenu #zone,
@ -1669,6 +1678,7 @@ input#reset-to-natural-dimensions {
order: 7;
}
/* sections to hide */
#properties-list.TextMenu #material,
#properties-list.TextMenu #light,
#properties-list.TextMenu #model,
#properties-list.TextMenu #zone,
@ -1681,6 +1691,39 @@ input#reset-to-natural-dimensions {
display: none
}
/* ----- Order of Menu items for Material ----- */
#properties-list.MaterialMenu #general {
order: 1;
}
#properties-list.MaterialMenu #material {
order: 2;
}
#properties-list.MaterialMenu #spatial {
order: 3;
}
#properties-list.MaterialMenu #hyperlink {
order: 4;
}
#properties-list.MaterialMenu #behavior {
order: 5;
}
/* sections to hide */
#properties-list.MaterialMenu #physical,
#properties-list.MaterialMenu #collision-info,
#properties-list.MaterialMenu #model,
#properties-list.MaterialMenu #light,
#properties-list.MaterialMenu #zone,
#properties-list.MaterialMenu #text,
#properties-list.MaterialMenu #web {
display: none;
}
/* items to hide */
#properties-list.MaterialMenu #shape-list,
#properties-list.MaterialMenu #base-color-section {
display: none
}
/* Currently always hidden */
#properties-list #polyvox {

View file

@ -761,6 +761,51 @@
</div>
</fieldset>
<fieldset id="material" class="major">
<legend class="section-header material-group material-section">
Material<span>M</span>
</legend>
<fieldset class="minor">
<div class="material-group material-section property url">
<label for="property-material-url">Material URL</label>
<input type="text" id="property-material-url">
</div>
</fieldset>
<fieldset class="minor">
<div class="material-group material-section property dropdown">
<label>Material mode </label>
<select name="SelectMaterialMode" id="property-material-mode">
<option value="uv">UV space material</option>
<option value="projected">3D projected material</option>
</select>
</div>
<div class="material-group material-section property number">
<label>Blend Factor </label>
<input type="number" id="property-blend-factor" min="0" max="1" step="0.1">
</div>
<div class="material-group material-section property number">
<label>Priority </label>
<input type="number" id="property-priority">
</div>
<div class="material-group material-section property number">
<label>Shape ID </label>
<input type="number" id="property-shape-id" min="0">
</div>
<div class="material-group material-section property tuple">
<label>Material Bounds </label>
<div><input type="number" class="x" id="property-material-bounds-x" min="0" max="1" step="0.1"><label for="property-material-bounds-x">Left:</label></div>
<div><input type="number" class="y" id="property-material-bounds-y" min="0" max="1" step="0.1"><label for="property-material-bounds-y">Top:</label></div>
<div><input type="number" class="z" id="property-material-bounds-z" min="0" max="1" step="0.1"><label for="property-material-bounds-z">Right:</label></div>
<div><input type="number" class="w" id="property-material-bounds-w" min="0" max="1" step="0.1"><label for="property-material-bounds-w">Bottom:</label></div>
</div>
</fieldset>
</fieldset>
</div>
</body>

View file

@ -24,7 +24,8 @@ var ICON_FOR_TYPE = {
Zone: "o",
PolyVox: "&#xe005;",
Multiple: "&#xe000;",
PolyLine: "&#xe01b;"
PolyLine: "&#xe01b;",
Material: "&#xe008;"
};
var EDITOR_TIMEOUT_DURATION = 1500;
@ -77,7 +78,6 @@ function disableProperties() {
if ($('#userdata-editor').css('display') === "block" && elLocked.checked === true) {
showStaticUserData();
}
}
function showElements(els, show) {
@ -192,6 +192,19 @@ function createEmitGroupVec3PropertyUpdateFunction(group, property, elX, elY, el
};
}
function createEmitVec4PropertyUpdateFunction(property, elX, elY, elZ, elW) {
return function () {
var properties = {};
properties[property] = {
x: elX.value,
y: elY.value,
z: elZ.value,
w: elW.value
};
updateProperties(properties);
};
}
function createEmitVec3PropertyUpdateFunctionWithMultiplier(property, elX, elY, elZ, multiplier) {
return function() {
var properties = {};
@ -473,7 +486,6 @@ function bindAllNonJSONEditorElements() {
} else {
if ($('#userdata-editor').css('height') !== "0px") {
saveJSONUserData(true);
}
}
});
@ -621,6 +633,16 @@ function loaded() {
var elModelTextures = document.getElementById("property-model-textures");
var elModelOriginalTextures = document.getElementById("property-model-original-textures");
var elMaterialURL = document.getElementById("property-material-url");
var elMaterialMode = document.getElementById("property-material-mode");
var elBlendFactor = document.getElementById("property-blend-factor");
var elPriority = document.getElementById("property-priority");
var elShapeID = document.getElementById("property-shape-id");
var elMaterialBoundsX = document.getElementById("property-material-bounds-x");
var elMaterialBoundsY = document.getElementById("property-material-bounds-y");
var elMaterialBoundsZ = document.getElementById("property-material-bounds-z");
var elMaterialBoundsW = document.getElementById("property-material-bounds-w");
var elWebSourceURL = document.getElementById("property-web-source-url");
var elWebDPI = document.getElementById("property-web-dpi");
@ -1105,6 +1127,17 @@ function loaded() {
elXTextureURL.value = properties.xTextureURL;
elYTextureURL.value = properties.yTextureURL;
elZTextureURL.value = properties.zTextureURL;
} else if (properties.type === "Material") {
elMaterialURL.value = properties.materialURL;
elMaterialMode.value = properties.materialMode;
setDropdownText(elMaterialMode);
elBlendFactor.value = properties.blendFactor.toFixed(2);
elPriority.value = properties.priority;
elShapeID.value = properties.shapeID;
elMaterialBoundsX.value = properties.materialBounds.x.toFixed(2);
elMaterialBoundsY.value = properties.materialBounds.y.toFixed(2);
elMaterialBoundsZ.value = properties.materialBounds.z.toFixed(2);
//elMaterialBoundsW.value = properties.materialBounds.w.toFixed(2);
}
if (properties.locked) {
@ -1375,6 +1408,19 @@ function loaded() {
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
elMaterialURL.addEventListener('change', createEmitTextPropertyUpdateFunction('materialURL'));
elMaterialMode.addEventListener('change', createEmitTextPropertyUpdateFunction('materialMode'));
elBlendFactor.addEventListener('change', createEmitNumberPropertyUpdateFunction('blendFactor', 2));
elPriority.addEventListener('change', createEmitNumberPropertyUpdateFunction('priority'));
elShapeID.addEventListener('change', createEmitNumberPropertyUpdateFunction('shapeID'));
var materialBoundsChangeFunction = createEmitVec4PropertyUpdateFunction('materialBounds',
elMaterialBoundsX, elMaterialBoundsY, elMaterialBoundsZ, elMaterialBoundsW);
elMaterialBoundsX.addEventListener('change', materialBoundsChangeFunction);
elMaterialBoundsY.addEventListener('change', materialBoundsChangeFunction);
elMaterialBoundsZ.addEventListener('change', materialBoundsChangeFunction);
elMaterialBoundsW.addEventListener('change', materialBoundsChangeFunction);
elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text'));
elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera'));
elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight'));

View file

@ -77,18 +77,24 @@ EntityListTool = function(opts) {
var properties = Entities.getEntityProperties(id);
if (!filterInView || Vec3.distance(properties.position, cameraPosition) <= searchRadius) {
var url = "";
if (properties.type == "Model") {
url = properties.modelURL;
} else if (properties.type == "Material") {
url = properties.materialURL;
}
entities.push({
id: id,
name: properties.name,
type: properties.type,
url: properties.type == "Model" ? properties.modelURL : "",
url: url,
locked: properties.locked,
visible: properties.visible,
verticesCount: valueIfDefined(properties.renderInfo.verticesCount),
texturesCount: valueIfDefined(properties.renderInfo.texturesCount),
texturesSize: valueIfDefined(properties.renderInfo.texturesSize),
hasTransparent: valueIfDefined(properties.renderInfo.hasTransparent),
isBaked: properties.type == "Model" ? properties.modelURL.toLowerCase().endsWith(".baked.fbx") : false,
isBaked: properties.type == "Model" ? url.toLowerCase().endsWith(".baked.fbx") : false,
drawCalls: valueIfDefined(properties.renderInfo.drawCalls),
hasScript: properties.script !== ""
});