Merge branch 'master' of github.com:highfidelity/hifi into run

This commit is contained in:
Seth Alves 2018-01-15 11:52:58 -08:00
commit eaeebc0215
39 changed files with 921 additions and 298 deletions

View file

@ -41,9 +41,9 @@ Item {
onNewViewRequestedCallback: {
// desktop is not defined for web-entities or tablet
if (typeof desktop !== "undefined") {
desktop.openBrowserWindow(request, profile);
desktop.openBrowserWindow(request, webViewCoreProfile);
} else {
tabletRoot.openBrowserWindow(request, profile);
tabletRoot.openBrowserWindow(request, webViewCoreProfile);
}
}

View file

@ -22,7 +22,6 @@ Item {
anchors.fill: parent
id: d
objectName: "stack"
initialItem: topMenu
property var menuStack: []
property var topMenu: null;

View file

@ -76,3 +76,5 @@ AnimPose::operator glm::mat4() const {
return glm::mat4(glm::vec4(xAxis, 0.0f), glm::vec4(yAxis, 0.0f),
glm::vec4(zAxis, 0.0f), glm::vec4(_trans, 1.0f));
}

View file

@ -1732,6 +1732,14 @@ glm::mat4 Rig::getJointTransform(int jointIndex) const {
}
}
AnimPose Rig::getJointPose(int jointIndex) const {
if (isIndexValid(jointIndex)) {
return _internalPoseSet._absolutePoses[jointIndex];
} else {
return AnimPose::identity;
}
}
void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
const AnimPose geometryToRigPose(_geometryToRigTransform);

View file

@ -164,6 +164,7 @@ public:
// rig space
glm::mat4 getJointTransform(int jointIndex) const;
AnimPose getJointPose(int jointIndex) const;
// Start or stop animations as needed.
void computeMotionAnimationState(float deltaTime, const glm::vec3& worldPosition, const glm::vec3& worldVelocity, const glm::quat& worldRotation, CharacterControllerState ccState);

View file

@ -116,6 +116,7 @@ public:
int jointIndex;
glm::mat4 inverseBindMatrix;
Transform inverseBindTransform;
};
const int MAX_NUM_PIXELS_FOR_FBX_TEXTURE = 2048 * 2048;
@ -225,7 +226,7 @@ public:
QVector<glm::vec2> texCoords;
QVector<glm::vec2> texCoords1;
QVector<uint16_t> clusterIndices;
QVector<uint8_t> clusterWeights;
QVector<uint16_t> clusterWeights;
QVector<int32_t> originalIndices;
QVector<FBXCluster> clusters;

View file

@ -1675,6 +1675,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
fbxCluster.jointIndex = 0;
}
fbxCluster.inverseBindMatrix = glm::inverse(cluster.transformLink) * modelTransform;
fbxCluster.inverseBindTransform = Transform(fbxCluster.inverseBindMatrix);
extracted.mesh.clusters.append(fbxCluster);
// override the bind rotation with the transform link
@ -1789,9 +1790,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
}
if (totalWeight > 0.0f) {
const float ALMOST_HALF = 0.499f;
float weightScalingFactor = (float)(UINT8_MAX) / totalWeight;
float weightScalingFactor = (float)(UINT16_MAX) / totalWeight;
for (int k = j; k < j + WEIGHTS_PER_VERTEX; ++k) {
extracted.mesh.clusterWeights[k] = (uint8_t)(weightScalingFactor * weightAccumulators[k] + ALMOST_HALF);
extracted.mesh.clusterWeights[k] = (uint16_t)(weightScalingFactor * weightAccumulators[k] + ALMOST_HALF);
}
}
}

View file

@ -624,7 +624,8 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
// we need 16 bits instead of just 8 for clusterIndices
clusterIndicesSize *= 2;
}
const int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(uint8_t);
const int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(uint16_t);
// Normals and tangents are interleaved
const int normalsOffset = 0;
@ -759,7 +760,7 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
if (clusterWeightsSize) {
mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT,
model::BufferView(attribBuffer, clusterWeightsOffset, clusterWeightsSize,
gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::XYZW)));
gpu::Element(gpu::VEC4, gpu::NUINT16, gpu::XYZW)));
}

View file

@ -63,12 +63,17 @@ namespace gl {
}
*/
qCWarning(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
qCCritical(glLogging) << "GLShader::compileShader - failed to compile the gl shader object:";
int lineNumber = 0;
for (auto s : srcstr) {
qCWarning(glLogging) << s;
QString str(s);
QStringList lines = str.split("\n");
for (auto& line : lines) {
qCCritical(glLogging).noquote() << QString("%1: %2").arg(lineNumber++, 5, 10, QChar('0')).arg(line);
}
}
qCWarning(glLogging) << "GLShader::compileShader - errors:";
qCWarning(glLogging) << temp;
qCCritical(glLogging) << "GLShader::compileShader - errors:";
qCCritical(glLogging) << temp;
error = std::string(temp);
delete[] temp;

View file

@ -20,16 +20,16 @@ using namespace render;
CauterizedMeshPartPayload::CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform)
: ModelMeshPartPayload(model, meshIndex, partIndex, shapeIndex, transform, offsetTransform) {}
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices, const std::vector<glm::mat4>& cauterizedClusterMatrices) {
ModelMeshPartPayload::updateClusterBuffer(clusterMatrices);
void CauterizedMeshPartPayload::updateClusterBuffer(const std::vector<TransformType>& clusterTransforms, const std::vector<TransformType>& cauterizedClusterTransforms) {
ModelMeshPartPayload::updateClusterBuffer(clusterTransforms);
if (cauterizedClusterMatrices.size() > 1) {
if (cauterizedClusterTransforms.size() > 1) {
if (!_cauterizedClusterBuffer) {
_cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterMatrices.size() * sizeof(glm::mat4),
(const gpu::Byte*) cauterizedClusterMatrices.data());
_cauterizedClusterBuffer = std::make_shared<gpu::Buffer>(cauterizedClusterTransforms.size() * sizeof(TransformType),
(const gpu::Byte*) cauterizedClusterTransforms.data());
} else {
_cauterizedClusterBuffer->setSubData(0, cauterizedClusterMatrices.size() * sizeof(glm::mat4),
(const gpu::Byte*) cauterizedClusterMatrices.data());
_cauterizedClusterBuffer->setSubData(0, cauterizedClusterTransforms.size() * sizeof(TransformType),
(const gpu::Byte*) cauterizedClusterTransforms.data());
}
}
}

View file

@ -15,7 +15,13 @@ class CauterizedMeshPartPayload : public ModelMeshPartPayload {
public:
CauterizedMeshPartPayload(ModelPointer model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices, const std::vector<glm::mat4>& cauterizedClusterMatrices);
#if defined(SKIN_DQ)
using TransformType = Model::TransformDualQuaternion;
#else
using TransformType = glm::mat4;
#endif
void updateClusterBuffer(const std::vector<TransformType>& clusterTransforms, const std::vector<TransformType>& cauterizedClusterTransforms);
void updateTransformForCauterizedMesh(const Transform& renderTransform);

View file

@ -9,13 +9,13 @@
#include "CauterizedModel.h"
#include <PerfStat.h>
#include <DualQuaternion.h>
#include "AbstractViewStateInterface.h"
#include "MeshPartPayload.h"
#include "CauterizedMeshPartPayload.h"
#include "RenderUtilsLogging.h"
CauterizedModel::CauterizedModel(QObject* parent) :
Model(parent) {
}
@ -35,7 +35,7 @@ bool CauterizedModel::updateGeometry() {
const FBXGeometry& fbxGeometry = getFBXGeometry();
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
Model::MeshState state;
state.clusterMatrices.resize(mesh.clusters.size());
state.clusterTransforms.resize(mesh.clusters.size());
_cauterizeMeshStates.append(state);
}
}
@ -109,30 +109,52 @@ void CauterizedModel::updateClusterMatrices() {
const FBXMesh& mesh = geometry.meshes.at(i);
for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j);
#if defined(SKIN_DQ)
auto jointPose = _rig.getJointPose(cluster.jointIndex);
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
Transform clusterTransform;
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
#else
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
#endif
}
}
// as an optimization, don't build cautrizedClusterMatrices if the boneSet is empty.
if (!_cauterizeBoneSet.empty()) {
#if defined(SKIN_DQ)
AnimPose cauterizePose = _rig.getJointPose(geometry.neckJointIndex);
cauterizePose.scale() = glm::vec3(0.0001f, 0.0001f, 0.0001f);
#else
static const glm::mat4 zeroScale(
glm::vec4(0.0f, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0001f, 0.0f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0001f, 0.0f, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0001f, 0.0f),
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
auto cauterizeMatrix = _rig.getJointTransform(geometry.neckJointIndex) * zeroScale;
#endif
for (int i = 0; i < _cauterizeMeshStates.size(); i++) {
Model::MeshState& state = _cauterizeMeshStates[i];
const FBXMesh& mesh = geometry.meshes.at(i);
for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j);
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
if (_cauterizeBoneSet.find(cluster.jointIndex) != _cauterizeBoneSet.end()) {
jointMatrix = cauterizeMatrix;
if (_cauterizeBoneSet.find(cluster.jointIndex) == _cauterizeBoneSet.end()) {
// not cauterized so just copy the value from the non-cauterized version.
state.clusterTransforms[j] = _meshStates[i].clusterTransforms[j];
} else {
#if defined(SKIN_DQ)
Transform jointTransform(cauterizePose.rot(), cauterizePose.scale(), cauterizePose.trans());
Transform clusterTransform;
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
#else
glm_mat4u_mul(cauterizeMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
#endif
}
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
}
}
}
@ -189,24 +211,38 @@ void CauterizedModel::updateRenderItems() {
auto itemID = self->_modelMeshRenderItemIDs[i];
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices);
auto clusterMatricesCauterized(self->getCauterizeMeshState(meshIndex).clusterMatrices);
auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms);
auto clusterTransformsCauterized(self->getCauterizeMeshState(meshIndex).clusterTransforms);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, clusterMatrices, clusterMatricesCauterized, invalidatePayloadShapeKey,
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, clusterTransforms, clusterTransformsCauterized, invalidatePayloadShapeKey,
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, enableCauterization](CauterizedMeshPartPayload& data) {
data.updateClusterBuffer(clusterMatrices, clusterMatricesCauterized);
data.updateClusterBuffer(clusterTransforms, clusterTransformsCauterized);
Transform renderTransform = modelTransform;
if (clusterMatrices.size() == 1) {
renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0]));
if (clusterTransforms.size() == 1) {
#if defined(SKIN_DQ)
Transform transform(clusterTransforms[0].getRotation(),
clusterTransforms[0].getScale(),
clusterTransforms[0].getTranslation());
renderTransform = modelTransform.worldTransform(transform);
#else
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0]));
#endif
}
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
renderTransform = modelTransform;
if (clusterMatricesCauterized.size() == 1) {
renderTransform = modelTransform.worldTransform(Transform(clusterMatricesCauterized[0]));
if (clusterTransformsCauterized.size() == 1) {
#if defined(SKIN_DQ)
Transform transform(clusterTransforms[0].getRotation(),
clusterTransforms[0].getScale(),
clusterTransforms[0].getTranslation());
renderTransform = modelTransform.worldTransform(Transform(transform));
#else
renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0]));
#endif
}
data.updateTransformForCauterizedMesh(renderTransform);

