mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-12-02 00:00:07 +00:00
1516 lines
50 KiB
C++
1516 lines
50 KiB
C++
//
|
|
// Copyright (C) Pixar. All rights reserved.
|
|
//
|
|
// This license governs use of the accompanying software. If you
|
|
// use the software, you accept this license. If you do not accept
|
|
// the license, do not use the software.
|
|
//
|
|
// 1. Definitions
|
|
// The terms "reproduce," "reproduction," "derivative works," and
|
|
// "distribution" have the same meaning here as under U.S.
|
|
// copyright law. A "contribution" is the original software, or
|
|
// any additions or changes to the software.
|
|
// A "contributor" is any person or entity that distributes its
|
|
// contribution under this license.
|
|
// "Licensed patents" are a contributor's patent claims that read
|
|
// directly on its contribution.
|
|
//
|
|
// 2. Grant of Rights
|
|
// (A) Copyright Grant- Subject to the terms of this license,
|
|
// including the license conditions and limitations in section 3,
|
|
// each contributor grants you a non-exclusive, worldwide,
|
|
// royalty-free copyright license to reproduce its contribution,
|
|
// prepare derivative works of its contribution, and distribute
|
|
// its contribution or any derivative works that you create.
|
|
// (B) Patent Grant- Subject to the terms of this license,
|
|
// including the license conditions and limitations in section 3,
|
|
// each contributor grants you a non-exclusive, worldwide,
|
|
// royalty-free license under its licensed patents to make, have
|
|
// made, use, sell, offer for sale, import, and/or otherwise
|
|
// dispose of its contribution in the software or derivative works
|
|
// of the contribution in the software.
|
|
//
|
|
// 3. Conditions and Limitations
|
|
// (A) No Trademark License- This license does not grant you
|
|
// rights to use any contributor's name, logo, or trademarks.
|
|
// (B) If you bring a patent claim against any contributor over
|
|
// patents that you claim are infringed by the software, your
|
|
// patent license from such contributor to the software ends
|
|
// automatically.
|
|
// (C) If you distribute any portion of the software, you must
|
|
// retain all copyright, patent, trademark, and attribution
|
|
// notices that are present in the software.
|
|
// (D) If you distribute any portion of the software in source
|
|
// code form, you may do so only under this license by including a
|
|
// complete copy of this license with your distribution. If you
|
|
// distribute any portion of the software in compiled or object
|
|
// code form, you may only do so under a license that complies
|
|
// with this license.
|
|
// (E) The software is licensed "as-is." You bear the risk of
|
|
// using it. The contributors give no express warranties,
|
|
// guarantees or conditions. You may have additional consumer
|
|
// rights under your local laws which this license cannot change.
|
|
// To the extent permitted under your local laws, the contributors
|
|
// exclude the implied warranties of merchantability, fitness for
|
|
// a particular purpose and non-infringement.
|
|
//
|
|
|
|
#include <GL/glew.h>
|
|
|
|
// Include this first to avoid winsock2.h problems on Windows:
|
|
#include <maya/MTypes.h>
|
|
|
|
#include <maya/MFnPlugin.h>
|
|
#include <maya/MFnPluginData.h>
|
|
#include <maya/MGlobal.h>
|
|
#include <maya/MFnMesh.h>
|
|
#include <maya/MItMeshPolygon.h>
|
|
#include <maya/MIntArray.h>
|
|
#include <maya/MUintArray.h>
|
|
#include <maya/MDoubleArray.h>
|
|
#include <maya/MFnTypedAttribute.h>
|
|
#include <maya/MFnNumericAttribute.h>
|
|
#include <maya/MFnEnumAttribute.h>
|
|
#include <maya/MPointArray.h>
|
|
#include <maya/MItMeshEdge.h>
|
|
|
|
#include <maya/MShaderManager.h>
|
|
#include <maya/MViewport2Renderer.h>
|
|
#include <maya/MDrawRegistry.h>
|
|
#include <maya/MPxHwShaderNode.h>
|
|
#include <maya/MPxShaderOverride.h>
|
|
#include <maya/MPxGeometryOverride.h>
|
|
#include <maya/MUserData.h>
|
|
#include <maya/MDrawContext.h>
|
|
#include <maya/MHWShaderSwatchGenerator.h>
|
|
#include <maya/MPxVertexBufferGenerator.h>
|
|
#include <maya/MStateManager.h>
|
|
|
|
#include <osd/mesh.h>
|
|
#include <osd/pTexture.h>
|
|
#include <osd/cpuDispatcher.h>
|
|
#include <Ptexture.h>
|
|
#include <PtexUtils.h>
|
|
|
|
#include <iostream>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
|
|
#include <osd/cudaDispatcher.h>
|
|
extern void cudaInit();
|
|
#include "hbrUtil.h"
|
|
|
|
static const char *defaultShaderSource =
|
|
#include "shader.inc"
|
|
;
|
|
|
|
#define CHECK_GL_ERROR(...) \
|
|
if(GLuint err = glGetError()) { \
|
|
printf("GL error %x :", err); \
|
|
printf(__VA_ARGS__); \
|
|
}
|
|
|
|
#ifdef __linux__
|
|
#define MAYA2013_PREVIEW
|
|
#endif
|
|
|
|
//---------------------------------------------------------------------------
|
|
template<class T> static int
|
|
FindAttribute( MFnDependencyNode &fnDN, const char *nm, T *val )
|
|
{
|
|
MStatus s;
|
|
MPlug p;
|
|
T ss;
|
|
p = fnDN.findPlug(nm, &s);
|
|
if(s != MS::kSuccess) return -1;
|
|
s = p.getValue(ss);
|
|
if( s != MS::kSuccess ) return -1;
|
|
*val = ss;
|
|
return 0;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
template<class T> static bool
|
|
CompareArray(const T &a, const T &b)
|
|
{
|
|
if(a.length() != b.length()) return false;
|
|
for(unsigned int i = 0; i < a.length(); ++i){
|
|
if(a[i] != b[i]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
class OpenSubdivPtexShader : public MPxHwShaderNode
|
|
{
|
|
public:
|
|
OpenSubdivPtexShader();
|
|
virtual ~OpenSubdivPtexShader();
|
|
|
|
static void *creator();
|
|
static MStatus initialize();
|
|
|
|
virtual void postConstructor()
|
|
{
|
|
setMPSafe(false);
|
|
}
|
|
|
|
virtual MStatus compute(const MPlug &plug, MDataBlock &data);
|
|
virtual MStatus bind(const MDrawRequest &request, M3dView &view);
|
|
virtual MStatus unbind(const MDrawRequest &request, M3dView &view);
|
|
virtual MStatus geometry( const MDrawRequest& request,
|
|
M3dView& view,
|
|
int prim,
|
|
unsigned int writable,
|
|
int indexCount,
|
|
const unsigned int * indexArray,
|
|
int vertexCount,
|
|
const int * vertexIDs,
|
|
const float * vertexArray,
|
|
int normalCount,
|
|
const float ** normalArrays,
|
|
int colorCount,
|
|
const float ** colorArrays,
|
|
int texCoordCount,
|
|
const float ** texCoordArrays);
|
|
virtual MStatus glBind(const MDagPath &);
|
|
virtual MStatus glUnBind(const MDagPath &);
|
|
virtual MStatus glGeometry(const MDagPath &path,
|
|
int prim,
|
|
unsigned int writable,
|
|
int indexCount,
|
|
const unsigned int * indexArray,
|
|
int vertexCount,
|
|
const int * vertexIDs,
|
|
const float * vertexArray,
|
|
int normalCount,
|
|
const float ** normalArrays,
|
|
int colorCount,
|
|
const float ** colorArrays,
|
|
int texCoordCount,
|
|
const float ** texCoordArrays);
|
|
virtual MStatus renderSwatchImage( MImage & image )
|
|
{
|
|
unsigned int width, height;
|
|
image.getSize(width, height);
|
|
unsigned char *p = image.pixels();
|
|
for(int i=0; i<width*height; i++){
|
|
*p++ = 0;
|
|
*p++ = 0;
|
|
*p++ = 0;
|
|
*p++ = 255;
|
|
}
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
|
|
// virtual bool isBounded() const;
|
|
// virtual MBoundingBox boundingBox() const;
|
|
virtual bool setInternalValueInContext(const MPlug &plug, const MDataHandle &handle, MDGContext &);
|
|
|
|
void bindTextures();
|
|
GLuint getProgram() const {return _program; }
|
|
void updateUniforms();
|
|
bool isWireframe() const { return _wireframe; }
|
|
int getLevel() const { return _level; }
|
|
int getScheme() const { return _scheme; }
|
|
|
|
static MTypeId id;
|
|
static MString drawRegistrantId;
|
|
|
|
private:
|
|
OpenSubdiv::OsdPTexture * loadPtex(MString &filename);
|
|
void bindPTexture(OpenSubdiv::OsdPTexture *osdPTex, GLuint data, GLuint packing, GLuint pages, int samplerUnit) const;
|
|
void linkProgram();
|
|
GLuint compileShader(GLenum shaderType, const char *section, const char *shaderSource);
|
|
|
|
static MObject colorFile;
|
|
static MObject displacementFile;
|
|
static MObject occlusionFile;
|
|
static MObject level;
|
|
static MObject scheme;
|
|
static MObject diffuseMapFile;
|
|
static MObject environmentMapFile;
|
|
static MObject shaderSource;
|
|
|
|
static MObject enableDisplacement;
|
|
static MObject enableColor;
|
|
static MObject enableOcclusion;
|
|
|
|
static MObject aDiffuse;
|
|
static MObject aSpecular;
|
|
static MObject aAmbient;
|
|
static MObject aFresnelBias;
|
|
static MObject aFresnelScale;
|
|
static MObject aFresnelPower;
|
|
static MObject aLight;
|
|
static MObject aWireframe;
|
|
|
|
enum { kCatmark, kLoop, kBilinear };
|
|
|
|
MString _ptexColorFile, _ptexDisplacementFile, _ptexOcclusionFile;
|
|
OpenSubdiv::OsdPTexture * _ptexColor;
|
|
OpenSubdiv::OsdPTexture * _ptexDisplacement;
|
|
OpenSubdiv::OsdPTexture * _ptexOcclusion;
|
|
|
|
MString _diffuseMap;
|
|
MString _environmentMap;
|
|
bool _invalidateDiffuseMap;
|
|
bool _invalidateEnvMap;
|
|
|
|
bool _enableColor;
|
|
bool _enableDisplacement;
|
|
bool _enableOcclusion;
|
|
|
|
GLuint _program;
|
|
bool _wireframe;
|
|
int _level;
|
|
int _scheme;
|
|
std::string _shaderSource;
|
|
};
|
|
|
|
MTypeId OpenSubdivPtexShader::id(0x88111);
|
|
MString OpenSubdivPtexShader::drawRegistrantId("OpenSubdivPtexShaderPlugin");
|
|
MObject OpenSubdivPtexShader::colorFile;
|
|
MObject OpenSubdivPtexShader::displacementFile;
|
|
MObject OpenSubdivPtexShader::occlusionFile;
|
|
MObject OpenSubdivPtexShader::level;
|
|
MObject OpenSubdivPtexShader::scheme;
|
|
MObject OpenSubdivPtexShader::diffuseMapFile;
|
|
MObject OpenSubdivPtexShader::environmentMapFile;
|
|
MObject OpenSubdivPtexShader::shaderSource;
|
|
MObject OpenSubdivPtexShader::enableDisplacement;
|
|
MObject OpenSubdivPtexShader::enableColor;
|
|
MObject OpenSubdivPtexShader::enableOcclusion;
|
|
MObject OpenSubdivPtexShader::aDiffuse;
|
|
MObject OpenSubdivPtexShader::aSpecular;
|
|
MObject OpenSubdivPtexShader::aAmbient;
|
|
MObject OpenSubdivPtexShader::aFresnelBias;
|
|
MObject OpenSubdivPtexShader::aFresnelScale;
|
|
MObject OpenSubdivPtexShader::aFresnelPower;
|
|
MObject OpenSubdivPtexShader::aLight;
|
|
MObject OpenSubdivPtexShader::aWireframe;
|
|
|
|
OpenSubdivPtexShader::OpenSubdivPtexShader()
|
|
: _ptexColor(NULL), _ptexDisplacement(NULL), _ptexOcclusion(NULL),
|
|
_invalidateDiffuseMap(true),
|
|
_invalidateEnvMap(true),
|
|
_enableColor(true),
|
|
_enableDisplacement(true),
|
|
_enableOcclusion(true),
|
|
_program(0),
|
|
_wireframe(false),
|
|
_level(1),
|
|
_scheme(0)
|
|
{
|
|
_shaderSource = defaultShaderSource;
|
|
linkProgram();
|
|
}
|
|
|
|
OpenSubdivPtexShader::~OpenSubdivPtexShader()
|
|
{
|
|
if (_ptexColor) delete _ptexColor;
|
|
if (_ptexDisplacement) delete _ptexDisplacement;
|
|
if (_ptexOcclusion) delete _ptexOcclusion;
|
|
|
|
if (_program)
|
|
glDeleteProgram(_program);
|
|
}
|
|
|
|
void *
|
|
OpenSubdivPtexShader::creator()
|
|
{
|
|
return new OpenSubdivPtexShader();
|
|
}
|
|
|
|
MStatus
|
|
OpenSubdivPtexShader::initialize()
|
|
{
|
|
MStatus stat;
|
|
MFnTypedAttribute typedAttr;
|
|
MFnNumericAttribute numAttr;
|
|
MFnEnumAttribute enumAttr;
|
|
|
|
colorFile = typedAttr.create("colorFile", "cf", MFnData::kString, &stat);
|
|
typedAttr.setInternal(true);
|
|
displacementFile = typedAttr.create("displacementFile", "df", MFnData::kString, &stat);
|
|
typedAttr.setInternal(true);
|
|
occlusionFile = typedAttr.create("occlusionFile", "of", MFnData::kString, &stat);
|
|
typedAttr.setInternal(true);
|
|
|
|
level = numAttr.create("level", "lv", MFnNumericData::kLong, 1);
|
|
numAttr.setInternal(true);
|
|
numAttr.setMin(1);
|
|
numAttr.setSoftMax(5);
|
|
|
|
scheme = enumAttr.create("scheme", "sc");
|
|
enumAttr.addField("Catmull-Clark", kCatmark);
|
|
enumAttr.addField("Loop", kLoop);
|
|
enumAttr.addField("Bilinear", kBilinear);
|
|
enumAttr.setInternal(true);
|
|
|
|
diffuseMapFile = typedAttr.create("diffuseMap", "difmap", MFnData::kString);
|
|
typedAttr.setInternal(true);
|
|
|
|
environmentMapFile = typedAttr.create("environmentMap", "envmap", MFnData::kString);
|
|
typedAttr.setInternal(true);
|
|
|
|
shaderSource = typedAttr.create("shaderSource", "ssrc", MFnData::kString);
|
|
typedAttr.setInternal(true);
|
|
|
|
|
|
enableColor = numAttr.create("enableColor", "enc", MFnNumericData::kBoolean, 1);
|
|
numAttr.setInternal(true);
|
|
enableDisplacement = numAttr.create("enableDisplacement", "end", MFnNumericData::kBoolean, 1);
|
|
numAttr.setInternal(true);
|
|
enableOcclusion = numAttr.create("enableOcclusion", "eno", MFnNumericData::kBoolean, 1);
|
|
numAttr.setInternal(true);
|
|
|
|
aDiffuse = numAttr.createColor("diffuse", "d");
|
|
aSpecular = numAttr.createColor("specular", "s");
|
|
aAmbient = numAttr.createColor("ambient", "a");
|
|
|
|
aLight = numAttr.create("light", "l", MFnNumericData::k3Float);
|
|
|
|
aWireframe = numAttr.create("wireframe", "wf", MFnNumericData::kBoolean);
|
|
|
|
aFresnelBias = numAttr.create("fresnelBias", "fb", MFnNumericData::kFloat, 0.2f);
|
|
numAttr.setMin(0);
|
|
numAttr.setMax(1);
|
|
aFresnelScale = numAttr.create("fresnelScale", "fs", MFnNumericData::kFloat, 1.0f);
|
|
numAttr.setMin(0);
|
|
numAttr.setSoftMax(1);
|
|
aFresnelPower = numAttr.create("fresnelPower", "fp", MFnNumericData::kFloat, 5.0f);
|
|
numAttr.setMin(0);
|
|
numAttr.setSoftMax(10);
|
|
|
|
addAttribute(colorFile);
|
|
addAttribute(displacementFile);
|
|
addAttribute(occlusionFile);
|
|
addAttribute(level);
|
|
addAttribute(scheme);
|
|
addAttribute(diffuseMapFile);
|
|
addAttribute(environmentMapFile);
|
|
addAttribute(shaderSource);
|
|
addAttribute(enableColor);
|
|
addAttribute(enableDisplacement);
|
|
addAttribute(enableOcclusion);
|
|
|
|
addAttribute(aDiffuse);
|
|
addAttribute(aSpecular);
|
|
addAttribute(aAmbient);
|
|
addAttribute(aFresnelBias);
|
|
addAttribute(aFresnelScale);
|
|
addAttribute(aFresnelPower);
|
|
addAttribute(aLight);
|
|
addAttribute(aWireframe);
|
|
|
|
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
MStatus
|
|
OpenSubdivPtexShader::compute(const MPlug &plug, MDataBlock &data)
|
|
{
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
OpenSubdiv::OsdPTexture *
|
|
OpenSubdivPtexShader::loadPtex(MString &filename)
|
|
{
|
|
if (filename.length() ){
|
|
printf("Load ptex %s\n", filename.asChar());
|
|
Ptex::String ptexError;
|
|
PtexTexture *ptex = PtexTexture::open(filename.asChar(), ptexError, true);
|
|
if (ptex) {
|
|
// create osdptex
|
|
OpenSubdiv::OsdPTexture *osdptex = OpenSubdiv::OsdPTexture::Create(ptex, 0);
|
|
ptex->release();
|
|
return osdptex;
|
|
}
|
|
printf("Fail in load ptex\n");
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void
|
|
OpenSubdivPtexShader::bindPTexture(OpenSubdiv::OsdPTexture *osdPTex, GLuint data, GLuint packing, GLuint pages, int samplerUnit) const
|
|
{
|
|
glProgramUniform1i(_program, data, samplerUnit + 0);
|
|
glActiveTexture(GL_TEXTURE0 + samplerUnit + 0);
|
|
glBindTexture(GL_TEXTURE_2D_ARRAY, osdPTex->GetTexelsTexture());
|
|
|
|
glProgramUniform1i(_program, packing, samplerUnit + 1);
|
|
glActiveTexture(GL_TEXTURE0 + samplerUnit + 1);
|
|
glBindTexture(GL_TEXTURE_BUFFER, osdPTex->GetLayoutTextureBuffer());
|
|
|
|
glProgramUniform1i(_program, pages, samplerUnit + 2);
|
|
glActiveTexture(GL_TEXTURE0 + samplerUnit + 2);
|
|
glBindTexture(GL_TEXTURE_BUFFER, osdPTex->GetPagesTextureBuffer());
|
|
|
|
glActiveTexture(GL_TEXTURE0);
|
|
}
|
|
|
|
void
|
|
OpenSubdivPtexShader::bindTextures()
|
|
{
|
|
if (_ptexColor)
|
|
{
|
|
// color ptex
|
|
GLint texData = glGetUniformLocation(_program, "textureImage_Data");
|
|
GLint texPacking = glGetUniformLocation(_program, "textureImage_Packing");
|
|
GLint texPages = glGetUniformLocation(_program, "textureImage_Pages");
|
|
bindPTexture(_ptexColor, texData, texPacking, texPages, 1);
|
|
}
|
|
|
|
// displacement ptex
|
|
if (_ptexDisplacement) {
|
|
GLint texData = glGetUniformLocation(_program, "textureDisplace_Data");
|
|
GLint texPacking = glGetUniformLocation(_program, "textureDisplace_Packing");
|
|
GLint texPages = glGetUniformLocation(_program, "textureDisplace_Pages");
|
|
bindPTexture(_ptexDisplacement, texData, texPacking, texPages, 4);
|
|
}
|
|
|
|
// occlusion ptex
|
|
if (_ptexOcclusion) {
|
|
GLint texData = glGetUniformLocation(_program, "textureOcclusion_Data");
|
|
GLint texPacking = glGetUniformLocation(_program, "textureOcclusion_Packing");
|
|
GLint texPages = glGetUniformLocation(_program, "textureOcclusion_Pages");
|
|
bindPTexture(_ptexOcclusion, texData, texPacking, texPages, 7);
|
|
}
|
|
|
|
MHWRender::MRenderer *theRenderer = MHWRender::MRenderer::theRenderer();
|
|
MHWRender::MTextureManager *theTextureManager = theRenderer->getTextureManager();
|
|
|
|
if (_invalidateDiffuseMap)
|
|
{
|
|
MHWRender::MTexture *texture = theTextureManager->acquireTexture(_diffuseMap);
|
|
if (texture) {
|
|
GLint difmap = glGetUniformLocation(_program, "diffuseMap");
|
|
glProgramUniform1i(_program, difmap, 10);
|
|
glActiveTexture(GL_TEXTURE0+10);
|
|
glBindTexture(GL_TEXTURE_2D, *(GLuint*)texture->resourceHandle());
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
_invalidateDiffuseMap = false;
|
|
} else {
|
|
printf("Can't read %s\n", _diffuseMap.asChar());
|
|
}
|
|
}
|
|
if (_invalidateEnvMap)
|
|
{
|
|
MHWRender::MTexture *texture = theTextureManager->acquireTexture(_environmentMap);
|
|
if (texture) {
|
|
GLint envmap = glGetUniformLocation(_program, "environmentMap");
|
|
glProgramUniform1i(_program, envmap, 11);
|
|
glActiveTexture(GL_TEXTURE0+11);
|
|
glBindTexture(GL_TEXTURE_2D, *(GLuint*)texture->resourceHandle());
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|
_invalidateEnvMap = false;
|
|
} else {
|
|
printf("Can't read %s\n", _environmentMap.asChar());
|
|
}
|
|
}
|
|
}
|
|
|
|
static MColor getColor(MObject object, MObject attr)
|
|
{
|
|
MPlug plug(object, attr);
|
|
|
|
MObject data;
|
|
plug.getValue(data);
|
|
MFnNumericData numFn(data);
|
|
float color[3];
|
|
numFn.getData(color[0], color[1], color[2]);
|
|
return MColor(color[0], color[1], color[2]);
|
|
}
|
|
|
|
static MFloatVector getVector(MObject object, MObject attr)
|
|
{
|
|
MPlug plug(object, attr);
|
|
|
|
MObject data;
|
|
plug.getValue(data);
|
|
MFnNumericData numFn(data);
|
|
float color[3];
|
|
numFn.getData(color[0], color[1], color[2]);
|
|
return MVector(color[0], color[1], color[2]);
|
|
}
|
|
|
|
void
|
|
OpenSubdivPtexShader::updateUniforms()
|
|
{
|
|
MObject object = thisMObject();
|
|
MColor diffuse = getColor(object, aDiffuse);
|
|
MColor ambient = getColor(object, aAmbient);
|
|
MColor specular = getColor(object, aSpecular);
|
|
MFnDependencyNode depFn(object);
|
|
float fresnelBias, fresnelScale, fresnelPower;
|
|
FindAttribute(depFn, "fresnelBias", &fresnelBias);
|
|
FindAttribute(depFn, "fresnelScale", &fresnelScale);
|
|
FindAttribute(depFn, "fresnelPower", &fresnelPower);
|
|
MFloatVector light = getVector(object, aLight);
|
|
FindAttribute(depFn, "wireframe", &_wireframe);
|
|
|
|
glProgramUniform3f(_program, glGetUniformLocation(_program, "diffuse"),
|
|
diffuse.r, diffuse.g, diffuse.b);
|
|
glProgramUniform3f(_program, glGetUniformLocation(_program, "ambient"),
|
|
ambient.r, ambient.g, ambient.b);
|
|
glProgramUniform3f(_program, glGetUniformLocation(_program, "specular"),
|
|
specular.r, specular.g, specular.b);
|
|
glProgramUniform3f(_program, glGetUniformLocation(_program, "light"),
|
|
light.x, light.y, light.z);
|
|
|
|
glProgramUniform1f(_program, glGetUniformLocation(_program, "fresnelBias"), fresnelBias);
|
|
glProgramUniform1f(_program, glGetUniformLocation(_program, "fresnelScale"), fresnelScale);
|
|
glProgramUniform1f(_program, glGetUniformLocation(_program, "fresnelPower"), fresnelPower);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool
|
|
OpenSubdivPtexShader::setInternalValueInContext(const MPlug &plug, const MDataHandle &handle, MDGContext &)
|
|
{
|
|
if(plug == level)
|
|
{
|
|
_level = handle.asLong();
|
|
}
|
|
else if(plug == scheme)
|
|
{
|
|
_scheme = handle.asShort();
|
|
}
|
|
else if(plug == environmentMapFile)
|
|
{
|
|
_invalidateEnvMap = true;
|
|
_environmentMap = handle.asString();
|
|
}
|
|
else if(plug == diffuseMapFile)
|
|
{
|
|
_invalidateDiffuseMap = true;
|
|
_diffuseMap = handle.asString();
|
|
}
|
|
else if(plug == colorFile)
|
|
{
|
|
MString filename = handle.asString();
|
|
if (_ptexColor) delete _ptexColor;
|
|
_ptexColor = loadPtex(filename);
|
|
}
|
|
else if(plug == displacementFile)
|
|
{
|
|
MString filename = handle.asString();
|
|
if (_ptexDisplacement) delete _ptexDisplacement;
|
|
_ptexDisplacement = loadPtex(filename);
|
|
}
|
|
else if(plug == occlusionFile)
|
|
{
|
|
MString filename = handle.asString();
|
|
if (_ptexOcclusion) delete _ptexOcclusion;
|
|
_ptexOcclusion = loadPtex(filename);
|
|
}
|
|
else if(plug == shaderSource)
|
|
{
|
|
MString filename = handle.asString();
|
|
std::ifstream ifs;
|
|
ifs.open(filename.asChar());
|
|
if (ifs.fail()) {
|
|
printf("link default shader\n");
|
|
_shaderSource = defaultShaderSource;
|
|
} else {
|
|
printf("link %s shader\n", filename.asChar());
|
|
std::stringstream buffer;
|
|
buffer << ifs.rdbuf();
|
|
_shaderSource = buffer.str();
|
|
}
|
|
ifs.close();
|
|
linkProgram();
|
|
}
|
|
else if(plug == enableColor)
|
|
{
|
|
_enableColor = handle.asBool();
|
|
linkProgram();
|
|
}
|
|
else if(plug == enableDisplacement)
|
|
{
|
|
_enableDisplacement = handle.asBool();
|
|
linkProgram();
|
|
}
|
|
else if(plug == enableOcclusion)
|
|
{
|
|
_enableOcclusion = handle.asBool();
|
|
linkProgram();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
MStatus
|
|
OpenSubdivPtexShader::bind(const MDrawRequest& request, M3dView &view)
|
|
{
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
MStatus
|
|
OpenSubdivPtexShader::unbind(const MDrawRequest& request, M3dView &view)
|
|
{
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
MStatus
|
|
OpenSubdivPtexShader::geometry( const MDrawRequest& request,
|
|
M3dView& view,
|
|
int prim,
|
|
unsigned int writable,
|
|
int indexCount,
|
|
const unsigned int * indexArray,
|
|
int vertexCount,
|
|
const int * vertexIDs,
|
|
const float * vertexArray,
|
|
int normalCount,
|
|
const float ** normalArrays,
|
|
int colorCount,
|
|
const float ** colorArrays,
|
|
int texCoordCount,
|
|
const float ** texCoordArrays)
|
|
{
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
MStatus OpenSubdivPtexShader::glBind(const MDagPath &)
|
|
{
|
|
return MS::kSuccess;
|
|
}
|
|
MStatus OpenSubdivPtexShader::glUnBind(const MDagPath &)
|
|
{
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
MStatus OpenSubdivPtexShader::glGeometry(const MDagPath &path,
|
|
int prim,
|
|
unsigned int writable,
|
|
int indexCount,
|
|
const unsigned int * indexArray,
|
|
int vertexCount,
|
|
const int * vertexIDs,
|
|
const float * vertexArray,
|
|
int normalCount,
|
|
const float ** normalArrays,
|
|
int colorCount,
|
|
const float ** colorArrays,
|
|
int texCoordCount,
|
|
const float ** texCoordArrays)
|
|
{
|
|
return MS::kSuccess;
|
|
}
|
|
|
|
|
|
GLuint
|
|
OpenSubdivPtexShader::compileShader(GLenum shaderType, const char *section, const char *shaderSource)
|
|
{
|
|
int color = _enableColor ? 1 : 0;
|
|
int displacement = _enableDisplacement ? 1 : 0;
|
|
int occlusion = _enableOcclusion ? 1 : 0;
|
|
|
|
const char *sources[2];
|
|
char define[1024];
|
|
sprintf(define,
|
|
"#define %s\n"
|
|
"#define USE_PTEX_COLOR %d\n"
|
|
"#define USE_PTEX_OCCLUSION %d\n"
|
|
"#define USE_PTEX_DISPLACEMENT %d\n",
|
|
section, color, occlusion, displacement);
|
|
|
|
sources[0] = define;
|
|
sources[1] = shaderSource;
|
|
|
|
GLuint shader = glCreateShader(shaderType);
|
|
glShaderSource(shader, 2, sources, NULL);
|
|
glCompileShader(shader);
|
|
|
|
GLint status;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
|
if( status == GL_FALSE ) {
|
|
GLchar emsg[1024];
|
|
glGetShaderInfoLog(shader, sizeof(emsg), 0, emsg);
|
|
fprintf(stderr, "Error compiling GLSL shader (%s): %s\n", section, emsg );
|
|
return 0;
|
|
}
|
|
|
|
return shader;
|
|
}
|
|
|
|
|
|
void
|
|
OpenSubdivPtexShader::linkProgram()
|
|
{
|
|
printf( "Link Program\n");
|
|
CHECK_GL_ERROR("link program 1\n");
|
|
if (_program)
|
|
glDeleteProgram(_program);
|
|
|
|
_invalidateEnvMap = true;
|
|
_invalidateDiffuseMap = true;
|
|
|
|
_program = glCreateProgram();
|
|
|
|
CHECK_GL_ERROR("link program 2\n");
|
|
|
|
const char *src = _shaderSource.c_str();
|
|
|
|
GLuint vertexShader = compileShader(GL_VERTEX_SHADER,
|
|
"VERTEX_SHADER", src);
|
|
GLuint geometryShader = compileShader(GL_GEOMETRY_SHADER,
|
|
"GEOMETRY_SHADER", src);
|
|
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER,
|
|
"FRAGMENT_SHADER", src);
|
|
|
|
glAttachShader(_program, vertexShader);
|
|
glAttachShader(_program, geometryShader);
|
|
glAttachShader(_program, fragmentShader);
|
|
|
|
glLinkProgram(_program);
|
|
|
|
glDeleteShader(vertexShader);
|
|
glDeleteShader(geometryShader);
|
|
glDeleteShader(fragmentShader);
|
|
|
|
CHECK_GL_ERROR("link program done\n");
|
|
GLint status;
|
|
glGetProgramiv(_program, GL_LINK_STATUS, &status );
|
|
if( status == GL_FALSE ) {
|
|
GLchar emsg[1024];
|
|
glGetProgramInfoLog(_program, sizeof(emsg), 0, emsg);
|
|
fprintf(stderr, "Error linking GLSL program : %s\n", emsg );
|
|
_program = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Viewport 2.0 override implementation
|
|
//---------------------------------------------------------------------------
|
|
class OsdPtexMeshData : public MUserData
|
|
{
|
|
public:
|
|
OsdPtexMeshData(MObject mesh);
|
|
virtual ~OsdPtexMeshData();
|
|
|
|
void populateIfNeeded(int level, int scheme);
|
|
void updateGeometry(const MHWRender::MVertexBuffer *point, const MHWRender::MVertexBuffer *normal);
|
|
void prepare();
|
|
void draw(GLuint program) const;
|
|
void update();
|
|
|
|
private:
|
|
void initializeOsd();
|
|
void initializeIndexBuffer();
|
|
void bindPtexCoordinates(GLuint program) const;
|
|
|
|
MObject _mesh;
|
|
|
|
OpenSubdiv::OsdHbrMesh *_hbrmesh;
|
|
OpenSubdiv::OsdMesh *_osdmesh;
|
|
// OpenSubdiv::OsdVertexBuffer *_vertexBuffer;
|
|
OpenSubdiv::OsdVertexBuffer *_positionBuffer, *_normalBuffer;
|
|
|
|
MFloatPointArray _pointArray;
|
|
MFloatVectorArray _normalArray;
|
|
|
|
// topology cache
|
|
MIntArray _vertexList;
|
|
MUintArray _edgeIds, _vtxIds;
|
|
MDoubleArray _edgeCreaseData, _vtxCreaseData;
|
|
int _level;
|
|
int _maxlevel;
|
|
int _interpBoundary;
|
|
int _scheme;
|
|
|
|
int _numIndices;
|
|
GLuint _indexBuffer;
|
|
|
|
bool _needsUpdate;
|
|
bool _needsInitializeOsd;
|
|
bool _needsInitializeIndexBuffer;
|
|
};
|
|
|
|
OsdPtexMeshData::OsdPtexMeshData(MObject mesh) :
|
|
MUserData(false), _mesh(mesh),
|
|
_hbrmesh(NULL), _osdmesh(NULL),
|
|
// _vertexBuffer(NULL),
|
|
_positionBuffer(NULL), _normalBuffer(NULL),
|
|
_level(0),
|
|
_interpBoundary(0),
|
|
_scheme(0),
|
|
_numIndices(0),
|
|
_indexBuffer(0),
|
|
_needsUpdate(false),
|
|
_needsInitializeOsd(false),
|
|
_needsInitializeIndexBuffer(false)
|
|
{
|
|
}
|
|
|
|
OsdPtexMeshData::~OsdPtexMeshData()
|
|
{
|
|
if (_hbrmesh) delete _hbrmesh;
|
|
if (_osdmesh) delete _osdmesh;
|
|
// if (_vertexBuffer) delete _vertexBuffer;
|
|
if (_positionBuffer) delete _positionBuffer;
|
|
if (_normalBuffer) delete _normalBuffer;
|
|
if (_indexBuffer)
|
|
glDeleteBuffers(1, &_indexBuffer);
|
|
|
|
}
|
|
|
|
void
|
|
OsdPtexMeshData::populateIfNeeded(int lv, int scheme)
|
|
{
|
|
MStatus s;
|
|
|
|
if (scheme == 1) scheme = 0; // avoid loop for now
|
|
|
|
MFnMesh meshFn(_mesh, &s);
|
|
if (s != MS::kSuccess) return;
|
|
|
|
if (lv < 1) lv =1;
|
|
|
|
MIntArray vertexCount, vertexList;
|
|
meshFn.getVertices(vertexCount, vertexList);
|
|
MUintArray edgeIds;
|
|
MDoubleArray edgeCreaseData;
|
|
meshFn.getCreaseEdges(edgeIds, edgeCreaseData);
|
|
MUintArray vtxIds;
|
|
MDoubleArray vtxCreaseData;
|
|
meshFn.getCreaseVertices(vtxIds, vtxCreaseData );
|
|
|
|
if (vertexCount.length() == 0) return;
|
|
|
|
short interpBoundary = 0;
|
|
FindAttribute(meshFn, "boundaryRule", &interpBoundary);
|
|
|
|
if(CompareArray(_vertexList, vertexList) &&
|
|
CompareArray(_edgeIds, edgeIds) &&
|
|
CompareArray(_edgeCreaseData, edgeCreaseData) &&
|
|
CompareArray(_vtxIds, vtxIds) &&
|
|
CompareArray(_vtxCreaseData, vtxCreaseData) &&
|
|
_interpBoundary == interpBoundary &&
|
|
_scheme == scheme &&
|
|
_maxlevel >= lv)
|
|
{
|
|
if(_level != lv) {
|
|
_level = lv;
|
|
_needsInitializeIndexBuffer = true;
|
|
}
|
|
return;
|
|
}
|
|
|
|
printf("Populate %s, level = %d < %d\n", meshFn.name().asChar(), lv, _level);
|
|
|
|
// update topology
|
|
_vertexList = vertexList;
|
|
_edgeIds = edgeIds;
|
|
_edgeCreaseData = edgeCreaseData;
|
|
_vtxIds = vtxIds;
|
|
_vtxCreaseData = vtxCreaseData;
|
|
_maxlevel = std::max(lv, _maxlevel);
|
|
_level = lv;
|
|
_interpBoundary = interpBoundary;
|
|
_scheme = scheme;
|
|
|
|
std::vector<int> numIndices, faceIndices, edgeCreaseIndices, vtxCreaseIndices;
|
|
std::vector<float> edgeCreases, vtxCreases;
|
|
numIndices.resize(vertexCount.length());
|
|
faceIndices.resize(vertexList.length());
|
|
for(int i = 0; i < (int)vertexCount.length(); ++i) numIndices[i] = vertexCount[i];
|
|
for(int i = 0; i < (int)vertexList.length(); ++i) faceIndices[i] = vertexList[i];
|
|
vtxCreaseIndices.resize(vtxIds.length());
|
|
for(int i = 0; i < (int)vtxIds.length(); ++i) vtxCreaseIndices[i] = vtxIds[i];
|
|
vtxCreases.resize(vtxCreaseData.length());
|
|
for(int i = 0; i < (int)vtxCreaseData.length(); ++i)
|
|
vtxCreases[i] = (float)vtxCreaseData[i];
|
|
edgeCreases.resize(edgeCreaseData.length());
|
|
for(int i = 0; i < (int)edgeCreaseData.length(); ++i)
|
|
edgeCreases[i] = (float)edgeCreaseData[i];
|
|
|
|
// edge crease index is stored as pair of <face id> <edge localid> ...
|
|
int nEdgeIds = edgeIds.length();
|
|
edgeCreaseIndices.resize(nEdgeIds*2);
|
|
for(int i = 0; i < nEdgeIds; ++i){
|
|
int2 vertices;
|
|
if (meshFn.getEdgeVertices(edgeIds[i], vertices) != MS::kSuccess) {
|
|
s.perror("ERROR can't get creased edge vertices");
|
|
continue;
|
|
}
|
|
edgeCreaseIndices[i*2] = vertices[0];
|
|
edgeCreaseIndices[i*2+1] = vertices[1];
|
|
}
|
|
|
|
_hbrmesh = ConvertToHBR(meshFn.numVertices(), numIndices, faceIndices,
|
|
vtxCreaseIndices, vtxCreases,
|
|
std::vector<int>(), std::vector<float>(),
|
|
edgeCreaseIndices, edgeCreases,
|
|
interpBoundary, scheme);
|
|
|
|
// GL function can't be used in prepareForDraw API.
|
|
_needsInitializeOsd = true;
|
|
}
|
|
|
|
void
|
|
OsdPtexMeshData::initializeOsd()
|
|
{
|
|
if (!_hbrmesh)
|
|
return;
|
|
|
|
// create Osd mesh
|
|
int kernel = OpenSubdiv::OsdKernelDispatcher::kCUDA;
|
|
// int kernel = OpenSubdiv::OsdKernelDispatcher::kCL;
|
|
// int kernel = OpenSubdiv::OsdKernelDispatcher::kCPU;
|
|
// if (OpenSubdiv::OsdKernelDispatcher::HasKernelType(OpenSubdiv::OsdKernelDispatcher::kOPENMP)) {
|
|
// kernel = OpenSubdiv::OsdKernelDispatcher::kOPENMP;
|
|
// }
|
|
if (_osdmesh)
|
|
delete _osdmesh;
|
|
|
|
_osdmesh = new OpenSubdiv::OsdMesh();
|
|
_osdmesh->Create(_hbrmesh, _level, kernel);
|
|
delete _hbrmesh;
|
|
_hbrmesh = NULL;
|
|
|
|
// create vertex buffer
|
|
// if (_vertexBuffer) delete _vertexBuffer;
|
|
// _vertexBuffer = _osdmesh->InitializeVertexBuffer(6 /* position + normal */);
|
|
if (_positionBuffer) delete _positionBuffer;
|
|
if (_normalBuffer) delete _normalBuffer;
|
|
_positionBuffer = _osdmesh->InitializeVertexBuffer(3);
|
|
_normalBuffer = _osdmesh->InitializeVertexBuffer(3);
|
|
|
|
_needsInitializeOsd = false;
|
|
_needsInitializeIndexBuffer = true;
|
|
|
|
// get geometry from maya mesh
|
|
MFnMesh meshFn(_mesh);
|
|
meshFn.getPoints(_pointArray);
|
|
meshFn.getVertexNormals(true, _normalArray);
|
|
|
|
_needsUpdate = true;
|
|
}
|
|
|
|
void
|
|
OsdPtexMeshData::updateGeometry(const MHWRender::MVertexBuffer *points, const MHWRender::MVertexBuffer *normals)
|
|
{
|
|
// Update vertex
|
|
// if (!_vertexBuffer) return;
|
|
if (!_positionBuffer) return;
|
|
if (!_normalBuffer) return;
|
|
|
|
int nCoarsePoints = _pointArray.length();
|
|
|
|
glBindBuffer(GL_COPY_READ_BUFFER, *(GLuint*)points->resourceHandle());
|
|
glBindBuffer(GL_COPY_WRITE_BUFFER, _positionBuffer->GetGpuBuffer());
|
|
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, nCoarsePoints*3*sizeof(float));
|
|
|
|
glBindBuffer(GL_COPY_READ_BUFFER, *(GLuint*)normals->resourceHandle());
|
|
glBindBuffer(GL_COPY_WRITE_BUFFER, _normalBuffer->GetGpuBuffer());
|
|
glCopyBufferSubData(GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, 0, 0, nCoarsePoints*3*sizeof(float));
|
|
|
|
glBindBuffer(GL_COPY_READ_BUFFER, 0);
|
|
glBindBuffer(GL_COPY_WRITE_BUFFER, 0);
|
|
|
|
_osdmesh->Subdivide(_positionBuffer, NULL);
|
|
_osdmesh->Subdivide(_normalBuffer, NULL);
|
|
|
|
#if 0
|
|
float *pbuffer = new float[nCoarsePoints*3];
|
|
float *nbuffer = new float[nCoarsePoints*3];
|
|
glBindBuffer(GL_ARRAY_BUFFER, *(GLuint*)points->resourceHandle());
|
|
glGetBufferSubData(GL_ARRAY_BUFFER, 0, nCoarsePoints*3*sizeof(float), pbuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, *(GLuint*)normals->resourceHandle());
|
|
glGetBufferSubData(GL_ARRAY_BUFFER, 0, nCoarsePoints*3*sizeof(float), nbuffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
|
|
const float *p = pbuffer, *n = nbuffer;;
|
|
for(int i = 0; i<nCoarsePoints; ++i) {
|
|
_pointArray[i] = MFloatPoint(p[0], p[1], p[2]);
|
|
_normalArray[i] = MFloatVector(n[0], n[1], n[2]);
|
|
p += 3;
|
|
n += 3;
|
|
}
|
|
delete[] pbuffer;
|
|
delete[] nbuffer;
|
|
|
|
int nPoints = _pointArray.length();
|
|
std::vector<float> vertex;
|
|
vertex.resize(nPoints*6);
|
|
|
|
for(int i = 0; i < nPoints; ++i){
|
|
vertex[i*6+0] = _pointArray[i].x;
|
|
vertex[i*6+1] = _pointArray[i].y;
|
|
vertex[i*6+2] = _pointArray[i].z;
|
|
vertex[i*6+3] = _normalArray[i].x;
|
|
vertex[i*6+4] = _normalArray[i].y;
|
|
vertex[i*6+5] = _normalArray[i].z;
|
|
}
|
|
|
|
_vertexBuffer->UpdateData(&vertex.at(0), nPoints);
|
|
_osdmesh->Subdivide(_vertexBuffer, NULL);
|
|
#endif
|
|
|
|
_needsUpdate = false;
|
|
}
|
|
|
|
void
|
|
OsdPtexMeshData::initializeIndexBuffer()
|
|
{
|
|
// update element array buffer
|
|
const std::vector<int> indices = _osdmesh->GetFarMesh()->GetFaceVertices(_level);
|
|
_numIndices = indices.size();
|
|
|
|
if (_indexBuffer == 0)
|
|
glGenBuffers(1, &_indexBuffer);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int)*_numIndices,
|
|
&(indices[0]), GL_STATIC_DRAW);
|
|
|
|
_needsInitializeIndexBuffer = false;
|
|
}
|
|
|
|
void
|
|
OsdPtexMeshData::bindPtexCoordinates(GLuint program) const
|
|
{
|
|
if (!_osdmesh) return;
|
|
|
|
// bind ptexture
|
|
GLint texIndices = glGetUniformLocation(program, "ptexIndices");
|
|
GLint ptexLevel = glGetUniformLocation(program, "ptexLevel");
|
|
|
|
glProgramUniform1i(program, ptexLevel, 1<<_level);
|
|
glProgramUniform1i(program, texIndices, 0);
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_BUFFER, _osdmesh->GetPtexCoordinatesTextureBuffer(_level));
|
|
}
|
|
|
|
void
|
|
OsdPtexMeshData::prepare()
|
|
{
|
|
if (_needsInitializeOsd) {
|
|
const_cast<OsdPtexMeshData*>(this)->initializeOsd();
|
|
}
|
|
if (_needsInitializeIndexBuffer) {
|
|
const_cast<OsdPtexMeshData*>(this)->initializeIndexBuffer();
|
|
}
|
|
}
|
|
|
|
void
|
|
OsdPtexMeshData::draw(GLuint program) const
|
|
{
|
|
MStatus status;
|
|
|
|
bindPtexCoordinates(program);
|
|
|
|
CHECK_GL_ERROR("draw begin\n");
|
|
|
|
glEnableVertexAttribArray(0);
|
|
glEnableVertexAttribArray(1);
|
|
#if 0
|
|
GLuint bVertex = _vertexBuffer->GetGpuBuffer();
|
|
glBindBuffer(GL_ARRAY_BUFFER, bVertex);
|
|
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, 0);
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 6, (float*)12);
|
|
#else
|
|
GLuint bPosition = _positionBuffer->GetGpuBuffer();
|
|
GLuint bNormal = _normalBuffer->GetGpuBuffer();
|
|
glBindBuffer(GL_ARRAY_BUFFER, bPosition);
|
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 3, 0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, bNormal);
|
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof (GLfloat) * 3, 0);
|
|
#endif
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
|
|
|
|
CHECK_GL_ERROR("before draw elements\n");
|
|
glDrawElements(GL_LINES_ADJACENCY, _numIndices, GL_UNSIGNED_INT, 0);
|
|
|
|
glDisableVertexAttribArray(0);
|
|
glDisableVertexAttribArray(1);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
|
|
CHECK_GL_ERROR("draw done\n");
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------
|
|
class OpenSubdivPtexShaderOverride : public MHWRender::MPxShaderOverride
|
|
{
|
|
public:
|
|
static MHWRender::MPxShaderOverride* creator(const MObject &obj)
|
|
{
|
|
return new OpenSubdivPtexShaderOverride(obj);
|
|
}
|
|
virtual ~OpenSubdivPtexShaderOverride();
|
|
|
|
virtual MString initialize(const MInitContext &initContext, MInitFeedback &initFeedback)
|
|
{
|
|
MString empty;
|
|
|
|
{
|
|
MHWRender::MVertexBufferDescriptor positionDesc(
|
|
empty,
|
|
MHWRender::MGeometry::kPosition,
|
|
MHWRender::MGeometry::kFloat,
|
|
3);
|
|
addGeometryRequirement(positionDesc);
|
|
}
|
|
|
|
MHWRender::MVertexBufferDescriptor positionDesc(
|
|
"osdPosition",
|
|
MHWRender::MGeometry::kTangent,
|
|
MHWRender::MGeometry::kFloat,
|
|
3);
|
|
positionDesc.setSemanticName("osdPosition");
|
|
addGeometryRequirement(positionDesc);
|
|
|
|
MHWRender::MVertexBufferDescriptor normalDesc(
|
|
"osdNormal",
|
|
MHWRender::MGeometry::kBitangent,
|
|
MHWRender::MGeometry::kFloat,
|
|
3);
|
|
normalDesc.setSemanticName("osdNormal");
|
|
addGeometryRequirement(normalDesc);
|
|
|
|
if (initFeedback.customData == NULL) {
|
|
OsdPtexMeshData *data = new OsdPtexMeshData(initContext.dagPath.node());
|
|
initFeedback.customData = data;
|
|
}
|
|
|
|
return MString("OpenSubdivPtexShaderOverride");
|
|
}
|
|
|
|
virtual void updateDG(MObject object)
|
|
{
|
|
if (object == MObject::kNullObj)
|
|
return;
|
|
|
|
_shader = (OpenSubdivPtexShader*)MPxHwShaderNode::getHwShaderNodePtr(object);
|
|
if (_shader) {
|
|
// MFnDependencyNode depFn(object);
|
|
// FindAttribute(depFn, "level", &_level);
|
|
|
|
_shader->updateUniforms();
|
|
}
|
|
}
|
|
virtual void updateDevice()
|
|
{
|
|
// only place to access GPU device safely
|
|
}
|
|
virtual void endUpdate()
|
|
{
|
|
}
|
|
|
|
/*
|
|
virtual void activateKey(MHWRender::MDrawContext &context, const MString &key)
|
|
{
|
|
}
|
|
|
|
virtual void terminateKey(MHWRender::MDrawContext &context, const MString &key)
|
|
{
|
|
}
|
|
*/
|
|
|
|
virtual bool draw(MHWRender::MDrawContext &context, const MHWRender::MRenderItemList &renderItemList) const;
|
|
|
|
virtual bool rebuildAlways()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
virtual MHWRender::DrawAPI supportedDrawAPIs() const
|
|
{
|
|
return MHWRender::kOpenGL;
|
|
}
|
|
virtual bool isTransparent()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
|
|
private:
|
|
OpenSubdivPtexShaderOverride(const MObject &obj);
|
|
|
|
OpenSubdivPtexShader *_shader;
|
|
int _level;
|
|
|
|
};
|
|
|
|
|
|
OpenSubdivPtexShaderOverride::OpenSubdivPtexShaderOverride(const MObject &obj)
|
|
: MHWRender::MPxShaderOverride(obj),
|
|
_shader(NULL)
|
|
{
|
|
}
|
|
|
|
OpenSubdivPtexShaderOverride::~OpenSubdivPtexShaderOverride()
|
|
{
|
|
}
|
|
|
|
|
|
bool
|
|
OpenSubdivPtexShaderOverride::draw(MHWRender::MDrawContext &context, const MHWRender::MRenderItemList &renderItemList) const
|
|
{
|
|
using namespace MHWRender;
|
|
{
|
|
MHWRender::MStateManager *stateMgr = context.getStateManager();
|
|
static const MDepthStencilState * depthState = NULL;
|
|
if (!depthState) {
|
|
MDepthStencilStateDesc desc;
|
|
depthState = stateMgr->acquireDepthStencilState(desc);
|
|
}
|
|
static const MBlendState *blendState = NULL;
|
|
if (!blendState) {
|
|
MBlendStateDesc desc;
|
|
|
|
for(int i = 0; i < (desc.independentBlendEnable ? MHWRender::MBlendState::kMaxTargets : 1); ++i)
|
|
{
|
|
desc.targetBlends[i].blendEnable = false;
|
|
}
|
|
blendState = stateMgr->acquireBlendState(desc);
|
|
}
|
|
|
|
stateMgr->setDepthStencilState(depthState);
|
|
stateMgr->setBlendState(blendState);
|
|
}
|
|
|
|
GLuint program = _shader->getProgram();
|
|
|
|
for(int i=0; i< renderItemList.length(); i++){
|
|
const MHWRender::MRenderItem *renderItem = renderItemList.itemAt(i);
|
|
// printf("draw: %d %s\n", i, renderItem->sourceDagPath().fullPathName().asChar());
|
|
// printf("# of indexBuffer = %d\n", renderItem->geometry()->indexBufferCount());
|
|
|
|
// const OsdPtexMeshData *data = (dynamic_cast<const OsdPtexMeshData*>(renderItem->customData());
|
|
OsdPtexMeshData *data = (OsdPtexMeshData*)(renderItem->customData());
|
|
if (data == NULL) {
|
|
return false;
|
|
}
|
|
|
|
data->populateIfNeeded(_shader->getLevel(), _shader->getScheme());
|
|
|
|
const MHWRender::MVertexBuffer *position = NULL, *normal = NULL;
|
|
{
|
|
const MHWRender::MGeometry *geometry = renderItem->geometry();
|
|
// printf("Vertex buffer count = %d\n", geometry->vertexBufferCount());
|
|
for(int i = 0; i < geometry->vertexBufferCount(); i++){
|
|
const MHWRender::MVertexBuffer *vb = geometry->vertexBuffer(i);
|
|
const MHWRender::MVertexBufferDescriptor &vdesc = vb->descriptor();
|
|
if (vdesc.name() == "osdPosition")
|
|
position = vb;
|
|
if (vdesc.name() == "osdNormal")
|
|
normal = vb;
|
|
// printf("%d: %s, offset=%d, stride=%d\n", i, vdesc.name().asChar(), vdesc.offset(), vdesc.stride());
|
|
}
|
|
}
|
|
|
|
glUseProgram(program);
|
|
{
|
|
// shader uniform setting
|
|
GLint position = glGetUniformLocation(program, "lightSource[0].position");
|
|
GLint ambient = glGetUniformLocation(program, "lightSource[0].ambient");
|
|
GLint diffuse = glGetUniformLocation(program, "lightSource[0].diffuse");
|
|
GLint specular = glGetUniformLocation(program, "lightSource[0].specular");
|
|
|
|
glProgramUniform4f(program, position, 0, 0.2f, 1, 0);
|
|
glProgramUniform4f(program, ambient, 0.4f, 0.4f, 0.4f, 1.0f);
|
|
glProgramUniform4f(program, diffuse, 0.3f, 0.3f, 0.3f, 1.0f);
|
|
glProgramUniform4f(program, specular, 0.2f, 0.2f, 0.2f, 1.0f);
|
|
|
|
GLint otcMatrix = glGetUniformLocation(program, "objectToClipMatrix");
|
|
GLint oteMatrix = glGetUniformLocation(program, "objectToEyeMatrix");
|
|
GLint etoMatrix = glGetUniformLocation(program, "eyeToObjectMatrix");
|
|
|
|
float modelview[4][4], mvp[4][4], modelviewI[4][4];
|
|
context.getMatrix(MHWRender::MDrawContext::kWorldViewMtx).get(modelview);
|
|
context.getMatrix(MHWRender::MDrawContext::kWorldViewProjMtx).get(mvp);
|
|
context.getMatrix(MHWRender::MDrawContext::kWorldViewInverseMtx).get(modelviewI);
|
|
|
|
glProgramUniformMatrix4fv(program, otcMatrix, 1, false, (float*)mvp);
|
|
glProgramUniformMatrix4fv(program, oteMatrix, 1, false, (float*)modelview);
|
|
glProgramUniformMatrix4fv(program, etoMatrix, 1, false, (float*)modelviewI);
|
|
|
|
GLint eye = glGetUniformLocation(program, "eyePositionInWorld");
|
|
MPoint e = MPoint(0,0,0) * context.getMatrix(MHWRender::MDrawContext::kWorldViewInverseMtx);
|
|
glProgramUniform3f(program, eye, e.x, e.y, e.z);
|
|
}
|
|
|
|
if (_shader->isWireframe()) {
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
|
} else {
|
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
|
}
|
|
|
|
_shader->bindTextures();
|
|
|
|
// CHECK_GL_ERROR("pre draw");
|
|
// draw meshdata
|
|
data->prepare();
|
|
|
|
data->updateGeometry(position, normal);
|
|
|
|
data->draw(program);
|
|
|
|
// CHECK_GL_ERROR("post draw");
|
|
|
|
glUseProgram(0);
|
|
}
|
|
return true;
|
|
}
|
|
// ------------------------------------------------------------------------------
|
|
|
|
using namespace MHWRender;
|
|
|
|
class OsdBufferGenerator : public MHWRender::MPxVertexBufferGenerator
|
|
{
|
|
public:
|
|
OsdBufferGenerator(bool normal) : _normal(normal) {}
|
|
virtual ~OsdBufferGenerator() {}
|
|
|
|
virtual bool getSourceIndexing(const MDagPath &dagPath, MHWRender::MComponentDataIndexing &sourceIndexing) const
|
|
{
|
|
MStatus status;
|
|
MFnMesh mesh(dagPath.node());
|
|
if (!status) return false;
|
|
|
|
MIntArray vertexCount, vertexList;
|
|
mesh.getVertices(vertexCount, vertexList);
|
|
|
|
MUintArray &vertices = sourceIndexing.indices();
|
|
for(unsigned int i = 0; i < vertexList.length(); ++i)
|
|
vertices.append((unsigned int)vertexList[i]);
|
|
|
|
sourceIndexing.setComponentType(MComponentDataIndexing::kFaceVertex); // .... although not facevertex
|
|
|
|
return true;
|
|
}
|
|
virtual bool getSourceStreams(const MDagPath &dagPath, MStringArray &) const
|
|
{
|
|
return false;
|
|
}
|
|
#ifdef MAYA2013_PREVIEW
|
|
virtual void createVertexStream(const MDagPath &dagPath, MVertexBuffer &vertexBuffer,
|
|
const MComponentDataIndexing &targetIndexing, const MComponentDataIndexing &,
|
|
const MVertexBufferArray &) const
|
|
#else
|
|
virtual void createVertexStream(const MDagPath &dagPath, MVertexBuffer &vertexBuffer,
|
|
const MComponentDataIndexing &targetIndexing) const
|
|
#endif
|
|
{
|
|
const MVertexBufferDescriptor &desc = vertexBuffer.descriptor();
|
|
|
|
MFnMesh meshFn(dagPath);
|
|
int nVertices = meshFn.numVertices();
|
|
if (!_normal) {
|
|
MFloatPointArray points;
|
|
meshFn.getPoints(points);
|
|
|
|
#ifdef MAYA2013_PREVIEW
|
|
float *buffer = (float*)vertexBuffer.acquire(nVertices, true);
|
|
#else
|
|
float *buffer = (float*)vertexBuffer.acquire(nVertices);
|
|
#endif
|
|
float *dst = buffer;
|
|
for(int i=0; i < nVertices; ++i){
|
|
*dst++ = points[i].x;
|
|
*dst++ = points[i].y;
|
|
*dst++ = points[i].z;
|
|
}
|
|
vertexBuffer.commit(buffer);
|
|
} else {
|
|
MFloatVectorArray normals;
|
|
meshFn.getVertexNormals(true, normals);
|
|
|
|
#ifdef MAYA2013_PREVIEW
|
|
float *buffer = (float*)vertexBuffer.acquire(nVertices, true);
|
|
#else
|
|
float *buffer = (float*)vertexBuffer.acquire(nVertices);
|
|
#endif
|
|
float *dst = buffer;
|
|
for(int i=0; i < nVertices; ++i){
|
|
*dst++ = normals[i].x;
|
|
*dst++ = normals[i].y;
|
|
*dst++ = normals[i].z;
|
|
}
|
|
vertexBuffer.commit(buffer);
|
|
}
|
|
}
|
|
|
|
static MPxVertexBufferGenerator *positionCreator()
|
|
{
|
|
return new OsdBufferGenerator(false);
|
|
}
|
|
static MPxVertexBufferGenerator *normalCreator()
|
|
{
|
|
return new OsdBufferGenerator(true);
|
|
}
|
|
private:
|
|
bool _normal;
|
|
};
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Plugin Registration
|
|
//---------------------------------------------------------------------------
|
|
MStatus
|
|
initializePlugin( MObject obj )
|
|
{
|
|
MStatus status;
|
|
MFnPlugin plugin( obj, "Pixar", "3.0", "Any" );// vender,version,apiversion
|
|
|
|
MString swatchName = MHWShaderSwatchGenerator::initialize();
|
|
MString userClassify("shader/surface/utility/:drawdb/shader/surface/OpenSubdivPtexShader:swatch/"+swatchName);
|
|
|
|
// shader node
|
|
status = plugin.registerNode( "openSubdivPtexShader",
|
|
OpenSubdivPtexShader::id,
|
|
&OpenSubdivPtexShader::creator,
|
|
&OpenSubdivPtexShader::initialize,
|
|
MPxNode::kHwShaderNode,
|
|
&userClassify);
|
|
|
|
MHWRender::MDrawRegistry::registerVertexBufferGenerator("osdPosition",
|
|
OsdBufferGenerator::positionCreator);
|
|
MHWRender::MDrawRegistry::registerVertexBufferGenerator("osdNormal",
|
|
OsdBufferGenerator::normalCreator);
|
|
|
|
// shaderoverride
|
|
status = MHWRender::MDrawRegistry::registerShaderOverrideCreator(
|
|
"drawdb/shader/surface/OpenSubdivPtexShader",
|
|
OpenSubdivPtexShader::drawRegistrantId,
|
|
OpenSubdivPtexShaderOverride::creator);
|
|
|
|
glewInit();
|
|
OpenSubdiv::OsdCpuKernelDispatcher::Register();
|
|
OpenSubdiv::OsdCudaKernelDispatcher::Register();
|
|
cudaInit();
|
|
|
|
OpenSubdiv::OsdPTexture::SetGutterWidth(1);
|
|
OpenSubdiv::OsdPTexture::SetPageMargin(8);
|
|
OpenSubdiv::OsdPTexture::SetGutterDebug(0);
|
|
|
|
return status;
|
|
}
|
|
|
|
MStatus
|
|
uninitializePlugin( MObject obj )
|
|
{
|
|
MFnPlugin plugin( obj );
|
|
|
|
MStatus status;
|
|
status = plugin.deregisterNode(OpenSubdivPtexShader::id);
|
|
|
|
MHWRender::MDrawRegistry::deregisterVertexBufferGenerator("osdPosition");
|
|
MHWRender::MDrawRegistry::deregisterVertexBufferGenerator("osdNormal");
|
|
|
|
status = MHWRender::MDrawRegistry::deregisterShaderOverrideCreator(
|
|
"drawdb/shader/surface/OpenSubdivPtexShader",
|
|
OpenSubdivPtexShader::drawRegistrantId);
|
|
|
|
return status;
|
|
}
|