@Override
    public TechniqueDef clone() throws CloneNotSupportedException {
        //cannot use super.clone because of the final fields instance that would be shared by the clones.
        TechniqueDef clone = new TechniqueDef(name, sortId);

        clone.noRender = noRender;
        clone.lightMode = lightMode;
        clone.shadowMode = shadowMode;
        clone.lightSpace = lightSpace;
        clone.usesNodes = usesNodes;
        clone.shaderPrologue = shaderPrologue;

        clone.setShaderFile(shaderNames, shaderLanguages);

        clone.defineNames = new ArrayList<>(defineNames.size());
        clone.defineNames.addAll(defineNames);

        clone.defineTypes = new ArrayList<>(defineTypes.size());
        clone.defineTypes.addAll(defineTypes);

        clone.paramToDefineId = new HashMap<>(paramToDefineId.size());
        clone.paramToDefineId.putAll(paramToDefineId);

        if (shaderNodes != null) {
            clone.shaderNodes = new ArrayList<>();
            for (ShaderNode shaderNode : shaderNodes) {
                clone.shaderNodes.add(shaderNode.clone());
            }
            clone.shaderGenerationInfo = shaderGenerationInfo.clone();
        }

        if (renderState != null) {
            clone.setRenderState(renderState.clone());
        }
        if (forcedRenderState != null) {
            clone.setForcedRenderState(forcedRenderState.clone());
        }

        try {
            clone.logic = logic.getClass().getConstructor(TechniqueDef.class).newInstance(clone);
        } catch (InstantiationException | IllegalAccessException
                | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        }

        clone.worldBinds = new ArrayList<>(worldBinds.size());
        clone.worldBinds.addAll(worldBinds);

        return clone;
    }
Sets the space in which the light data should be passed to the shader.
@param lightSpace the light space
jme3-core/src/main/java/com/jme3/material/TechniqueDef.java