View file

@ -46,6 +46,15 @@ struct DeferredFragment {
float depthVal;
};
<@if not GETFRESNEL0@>
<@def GETFRESNEL0@>
vec3 getFresnelF0(float metallic, vec3 metalF0) {
// Enable continuous metallness value by lerping between dielectric
// and metal fresnel F0 value based on the "metallic" parameter
return mix(vec3(0.03), metalF0, metallic);
}
<@endif@>
DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) {
vec4 normalVal;
vec4 diffuseVal;
@ -73,13 +82,7 @@ DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) {
frag.scattering = specularVal.x;
}
if (frag.metallic <= 0.5) {
frag.metallic = 0.0;
frag.fresnel = vec3(0.03); // Default Di-electric fresnel value
} else {
frag.fresnel = vec3(diffuseVal.xyz);
frag.metallic = 1.0;
}
frag.fresnel = getFresnelF0(frag.metallic, diffuseVal.xyz);
return frag;
}
@ -106,14 +109,7 @@ DeferredFragment unpackDeferredFragmentNoPositionNoAmbient(vec2 texcoord) {
//frag.emissive = specularVal.xyz;
frag.obscurance = 1.0;
if (frag.metallic <= 0.5) {
frag.metallic = 0.0;
frag.fresnel = vec3(0.03); // Default Di-electric fresnel value
} else {
frag.fresnel = vec3(diffuseVal.xyz);
frag.metallic = 1.0;
}
frag.fresnel = getFresnelF0(frag.metallic, diffuseVal.xyz);
return frag;
}

View file

@ -65,10 +65,12 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness
<$prepareGlobalLight($supportScattering$)$>
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
// Ambient
vec3 ambientDiffuse;
vec3 ambientSpecular;
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, surface, metallic, fresnel, albedo, obscurance
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@> );
@ -79,7 +81,7 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@> );
@ -110,10 +112,12 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
) {
<$prepareGlobalLight($supportScattering$)$>
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
// Ambient
vec3 ambientDiffuse;
vec3 ambientSpecular;
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, surface, metallic, fresnel, albedo, obscurance
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@>
@ -123,7 +127,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
vec3 directionalDiffuse;
vec3 directionalSpecular;
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@>
@ -174,19 +178,21 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur
vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float metallic, vec3 emissive, float roughness, float opacity) {
<$prepareGlobalLight()$>
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
color += emissive * isEmissiveEnabled();
// Ambient
vec3 ambientDiffuse;
vec3 ambientSpecular;
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance);
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, surface, metallic, fresnel, albedo, obscurance);
color += ambientDiffuse;
color += ambientSpecular / opacity;
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation);
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation);
color += directionalDiffuse;
color += directionalSpecular / opacity;
@ -199,19 +205,21 @@ vec3 evalGlobalLightingAlphaBlendedWithHaze(
{
<$prepareGlobalLight()$>
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
color += emissive * isEmissiveEnabled();
// Ambient
vec3 ambientDiffuse;
vec3 ambientSpecular;
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance);
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, surface, metallic, fresnel, albedo, obscurance);
color += ambientDiffuse;
color += ambientSpecular / opacity;
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation);
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation);
color += directionalDiffuse;
color += directionalSpecular / opacity;

View file

@ -65,10 +65,12 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness
<$prepareGlobalLight($supportScattering$)$>
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
// Ambient
vec3 ambientDiffuse;
vec3 ambientSpecular;
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, surface, metallic, fresnel, albedo, obscurance
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@> );
@ -79,7 +81,7 @@ vec3 albedo, vec3 fresnel, float metallic, float roughness
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@> );
@ -109,10 +111,12 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
) {
<$prepareGlobalLight($supportScattering$)$>
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
// Ambient
vec3 ambientDiffuse;
vec3 ambientSpecular;
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, surface, metallic, fresnel, albedo, obscurance
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@>
@ -124,7 +128,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, float obscu
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@>
@ -173,19 +177,21 @@ vec3 evalLightmappedColor(mat4 invViewMat, float shadowAttenuation, float obscur
vec3 evalGlobalLightingAlphaBlended(mat4 invViewMat, float shadowAttenuation, float obscurance, vec3 position, vec3 normal, vec3 albedo, vec3 fresnel, float metallic, vec3 emissive, float roughness, float opacity) {
<$prepareGlobalLight()$>
SurfaceData surface = initSurfaceData(roughness, fragNormal, fragEyeDir);
color += emissive * isEmissiveEnabled();
// Ambient
vec3 ambientDiffuse;
vec3 ambientSpecular;
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, obscurance);
evalLightingAmbient(ambientDiffuse, ambientSpecular, lightAmbient, surface, metallic, fresnel, albedo, obscurance);
color += ambientDiffuse;
color += ambientSpecular / opacity;
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation);
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation);
color += directionalDiffuse;
color += directionalSpecular / opacity;

View file

