material { name : ubershader_gpu, requires : [ uv0, uv1, color ], shadingModel : lit, blending : transparent, depthWrite : true, doubleSided : true, flipUV : false, specularAmbientOcclusion : simple, specularAntiAliasing : true, clearCoatIorChange : false, vertexDomain: world, parameters : [ { type : float3, name : specularFactor }, { type : float, name : glossinessFactor }, // Base Color { type : int, name : baseColorIndex }, { type : float4, name : baseColorFactor }, { type : sampler2d, name : baseColorMap }, { type : mat3, name : baseColorUvMatrix, precision: high }, // Metallic-Roughness Map { type : int, name : metallicRoughnessIndex }, { type : float, name : metallicFactor }, { type : float, name : roughnessFactor }, { type : sampler2d, name : metallicRoughnessMap }, { type : mat3, name : metallicRoughnessUvMatrix, precision: high }, // Normal Map { type : int, name : normalIndex }, { type : float, name : normalScale }, { type : sampler2d, name : normalMap }, { type : mat3, name : normalUvMatrix, precision: high }, // Ambient Occlusion { type : int, name : aoIndex }, { type : float, name : aoStrength }, { type : sampler2d, name : occlusionMap }, { type : mat3, name : occlusionUvMatrix, precision: high }, // Emissive Map { type : int, name : emissiveIndex }, { type : float3, name : emissiveFactor }, { type : sampler2d, name : emissiveMap }, { type : mat3, name : emissiveUvMatrix, precision: high }, // Cleat coat { type : float, name : clearCoatFactor }, { type : float, name : clearCoatRoughnessFactor }, { type : int, name : clearCoatIndex }, { type : sampler2d, name : clearCoatMap }, { type : mat3, name : clearCoatUvMatrix, precision: high }, { type : int, name : clearCoatRoughnessIndex }, { type : sampler2d, name : clearCoatRoughnessMap }, { type : mat3, name : clearCoatRoughnessUvMatrix, precision: high }, { type : int, name : clearCoatNormalIndex }, { type : sampler2d, name : clearCoatNormalMap }, { type : mat3, name : clearCoatNormalUvMatrix, precision: high }, { type : float, name : clearCoatNormalScale }, // Reflectance { type : float, name : reflectance }, { type : int3, name: dimensions }, { type : float[255], name:"morphTargetWeights" }, { type: sampler2dArray, format: float, name:"morphTargets" } ], } fragment { void material(inout MaterialInputs material) { highp float2 uvs[2]; uvs[0] = getUV0(); uvs[1] = getUV1(); if (materialParams.normalIndex > -1) { highp float2 uv = uvs[materialParams.normalIndex]; uv = (vec3(uv, 1.0) * materialParams.normalUvMatrix).xy; material.normal = texture(materialParams_normalMap, uv).xyz * 2.0 - 1.0; material.normal.xy *= materialParams.normalScale; } if (materialParams.clearCoatNormalIndex > -1) { highp float2 uv = uvs[materialParams.clearCoatNormalIndex]; uv = (vec3(uv, 1.0) * materialParams.clearCoatNormalUvMatrix).xy; material.clearCoatNormal = texture(materialParams_clearCoatNormalMap, uv).xyz * 2.0 - 1.0; material.clearCoatNormal.xy *= materialParams.clearCoatNormalScale; } prepareMaterial(material); material.baseColor = materialParams.baseColorFactor; if (materialParams.baseColorIndex > -1) { highp float2 uv = uvs[materialParams.baseColorIndex]; uv = (vec3(uv, 1.0) * materialParams.baseColorUvMatrix).xy; material.baseColor *= texture(materialParams_baseColorMap, uv); } material.baseColor *= getColor(); material.baseColor.rgb *= material.baseColor.a; material.roughness = materialParams.roughnessFactor; material.metallic = materialParams.metallicFactor; // KHR_materials_clearcoat forbids clear coat from // being applied in the specular/glossiness model material.clearCoat = materialParams.clearCoatFactor; material.clearCoatRoughness = materialParams.clearCoatRoughnessFactor; if (materialParams.clearCoatIndex > -1) { highp float2 uv = uvs[materialParams.clearCoatIndex]; uv = (vec3(uv, 1.0) * materialParams.clearCoatUvMatrix).xy; material.clearCoat *= texture(materialParams_clearCoatMap, uv).r; } if (materialParams.clearCoatRoughnessIndex > -1) { highp float2 uv = uvs[materialParams.clearCoatRoughnessIndex]; uv = (vec3(uv, 1.0) * materialParams.clearCoatRoughnessUvMatrix).xy; material.clearCoatRoughness *= texture(materialParams_clearCoatRoughnessMap, uv).g; } material.emissive = vec4(materialParams.emissiveFactor.rgb, 0.0); if (materialParams.metallicRoughnessIndex > -1) { highp float2 uv = uvs[materialParams.metallicRoughnessIndex]; uv = (vec3(uv, 1.0) * materialParams.metallicRoughnessUvMatrix).xy; vec4 mr = texture(materialParams_metallicRoughnessMap, uv); material.roughness *= mr.g; material.metallic *= mr.b; } if (materialParams.aoIndex > -1) { highp float2 uv = uvs[materialParams.aoIndex]; uv = (vec3(uv, 1.0) * materialParams.occlusionUvMatrix).xy; material.ambientOcclusion = texture(materialParams_occlusionMap, uv).r * materialParams.aoStrength; } if (materialParams.emissiveIndex > -1) { highp float2 uv = uvs[materialParams.emissiveIndex]; uv = (vec3(uv, 1.0) * materialParams.emissiveUvMatrix).xy; material.emissive.rgb *= texture(materialParams_emissiveMap, uv).rgb; } } } vertex { vec3 getMorphTarget(int vertexIndex, int morphTargetIndex) { // our texture is laid out as (x,y,z) where y is 1, z is the number of morph targets, and x is the number of vertices * 2 (multiplication accounts for position + normal) // UV coordinates are normalized to (-1,1), so we divide the current vertex index by the total number of vertices to find the correct coordinate for this vertex vec3 uv = vec3( (float(vertexIndex) + 0.5) / float(materialParams.dimensions.x), 0.0f, //(float(morphTargetIndex) + 0.5f) / float(materialParams.dimensions.z)); float(morphTargetIndex)); return texture(materialParams_morphTargets, uv).xyz; } void materialVertex(inout MaterialVertexInputs material) { // for every morph target for(int morphTargetIndex = 0; morphTargetIndex < materialParams.dimensions.z; morphTargetIndex++) { // get the weight to apply float weight = materialParams.morphTargetWeights[morphTargetIndex]; // get the ID of this vertex, which will be the x-offset of the position attribute in the texture sampler int vertexId = getVertexIndex(); // get the position of the target for this vertex vec3 morphTargetPosition = getMorphTarget(vertexId, morphTargetIndex); // update the world position of this vertex material.worldPosition.xyz += (weight * morphTargetPosition); // increment the vertexID by half the size of the texture to get the x-offset of the normal (all positions stored in the first half, all normals stored in the second half) vertexId += (materialParams.dimensions.x / 2); // get the normal of this target for this vertex vec3 morphTargetNormal = getMorphTarget(vertexId, morphTargetIndex); material.worldNormal += (weight * morphTargetNormal); } mat4 transform = getWorldFromModelMatrix(); material.worldPosition = mulMat4x4Float3(transform, material.worldPosition.xyz); } }