add GPU morpher + Dart API
This commit is contained in:
BIN
example/assets/compiled.mat
Normal file
BIN
example/assets/compiled.mat
Normal file
Binary file not shown.
185
example/assets/ubershader_gpu.mat.in
Normal file
185
example/assets/ubershader_gpu.mat.in
Normal file
@@ -0,0 +1,185 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:async';
|
||||
|
||||
@@ -19,6 +21,10 @@ class MyApp extends StatefulWidget {
|
||||
class _MyAppState extends State<MyApp> {
|
||||
final FilamentController _filamentController = MimeticFilamentController();
|
||||
|
||||
double _zoomValue = 0;
|
||||
int _primitiveIndex = 0;
|
||||
double _weight = 0.0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -38,7 +44,6 @@ class _MyAppState extends State<MyApp> {
|
||||
details.localPosition.dx, details.localPosition.dy);
|
||||
},
|
||||
onPanUpdate: (details) {
|
||||
print(details.localPosition.dx);
|
||||
_filamentController.panUpdate(
|
||||
details.localPosition.dx, details.localPosition.dy);
|
||||
},
|
||||
@@ -51,22 +56,78 @@ class _MyAppState extends State<MyApp> {
|
||||
ElevatedButton(
|
||||
child: Text("initialize"),
|
||||
onPressed: () {
|
||||
_filamentController.initialize();
|
||||
}),
|
||||
ElevatedButton(
|
||||
child: Text("load skybox"),
|
||||
onPressed: () {
|
||||
_filamentController.initialize(
|
||||
materialPath: "assets/compiled.mat");
|
||||
_filamentController.loadSkybox(
|
||||
"assets/default_env/default_env_skybox.ktx",
|
||||
"assets/default_env/default_env_ibl.ktx");
|
||||
}),
|
||||
ElevatedButton(
|
||||
child: Text("load gltf"),
|
||||
onPressed: () {
|
||||
_filamentController.loadGltf(
|
||||
"assets/BusterDrone/scene.gltf",
|
||||
"assets/BusterDrone");
|
||||
"assets/guy.gltf", "assets", "Material");
|
||||
_filamentController.createMorpher(
|
||||
"CC_Base_Body.003", "CC_Base_Body.003",
|
||||
materialName: "Material");
|
||||
}),
|
||||
// ElevatedButton(
|
||||
// child: Text("load skybox"),
|
||||
// onPressed: () {
|
||||
// _filamentController.loadSkybox(
|
||||
// "assets/default_env/default_env_skybox.ktx",
|
||||
// "assets/default_env/default_env_ibl.ktx");
|
||||
// }),
|
||||
// ElevatedButton(
|
||||
// child: Text("load gltf"),
|
||||
// onPressed: () {
|
||||
// _filamentController.loadGltf(
|
||||
// "assets/guy.gltf", "assets", "Material");
|
||||
// }),
|
||||
// ElevatedButton(
|
||||
// child: Text("create morpher"),
|
||||
// onPressed: () {
|
||||
// _filamentController.createMorpher(
|
||||
// "CC_Base_Body.003", "CC_Base_Body.003",
|
||||
// materialName: "Material");
|
||||
// }),
|
||||
Row(children: [
|
||||
Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
color: Colors.white,
|
||||
child: Text(_primitiveIndex.toString())),
|
||||
ElevatedButton(
|
||||
child: Text("+"),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_primitiveIndex = min(_primitiveIndex + 1, 5);
|
||||
});
|
||||
}),
|
||||
ElevatedButton(
|
||||
child: Text("-"),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_primitiveIndex = max(_primitiveIndex - 1, 0);
|
||||
});
|
||||
}),
|
||||
]),
|
||||
Slider(
|
||||
min: 0,
|
||||
max: 1,
|
||||
divisions: 10,
|
||||
value: _weight,
|
||||
onChanged: (v) {
|
||||
setState(() {
|
||||
_weight = v;
|
||||
_filamentController.applyWeights(
|
||||
List.filled(255, _weight), _primitiveIndex.toInt());
|
||||
print("Set $_primitiveIndex to $_weight");
|
||||
});
|
||||
}),
|
||||
Row(children: [
|
||||
ElevatedButton(
|
||||
onPressed: () => _filamentController.zoom(1.0),
|
||||
child: Text("+")),
|
||||
ElevatedButton(
|
||||
onPressed: () => _filamentController.zoom(-1.0),
|
||||
child: Text("-"))
|
||||
])
|
||||
]),
|
||||
])),
|
||||
),
|
||||
|
||||
@@ -47,6 +47,7 @@ flutter:
|
||||
- assets/BusterDrone/textures/
|
||||
- assets/FlightHelmet/
|
||||
- assets/FlightHelmet/textures/
|
||||
- assets/textures/
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
# https://flutter.dev/assets-and-images/#resolution-aware.
|
||||
|
||||
Reference in New Issue
Block a user