@ -16,22 +16,27 @@ uniform samplerCube skyboxMap;
vec4 evalSkyboxLight(vec3 direction, float lod) {
// textureQueryLevels is not available until #430, so we require explicit lod
// float mipmapLevel = lod * textureQueryLevels(skyboxMap);
float filterLod = textureQueryLod(skyboxMap, direction).x;
// Keep texture filtering LOD as limit to prevent aliasing on specular reflection
lod = max(lod, filterLod);
return textureLod(skyboxMap, direction, lod);
}
<@endfunc@>
<@func declareEvalAmbientSpecularIrradiance(supportAmbientSphere, supportAmbientMap, supportIfAmbientMapElseAmbientSphere)@>
vec3 fresnelSchlickAmbient(vec3 fresnelColor, vec3 lightDir, vec3 halfDir, float gloss) {
return fresnelColor + (max(vec3(gloss), fresnelColor) - fresnelColor) * pow(1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0), 5.0);
vec3 fresnelSchlickAmbient(vec3 fresnelColor, float ndotd, float gloss) {
float f = pow(1.0 - ndotd, 5.0);
return fresnelColor + (max(vec3(gloss), fresnelColor) - fresnelColor) * f;
// return fresnelColor + (vec3(1.0) - fresnelColor) * f;
}
<@if supportAmbientMap@>
<$declareSkyboxMap()$>
<@endif@>
vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, vec3 fragEyeDir, vec3 fragNormal, float roughness) {
vec3 direction = -reflect(fragEyeDir, fragNormal);
vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, SurfaceData surface) {
vec3 lightDir = -reflect(surface.eyeDir, surface.normal);
vec3 specularLight;
<@if supportIfAmbientMapElseAmbientSphere@>
if (getLightHasAmbientMap(ambient))
@ -39,8 +44,10 @@ vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, vec3 fragEyeDir, vec3 f
<@if supportAmbientMap@>
{
float levels = getLightAmbientMapNumMips(ambient);
float lod = min(((roughness)* levels), levels);
specularLight = evalSkyboxLight(direction, lod).xyz;
float m = 12.0 / (1.0+11.0*surface.roughness);
float lod = levels - m;
lod = max(lod, 0);
specularLight = evalSkyboxLight(lightDir, lod).xyz;
}
<@endif@>
<@if supportIfAmbientMapElseAmbientSphere@>
@ -48,11 +55,11 @@ vec3 evalAmbientSpecularIrradiance(LightAmbient ambient, vec3 fragEyeDir, vec3 f
<@endif@>
<@if supportAmbientSphere@>
{
specularLight = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), direction).xyz;
specularLight = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), lightDir).xyz;
}
<@endif@>
return specularLight;
return specularLight;
}
<@endfunc@>
@ -66,21 +73,21 @@ float curvatureAO(in float k) {
}
<@endif@>
void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambient, vec3 eyeDir, vec3 normal,
float roughness, float metallic, vec3 fresnel, vec3 albedo, float obscurance
void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambient, SurfaceData surface,
float metallic, vec3 fresnelF0, vec3 albedo, float obscurance
<@if supportScattering@>
, float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature
<@endif@>
) {
// Fresnel
vec3 ambientFresnel = fresnelSchlickAmbient(fresnel, eyeDir, normal, 1.0 - roughness);
vec3 ambientFresnel = fresnelSchlickAmbient(fresnelF0, surface.ndotv, 1.0-surface.roughness);
// Diffuse from ambient
diffuse = (1.0 - metallic) * (vec3(1.0) - ambientFresnel) * sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), normal).xyz;
diffuse = (1.0 - metallic) * (vec3(1.0) - ambientFresnel) * sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), surface.normal).xyz;
// Specular highlight from ambient
specular = evalAmbientSpecularIrradiance(ambient, eyeDir, normal, roughness) * ambientFresnel;
specular = evalAmbientSpecularIrradiance(ambient, surface) * ambientFresnel;
<@if supportScattering@>
if (scattering * isScatteringEnabled() > 0.0) {
@ -92,7 +99,7 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie
// Diffuse from ambient
diffuse = sphericalHarmonics_evalSphericalLight(getLightAmbientSphere(ambient), lowNormalCurvature.xyz).xyz;
diffuse /= 3.1415926;
specular = vec3(0.0);
}
<@endif@>
@ -107,8 +114,9 @@ void evalLightingAmbient(out vec3 diffuse, out vec3 specular, LightAmbient ambie
diffuse *= albedo;
}
diffuse *= lightEnergy * isDiffuseEnabled() * isAmbientEnabled();
specular *= lightEnergy * isSpecularEnabled() * isAmbientEnabled();
lightEnergy *= isAmbientEnabled();
diffuse *= lightEnergy * isDiffuseEnabled();
specular *= lightEnergy * isSpecularEnabled();
}
<@endfunc@>

View file

