Compare commits
4 Commits
master
...
shader-nod
Author | SHA1 | Date |
---|---|---|
Nehon | 523087a82f | 7 years ago |
Nehon | b57ecf35ea | 7 years ago |
Nehon | 9f9edee332 | 7 years ago |
Nehon | 7055de4531 | 7 years ago |
@ -0,0 +1,105 @@ |
|||||||
|
package com.jme3.shader.builder; |
||||||
|
|
||||||
|
import com.jme3.material.TechniqueDef; |
||||||
|
import com.jme3.shader.*; |
||||||
|
|
||||||
|
import java.util.regex.Matcher; |
||||||
|
import java.util.regex.Pattern; |
||||||
|
|
||||||
|
public class InlineShaderNodeBuilder extends ShaderNodeBuilder { |
||||||
|
|
||||||
|
|
||||||
|
private TechniqueDef technique; |
||||||
|
private Pattern varPattern = Pattern.compile("%(\\w+)"); |
||||||
|
private String[] outputTypes; |
||||||
|
|
||||||
|
public InlineShaderNodeBuilder(String name, ShaderNodeDefinition def, String code, TechniqueDef technique) { |
||||||
|
super(name, def); |
||||||
|
this.technique = technique; |
||||||
|
Matcher m = varPattern.matcher(code); |
||||||
|
while (m.find()) { |
||||||
|
// type will be inferred with mapping
|
||||||
|
ShaderNodeVariable v = new ShaderNodeVariable(null, m.group(1)); |
||||||
|
def.getParams().add(v); |
||||||
|
def.getInputs().add(v); |
||||||
|
} |
||||||
|
def.setInlinedCode(code.replaceAll("%", "")); |
||||||
|
def.getOutputs().add(new ShaderNodeVariable(def.getReturnType(), "result")); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public InlineShaderNodeBuilder inputs(VariableMappingBuilder... inputs) { |
||||||
|
ShaderNodeDefinition def = getNode().getDefinition(); |
||||||
|
for (VariableMappingBuilder map : inputs) { |
||||||
|
ShaderNodeVariable v = findVariable(map.getName(), def.getInputs()); |
||||||
|
|
||||||
|
def.getInputs().add(v); |
||||||
|
ShaderNodeVariable right = map.getVariable(); |
||||||
|
if (right.getDefaultValue() != null) { |
||||||
|
throw new IllegalArgumentException("Inlined expression for input " + v.getName() |
||||||
|
+ " is not supported with inline node " + getNode().getName() |
||||||
|
+ ". Please inline the expression in the node code."); |
||||||
|
} |
||||||
|
// infer type
|
||||||
|
int idx = right.getType().indexOf("|"); |
||||||
|
if (idx > 0) { |
||||||
|
// texture type, taking the first available type
|
||||||
|
String type = right.getType().substring(0, right.getType().indexOf("|")); |
||||||
|
right.setType(type); |
||||||
|
} |
||||||
|
|
||||||
|
v.setType(right.getType()); |
||||||
|
|
||||||
|
} |
||||||
|
super.inputs(inputs); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public InlineShaderNodeBuilder outputs(VariableMappingBuilder... outputs) { |
||||||
|
if (outputs.length > 1 || !outputs[0].getName().equals("result")) { |
||||||
|
throw new IllegalArgumentException("Only the 'result' output can be mapped for an inlined node"); |
||||||
|
} |
||||||
|
super.outputs(outputs); |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void build() { |
||||||
|
ShaderNodeDefinition def = getNode().getDefinition(); |
||||||
|
//generate the code
|
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
sb.append(def.getReturnType()).append(" ").append(def.getName()).append("("); |
||||||
|
boolean isFirst = true; |
||||||
|
int outTypeIndex = 0; |
||||||
|
for (ShaderNodeVariable v : def.getParams()) { |
||||||
|
if (!isFirst) { |
||||||
|
sb.append(", "); |
||||||
|
} |
||||||
|
sb.append("const in "); |
||||||
|
if (def.getInputs().contains(v)) { |
||||||
|
|
||||||
|
} else { |
||||||
|
sb.append("out "); |
||||||
|
if (!def.getOutputs().contains(v)) { |
||||||
|
// the variable is not in the output list
|
||||||
|
def.getOutputs().add(v); |
||||||
|
} |
||||||
|
if (v.getType() == null && outTypeIndex < outputTypes.length) { |
||||||
|
v.setType(outputTypes[outTypeIndex]); |
||||||
|
} else { |
||||||
|
throw new IllegalArgumentException("Output variable " + v.getName() + " has no type in node " + getNode().getName() + ". Make sure you properly declare it"); |
||||||
|
} |
||||||
|
} |
||||||
|
if (v.getType() == null) { |
||||||
|
throw new IllegalArgumentException("Unable to infer type for input variable " + v.getName() + " in node " + getNode().getName()); |
||||||
|
} |
||||||
|
sb.append(v.getType()).append(" "); |
||||||
|
sb.append(v.getName()); |
||||||
|
isFirst = false; |
||||||
|
} |
||||||
|
sb.append("){\n\treturn ").append(def.getInlinedCode()).append(";\n}"); |
||||||
|
def.setInlinedCode(sb.toString()); |
||||||
|
super.build(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,146 @@ |
|||||||
|
package com.jme3.shader.builder; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.material.*; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
import com.jme3.shader.*; |
||||||
|
import com.jme3.texture.image.ColorSpace; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
public class MaterialBuilder { |
||||||
|
|
||||||
|
private MaterialDef matDef; |
||||||
|
private Map<String, TechniqueBuilder> techBuilders = new HashMap<>(); |
||||||
|
private AssetManager assetManager; |
||||||
|
private TechniqueBuilder currentTechnique; |
||||||
|
|
||||||
|
public MaterialBuilder(AssetManager assetManager) { |
||||||
|
matDef = new MaterialDef(assetManager, "MatDef"); |
||||||
|
this.assetManager = assetManager; |
||||||
|
} |
||||||
|
|
||||||
|
public MaterialBuilder(AssetManager assetManager, MaterialDef matDef) { |
||||||
|
this.matDef = matDef; |
||||||
|
this.assetManager = assetManager; |
||||||
|
} |
||||||
|
|
||||||
|
public MaterialBuilder(AssetManager assetManager, String matDefName) { |
||||||
|
this.matDef = (MaterialDef) assetManager.loadAsset(matDefName); |
||||||
|
this.assetManager = assetManager; |
||||||
|
} |
||||||
|
|
||||||
|
public TechniqueBuilder technique(String name) { |
||||||
|
TechniqueBuilder tb = techBuilders.get(name); |
||||||
|
if (tb == null) { |
||||||
|
List<TechniqueDef> defs = matDef.getTechniqueDefs(name); |
||||||
|
if (defs == null || defs.isEmpty()) { |
||||||
|
String techniqueUniqueName = matDef.getAssetName() + "@" + name; |
||||||
|
tb = new TechniqueBuilder(assetManager, name, techniqueUniqueName.hashCode()); |
||||||
|
matDef.addTechniqueDef(tb.getTechniqueDef()); |
||||||
|
|
||||||
|
} else { |
||||||
|
tb = new TechniqueBuilder(assetManager, defs.get(0)); |
||||||
|
} |
||||||
|
techBuilders.put(name, tb); |
||||||
|
} |
||||||
|
currentTechnique = tb; |
||||||
|
return tb; |
||||||
|
} |
||||||
|
|
||||||
|
public TechniqueBuilder technique() { |
||||||
|
return this.technique("Default"); |
||||||
|
} |
||||||
|
|
||||||
|
public Material build() { |
||||||
|
|
||||||
|
for (Map.Entry<String, TechniqueBuilder> entry : techBuilders.entrySet()) { |
||||||
|
TechniqueBuilder tb = entry.getValue(); |
||||||
|
tb.build(); |
||||||
|
ShaderUtils.computeShaderNodeGenerationInfo(tb.getTechniqueDef(), matDef); |
||||||
|
} |
||||||
|
return new Material(matDef); |
||||||
|
} |
||||||
|
|
||||||
|
public ShaderNodeVariable var(String expression) { |
||||||
|
String[] names = expression.split("\\."); |
||||||
|
if (names.length != 2) { |
||||||
|
// we might have an inlined expression
|
||||||
|
ShaderNodeVariable tmp = new ShaderNodeVariable(null, null); |
||||||
|
tmp.setDefaultValue(expression); |
||||||
|
return tmp; |
||||||
|
} |
||||||
|
if (names[0].equals("MatParam")) { |
||||||
|
MatParam param = matDef.getMaterialParam(names[1]); |
||||||
|
if (param == null) { |
||||||
|
throw new IllegalArgumentException("Couldn't find material parameter named " + names[1]); |
||||||
|
} |
||||||
|
return new ShaderNodeVariable(param.getVarType().getGlslType(), names[0], names[1], null, "m_"); |
||||||
|
} |
||||||
|
if (names[0].equals("WorldParam")) { |
||||||
|
UniformBinding worldParam = UniformBinding.valueOf(names[1]); |
||||||
|
currentTechnique.addWorldParam(worldParam.name()); |
||||||
|
return new ShaderNodeVariable(worldParam.getGlslType(), "WorldParam", worldParam.name(), null, "g_"); |
||||||
|
} |
||||||
|
if (names[0].equals("Attr")) { |
||||||
|
String n = names[1].substring(2); |
||||||
|
VertexBuffer.Type attribute = VertexBuffer.Type.valueOf(n); |
||||||
|
return new ShaderNodeVariable(ShaderUtils.getDefaultAttributeType(attribute), names[0], names[1]); |
||||||
|
} |
||||||
|
|
||||||
|
if (names[0].equals("Global")) { |
||||||
|
if(!names[1].equals("position") && !names[1].startsWith("color")){ |
||||||
|
throw new IllegalArgumentException("Global output must be outPosition or outColor, got " + names[1]); |
||||||
|
} |
||||||
|
|
||||||
|
return new ShaderNodeVariable("vec4", names[0], names[1]); |
||||||
|
} |
||||||
|
|
||||||
|
ShaderNodeBuilder nb = currentTechnique.node(names[0]); |
||||||
|
if (nb == null) { |
||||||
|
throw new IllegalArgumentException("Couldn't find node named " + names[0]); |
||||||
|
} |
||||||
|
|
||||||
|
ShaderNodeVariable v = nb.variable(names[1]); |
||||||
|
if (v == null) { |
||||||
|
throw new IllegalArgumentException("Couldn't find variable named " + names[1] + " in node " + names[0]); |
||||||
|
} |
||||||
|
|
||||||
|
return v; |
||||||
|
} |
||||||
|
|
||||||
|
public VariableMappingBuilder map(String param, String expression) { |
||||||
|
return new VariableMappingBuilder(param, var(expression)); |
||||||
|
} |
||||||
|
|
||||||
|
public VariableMappingBuilder map(String param, ShaderNodeVariable variable) { |
||||||
|
return new VariableMappingBuilder(param, variable); |
||||||
|
} |
||||||
|
|
||||||
|
public VariableMappingBuilder map(String param, VertexBuffer.Type attribute) { |
||||||
|
ShaderNodeVariable variable = new ShaderNodeVariable(ShaderUtils.getDefaultAttributeType(attribute), "Attr", "in" + attribute.name()); |
||||||
|
return new VariableMappingBuilder(param, variable); |
||||||
|
} |
||||||
|
|
||||||
|
public VariableMappingBuilder map(String param, UniformBinding worldParam) { |
||||||
|
ShaderNodeVariable variable = new ShaderNodeVariable(worldParam.getGlslType(), "WorldParam", worldParam.name(), null, "g_"); |
||||||
|
currentTechnique.addWorldParam(worldParam.name()); |
||||||
|
return new VariableMappingBuilder(param, variable); |
||||||
|
} |
||||||
|
|
||||||
|
public void addMatParam(VarType type, String name){ |
||||||
|
if(type.isTextureType()){ |
||||||
|
matDef.addMaterialParamTexture(type, name, ColorSpace.sRGB); |
||||||
|
} else { |
||||||
|
matDef.addMaterialParam(type, name, null); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void addMatParamTexture(VarType type, String name, ColorSpace colorSpace){ |
||||||
|
if(!type.isTextureType()){ |
||||||
|
throw new IllegalArgumentException(type + "is not a texture type "); |
||||||
|
} |
||||||
|
matDef.addMaterialParamTexture(type, name, colorSpace); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,113 @@ |
|||||||
|
package com.jme3.shader.builder; |
||||||
|
|
||||||
|
import com.jme3.shader.*; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
public class ShaderNodeBuilder { |
||||||
|
|
||||||
|
private ShaderNode node; |
||||||
|
|
||||||
|
protected ShaderNodeBuilder(String name, ShaderNodeDefinition def) { |
||||||
|
node = new ShaderNode(name, def, null); |
||||||
|
} |
||||||
|
|
||||||
|
protected ShaderNodeBuilder(ShaderNode node) { |
||||||
|
this.node = node; |
||||||
|
} |
||||||
|
|
||||||
|
protected ShaderNode getNode() { |
||||||
|
return node; |
||||||
|
} |
||||||
|
|
||||||
|
protected ShaderNodeVariable variable(String name){ |
||||||
|
ShaderNodeDefinition def = node.getDefinition(); |
||||||
|
for (ShaderNodeVariable variable : def.getParams()) { |
||||||
|
if(variable.getName().equals(name)){ |
||||||
|
ShaderNodeVariable var = variable.clone(); |
||||||
|
var.setNameSpace(node.getName()); |
||||||
|
return var; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (ShaderNodeVariable variable : def.getOutputs()) { |
||||||
|
if(variable.getName().equals(name)){ |
||||||
|
ShaderNodeVariable var = variable.clone(); |
||||||
|
var.setNameSpace(node.getName()); |
||||||
|
return var; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public ShaderNodeBuilder inputs(VariableMappingBuilder... inputs){ |
||||||
|
List<VariableMapping> mappings = node.getInputMapping(); |
||||||
|
mappings.clear(); |
||||||
|
for (VariableMappingBuilder mb : inputs) { |
||||||
|
ShaderNodeVariable left = findVariable(mb.getName(), node.getDefinition().getInputs() ); |
||||||
|
if(left == null){ |
||||||
|
throw new IllegalArgumentException("Couldn't find input " + mb.getName() + " in node definition " + node.getDefinition().getName()); |
||||||
|
} |
||||||
|
left = left.clone(); |
||||||
|
left.setNameSpace(node.getName()); |
||||||
|
ShaderNodeVariable right = mb.getVariable(); |
||||||
|
VariableMapping m = map(left, right); |
||||||
|
mappings.add(m); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public ShaderNodeBuilder outputs(VariableMappingBuilder... outputs){ |
||||||
|
List<VariableMapping> mappings = node.getOutputMapping(); |
||||||
|
mappings.clear(); |
||||||
|
for (VariableMappingBuilder mb : outputs) { |
||||||
|
ShaderNodeVariable right = findVariable(mb.getName(), node.getDefinition().getOutputs() ); |
||||||
|
if(right == null){ |
||||||
|
throw new IllegalArgumentException("Couldn't find input " + mb.getName() + " in node definition " + node.getDefinition().getName()); |
||||||
|
} |
||||||
|
right = right.clone(); |
||||||
|
right.setNameSpace(node.getName()); |
||||||
|
ShaderNodeVariable left = mb.getVariable(); |
||||||
|
VariableMapping m = map(left, right); |
||||||
|
mappings.add(m); |
||||||
|
} |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private VariableMapping map(ShaderNodeVariable left, ShaderNodeVariable right) { |
||||||
|
if(right.getType() == null){ |
||||||
|
// tmp variable, with default value
|
||||||
|
VariableMapping m = new VariableMapping(); |
||||||
|
m.setLeftVariable(left); |
||||||
|
m.setRightExpression(right.getDefaultValue()); |
||||||
|
return m; |
||||||
|
} |
||||||
|
int leftCard = ShaderUtils.getCardinality(left.getType(), ""); |
||||||
|
int rightCard = ShaderUtils.getCardinality(right.getType(), ""); |
||||||
|
String swizzle = "xyzw"; |
||||||
|
String rightVarSwizzle = ""; |
||||||
|
String leftVarSwizzle =""; |
||||||
|
if (rightCard > leftCard) { |
||||||
|
rightVarSwizzle = swizzle.substring(0, leftCard); |
||||||
|
} else if (rightCard > rightCard) { |
||||||
|
leftVarSwizzle = swizzle.substring(0, rightCard); |
||||||
|
} |
||||||
|
|
||||||
|
return new VariableMapping(left, leftVarSwizzle, right, rightVarSwizzle, null); |
||||||
|
} |
||||||
|
|
||||||
|
protected ShaderNodeVariable findVariable(String name, List<ShaderNodeVariable> list){ |
||||||
|
for (ShaderNodeVariable variable : list) { |
||||||
|
if(variable.getName().equals(name)){ |
||||||
|
return variable; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public void build(){ |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,145 @@ |
|||||||
|
package com.jme3.shader.builder; |
||||||
|
|
||||||
|
import com.jme3.asset.AssetManager; |
||||||
|
import com.jme3.asset.ShaderNodeDefinitionKey; |
||||||
|
import com.jme3.material.ShaderGenerationInfo; |
||||||
|
import com.jme3.material.TechniqueDef; |
||||||
|
import com.jme3.material.logic.*; |
||||||
|
import com.jme3.shader.*; |
||||||
|
|
||||||
|
import java.text.ParseException; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
public class TechniqueBuilder { |
||||||
|
|
||||||
|
private TechniqueDef techniqueDef; |
||||||
|
private AssetManager assetManager; |
||||||
|
private Map<String, ShaderNodeBuilder> nodeBuilders = new HashMap<>(); |
||||||
|
|
||||||
|
protected TechniqueBuilder(AssetManager assetManager, String name, int sortId) { |
||||||
|
techniqueDef = new TechniqueDef(name, sortId); |
||||||
|
this.assetManager = assetManager; |
||||||
|
} |
||||||
|
|
||||||
|
protected TechniqueBuilder(AssetManager assetManager, TechniqueDef techniqueDef) { |
||||||
|
this.techniqueDef = techniqueDef; |
||||||
|
this.assetManager = assetManager; |
||||||
|
} |
||||||
|
|
||||||
|
protected TechniqueDef getTechniqueDef() { |
||||||
|
return techniqueDef; |
||||||
|
} |
||||||
|
|
||||||
|
public ShaderNodeBuilder node(String name) { |
||||||
|
ShaderNodeBuilder b = nodeBuilders.get(name); |
||||||
|
if (b == null){ |
||||||
|
ShaderNode n = findShaderNode(name); |
||||||
|
if(n == null){ |
||||||
|
throw new IllegalArgumentException("Can't find node with name " + name + " in technique definition " + techniqueDef.getName()); |
||||||
|
} |
||||||
|
b = new ShaderNodeBuilder(n); |
||||||
|
nodeBuilders.put(name, b); |
||||||
|
} |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
public ShaderNodeBuilder addNode(String name, String defName, String shaderNodeDefPath) { |
||||||
|
List<ShaderNodeDefinition> defs; |
||||||
|
if(shaderNodeDefPath.endsWith(".j3sn")){ |
||||||
|
defs = assetManager.loadAsset(new ShaderNodeDefinitionKey(shaderNodeDefPath)); |
||||||
|
} else { |
||||||
|
try { |
||||||
|
defs = ShaderUtils.loadSahderNodeDefinition(assetManager, shaderNodeDefPath); |
||||||
|
} catch (ParseException e) { |
||||||
|
throw new IllegalArgumentException("Couldn't parse definition " + shaderNodeDefPath, e); |
||||||
|
} |
||||||
|
} |
||||||
|
ShaderNodeDefinition definition = findDefinition(defName, defs); |
||||||
|
if(definition == null){ |
||||||
|
throw new IllegalArgumentException("Couldn't find definition " + defName + " in " + shaderNodeDefPath); |
||||||
|
} |
||||||
|
|
||||||
|
ShaderNodeBuilder b = new ShaderNodeBuilder(name,definition); |
||||||
|
if(techniqueDef.getShaderNodes() == null){ |
||||||
|
techniqueDef.setShaderNodes(new ArrayList<ShaderNode>()); |
||||||
|
} |
||||||
|
techniqueDef.setShaderFile(techniqueDef.hashCode() + "", techniqueDef.hashCode() + "", "GLSL100", "GLSL100"); |
||||||
|
techniqueDef.getShaderNodes().add(b.getNode()); |
||||||
|
techniqueDef.setShaderGenerationInfo(new ShaderGenerationInfo()); |
||||||
|
techniqueDef.setLogic(new DefaultTechniqueDefLogic(techniqueDef)); |
||||||
|
techniqueDef.setShaderPrologue(""); |
||||||
|
nodeBuilders.put(name, b); |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public InlineShaderNodeBuilder inlineVertexNode(String type, String name, String code){ |
||||||
|
return inlineNode(type, name, code, Shader.ShaderType.Vertex); |
||||||
|
} |
||||||
|
|
||||||
|
public InlineShaderNodeBuilder inlineFragmentNode(String type, String name, String code){ |
||||||
|
return inlineNode(type, name, code, Shader.ShaderType.Fragment); |
||||||
|
} |
||||||
|
|
||||||
|
public InlineShaderNodeBuilder inlineNode(String returnType, String name, String code, Shader.ShaderType type){ |
||||||
|
ShaderNodeDefinition def = new ShaderNodeDefinition(); |
||||||
|
def.setName(name); |
||||||
|
def.setType(type); |
||||||
|
def.setReturnType(returnType); |
||||||
|
InlineShaderNodeBuilder sb = new InlineShaderNodeBuilder(name, def, code, techniqueDef); |
||||||
|
nodeBuilders.put(name, sb); |
||||||
|
techniqueDef.getShaderNodes().add(sb.getNode()); |
||||||
|
return sb; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean addWorldParam(String name){ |
||||||
|
return techniqueDef.addWorldParam(name); |
||||||
|
} |
||||||
|
|
||||||
|
private void setLightMode(TechniqueDef.LightMode mode){ |
||||||
|
switch (techniqueDef.getLightMode()) { |
||||||
|
case Disable: |
||||||
|
techniqueDef.setLogic(new DefaultTechniqueDefLogic(techniqueDef)); |
||||||
|
break; |
||||||
|
case MultiPass: |
||||||
|
techniqueDef.setLogic(new MultiPassLightingLogic(techniqueDef)); |
||||||
|
break; |
||||||
|
case SinglePass: |
||||||
|
techniqueDef.setLogic(new SinglePassLightingLogic(techniqueDef)); |
||||||
|
break; |
||||||
|
case StaticPass: |
||||||
|
techniqueDef.setLogic(new StaticPassLightingLogic(techniqueDef)); |
||||||
|
break; |
||||||
|
case SinglePassAndImageBased: |
||||||
|
techniqueDef.setLogic(new SinglePassAndImageBasedLightingLogic(techniqueDef)); |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw new UnsupportedOperationException(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private ShaderNodeDefinition findDefinition(String defName, List<ShaderNodeDefinition> defs) { |
||||||
|
for (ShaderNodeDefinition def : defs) { |
||||||
|
if(def.getName().equals(defName)){ |
||||||
|
return def; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
private ShaderNode findShaderNode(String name){ |
||||||
|
for (ShaderNode shaderNode : techniqueDef.getShaderNodes()) { |
||||||
|
if(shaderNode.getName().equals(name)){ |
||||||
|
return shaderNode; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
protected void build(){ |
||||||
|
for (Map.Entry<String, ShaderNodeBuilder> entry : nodeBuilders.entrySet()) { |
||||||
|
ShaderNodeBuilder nb = entry.getValue(); |
||||||
|
nb.build(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
package com.jme3.shader.builder; |
||||||
|
|
||||||
|
import com.jme3.shader.ShaderNodeVariable; |
||||||
|
|
||||||
|
public class VariableMappingBuilder { |
||||||
|
|
||||||
|
private String name; |
||||||
|
private ShaderNodeVariable variable; |
||||||
|
|
||||||
|
protected VariableMappingBuilder(String name, ShaderNodeVariable variable) { |
||||||
|
this.name = name; |
||||||
|
this.variable = variable; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
public ShaderNodeVariable getVariable() { |
||||||
|
return variable; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -1,8 +1,8 @@ |
|||||||
|
#import "Common/ShaderLib/Skinning.glsllib" |
||||||
|
|
||||||
void main(){ |
void main(){ |
||||||
modModelPosition = (mat4(0.0) + |
#ifdef NUM_BONES |
||||||
boneMatrices[int(boneIndex.x)] * boneWeight.x + |
modModelPosition = modelPosition; |
||||||
boneMatrices[int(boneIndex.y)] * boneWeight.y + |
Skinning_Compute(modModelPosition); |
||||||
boneMatrices[int(boneIndex.z)] * boneWeight.z + |
#endif |
||||||
boneMatrices[int(boneIndex.w)] * boneWeight.w) * vec4(modelPosition.xyz,1.0); |
|
||||||
} |
} |
@ -1,12 +1,10 @@ |
|||||||
|
#import "Common/ShaderLib/Skinning.glsllib" |
||||||
|
|
||||||
void main(){ |
void main(){ |
||||||
modModelPosition = (mat4(0.0) + |
#ifdef NUM_BONES |
||||||
boneMatrices[int(boneIndex.x)] * boneWeight.x + |
modModelPosition = modelPosition; |
||||||
boneMatrices[int(boneIndex.y)] * boneWeight.y + |
modModelNormal = modelNormal; |
||||||
boneMatrices[int(boneIndex.z)] * boneWeight.z + |
modModelTangents = modelTangents; |
||||||
boneMatrices[int(boneIndex.w)] * boneWeight.w) * modelPosition; |
Skinning_Compute(modModelPosition, modModelNormal, modModelTangents); |
||||||
|
#endif |
||||||
mat3 rotMat = mat3(mat[0].xyz, mat[1].xyz, mat[2].xyz); |
|
||||||
modModelTangent = rotMat * modelTangent; |
|
||||||
modModelNormal = rotMat * modelNormal; |
|
||||||
} |
} |
@ -0,0 +1,86 @@ |
|||||||
|
package jme3test.material; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.material.Material; |
||||||
|
import com.jme3.material.Technique; |
||||||
|
import com.jme3.material.TechniqueDef; |
||||||
|
import com.jme3.math.*; |
||||||
|
import com.jme3.scene.Geometry; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
import com.jme3.scene.shape.Box; |
||||||
|
import com.jme3.shader.*; |
||||||
|
import com.jme3.shader.builder.MaterialBuilder; |
||||||
|
import com.jme3.texture.Texture; |
||||||
|
|
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
public class TestShaderNodesApi extends SimpleApplication { |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
TestShaderNodesApi app = new TestShaderNodesApi(); |
||||||
|
app.start(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
flyCam.setMoveSpeed(20); |
||||||
|
Logger.getLogger("com.jme3").setLevel(Level.WARNING); |
||||||
|
Box boxshape1 = new Box(1f, 1f, 1f); |
||||||
|
Geometry cube = new Geometry("A Box", boxshape1); |
||||||
|
Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); |
||||||
|
|
||||||
|
MaterialBuilder mb = new MaterialBuilder(assetManager); |
||||||
|
mb.addMatParam(VarType.Vector4, "Color"); |
||||||
|
mb.addMatParam(VarType.Texture2D, "Texture"); |
||||||
|
|
||||||
|
mb.technique().addNode("CommonVert", "CommonVert", "jme3test/matdefs/CommonVert.vert") |
||||||
|
.inputs( |
||||||
|
mb.map("worldViewProjectionMatrix", UniformBinding.WorldViewProjectionMatrix), |
||||||
|
mb.map("modelPosition", VertexBuffer.Type.Position)) |
||||||
|
.outputs( |
||||||
|
mb.map("result", "Global.position") |
||||||
|
); |
||||||
|
|
||||||
|
mb.technique().inlineVertexNode("vec2","TexCoord", "%texIn") |
||||||
|
.inputs( |
||||||
|
mb.map("texIn", VertexBuffer.Type.TexCoord) |
||||||
|
); |
||||||
|
|
||||||
|
mb.technique().addNode("ColorMult", "ColorMult", "jme3test/matdefs/ColorMult.frag") |
||||||
|
.inputs( |
||||||
|
mb.map("color1", "vec4(0.1, 0.1, 0.1, 1.0)"), |
||||||
|
mb.map("color2", "MatParam.Color")) |
||||||
|
.outputs( |
||||||
|
mb.map("result", "Global.color") |
||||||
|
); |
||||||
|
|
||||||
|
mb.technique().inlineFragmentNode("vec4","InlineNode","%color1 * texture2D(%tex, %texCoord)") |
||||||
|
.inputs( |
||||||
|
mb.map("color1", "ColorMult.result"), |
||||||
|
mb.map("tex", "MatParam.Texture"), |
||||||
|
mb.map("texCoord", "TexCoord.result") |
||||||
|
).outputs( |
||||||
|
mb.map("result", "Global.color") |
||||||
|
); |
||||||
|
|
||||||
|
Material mat = mb.build(); |
||||||
|
|
||||||
|
//Material mat = new Material(assetManager, "jme3test/matdefs/test2.j3md");
|
||||||
|
|
||||||
|
mat.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); |
||||||
|
Technique t = mat.getActiveTechnique(); |
||||||
|
|
||||||
|
for (Shader.ShaderSource shaderSource : t.getDef().getShader(assetManager, renderer.getCaps(), t.getDynamicDefines()).getSources()) { |
||||||
|
System.out.println(shaderSource.getSource()); |
||||||
|
} |
||||||
|
|
||||||
|
mat.setColor("Color", ColorRGBA.Yellow); |
||||||
|
mat.setTexture("Texture", tex); |
||||||
|
cube.setMaterial(mat); |
||||||
|
cube.move(0, 0, 0); |
||||||
|
rootNode.attachChild(cube); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
package jme3test.material; |
||||||
|
|
||||||
|
import com.jme3.app.SimpleApplication; |
||||||
|
import com.jme3.material.*; |
||||||
|
import com.jme3.math.ColorRGBA; |
||||||
|
import com.jme3.scene.Geometry; |
||||||
|
import com.jme3.scene.VertexBuffer; |
||||||
|
import com.jme3.scene.shape.Box; |
||||||
|
import com.jme3.shader.*; |
||||||
|
import com.jme3.shader.builder.MaterialBuilder; |
||||||
|
import com.jme3.texture.Texture; |
||||||
|
|
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
public class TestShaderNodesModifApi extends SimpleApplication { |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
TestShaderNodesModifApi app = new TestShaderNodesModifApi(); |
||||||
|
app.start(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void simpleInitApp() { |
||||||
|
flyCam.setMoveSpeed(20); |
||||||
|
Logger.getLogger("com.jme3").setLevel(Level.WARNING); |
||||||
|
Box boxshape1 = new Box(1f, 1f, 1f); |
||||||
|
Geometry cube = new Geometry("A Box", boxshape1); |
||||||
|
Texture tex = assetManager.loadTexture("Interface/Logo/Monkey.jpg"); |
||||||
|
|
||||||
|
MaterialBuilder mb = new MaterialBuilder(assetManager,"jme3test/matdefs/test.j3md"); |
||||||
|
mb.addMatParam(VarType.Vector4, "Color2"); |
||||||
|
mb.addMatParam(VarType.Texture2D, "Texture"); |
||||||
|
|
||||||
|
mb.technique().inlineVertexNode("vec2","TexCoord", "%texIn") |
||||||
|
.inputs( |
||||||
|
mb.map("texIn", VertexBuffer.Type.TexCoord) |
||||||
|
); |
||||||
|
|
||||||
|
|
||||||
|
mb.technique().inlineFragmentNode("vec4","TextureFetch","texture2D(%tex, %texCoord)") |
||||||
|
.inputs( |
||||||
|
mb.map("tex", "MatParam.Texture"), |
||||||
|
mb.map("texCoord", "TexCoord.result") |
||||||
|
).outputs( |
||||||
|
mb.map("result", "Global.color") |
||||||
|
); |
||||||
|
|
||||||
|
|
||||||
|
mb.technique().addNode("ColorMult2", "ColorMult", "jme3test/matdefs/ColorMult.frag") |
||||||
|
.inputs( |
||||||
|
mb.map("color1", "ColorMult.result"), |
||||||
|
mb.map("color2", "MatParam.Color2"), |
||||||
|
mb.map("color3", "TextureFetch.result")) |
||||||
|
.outputs( |
||||||
|
mb.map("result", "Global.color") |
||||||
|
); |
||||||
|
|
||||||
|
// TODO we need a way to order the nodes. They could be sorted by scanning the inputs and outputs and building a node tree, then sort it with a topological sort,
|
||||||
|
// but that won't work in some cases when node output is the Global color or Global position. So we'd need a fallback to manually order the nodes.
|
||||||
|
// So as long as we implement the fallback... The sort is maybe not worth it.
|
||||||
|
// API could be mb.technique().moveNode("Node1").before("Node2") or after("Node2")...
|
||||||
|
// or something like mb.technique().setOrder("Node1", "Node2", etc...) but this would require the user to know all the existing nodes.
|
||||||
|
// or maybe both...
|
||||||
|
|
||||||
|
Material mat = mb.build(); |
||||||
|
|
||||||
|
mat.selectTechnique(TechniqueDef.DEFAULT_TECHNIQUE_NAME, renderManager); |
||||||
|
Technique t = mat.getActiveTechnique(); |
||||||
|
|
||||||
|
for (Shader.ShaderSource shaderSource : t.getDef().getShader(assetManager, renderer.getCaps(), t.getDynamicDefines()).getSources()) { |
||||||
|
System.out.println(shaderSource.getSource()); |
||||||
|
} |
||||||
|
|
||||||
|
mat.setColor("Color", ColorRGBA.Yellow); |
||||||
|
mat.setColor("Color2", ColorRGBA.Red); |
||||||
|
mat.setTexture("Texture", tex); |
||||||
|
cube.setMaterial(mat); |
||||||
|
cube.move(0, 0, 0); |
||||||
|
rootNode.attachChild(cube); |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
#pragma ShaderNode defaults(vec4(1.0), ,vec4(1.0)) |
||||||
|
vec4 ColorMult(const in vec4 color1, const in vec4 color2, const in vec4 color3){ |
||||||
|
return color1 * color2 * color3; |
||||||
|
} |
||||||
|
|
@ -0,0 +1,9 @@ |
|||||||
|
#pragma ShaderNode |
||||||
|
vec4 CommonVert(const in mat4 worldViewProjectionMatrix, const in vec3 modelPosition){ |
||||||
|
return worldViewProjectionMatrix * vec4(modelPosition, 1.0); |
||||||
|
} |
||||||
|
|
||||||
|
#pragma ShaderNode |
||||||
|
vec4 DoThing( in vec4 color ){ |
||||||
|
return color * 0.1; |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
MaterialDef Simple { |
||||||
|
MaterialParameters { |
||||||
|
Vector4 Color |
||||||
|
} |
||||||
|
|
||||||
|
Technique { |
||||||
|
WorldParameters { |
||||||
|
WorldViewProjectionMatrix |
||||||
|
} |
||||||
|
|
||||||
|
VertexShaderNodes { |
||||||
|
ShaderNode CommonVert { |
||||||
|
Definition: CommonVert: jme3test/matdefs/CommonVert.vert |
||||||
|
InputMappings{ |
||||||
|
worldViewProjectionMatrix = WorldParam.WorldViewProjectionMatrix |
||||||
|
modelPosition = Attr.inPosition |
||||||
|
} |
||||||
|
OutputMappings{ |
||||||
|
Global.position = result |
||||||
|
} |
||||||
|
} |
||||||
|
ShaderNode ColorStuff { |
||||||
|
Definition: DoThing: jme3test/matdefs/CommonVert.vert |
||||||
|
InputMappings{ |
||||||
|
color = MatParam.Color |
||||||
|
} |
||||||
|
OutputMappings{ |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
FragmentShaderNodes { |
||||||
|
ShaderNode ColorMult { |
||||||
|
Definition: ColorMult: jme3test/matdefs/ColorMult.frag |
||||||
|
InputMappings{ |
||||||
|
color2 = ColorStuff.result |
||||||
|
} |
||||||
|
OutputMappings{ |
||||||
|
Global.color = result |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue