-- glslfx version 0.1 // // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // --- This is what an import might look like. --- #import $TOOLS/hdSt/shaders/mesh.glslfx #import $TOOLS/hdSt/shaders/instancing.glslfx #import $TOOLS/hdSt/shaders/meshNormal.glslfx #import $TOOLS/hdSt/shaders/meshWire.glslfx #import $TOOLS/hdSt/shaders/terminals.glslfx #import $TOOLS/hdSt/shaders/edgeId.glslfx #import $TOOLS/hdSt/shaders/pointId.glslfx #import $TOOLS/hdSt/shaders/visibility.glslfx --- -------------------------------------------------------------------------- -- glsl Mesh.Vertex out VertexData { vec4 Peye; vec3 Neye; } outData; out vec4 tesPatchCoord; out vec2 tesTessCoord; out vec4 gsPatchCoord; out vec2 gsTessCoord; // Fwd declare methods defined in pointId.glslfx, that are used below. int GetPointId(); float GetPointRasterSize(int); void ProcessPointId(int); void main(void) { ProcessPrimvars(); MAT4 transform = ApplyInstanceTransform(HdGet_transform()); vec4 point = vec4(HdGet_points().xyz, 1); outData.Peye = vec4(GetWorldToViewMatrix() * transform * point); outData.Neye = GetNormal(vec3(0), 0); // normalized // Fill out redundantly, since at this point we don't know // the following stages include tessellation or geometry shader. // we rely on that compiler (linker) optimizes out these redundant // assignment and attribute plumbing. tesPatchCoord = gsPatchCoord = vec4(0); tesTessCoord = gsTessCoord = vec2(0); int pointId = GetPointId(); gl_PointSize = GetPointRasterSize(pointId); ProcessPointId(pointId); gl_Position = vec4(GetProjectionMatrix() * outData.Peye); ApplyClipPlanes(outData.Peye); } --- -------------------------------------------------------------------------- -- glsl Mesh.TessControl.BSplineQuad layout(vertices = 16) out; patch out vec4 tessOuterLo, tessOuterHi; in VertexData { vec4 Peye; vec3 Neye; } inpt[gl_MaxPatchVertices]; out VertexDataTess { OsdPerPatchVertexBezier v; } outpt[16]; void main(void) { vec3 cv[16]; for (int i = 0; i < 16; ++i) { cv[i] = inpt[i].Peye.xyz; } ivec3 patchParam = GetPatchParam(); OsdComputePerPatchVertexBSpline(patchParam, gl_InvocationID, cv, outpt[gl_InvocationID].v); // Wait for all basis conversion to be finished barrier(); if (gl_InvocationID == 0) { vec4 tessLevelOuter = vec4(0); vec2 tessLevelInner = vec2(0); // Gather bezier control points to compute limit surface tess levels OsdPerPatchVertexBezier cpBezier[16]; for (int i = 0; i < 16; ++i) { cpBezier[i] = outpt[i].v; } OsdGetTessLevelsAdaptiveLimitPoints(cpBezier, patchParam, tessLevelOuter, tessLevelInner, tessOuterLo, tessOuterHi); gl_TessLevelOuter[0] = tessLevelOuter[0]; gl_TessLevelOuter[1] = tessLevelOuter[1]; gl_TessLevelOuter[2] = tessLevelOuter[2]; gl_TessLevelOuter[3] = tessLevelOuter[3]; gl_TessLevelInner[0] = tessLevelInner[0]; gl_TessLevelInner[1] = tessLevelInner[1]; } ProcessPrimvars(); } --- -------------------------------------------------------------------------- -- glsl Mesh.TessEval.BezierQuad layout(quads) in; patch in vec4 tessOuterLo, tessOuterHi; in VertexDataTess { OsdPerPatchVertexBezier v; } inpt[gl_MaxPatchVertices]; out VertexData { vec4 Peye; vec3 Neye; } outData; // XXX: due to NVIDIA shader compiler bug (filed as 1687344) // we can't put patchCoord into interface block. out vec4 tesPatchCoord; out vec2 tesTessCoord; void main(void) { OsdPerPatchVertexBezier cv[16]; for (int i = 0; i < 16; ++i) { cv[i] = inpt[i].v; } vec2 UV = OsdGetTessParameterization(gl_TessCoord.xy, tessOuterLo, tessOuterHi); vec3 P = vec3(0), dPu = vec3(0), dPv = vec3(0); vec3 N = vec3(0), dNu = vec3(0), dNv = vec3(0); ivec3 patchParam = inpt[0].v.patchParam; OsdEvalPatchBezier(patchParam, UV, cv, P, dPu, dPv, N, dNu, dNv); outData.Peye = vec4(P, 1); outData.Neye = N; // normalized tesPatchCoord = OsdInterpolatePatchCoord(UV, patchParam); tesTessCoord = UV; // Bilinear basis vec4 basis = vec4( (1.0-UV.x) * (1.0-UV.y), UV.x * (1.0-UV.y), (1.0-UV.x) * UV.y, UV.x * UV.y ); ProcessPrimvars(basis, 5, 6, 9, 10); } --- -------------------------------------------------------------------------- -- glsl Mesh.TessControl.BoxSplineTriangle layout(vertices = 15) out; patch out vec4 tessOuterLo, tessOuterHi; in VertexData { vec4 Peye; vec3 Neye; } inpt[gl_MaxPatchVertices]; out VertexDataTess { OsdPerPatchVertexBezier v; } outpt[16]; void main(void) { vec3 cv[12]; for (int i = 0; i < 12; ++i) { cv[i] = inpt[i].Peye.xyz; } ivec3 patchParam = GetPatchParam(); OsdComputePerPatchVertexBoxSplineTriangle(patchParam, gl_InvocationID, cv, outpt[gl_InvocationID].v); // Wait for all basis conversion to be finished barrier(); if (gl_InvocationID == 0) { vec4 tessLevelOuter = vec4(0); vec2 tessLevelInner = vec2(0); // Gather bezier control points to compute limit surface tess levels vec3 cpBezier[15]; for (int i = 0; i < 15; ++i) { cpBezier[i] = outpt[i].v.P; } OsdEvalPatchBezierTriangleTessLevels(cpBezier, patchParam, tessLevelOuter, tessLevelInner, tessOuterLo, tessOuterHi); gl_TessLevelOuter[0] = tessLevelOuter[0]; gl_TessLevelOuter[1] = tessLevelOuter[1]; gl_TessLevelOuter[2] = tessLevelOuter[2]; gl_TessLevelInner[0] = tessLevelInner[0]; } ProcessPrimvars(); } --- -------------------------------------------------------------------------- -- glsl Mesh.TessEval.BezierTriangle layout(triangles) in; patch in vec4 tessOuterLo, tessOuterHi; in VertexDataTess { OsdPerPatchVertexBezier v; } inpt[gl_MaxPatchVertices]; out VertexData { vec4 Peye; vec3 Neye; } outData; // XXX: due to NVIDIA shader compiler bug (filed as 1687344) // we can't put patchCoord into interface block. out vec4 tesPatchCoord; out vec2 tesTessCoord; void main(void) { OsdPerPatchVertexBezier cv[15]; for (int i = 0; i < 15; ++i) { cv[i] = inpt[i].v; } vec2 UV = OsdGetTessParameterizationTriangle(gl_TessCoord.xyz, tessOuterLo, tessOuterHi); vec3 P = vec3(0), dPu = vec3(0), dPv = vec3(0); vec3 N = vec3(0), dNu = vec3(0), dNv = vec3(0); ivec3 patchParam = inpt[0].v.patchParam; OsdEvalPatchBezierTriangle(patchParam, UV, cv, P, dPu, dPv, N, dNu, dNv); outData.Peye = vec4(P, 1); outData.Neye = N; // normalized tesPatchCoord = OsdInterpolatePatchCoordTriangle(UV, patchParam); tesTessCoord = vec2(0); // used only for hiding internal edges w/ quad tess // Barycentric basis vec4 basis = vec4( (1.0f-UV.x-UV.y), UV.x, UV.y, 0.0f); ProcessPrimvars(basis, 4, 5, 8, 0); } --- -------------------------------------------------------------------------- -- glsl Mesh.Geometry.TriangleTess layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; in VertexData { vec4 Peye; vec3 Neye; } inData[3]; in vec4 tesPatchCoord[3]; in vec2 tesTessCoord[3]; out VertexData { vec4 Peye; vec3 Neye; } outData; out vec4 gsPatchCoord; out vec2 gsTessCoord; vec4 GetPatchCoord(int index) { return tesPatchCoord[index]; } void emit(int index, vec4 Peye, vec3 Neye, vec4 triPeye0, vec4 triPeye1, vec4 triPeye2) { outData.Peye = Peye; outData.Neye = Neye; gsPatchCoord = GetPatchCoord(index); gsTessCoord = vec2(0); gl_Position = vec4(GetProjectionMatrix() * outData.Peye); ApplyClipPlanes(outData.Peye); int inEdgeFlag = 0; vec2 dt01 = abs(tesTessCoord[0] - tesTessCoord[1]); vec2 dt12 = abs(tesTessCoord[1] - tesTessCoord[2]); vec2 dt20 = abs(tesTessCoord[2] - tesTessCoord[0]); if (min(dt01.x, dt01.y) > 0.03) inEdgeFlag |= 2; if (min(dt12.x, dt12.y) > 0.03) inEdgeFlag |= 4; if (min(dt20.x, dt20.y) > 0.03) inEdgeFlag |= 1; ProcessTriEdgeDistance(Peye, triPeye0, triPeye1, triPeye2, inEdgeFlag); ProcessEdgeId(index, gsPatchCoord.xy); ProcessPrimvars(index); EmitVertex(); } void main(void) { gl_PrimitiveID = gl_PrimitiveIDIn; bool isFlipped = IsFlipped(); // consider handedness AND negative-scale vec3 Neye0 = isFlipped ? -inData[0].Neye : inData[0].Neye; Neye0 = GetNormal(Neye0, 0); Neye0 = GetTriGeometryNormal(Neye0, inData[0].Peye, inData[1].Peye, inData[2].Peye, isFlipped); vec3 Neye1 = isFlipped ? -inData[1].Neye : inData[1].Neye; Neye1 = GetNormal(Neye1, 0); Neye1 = GetTriGeometryNormal(Neye1, inData[0].Peye, inData[1].Peye, inData[2].Peye, isFlipped); vec3 Neye2 = isFlipped ? -inData[2].Neye : inData[2].Neye; Neye2 = GetNormal(Neye2, 0); Neye2 = GetTriGeometryNormal(Neye2, inData[0].Peye, inData[1].Peye, inData[2].Peye, isFlipped); vec4 Peye0 = DisplacementTerminal( 0, inData[0].Peye, Neye0, GetPatchCoord(0)); vec4 Peye1 = DisplacementTerminal( 1, inData[1].Peye, Neye1, GetPatchCoord(1)); vec4 Peye2 = DisplacementTerminal( 2, inData[2].Peye, Neye2, GetPatchCoord(2)); // triangle 0: vertices (0,1,2) emit(0, Peye0, Neye0, Peye0, Peye1, Peye2); emit(1, Peye1, Neye1, Peye0, Peye1, Peye2); emit(2, Peye2, Neye2, Peye0, Peye1, Peye2); EndPrimitive(); } --- -------------------------------------------------------------------------- -- glsl Mesh.Geometry.Triangle layout(triangles) in; layout(triangle_strip, max_vertices = 3) out; in VertexData { vec4 Peye; vec3 Neye; } inData[3]; out VertexData { vec4 Peye; vec3 Neye; } outData; out vec4 gsPatchCoord; out vec2 gsTessCoord; // The OpenSubdiv implementation does not yet provide a utility // method to interpolate barycentric patch coordinates so we provide // our own implementation modeled after OsdInterpolatePatchCoord(). // We need to interpolate only two of the three barycentric coordinates. vec4 InterpolatePatchCoordBarycentric(vec2 localUV, ivec3 patchParam) { ivec4 perPrimPatchCoord = OsdGetPatchCoord(patchParam); int faceId = perPrimPatchCoord.w; int faceLevel = perPrimPatchCoord.z; vec2 faceUV = vec2(perPrimPatchCoord.x, perPrimPatchCoord.y); localUV = (faceUV + localUV) / faceLevel; if ((faceUV.x + faceUV.y) >= faceLevel) { localUV = vec2(1.0f) - localUV; } // add 0.5 to integer values for more robust interpolation return vec4(localUV.x, localUV.y, faceLevel+0.5f, faceId+0.5f); } vec4 GetPatchCoord(int index) { vec2 uv[3]; uv[0] = vec2(0, 0); // (0, 0, 1); uv[1] = vec2(1, 0); // (1, 0, 0); uv[2] = vec2(0, 1); // (0, 1, 0); ivec3 patchParam = GetPatchParam(); return InterpolatePatchCoordBarycentric(uv[index], patchParam); } void emit(int index, vec4 Peye, vec3 Neye, vec4 triPeye0, vec4 triPeye1, vec4 triPeye2) { outData.Peye = Peye; outData.Neye = Neye; gsPatchCoord = GetPatchCoord(index); gsTessCoord = vec2(0); gl_Position = vec4(GetProjectionMatrix() * outData.Peye); ApplyClipPlanes(outData.Peye); int inEdgeFlag = 0; ProcessTriEdgeDistance(Peye, triPeye0, triPeye1, triPeye2, inEdgeFlag); ProcessEdgeId(index, gsPatchCoord.xy); ProcessPrimvars(index); EmitVertex(); } void main(void) { gl_PrimitiveID = gl_PrimitiveIDIn; bool isFlipped = IsFlipped(); // consider handedness AND negative-scale vec3 Neye0 = GetNormal(inData[0].Neye, 0); Neye0 = GetTriGeometryNormal(Neye0, inData[0].Peye, inData[1].Peye, inData[2].Peye, isFlipped); vec3 Neye1 = GetNormal(inData[1].Neye, 1); Neye1 = GetTriGeometryNormal(Neye1, inData[0].Peye, inData[1].Peye, inData[2].Peye, isFlipped); vec3 Neye2 = GetNormal(inData[2].Neye, 2); Neye2 = GetTriGeometryNormal(Neye2, inData[0].Peye, inData[1].Peye, inData[2].Peye, isFlipped); vec4 Peye0 = DisplacementTerminal( 0, inData[0].Peye, Neye0, GetPatchCoord(0)); vec4 Peye1 = DisplacementTerminal( 1, inData[1].Peye, Neye1, GetPatchCoord(1)); vec4 Peye2 = DisplacementTerminal( 2, inData[2].Peye, Neye2, GetPatchCoord(2)); // triangle 0: vertices (0,1,2) emit(0, Peye0, Neye0, Peye0, Peye1, Peye2); emit(1, Peye1, Neye1, Peye0, Peye1, Peye2); emit(2, Peye2, Neye2, Peye0, Peye1, Peye2); EndPrimitive(); } --- -------------------------------------------------------------------------- -- glsl Mesh.Geometry.Quad layout(lines_adjacency) in; layout(triangle_strip, max_vertices = 6) out; in VertexData { vec4 Peye; vec3 Neye; } inData[4]; out VertexData { vec4 Peye; vec3 Neye; } outData; out vec4 gsPatchCoord; out vec2 gsTessCoord; vec4 GetPatchCoord(int index) { vec2 uv[4]; uv[0] = vec2(0, 0); uv[1] = vec2(1, 0); uv[2] = vec2(1, 1); uv[3] = vec2(0, 1); ivec3 patchParam = GetPatchParam(); return OsdInterpolatePatchCoord(uv[index], patchParam); } void emit(int triCounter, int index, vec4 Peye, vec3 Neye, vec4 triPeye0, vec4 triPeye1, vec4 triPeye2) { outData.Peye = Peye; outData.Neye = Neye; gsPatchCoord = GetPatchCoord(index); gsTessCoord = vec2(0); gl_Position = vec4(GetProjectionMatrix() * outData.Peye); ApplyClipPlanes(outData.Peye); ProcessQuadEdgeDistance(Peye, triPeye0, triPeye1, triPeye2, triCounter); ProcessEdgeId(index, gsPatchCoord.xy); ProcessPrimvars(index); EmitVertex(); } void main(void) { gl_PrimitiveID = gl_PrimitiveIDIn; bool isFlipped = IsFlipped(); // consider handedness AND negative-scale vec3 Neye0 = GetNormal(inData[0].Neye, 0); Neye0 = GetQuadGeometryNormal(Neye0, inData[0].Peye, inData[1].Peye, inData[2].Peye, inData[3].Peye, isFlipped); vec3 Neye1 = GetNormal(inData[1].Neye, 1); Neye1 = GetQuadGeometryNormal(Neye1, inData[0].Peye, inData[1].Peye, inData[2].Peye, inData[3].Peye, isFlipped); vec3 Neye2 = GetNormal(inData[2].Neye, 2); Neye2 = GetQuadGeometryNormal(Neye2, inData[0].Peye, inData[1].Peye, inData[2].Peye, inData[3].Peye, isFlipped); vec3 Neye3 = GetNormal(inData[3].Neye, 3); Neye3 = GetQuadGeometryNormal(Neye3, inData[0].Peye, inData[1].Peye, inData[2].Peye, inData[3].Peye, isFlipped); vec4 Peye0 = DisplacementTerminal( 0, inData[0].Peye, Neye0, GetPatchCoord(0)); vec4 Peye1 = DisplacementTerminal( 1, inData[1].Peye, Neye1, GetPatchCoord(1)); vec4 Peye2 = DisplacementTerminal( 2, inData[2].Peye, Neye2, GetPatchCoord(2)); vec4 Peye3 = DisplacementTerminal( 3, inData[3].Peye, Neye3, GetPatchCoord(3)); // Generate triangles (3,0,2) and (2,0,1) // 0---3 // |. | // | . | // | .| // 1---2 // The indices post-quadrangulation/subdivision follow the convention: // 0 -> original (hull) vertex // 1,3 -> edge vertices // 2 -> center vertex // // By having index 2 in both the triangles, we ensure the pre-quadrangulated // face's normal (at the center) is part of the rasterizer interpolation, // which matters when we use smooth/limit normals. // In the case of flat normals, we use the vertex positions, so it doesn't // matter. // triangle 0: vertices (3,0,2) emit(0, 3, Peye3, Neye3, Peye3, Peye0, Peye2); emit(0, 0, Peye0, Neye0, Peye3, Peye0, Peye2); emit(0, 2, Peye2, Neye2, Peye3, Peye0, Peye2); EndPrimitive(); // triangle 1: vertices (2,0,1) emit(1, 2, Peye2, Neye2, Peye2, Peye0, Peye1); emit(1, 0, Peye0, Neye0, Peye2, Peye0, Peye1); emit(1, 1, Peye1, Neye1, Peye2, Peye0, Peye1); EndPrimitive(); } --- -------------------------------------------------------------------------- -- glsl Mesh.Fragment in VertexData { vec4 Peye; vec3 Neye; } inData; in vec4 gsPatchCoord; in vec2 gsTessCoord; #ifndef HD_HAS_ptexFaceOffset #define HD_HAS_ptexFaceOffset int HdGet_ptexFaceOffset() { return 0; } #endif vec4 GetPatchCoord(int localIndex) { return vec4(gsPatchCoord.xyz, gsPatchCoord.w + HdGet_ptexFaceOffset()); } void main(void) { bool isFlipped = IsFlipped(); if (ShouldCullFaceAccordingToShading(gl_FrontFacing, isFlipped)) { discard; } DiscardBasedOnTopologicalVisibility(); vec4 color = vec4(0.5, 0.5, 0.5, 1); #ifdef HD_HAS_displayColor color.rgb = HdGet_displayColor().rgb; #endif #ifdef HD_HAS_displayOpacity color.a = HdGet_displayOpacity().r; #endif vec3 Peye = inData.Peye.xyz / inData.Peye.w; vec3 Neye = inData.Neye; // Normalize Neye after rasterizer interpolation. if (length(Neye) > 0.0) { Neye = normalize(Neye); } // Give the shader key a chance to override the normal. Neye = GetNormal(Neye, 0); // Orient the normal for shading. Neye = GetShadingNormal(Neye, isFlipped); vec4 patchCoord = GetPatchCoord(); color = ShadingTerminal(vec4(Peye, 1), Neye, color, patchCoord); color = ApplyEdgeColor(color, patchCoord); if (ShouldDiscardByAlpha(color)) { discard; } RenderOutput(vec4(Peye, 1), Neye, color, patchCoord); }