@ -12,7 +12,7 @@
<@func declareLightingDirectional(supportScattering)@>
void evalLightingDirectional(out vec3 diffuse, out vec3 specular, vec3 lightDir, vec3 lightIrradiance,
vec3 eyeDir, vec3 normal, float roughness,
SurfaceData surface,
float metallic, vec3 fresnel, vec3 albedo, float shadow
<@if supportScattering@>
, float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature
@ -22,14 +22,17 @@ void evalLightingDirectional(out vec3 diffuse, out vec3 specular, vec3 lightDir,
// Attenuation
vec3 lightEnergy = shadow * lightIrradiance;
evalFragShading(diffuse, specular, normal, -lightDir, eyeDir, metallic, fresnel, roughness, albedo
updateSurfaceDataWithLight(surface, -lightDir);
evalFragShading(diffuse, specular, metallic, fresnel, surface, albedo
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@>
);
diffuse *= lightEnergy * isDiffuseEnabled() * isDirectionalEnabled();
specular *= lightEnergy * isSpecularEnabled() * isDirectionalEnabled();
lightEnergy *= isDirectionalEnabled();
diffuse *= lightEnergy * isDiffuseEnabled();
specular *= lightEnergy * isSpecularEnabled();
}
<@endfunc@>

View file

@ -12,7 +12,7 @@
<@func declareLightingPoint(supportScattering)@>
void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light,
vec4 fragLightDirLen, vec3 fragEyeDir, vec3 normal, float roughness,
vec4 fragLightDirLen, SurfaceData surface,
float metallic, vec3 fresnel, vec3 albedo, float shadow
<@if supportScattering@>
, float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature
@ -23,19 +23,22 @@ void evalLightingPoint(out vec3 diffuse, out vec3 specular, Light light,
float fragLightDistance = fragLightDirLen.w;
vec3 fragLightDir = fragLightDirLen.xyz;
updateSurfaceDataWithLight(surface, fragLightDir);
// Eval attenuation
float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance);
vec3 lightEnergy = radialAttenuation * shadow * getLightIrradiance(light);
// Eval shading
evalFragShading(diffuse, specular, normal, fragLightDir, fragEyeDir, metallic, fresnel, roughness, albedo
evalFragShading(diffuse, specular, metallic, fresnel, surface, albedo
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@>
);
diffuse *= lightEnergy * isDiffuseEnabled() * isPointEnabled();
specular *= lightEnergy * isSpecularEnabled() * isPointEnabled();
lightEnergy *= isPointEnabled();
diffuse *= lightEnergy * isDiffuseEnabled();
specular *= lightEnergy * isSpecularEnabled();
if (isShowLightContour() > 0.0) {
// Show edge

View file

@ -12,7 +12,7 @@
<@func declareLightingSpot(supportScattering)@>
void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light,
vec4 fragLightDirLen, float cosSpotAngle, vec3 fragEyeDir, vec3 normal, float roughness,
vec4 fragLightDirLen, float cosSpotAngle, SurfaceData surface,
float metallic, vec3 fresnel, vec3 albedo, float shadow
<@if supportScattering@>
, float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature
@ -23,6 +23,7 @@ void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light,
float fragLightDistance = fragLightDirLen.w;
vec3 fragLightDir = fragLightDirLen.xyz;
updateSurfaceDataWithLight(surface, fragLightDir);
// Eval attenuation
float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance);
@ -30,14 +31,15 @@ void evalLightingSpot(out vec3 diffuse, out vec3 specular, Light light,
vec3 lightEnergy = angularAttenuation * radialAttenuation * shadow *getLightIrradiance(light);
// Eval shading
evalFragShading(diffuse, specular, normal, fragLightDir, fragEyeDir, metallic, fresnel, roughness, albedo
evalFragShading(diffuse, specular, metallic, fresnel, surface, albedo
<@if supportScattering@>
,scattering, midNormalCurvature, lowNormalCurvature
<@endif@>
);
diffuse *= lightEnergy * isDiffuseEnabled() * isSpotEnabled();
specular *= lightEnergy * isSpecularEnabled() * isSpotEnabled();
lightEnergy *= isSpotEnabled();
diffuse *= lightEnergy * isDiffuseEnabled();
specular *= lightEnergy * isSpecularEnabled();
if (isShowLightContour() > 0.0) {
// Show edges

View file

@ -77,6 +77,30 @@ float isWireframeEnabled() {
<@endfunc@>
<$declareLightingModel()$>
struct SurfaceData {
vec3 normal;
vec3 eyeDir;
vec3 lightDir;
vec3 halfDir;
float roughness;
float roughness2;
float roughness4;
float ndotv;
float ndotl;
float ndoth;
float ldoth;
float smithInvG1NdotV;
};
<@if not GETFRESNEL0@>
<@def GETFRESNEL0@>
vec3 getFresnelF0(float metallic, vec3 metalF0) {
// Enable continuous metallness value by lerping between dielectric
// and metal fresnel F0 value based on the "metallic" parameter
return mix(vec3(0.03), metalF0, metallic);
}
<@endif@>
<@func declareBeckmannSpecular()@>
uniform sampler2D scatteringSpecularBeckmann;
@ -85,17 +109,13 @@ float fetchSpecularBeckmann(float ndoth, float roughness) {
return pow(2.0 * texture(scatteringSpecularBeckmann, vec2(ndoth, roughness)).r, 10.0);
}
vec2 skinSpecular(vec3 N, vec3 L, vec3 V, float roughness, float intensity) {
vec2 skinSpecular(SurfaceData surface, float intensity) {
vec2 result = vec2(0.0, 1.0);
float ndotl = dot(N, L);
if (ndotl > 0.0) {
vec3 h = L + V;
vec3 H = normalize(h);
float ndoth = dot(N, H);
float PH = fetchSpecularBeckmann(ndoth, roughness);
float F = fresnelSchlickScalar(0.028, H, V);
float frSpec = max(PH * F / dot(h, h), 0.0);
result.x = ndotl * intensity * frSpec;
if (surface.ndotl > 0.0) {
float PH = fetchSpecularBeckmann(surface.ndoth, surface.roughness);
float F = fresnelSchlickScalar(0.028, surface);
float frSpec = max(PH * F / dot(surface.halfDir, surface.halfDir), 0.0);
result.x = surface.ndotl * intensity * frSpec;
result.y -= F;
}
@ -105,117 +125,136 @@ vec2 skinSpecular(vec3 N, vec3 L, vec3 V, float roughness, float intensity) {
<@func declareEvalPBRShading()@>
vec3 fresnelSchlickColor(vec3 fresnelColor, vec3 lightDir, vec3 halfDir) {
float base = 1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0);
float evalSmithInvG1(float roughness4, float ndotd) {
return ndotd + sqrt(roughness4+ndotd*ndotd*(1.0-roughness4));
}
SurfaceData initSurfaceData(float roughness, vec3 normal, vec3 eyeDir) {
SurfaceData surface;
surface.eyeDir = eyeDir;
surface.normal = normal;
surface.roughness = mix(0.001, 1.0, roughness);
surface.roughness2 = surface.roughness * surface.roughness;
surface.roughness4 = surface.roughness2 * surface.roughness2;
surface.ndotv = clamp(dot(normal, eyeDir), 0.0, 1.0);
surface.smithInvG1NdotV = evalSmithInvG1(surface.roughness4, surface.ndotv);
// These values will be set when we know the light direction, in updateSurfaceDataWithLight
surface.ndoth = 0.0;
surface.ndotl = 0.0;
surface.ldoth = 0.0;
surface.lightDir = vec3(0,0,1);
surface.halfDir = vec3(0,0,1);
return surface;
}
void updateSurfaceDataWithLight(inout SurfaceData surface, vec3 lightDir) {
surface.lightDir = lightDir;
surface.halfDir = normalize(surface.eyeDir + lightDir);
vec3 dots;
dots.x = dot(surface.normal, surface.halfDir);
dots.y = dot(surface.normal, surface.lightDir);
dots.z = dot(surface.halfDir, surface.lightDir);
dots = clamp(dots, vec3(0), vec3(1));
surface.ndoth = dots.x;
surface.ndotl = dots.y;
surface.ldoth = dots.z;
}
vec3 fresnelSchlickColor(vec3 fresnelColor, SurfaceData surface) {
float base = 1.0 - surface.ldoth;
//float exponential = pow(base, 5.0);
float base2 = base * base;
float exponential = base * base2 * base2;
return vec3(exponential) + fresnelColor * (1.0 - exponential);
}
float fresnelSchlickScalar(float fresnelScalar, vec3 lightDir, vec3 halfDir) {
float base = 1.0 - clamp(dot(lightDir, halfDir), 0.0, 1.0);
float fresnelSchlickScalar(float fresnelScalar, SurfaceData surface) {
float base = 1.0 - surface.ldoth;
//float exponential = pow(base, 5.0);
float base2 = base * base;
float exponential = base * base2 * base2;
return (exponential) + fresnelScalar * (1.0 - exponential);
}
float specularDistribution(float roughness, vec3 normal, vec3 halfDir) {
float ndoth = clamp(dot(halfDir, normal), 0.0, 1.0);
// float gloss2 = pow(0.001 + roughness, 4);
float gloss2 = (0.001 + roughness);
gloss2 *= gloss2; // pow 2
gloss2 *= gloss2; // pow 4
float denom = (ndoth * ndoth*(gloss2 - 1.0) + 1.0);
float power = gloss2 / (3.14159 * denom * denom);
float specularDistribution(SurfaceData surface) {
// See https://www.khronos.org/assets/uploads/developers/library/2017-web3d/glTF-2.0-Launch_Jun17.pdf
// for details of equations, especially page 20
float denom = (surface.ndoth*surface.ndoth * (surface.roughness2 - 1.0) + 1.0);
denom *= denom;
// Add geometric factors G1(n,l) and G1(n,v)
float smithInvG1NdotL = evalSmithInvG1(surface.roughness4, surface.ndotl);
denom *= surface.smithInvG1NdotV * smithInvG1NdotL;
// Don't divide by PI as it will be done later
float power = surface.roughness4 / denom;
return power;
}
float specularDistributionGloss(float gloss2, vec3 normal, vec3 halfDir) {
float ndoth = clamp(dot(halfDir, normal), 0.0, 1.0);
// float gloss2 = pow(0.001 + roughness, 4);
float denom = (ndoth * ndoth*(gloss2 - 1.0) + 1.0);
float power = gloss2 / (3.14159 * denom * denom);
return power;
}
<! //NOTE: ANother implementation for specularDistribution
float specularDistribution(float roughness, vec3 normal, vec3 halfDir) {
float gloss = exp2(10 * (1.0 - roughness) + 1);
float power = pow(clamp(dot(halfDir, normal), 0.0, 1.0), gloss);
power *= (gloss * 0.125 + 0.25);
return power;
}
!>
// Frag Shading returns the diffuse amount as W and the specular rgb as xyz
vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float roughness) {
// Diffuse Lighting
float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0);
// Specular Lighting
vec3 halfDir = normalize(fragEyeDir + fragLightDir);
vec3 fresnelColor = fresnelSchlickColor(fresnel, fragLightDir, halfDir);
float power = specularDistribution(roughness, fragNormal, halfDir);
vec3 specular = fresnelColor * power * diffuse;
return vec4(specular, (1.0 - metallic) * diffuse * (1.0 - fresnelColor.x));
}
// Frag Shading returns the diffuse amount as W and the specular rgb as xyz
vec4 evalPBRShadingDielectric(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float roughness, float fresnel) {
// Diffuse Lighting
float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0);
vec4 evalPBRShading(float metallic, vec3 fresnel, SurfaceData surface) {
// Incident angle attenuation
float angleAttenuation = surface.ndotl;
// Specular Lighting
vec3 halfDir = normalize(fragEyeDir + fragLightDir);
float fresnelScalar = fresnelSchlickScalar(fresnel, fragLightDir, halfDir);
float power = specularDistribution(roughness, fragNormal, halfDir);
vec3 specular = vec3(fresnelScalar) * power * diffuse;
vec3 fresnelColor = fresnelSchlickColor(fresnel, surface);
float power = specularDistribution(surface);
vec3 specular = fresnelColor * power * angleAttenuation;
float diffuse = (1.0 - metallic) * angleAttenuation * (1.0 - fresnelColor.x);
return vec4(specular, diffuse * (1.0 - fresnelScalar));
diffuse /= 3.1415926;
// Diffuse is divided by PI but specular isn't because an infinitesimal volume light source
// has a multiplier of PI, says Naty Hoffman.
// (see http://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf
// page 23 paragraph "Punctual light sources")
return vec4(specular, diffuse);
}
vec4 evalPBRShadingMetallic(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float roughness, vec3 fresnel) {
// Diffuse Lighting
float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0);
// Frag Shading returns the diffuse amount as W and the specular rgb as xyz
vec4 evalPBRShadingDielectric(SurfaceData surface, float fresnel) {
// Incident angle attenuation
float angleAttenuation = surface.ndotl;
// Specular Lighting
vec3 halfDir = normalize(fragEyeDir + fragLightDir);
vec3 fresnelColor = fresnelSchlickColor(fresnel, fragLightDir, halfDir);
float power = specularDistribution(roughness, fragNormal, halfDir);
vec3 specular = fresnelColor * power * diffuse;
float fresnelScalar = fresnelSchlickScalar(fresnel, surface);
float power = specularDistribution(surface);
vec3 specular = vec3(fresnelScalar) * power * angleAttenuation;
float diffuse = angleAttenuation * (1.0 - fresnelScalar);
diffuse /= 3.1415926;
// Diffuse is divided by PI but specular isn't because an infinitesimal volume light source
// has a multiplier of PI, says Naty Hoffman.
// (see http://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf
// page 23 paragraph "Punctual light sources")
return vec4(specular, diffuse);
}
vec4 evalPBRShadingMetallic(SurfaceData surface, vec3 fresnel) {
// Incident angle attenuation
float angleAttenuation = surface.ndotl;
// Specular Lighting
vec3 fresnelColor = fresnelSchlickColor(fresnel, surface);
float power = specularDistribution(surface);
vec3 specular = fresnelColor * power * angleAttenuation;
// Specular isn't divided by PI because an infinitesimal volume light source
// has a multiplier of PI, says Naty Hoffman.
// (see http://blog.selfshadow.com/publications/s2013-shading-course/hoffman/s2013_pbs_physics_math_notes.pdf
// page 23 paragraph "Punctual light sources")
return vec4(specular, 0.f);
}
// Frag Shading returns the diffuse amount as W and the specular rgb as xyz
vec4 evalPBRShadingGloss(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float gloss2) {
// Diffuse Lighting
float diffuse = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0);
// Specular Lighting
vec3 halfDir = normalize(fragEyeDir + fragLightDir);
vec3 fresnelColor = fresnelSchlickColor(fresnel, fragLightDir, halfDir);
float power = specularDistributionGloss(gloss2, fragNormal, halfDir);
vec3 specular = fresnelColor * power * diffuse;
return vec4(specular, (1.0 - metallic) * diffuse * (1.0 - fresnelColor.x));
}
<@endfunc@>
<$declareEvalPBRShading()$>
// Return xyz the specular/reflection component and w the diffuse component
//vec4 evalFragShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, float metallic, vec3 fresnel, float roughness) {
// return evalPBRShading(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, roughness);
//}
void evalFragShading(out vec3 diffuse, out vec3 specular,
vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir,
float metallic, vec3 fresnel, float roughness, vec3 albedo) {
vec4 shading = evalPBRShading(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, roughness);
float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo) {
vec4 shading = evalPBRShading(metallic, fresnel, surface);
diffuse = vec3(shading.w);
if (isAlbedoEnabled() > 0.0) {
diffuse *= albedo;
@ -229,22 +268,19 @@ void evalFragShading(out vec3 diffuse, out vec3 specular,
void evalFragShading(out vec3 diffuse, out vec3 specular,
vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir,
float metallic, vec3 fresnel, float roughness, vec3 albedo,
float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo,
float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature) {
if (scattering * isScatteringEnabled() > 0.0) {
vec3 brdf = evalSkinBRDF(fragLightDir, fragNormal, midNormalCurvature.xyz, lowNormalCurvature.xyz, lowNormalCurvature.w);
float NdotL = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0);
diffuse = mix(vec3(NdotL), brdf, scattering);
vec3 brdf = evalSkinBRDF(surface.lightDir, surface.normal, midNormalCurvature.xyz, lowNormalCurvature.xyz, lowNormalCurvature.w);
diffuse = mix(vec3(surface.ndotl), brdf, scattering);
// Specular Lighting
vec3 halfDir = normalize(fragEyeDir + fragLightDir);
vec2 specularBrdf = skinSpecular(fragNormal, fragLightDir, fragEyeDir, roughness, 1.0);
vec2 specularBrdf = skinSpecular(surface, 1.0);
diffuse *= specularBrdf.y;
specular = vec3(specularBrdf.x);
} else {
vec4 shading = evalPBRShadingGloss(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, roughness);
vec4 shading = evalPBRShading(metallic, fresnel, surface);
diffuse = vec3(shading.w);
specular = shading.xyz;
}
@ -253,17 +289,15 @@ void evalFragShading(out vec3 diffuse, out vec3 specular,
void evalFragShadingScattering(out vec3 diffuse, out vec3 specular,
vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir,
float metallic, vec3 fresnel, float roughness, vec3 albedo
float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo
,float scattering, vec4 midNormalCurvature, vec4 lowNormalCurvature
) {
vec3 brdf = evalSkinBRDF(fragLightDir, fragNormal, midNormalCurvature.xyz, lowNormalCurvature.xyz, lowNormalCurvature.w);
float NdotL = clamp(dot(fragNormal, fragLightDir), 0.0, 1.0);
vec3 brdf = evalSkinBRDF(surface.lightDir, surface.normal, midNormalCurvature.xyz, lowNormalCurvature.xyz, lowNormalCurvature.w);
float NdotL = surface.ndotl;
diffuse = mix(vec3(NdotL), brdf, scattering);
// Specular Lighting
vec3 halfDir = normalize(fragEyeDir + fragLightDir);
vec2 specularBrdf = skinSpecular(fragNormal, fragLightDir, fragEyeDir, roughness, 1.0);
vec2 specularBrdf = skinSpecular(surface, 1.0);
diffuse *= specularBrdf.y;
specular = vec3(specularBrdf.x);
@ -271,10 +305,9 @@ void evalFragShadingScattering(out vec3 diffuse, out vec3 specular,
}
void evalFragShadingGloss(out vec3 diffuse, out vec3 specular,
vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir,
float metallic, vec3 fresnel, float gloss, vec3 albedo
float metallic, vec3 fresnel, SurfaceData surface, vec3 albedo
) {
vec4 shading = evalPBRShadingGloss(fragNormal, fragLightDir, fragEyeDir, metallic, fresnel, gloss);
vec4 shading = evalPBRShading(metallic, fresnel, surface);
diffuse = vec3(shading.w);
diffuse *= mix(vec3(1.0), albedo, isAlbedoEnabled());
specular = shading.xyz;

View file

@ -12,6 +12,7 @@
#include "MeshPartPayload.h"
#include <PerfStat.h>
#include <DualQuaternion.h>
#include "DeferredLightingEffect.h"
@ -325,12 +326,20 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in
const Model::MeshState& state = model->getMeshState(_meshIndex);
updateMeshPart(modelMesh, partIndex);
computeAdjustedLocalBound(state.clusterMatrices);
computeAdjustedLocalBound(state.clusterTransforms);
updateTransform(transform, offsetTransform);
Transform renderTransform = transform;
if (state.clusterMatrices.size() == 1) {
renderTransform = transform.worldTransform(Transform(state.clusterMatrices[0]));
if (state.clusterTransforms.size() == 1) {
#if defined(SKIN_DQ)
Transform transform(state.clusterTransforms[0].getRotation(),
state.clusterTransforms[0].getScale(),
state.clusterTransforms[0].getTranslation());
renderTransform = transform.worldTransform(Transform(transform));
#else
renderTransform = transform.worldTransform(Transform(state.clusterTransforms[0]));
#endif
}
updateTransformForSkinnedMesh(renderTransform, transform);
@ -360,17 +369,16 @@ void ModelMeshPartPayload::notifyLocationChanged() {
}
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices) {
void ModelMeshPartPayload::updateClusterBuffer(const std::vector<TransformType>& clusterTransforms) {
// Once computed the cluster matrices, update the buffer(s)
if (clusterMatrices.size() > 1) {
if (clusterTransforms.size() > 1) {
if (!_clusterBuffer) {
_clusterBuffer = std::make_shared<gpu::Buffer>(clusterMatrices.size() * sizeof(glm::mat4),
(const gpu::Byte*) clusterMatrices.data());
_clusterBuffer = std::make_shared<gpu::Buffer>(clusterTransforms.size() * sizeof(TransformType),
(const gpu::Byte*) clusterTransforms.data());
}
else {
_clusterBuffer->setSubData(0, clusterMatrices.size() * sizeof(glm::mat4),
(const gpu::Byte*) clusterMatrices.data());
_clusterBuffer->setSubData(0, clusterTransforms.size() * sizeof(TransformType),
(const gpu::Byte*) clusterTransforms.data());
}
}
}
@ -530,13 +538,29 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
}
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices) {
void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector<TransformType>& clusterTransforms) {
_adjustedLocalBound = _localBound;
if (clusterMatrices.size() > 0) {
_adjustedLocalBound.transform(clusterMatrices[0]);
for (int i = 1; i < (int)clusterMatrices.size(); ++i) {
if (clusterTransforms.size() > 0) {
#if defined(SKIN_DQ)
Transform rootTransform(clusterTransforms[0].getRotation(),
clusterTransforms[0].getScale(),
clusterTransforms[0].getTranslation());
_adjustedLocalBound.transform(rootTransform);
#else
_adjustedLocalBound.transform(clusterTransforms[0]);
#endif
for (int i = 1; i < (int)clusterTransforms.size(); ++i) {
AABox clusterBound = _localBound;
clusterBound.transform(clusterMatrices[i]);
#if defined(SKIN_DQ)
Transform transform(clusterTransforms[i].getRotation(),
clusterTransforms[i].getScale(),
clusterTransforms[i].getTranslation());
clusterBound.transform(transform);
#else
clusterBound.transform(clusterTransforms[i]);
#endif
_adjustedLocalBound += clusterBound;
}
}

View file

@ -87,7 +87,14 @@ public:
typedef Payload::DataPointer Pointer;
void notifyLocationChanged() override;
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices);
#if defined(SKIN_DQ)
using TransformType = Model::TransformDualQuaternion;
#else
using TransformType = glm::mat4;
#endif
void updateClusterBuffer(const std::vector<TransformType>& clusterTransforms);
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
// Render Item interface
@ -104,7 +111,7 @@ public:
void bindMesh(gpu::Batch& batch) override;
void bindTransform(gpu::Batch& batch, const render::ShapePipeline::LocationsPointer locations, RenderArgs::RenderMode renderMode) const override;
void computeAdjustedLocalBound(const std::vector<glm::mat4>& clusterMatrices);
void computeAdjustedLocalBound(const std::vector<TransformType>& clusterTransforms);
gpu::BufferPointer _clusterBuffer;

View file

@ -27,6 +27,7 @@
#include <TBBHelpers.h>
#include <model-networking/SimpleMeshProxy.h>
#include <DualQuaternion.h>
#include <glm/gtc/packing.hpp>
@ -269,16 +270,24 @@ void Model::updateRenderItems() {
auto itemID = self->_modelMeshRenderItemIDs[i];
auto meshIndex = self->_modelMeshRenderItemShapes[i].meshIndex;
auto clusterMatrices(self->getMeshState(meshIndex).clusterMatrices);
auto clusterTransforms(self->getMeshState(meshIndex).clusterTransforms);
bool invalidatePayloadShapeKey = self->shouldInvalidatePayloadShapeKey(meshIndex);
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterMatrices, invalidatePayloadShapeKey,
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, clusterTransforms, invalidatePayloadShapeKey,
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD](ModelMeshPartPayload& data) {
data.updateClusterBuffer(clusterMatrices);
data.updateClusterBuffer(clusterTransforms);
Transform renderTransform = modelTransform;
if (clusterMatrices.size() == 1) {
renderTransform = modelTransform.worldTransform(Transform(clusterMatrices[0]));
if (clusterTransforms.size() == 1) {
#if defined(SKIN_DQ)
Transform transform(clusterTransforms[0].getRotation(),
clusterTransforms[0].getScale(),
clusterTransforms[0].getTranslation());
renderTransform = modelTransform.worldTransform(Transform(transform));
#else
renderTransform = modelTransform.worldTransform(Transform(clusterTransforms[0]));
#endif
}
data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
@ -359,7 +368,7 @@ bool Model::updateGeometry() {
const FBXGeometry& fbxGeometry = getFBXGeometry();
foreach (const FBXMesh& mesh, fbxGeometry.meshes) {
MeshState state;
state.clusterMatrices.resize(mesh.clusters.size());
state.clusterTransforms.resize(mesh.clusters.size());
_meshStates.push_back(state);
// Note: we add empty buffers for meshes that lack blendshapes so we can access the buffers by index
@ -1211,7 +1220,7 @@ void Model::updateRig(float deltaTime, glm::mat4 parentTransform) {
void Model::computeMeshPartLocalBounds() {
for (auto& part : _modelMeshRenderItems) {
const Model::MeshState& state = _meshStates.at(part->_meshIndex);
part->computeAdjustedLocalBound(state.clusterMatrices);
part->computeAdjustedLocalBound(state.clusterTransforms);
}
}
@ -1222,6 +1231,7 @@ void Model::updateClusterMatrices() {
if (!_needsUpdateClusterMatrices || !isLoaded()) {
return;
}
_needsUpdateClusterMatrices = false;
const FBXGeometry& geometry = getFBXGeometry();
for (int i = 0; i < (int) _meshStates.size(); i++) {
@ -1229,8 +1239,16 @@ void Model::updateClusterMatrices() {
const FBXMesh& mesh = geometry.meshes.at(i);
for (int j = 0; j < mesh.clusters.size(); j++) {
const FBXCluster& cluster = mesh.clusters.at(j);
#if defined(SKIN_DQ)
auto jointPose = _rig.getJointPose(cluster.jointIndex);
Transform jointTransform(jointPose.rot(), jointPose.scale(), jointPose.trans());
Transform clusterTransform;
Transform::mult(clusterTransform, jointTransform, cluster.inverseBindTransform);
state.clusterTransforms[j] = Model::TransformDualQuaternion(clusterTransform);
#else
auto jointMatrix = _rig.getJointTransform(cluster.jointIndex);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
#endif
}
}

View file

@ -30,11 +30,15 @@
#include <Transform.h>
#include <SpatiallyNestable.h>
#include <TriangleSet.h>
#include <DualQuaternion.h>
#include "GeometryCache.h"
#include "TextureCache.h"
#include "Rig.h"
// Use dual quaternion skinning!
// Must match define in Skinning.slh
#define SKIN_DQ
class AbstractViewStateInterface;
class QScriptEngine;
@ -246,9 +250,46 @@ public:
int getRenderInfoDrawCalls() const { return _renderInfoDrawCalls; }
bool getRenderInfoHasTransparent() const { return _renderInfoHasTransparent; }
#if defined(SKIN_DQ)
class TransformDualQuaternion {
public:
TransformDualQuaternion() {}
TransformDualQuaternion(const glm::mat4& m) {
AnimPose p(m);
_scale.x = p.scale().x;
_scale.y = p.scale().y;
_scale.z = p.scale().z;
_dq = DualQuaternion(p.rot(), p.trans());
}
TransformDualQuaternion(const glm::vec3& scale, const glm::quat& rot, const glm::vec3& trans) {
_scale.x = scale.x;
_scale.y = scale.y;
_scale.z = scale.z;
_dq = DualQuaternion(rot, trans);
}
TransformDualQuaternion(const Transform& transform) {
_scale = glm::vec4(transform.getScale(), 0.0f);
_dq = DualQuaternion(transform.getRotation(), transform.getTranslation());
}
glm::vec3 getScale() const { return glm::vec3(_scale); }
glm::quat getRotation() const { return _dq.getRotation(); }
glm::vec3 getTranslation() const { return _dq.getTranslation(); }
glm::mat4 getMatrix() const { return createMatFromScaleQuatAndPos(getScale(), getRotation(), getTranslation()); };
protected:
glm::vec4 _scale { 1.0f, 1.0f, 1.0f, 0.0f };
DualQuaternion _dq;
glm::vec4 _padding;
};
#endif
class MeshState {
public:
std::vector<glm::mat4> clusterMatrices;
#if defined(SKIN_DQ)
std::vector<TransformDualQuaternion> clusterTransforms;
#else
std::vector<glm::mat4> clusterTransforms;
#endif
};
const MeshState& getMeshState(int index) { return _meshStates.at(index); }

View file

@ -11,6 +11,10 @@
<@if not SKINNING_SLH@>
<@def SKINNING_SLH@>
// Use dual quaternion skinning
// Must match #define SKIN_DQ in Model.h
<@def SKIN_DQ@>
const int MAX_CLUSTERS = 128;
const int INDICES_PER_VERTEX = 4;
@ -18,6 +22,156 @@ layout(std140) uniform skinClusterBuffer {
mat4 clusterMatrices[MAX_CLUSTERS];
};
<@if SKIN_DQ@>
mat4 dualQuatToMat4(vec4 real, vec4 dual) {
float twoRealXSq = 2.0 * real.x * real.x;
float twoRealYSq = 2.0 * real.y * real.y;
float twoRealZSq = 2.0 * real.z * real.z;
float twoRealXY = 2.0 * real.x * real.y;
float twoRealXZ = 2.0 * real.x * real.z;
float twoRealXW = 2.0 * real.x * real.w;
float twoRealZW = 2.0 * real.z * real.w;
float twoRealYZ = 2.0 * real.y * real.z;
float twoRealYW = 2.0 * real.y * real.w;
vec4 col0 = vec4(1.0 - twoRealYSq - twoRealZSq,
twoRealXY + twoRealZW,
twoRealXZ - twoRealYW,
0.0);
vec4 col1 = vec4(twoRealXY - twoRealZW,
1 - twoRealXSq - twoRealZSq,
twoRealYZ + twoRealXW,
0.0);
vec4 col2 = vec4(twoRealXZ + twoRealYW,
twoRealYZ - twoRealXW,
1 - twoRealXSq - twoRealYSq,
0.0);
vec4 col3 = vec4(2.0 * (-dual.w * real.x + dual.x * real.w - dual.y * real.z + dual.z * real.y),
2.0 * (-dual.w * real.y + dual.x * real.z + dual.y * real.w - dual.z * real.x),
2.0 * (-dual.w * real.z - dual.x * real.y + dual.y * real.x + dual.z * real.w),
1.0);
return mat4(col0, col1, col2, col3);
}
// dual quaternion linear blending
void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
// linearly blend scale and dual quaternion components
vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
vec3 scale = vec3(clusterMatrix[0]);
vec4 real = clusterMatrix[1];
vec4 dual = clusterMatrix[2];
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
float dqClusterWeight = clusterWeight;
if (dot(real, polarityReference) < 0) {
dqClusterWeight = -clusterWeight;
}
sAccum += scale * clusterWeight;
rAccum += real * dqClusterWeight;
dAccum += dual * dqClusterWeight;
}
// normalize dual quaternion
float norm = length(rAccum);
rAccum /= norm;
dAccum /= norm;
// conversion from dual quaternion to 4x4 matrix.
mat4 m = dualQuatToMat4(rAccum, dAccum);
skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
}
void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal,
out vec4 skinnedPosition, out vec3 skinnedNormal) {
// linearly blend scale and dual quaternion components
vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
vec3 scale = vec3(clusterMatrix[0]);
vec4 real = clusterMatrix[1];
vec4 dual = clusterMatrix[2];
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
float dqClusterWeight = clusterWeight;
if (dot(real, polarityReference) < 0) {
dqClusterWeight = -clusterWeight;
}
sAccum += scale * clusterWeight;
rAccum += real * dqClusterWeight;
dAccum += dual * dqClusterWeight;
}
// normalize dual quaternion
float norm = length(rAccum);
rAccum /= norm;
dAccum /= norm;
// conversion from dual quaternion to 4x4 matrix.
mat4 m = dualQuatToMat4(rAccum, dAccum);
skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
skinnedNormal = vec3(m * vec4(inNormal, 0));
}
void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent,
out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) {
// linearly blend scale and dual quaternion components
vec3 sAccum = vec3(0.0, 0.0, 0.0);
vec4 rAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 dAccum = vec4(0.0, 0.0, 0.0, 0.0);
vec4 polarityReference = clusterMatrices[skinClusterIndex[0]][1];
for (int i = 0; i < INDICES_PER_VERTEX; i++) {
mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])];
float clusterWeight = skinClusterWeight[i];
vec3 scale = vec3(clusterMatrix[0]);
vec4 real = clusterMatrix[1];
vec4 dual = clusterMatrix[2];
// to ensure that we rotate along the shortest arc, reverse dual quaternions with negative polarity.
float dqClusterWeight = clusterWeight;
if (dot(real, polarityReference) < 0) {
dqClusterWeight = -clusterWeight;
}
sAccum += scale * clusterWeight;
rAccum += real * dqClusterWeight;
dAccum += dual * dqClusterWeight;
}
// normalize dual quaternion
float norm = length(rAccum);
rAccum /= norm;
dAccum /= norm;
// conversion from dual quaternion to 4x4 matrix.
mat4 m = dualQuatToMat4(rAccum, dAccum);
skinnedPosition = m * (vec4(sAccum, 1) * inPosition);
skinnedNormal = vec3(m * vec4(inNormal, 0));
skinnedTangent = vec3(m * vec4(inTangent, 0));
}
<@else@> // SKIN_DQ
void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) {
vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0);
@ -65,5 +219,6 @@ void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, v
skinnedTangent = newTangent.xyz;
}
<@endif@> // if SKIN_DQ
<@endif@>
<@endif@> // if not SKINNING_SLH

View file

@ -52,13 +52,27 @@ void SoftAttachmentModel::updateClusterMatrices() {
// TODO: cache these look-ups as an optimization
int jointIndexOverride = getJointIndexOverride(cluster.jointIndex);
#if defined(SKIN_DQ)
glm::mat4 jointMatrix;
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) {
jointMatrix = _rigOverride.getJointTransform(jointIndexOverride);
} else {
jointMatrix = _rig.getJointTransform(cluster.jointIndex);
}
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterMatrices[j]);
glm::mat4 m;
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, m);
state.clusterTransforms[j] = Model::TransformDualQuaternion(m);
#else
glm::mat4 jointMatrix;
if (jointIndexOverride >= 0 && jointIndexOverride < _rigOverride.getJointStateCount()) {
jointMatrix = _rigOverride.getJointTransform(jointIndexOverride);
} else {
jointMatrix = _rig.getJointTransform(cluster.jointIndex);
}
glm_mat4u_mul(jointMatrix, cluster.inverseBindMatrix, state.clusterTransforms[j]);
#endif
}
}

View file

@ -63,38 +63,6 @@ vec3 scatter(float r) {
<@endfunc@>
<@func declareSkinSpecularLighting()@>
uniform sampler2D scatteringSpecularBeckmann;
float fetchSpecularBeckmann(float ndoth, float roughness) {
return pow( 2.0 * texture(scatteringSpecularBeckmann, vec2(ndoth, roughness)).r, 10.0);
}
float fresnelReflectance(vec3 H, vec3 V, float Fo) {
float base = 1.0 - dot(V, H);
float exponential = pow(base, 5.0);
return exponential + Fo * (1.0 - exponential);
}
float skinSpecular(vec3 N, vec3 L, vec3 V, float roughness, float intensity) {
float result = 0.0;
float ndotl = dot(N, L);
if (ndotl > 0.0) {
vec3 h = L + V;
vec3 H = normalize(h);
float ndoth = dot(N, H);
float PH = fetchSpecularBeckmann(ndoth, roughness);
float F = fresnelReflectance(H, V, 0.028);
float frSpec = max(PH * F / dot(h, h), 0.0);
result = ndotl * intensity * frSpec;
}
return result;
}
<@endfunc@>
<@func declareSubsurfaceScatteringIntegrate(NumIntegrationSteps)@>

View file

@ -84,9 +84,8 @@ void main(void) {
// Frag to eye vec
vec4 fragEyeVector = invViewMat * vec4(-frag.position.xyz, 0.0);
vec3 fragEyeDir = normalize(fragEyeVector.xyz);
// Compute the rougness into gloss2 once:
float fragGloss2 = pow(frag.roughness + 0.001, 4.0);
SurfaceData surface = initSurfaceData(frag.roughness, frag.normal, fragEyeDir);
bool withScattering = (frag.scattering * isScatteringEnabled() > 0.0);
int numLightTouching = 0;
@ -119,16 +118,18 @@ void main(void) {
float fragLightDistance = fragLightDirLen.w;
vec3 fragLightDir = fragLightDirLen.xyz;
updateSurfaceDataWithLight(surface, fragLightDir);
// Eval attenuation
float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance);
vec3 lightEnergy = radialAttenuation * getLightIrradiance(light);
// Eval shading
if (withScattering) {
evalFragShadingScattering(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo
evalFragShadingScattering(diffuse, specular, frag.metallic, frag.fresnel, surface, frag.albedo
,frag.scattering, midNormalCurvature, lowNormalCurvature );
} else {
evalFragShadingGloss(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, fragGloss2, frag.albedo);
evalFragShadingGloss(diffuse, specular, frag.metallic, frag.fresnel, surface, frag.albedo);
}
diffuse *= lightEnergy * isDiffuseEnabled();
@ -173,6 +174,8 @@ void main(void) {
float fragLightDistance = fragLightDirLen.w;
vec3 fragLightDir = fragLightDirLen.xyz;
updateSurfaceDataWithLight(surface, fragLightDir);
// Eval attenuation
float radialAttenuation = lightIrradiance_evalLightAttenuation(light.irradiance, fragLightDistance);
float angularAttenuation = lightIrradiance_evalLightSpotAttenuation(light.irradiance, cosSpotAngle);
@ -180,10 +183,10 @@ void main(void) {
// Eval shading
if (withScattering) {
evalFragShadingScattering(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, frag.roughness, frag.albedo
evalFragShadingScattering(diffuse, specular, frag.metallic, frag.fresnel, surface, frag.albedo
,frag.scattering, midNormalCurvature, lowNormalCurvature );
} else {
evalFragShadingGloss(diffuse, specular, frag.normal, fragLightDir, fragEyeDir, frag.metallic, frag.fresnel, fragGloss2, frag.albedo);
evalFragShadingGloss(diffuse, specular, frag.metallic, frag.fresnel, surface, frag.albedo);
}
diffuse *= lightEnergy * isDiffuseEnabled();

View file

@ -50,13 +50,7 @@ void main(void) {
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
float metallic = getMaterialMetallic(mat);
vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value
if (metallic <= 0.5) {
metallic = 0.0;
} else {
fresnel = albedo;
metallic = 1.0;
}
vec3 fresnel = getFresnelF0(metallic, albedo);
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;

View file

@ -60,13 +60,7 @@ void main(void) {
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;
float metallic = getMaterialMetallic(mat);
vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value
if (metallic <= 0.5) {
metallic = 0.0;
} else {
fresnel = albedo;
metallic = 1.0;
}
vec3 fresnel = getFresnelF0(metallic, albedo);
vec3 emissive = getMaterialEmissive(mat);
<$evalMaterialEmissive(emissiveTex, emissive, matKey, emissive)$>;

View file

@ -40,12 +40,14 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 a
vec3 fragEyeDir;
<$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$>
SurfaceData surface = initSurfaceData(roughness, normal, fragEyeDir);
vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(ambient);
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation);
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation);
color += directionalDiffuse * isDiffuseEnabled() * isDirectionalEnabled();
color += directionalSpecular * isSpecularEnabled() * isDirectionalEnabled();

View file

@ -46,13 +46,7 @@ void main(void) {
albedo *= _color;
float metallic = getMaterialMetallic(mat);
vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value
if (metallic <= 0.5) {
metallic = 0.0;
} else {
fresnel = albedo;
metallic = 1.0;
}
vec3 fresnel = getFresnelF0(metallic, albedo);
float roughness = getMaterialRoughness(mat);
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;

View file

@ -44,13 +44,7 @@ void main(void) {
albedo *= _color;
float metallic = getMaterialMetallic(mat);
vec3 fresnel = vec3(0.03); // Default Di-electric fresnel value
if (metallic <= 0.5) {
metallic = 0.0;
} else {
fresnel = albedo;
metallic = 1.0;
}
vec3 fresnel = getFresnelF0(metallic, albedo);
float roughness = getMaterialRoughness(mat);
<$evalMaterialRoughness(roughnessTex, roughness, matKey, roughness)$>;

View file

@ -40,12 +40,14 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 a
vec3 fragEyeDir;
<$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$>
SurfaceData surface = initSurfaceData(roughness, normal, fragEyeDir);
vec3 color = opacity * albedo * getLightColor(light) * getLightAmbientIntensity(ambient);
// Directional
vec3 directionalDiffuse;
vec3 directionalSpecular;
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, fragEyeDir, fragNormal, roughness, metallic, fresnel, albedo, shadowAttenuation);
evalLightingDirectional(directionalDiffuse, directionalSpecular, lightDirection, lightIrradiance, surface, metallic, fresnel, albedo, shadowAttenuation);
color += directionalDiffuse;
color += directionalSpecular / opacity;

View file

@ -0,0 +1,92 @@
//
// DualQuaternion.cpp
//
// Created by Anthony J. Thibault on Dec 13th 2017.
// Copyright (c) 2017 High Fidelity, Inc. All rights reserved.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "DualQuaternion.h"
#include "GLMHelpers.h"
// delegating constructor
DualQuaternion::DualQuaternion() : _real(1.0f, 0.0f, 0.0f, 0.0), _dual(0.0f, 0.0f, 0.0f, 0.0f) {
}
DualQuaternion::DualQuaternion(const glm::mat4& m) : DualQuaternion(glmExtractRotation(m), extractTranslation(m)) {
}
DualQuaternion::DualQuaternion(const glm::quat& real, const glm::quat& dual) : _real(real), _dual(dual) {
}
DualQuaternion::DualQuaternion(const glm::vec4& real, const glm::vec4& dual) :
_real(real.w, real.x, real.y, real.z),
_dual(dual.w, dual.x, dual.y, dual.z) {
}
DualQuaternion::DualQuaternion(const glm::quat& rotation, const glm::vec3& translation) {
_real = rotation;
_dual = glm::quat(0.0f, 0.5f * translation.x, 0.5f * translation.y, 0.5f * translation.z) * rotation;
}
DualQuaternion DualQuaternion::operator*(const DualQuaternion& rhs) const {
return DualQuaternion(_real * rhs._real, _real * rhs._dual + _dual * rhs._real);
}
DualQuaternion DualQuaternion::operator*(float scalar) const {
return DualQuaternion(_real * scalar, _dual * scalar);
}
DualQuaternion DualQuaternion::operator+(const DualQuaternion& rhs) const {
return DualQuaternion(_real + rhs._real, _dual + rhs._dual);
}
glm::vec3 DualQuaternion::xformPoint(const glm::vec3& rhs) const {
DualQuaternion v(glm::quat(), glm::quat(0.0f, rhs.x, rhs.y, rhs.z));
DualQuaternion dualConj(glm::conjugate(_real), -glm::conjugate(_dual));
DualQuaternion result = *this * v * dualConj;
return vec3(result._dual.x, result._dual.y, result._dual.z);
}
glm::quat DualQuaternion::getRotation() const {
return _real;
}
glm::vec3 DualQuaternion::getTranslation() const {
glm::quat result = 2.0f * (_dual * glm::inverse(_real));
return glm::vec3(result.x, result.y, result.z);
}
glm::vec3 DualQuaternion::xformVector(const glm::vec3& rhs) const {
return _real * rhs;
}
DualQuaternion DualQuaternion::inverse() const {
glm::quat invReal = glm::inverse(_real);
return DualQuaternion(invReal, - invReal * _dual * invReal);
}
DualQuaternion DualQuaternion::conjugate() const {
return DualQuaternion(glm::conjugate(_real), glm::conjugate(_dual));
}
float DualQuaternion::length() const {
float dot = this->dot(*this);
return sqrtf(dot);
}
DualQuaternion DualQuaternion::normalize() const {
float invLen = 1.0f / length();
return *this * invLen;
}
float DualQuaternion::dot(const DualQuaternion& rhs) const {
DualQuaternion result = *this * conjugate();
return result._real.w;
}
DualQuaternion DualQuaternion::operator-() const {
return DualQuaternion(-_real, -_dual);
}

View file

@ -0,0 +1,62 @@
//
// DualQuaternion.h
//
// Created by Anthony J. Thibault on Dec 13th 2017.
// Copyright (c) 2017 High Fidelity, Inc. All rights reserved.
//
// 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_DualQuaternion
#define hifi_DualQuaternion
#include <QtGlobal>
#include <QDebug>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
class DualQuaternion {
public:
DualQuaternion();
explicit DualQuaternion(const glm::mat4& m);
DualQuaternion(const glm::quat& real, const glm::quat& imag);
DualQuaternion(const glm::quat& rotation, const glm::vec3& translation);
DualQuaternion(const glm::vec4& real, const glm::vec4& imag);
DualQuaternion operator*(const DualQuaternion& rhs) const;
DualQuaternion operator*(float scalar) const;
DualQuaternion operator+(const DualQuaternion& rhs) const;
const glm::quat& real() const { return _real; }
glm::quat& real() { return _real; }
const glm::quat& dual() const { return _dual; }
glm::quat& dual() { return _dual; }
glm::quat getRotation() const;
glm::vec3 getTranslation() const;
glm::vec3 xformPoint(const glm::vec3& rhs) const;
glm::vec3 xformVector(const glm::vec3& rhs) const;
DualQuaternion inverse() const;
DualQuaternion conjugate() const;
float length() const;
DualQuaternion normalize() const;
float dot(const DualQuaternion& rhs) const;
DualQuaternion operator-() const;
protected:
friend QDebug operator<<(QDebug debug, const DualQuaternion& pose);
glm::quat _real;
glm::quat _dual;
};
inline QDebug operator<<(QDebug debug, const DualQuaternion& dq) {
debug << "AnimPose, real = (" << dq._real.x << dq._real.y << dq._real.z << dq._real.w << "), dual = (" << dq._dual.x << dq._dual.y << dq._dual.z << dq._dual.w << ")";
return debug;
}
#endif

View file

@ -58,7 +58,7 @@ public:
_rotation(rotation),
_scale(scale),
_translation(translation),
_flags(FLAG_CACHE_INVALID_BITSET) // invalid cache
_flags(0xf) // FLAG_TRANSLATION | FLAG_ROTATION | FLAG_SCALING | FLAG_NON_UNIFORM
{
if (!isValidScale(_scale)) {
_scale = Vec3(1.0f);

View file

@ -0,0 +1,115 @@
//
// DualQuaternionTests.cpp
// tests/shared/src
//
// Copyright 2017 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 <iostream>
#include "DualQuaternionTests.h"
#include <DualQuaternion.h>
#include <GLMHelpers.h>
#include <NumericalConstants.h>
#include <StreamUtils.h>
#include <../GLMTestUtils.h>
#include <../QTestExtensions.h>
QTEST_MAIN(DualQuaternionTests)
static void quatComp(const glm::quat& q1, const glm::quat& q2) {
QCOMPARE_WITH_ABS_ERROR(q1.x, q2.x, EPSILON);
QCOMPARE_WITH_ABS_ERROR(q1.y, q2.y, EPSILON);
QCOMPARE_WITH_ABS_ERROR(q1.z, q2.z, EPSILON);
QCOMPARE_WITH_ABS_ERROR(q1.w, q2.w, EPSILON);
}
void DualQuaternionTests::ctor() {
glm::quat real = angleAxis(PI / 2.0f, Vectors::UNIT_Y);
glm::quat dual(0.0f, 1.0f, 2.0f, 3.0f);
DualQuaternion dq(real, dual);
quatComp(real, dq.real());
quatComp(dual, dq.dual());
glm::quat rotation = angleAxis(PI / 3.0f, Vectors::UNIT_X);
glm::vec3 translation(1.0, 2.0f, 3.0f);
dq = DualQuaternion(rotation, translation);
quatComp(rotation, dq.getRotation());
QCOMPARE_WITH_ABS_ERROR(translation, dq.getTranslation(), EPSILON);
rotation = angleAxis(-2.0f * PI / 7.0f, Vectors::UNIT_Z);
translation = glm::vec3(-1.0, 12.0f, 2.0f);
glm::mat4 m = createMatFromQuatAndPos(rotation, translation);
dq = DualQuaternion(m);
quatComp(rotation, dq.getRotation());
QCOMPARE_WITH_ABS_ERROR(translation, dq.getTranslation(), EPSILON);
}
void DualQuaternionTests::mult() {
glm::quat rotation = angleAxis(PI / 3.0f, Vectors::UNIT_X);
glm::vec3 translation(1.0, 2.0f, 3.0f);
glm::mat4 m1 = createMatFromQuatAndPos(rotation, translation);
DualQuaternion dq1(m1);
rotation = angleAxis(-2.0f * PI / 7.0f, Vectors::UNIT_Z);
translation = glm::vec3(-1.0, 12.0f, 2.0f);
glm::mat4 m2 = createMatFromQuatAndPos(rotation, translation);
DualQuaternion dq2(m2);
DualQuaternion dq3 = dq1 * dq2;
glm::mat4 m3 = m1 * m2;
rotation = glmExtractRotation(m3);
translation = extractTranslation(m3);
quatComp(rotation, dq3.getRotation());
QCOMPARE_WITH_ABS_ERROR(translation, dq3.getTranslation(), EPSILON);
}
void DualQuaternionTests::xform() {
glm::quat rotation = angleAxis(PI / 3.0f, Vectors::UNIT_X);
glm::vec3 translation(1.0, 2.0f, 3.0f);
glm::mat4 m1 = createMatFromQuatAndPos(rotation, translation);
DualQuaternion dq1(m1);
rotation = angleAxis(-2.0f * PI / 7.0f, Vectors::UNIT_Z);
translation = glm::vec3(-1.0, 12.0f, 2.0f);
glm::mat4 m2 = createMatFromQuatAndPos(rotation, translation);
DualQuaternion dq2(m2);
DualQuaternion dq3 = dq1 * dq2;
glm::mat4 m3 = m1 * m2;
glm::vec3 p(1.0f, 2.0f, 3.0f);
glm::vec3 p1 = transformPoint(m3, p);
glm::vec3 p2 = dq3.xformPoint(p);
QCOMPARE_WITH_ABS_ERROR(p1, p2, 0.001f);
p1 = transformVectorFast(m3, p);
p2 = dq3.xformVector(p);
QCOMPARE_WITH_ABS_ERROR(p1, p2, 0.001f);
}
void DualQuaternionTests::trans() {
glm::vec3 t1 = glm::vec3();
DualQuaternion dq1(Quaternions::IDENTITY, t1);
glm::vec3 t2 = glm::vec3(1.0f, 2.0f, 3.0f);
DualQuaternion dq2(angleAxis(PI / 3.0f, Vectors::UNIT_X), t2);
glm::vec3 t3 = glm::vec3(3.0f, 2.0f, 1.0f);
DualQuaternion dq3(angleAxis(PI / 5.0f, Vectors::UNIT_Y), t3);
QCOMPARE_WITH_ABS_ERROR(t1, dq1.getTranslation(), 0.001f);
QCOMPARE_WITH_ABS_ERROR(t2, dq2.getTranslation(), 0.001f);
QCOMPARE_WITH_ABS_ERROR(t3, dq3.getTranslation(), 0.001f);
}

View file

@ -0,0 +1,25 @@
//
// DualQuaternionTests.h
// tests/shared/src
//
// Copyright 2017 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_DualQuaternionTests_h
#define hifi_DualQuaternionTests_h
#include <QtTest/QtTest>
class DualQuaternionTests : public QObject {
Q_OBJECT
private slots:
void ctor();
void mult();
void xform();
void trans();
};
#endif // hifi_DualQuaternionTests_h