mirror of
https://github.com/overte-org/overte.git
synced 2025-04-11 04:12:09 +02:00
wip finish adding material entity
This commit is contained in:
parent
134a026d8a
commit
d7f4b033e8
35 changed files with 1291 additions and 219 deletions
|
@ -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 {
|
||||
|
|
174
interface/resources/qml/hifi/tablet/NewMaterialDialog.qml
Normal file
174
interface/resources/qml/hifi/tablet/NewMaterialDialog.qml
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -59,7 +59,6 @@ protected:
|
|||
virtual void onAddToScene(const EntityItemPointer& entity);
|
||||
virtual void onRemoveFromScene(const EntityItemPointer& entity);
|
||||
|
||||
protected:
|
||||
EntityRenderer(const EntityItemPointer& entity);
|
||||
~EntityRenderer();
|
||||
|
||||
|
|
238
libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
Normal file
238
libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp
Normal 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;
|
||||
}
|
|
@ -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
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -221,4 +221,4 @@ bool Material::calculateMaterialInfo() const {
|
|||
_hasCalculatedTextureInfo = allTextures;
|
||||
}
|
||||
return _hasCalculatedTextureInfo;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -206,7 +206,8 @@ enum class EntityVersion : PacketVersion {
|
|||
OwnershipChallengeFix,
|
||||
ZoneLightInheritModes = 82,
|
||||
ZoneStageRemoved,
|
||||
SoftEntities
|
||||
SoftEntities,
|
||||
MaterialEntities
|
||||
};
|
||||
|
||||
enum class EntityScriptCallMethodVersion : PacketVersion {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
24
libraries/shared/src/MaterialMode.cpp
Normal file
24
libraries/shared/src/MaterialMode.cpp
Normal 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];
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -24,7 +24,8 @@ var ICON_FOR_TYPE = {
|
|||
Zone: "o",
|
||||
PolyVox: "",
|
||||
Multiple: "",
|
||||
PolyLine: ""
|
||||
PolyLine: "",
|
||||
Material: ""
|
||||
};
|
||||
|
||||
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'));
|
||||
|
|
|
@ -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 !== ""
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue