How to not render a Material?

Hi,

I would like to render some Geometries only via a SceneProcessor. The SceneProcessor forces the technique to be used by material.
I would like to not render those Geometries via the default pipeline.
I try to define empty “Default” Technique like :

MaterialDef lbuffer {

	MaterialParameters {
///...
	}

	Technique {
	}

	Technique LBuf {
///...
	}
}

But I’ve got Exception :

java.lang.IllegalStateException: Cannot render mesh without shader bound
	at com.jme3.renderer.lwjgl.LwjglRendererCustom.setVertexAttrib(LwjglRendererCustom.java:2222)
	at com.jme3.renderer.lwjgl.LwjglRendererCustom.setVertexAttrib(LwjglRendererCustom.java:2227)
	at com.jme3.renderer.lwjgl.LwjglRendererCustom.renderMeshDefault(LwjglRendererCustom.java:2432)
	at com.jme3.renderer.lwjgl.LwjglRendererCustom.renderMesh(LwjglRendererCustom.java:2483)
	at com.jme3.material.Material.render(Material.java:1119)
	at com.jme3.renderer.RenderManager.renderGeometry(RenderManager.java:523)
	at com.jme3.renderer.queue.RenderQueue.renderGeometryList(RenderQueue.java:322)

I’ve try to ignore/skip rendering of Technique without shader in LwjglRenderer.renderMesh. But Texture and mesh seems to swap between spatial (quad display as teapot,…).

    public void renderMesh(Mesh mesh, int lod, int count) {
        if (mesh.getVertexCount() == 0) {
            return;
        }
        //HACK (DB): ignore technique without shader (eg: material that should only be used with non default Technique)
        if (context.boundShaderProgram < 1) {
            return;
        }

Any advice ?

I found a crappy workaround, until better solution. For the object that should not be rendered with default technique. I used a custom Material:

package com.jme3.material;

import com.jme3.asset.AssetManager;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;

public class MaterialCustom extends Material {
	public MaterialCustom(MaterialDef def) {
		super(def);
	}

	public MaterialCustom(AssetManager contentMan, String defName) {
		super(contentMan, defName);
	}

	/**
	 * Do not use this constructor. Serialization purposes only.
	 */
	public MaterialCustom() {
	}

	public void render(Geometry geom, RenderManager rm) {
		//super.autoSelectTechnique(rm);
		Technique technique= super.getActiveTechnique();
		if (technique == null) {
			selectTechnique("Default", rm);
			technique= super.getActiveTechnique();
		}
		if ("Default".equals(technique.getDef().getName())) {
			TechniqueDef techDef = technique.getDef();
			if (!techDef.isUsingShaders() || technique.getShader().getId() < 1) return;
		}
		super.render(geom, rm);
	}
}

Skipping in LwjglRenderer.renderMesh is too late, because the part of the renderer as already be filled (uniforms,…) take cause the issue I’d got (mixed object defintion).

so you don’t want to render those objects in the main view right?
Why don’t you set up another viewport with another rootNode for those objects? You’d be able to render them separately.

It’s an option, I didn’t take currently. Because I would like to mixed with object (particles,…) without taking care of which rootNode I should use.
I would like to have an unique scenetree.
In my sample test I spawn Node in the scene where some children is a unshaded particle and an other is the light geometry. The node is moving (physics).

I noted this option in my commit + use of custom bucket (when it’ll be possible).

UPDATE 01: having 2 scenetree, will require to add controls to sync/replicate change between the 2 scenetrees.

You can render materials with a particular technique by using RenderManager.setForcedTechnique().

The comment explains how it works


if forcedTechnique we try to force it for render,
if it does not exists in the mat def, we check for forcedMaterial and render the geom if not null
else the geom is not rendered

So only materials with the technique you selected will be rendered.

Perhaps it would be better if you explained what you’re trying to do?

I made a video exemple :

The light particle are composed by :

node (with RigidBodyControl)
±- particle image (unshaded + additive texture, renderer by normal forward pipeline)
±- light volume (only rendered by custom sceneprocessor)

You gotta go through the whole scene to render the GBuffer anyway, so at that point you can gather all the lights which you then render in a separate pass. I am not sure what representation you use for lights here, I assume its the standard jME3 Light class.

jME3 wasn’t really designed for deferred rendering so you will probably need to make some modifications to the rendering architecture to make it happen.

In my deferred pipeline I’ve got geometris with material GBuffer (for opaque) and material LBuffer (for light volume).
Both materials has empty default technique + named techniques.
I use forcedTechnique to select the named techniques I want to run.
Today, I try to mix deferred renderer with forward to display some particles,… But I’ve got the error listed above. because I can’t filter bucket,…

Is it clearer ?

source : GitHub - davidB/jme3_ext_deferred: [experimental] a deferred rendering for jME3

I didn’t use jme Light class. There are geometries with a custom material (to fill LBuffer, stencil,…).

That could happen if you try to render something without a shader, e.g. if the Default technique is being rendered. You need to make sure the default technique is never rendered in your case or the error will appear.

It’s what I made with the workaround MaterialCustom (I hope), may be there an other way ?

Thanks

Sounds like potentially another use-case for custom buckets. I may need to see about resurrecting those design notes and reassessing. Nothing in time to help you, though, sorry. :-/

1 Like

As a side note, what is the relation between techDef.isUsingShaders() / techDef.isUsingShaderNodes() / and the definition of shaders in Technique (j3md)?

What is the use case when techDef.isUsingShaders() == false ? Material can be rendered ?

    public void render(Geometry geom, RenderManager rm) {
        autoSelectTechnique(rm);

        Renderer r = rm.getRenderer();

        TechniqueDef techDef = technique.getDef();
//...

        // update camera and world matrices
        // NOTE: setWorldTransform should have been called already
        if (techDef.isUsingShaders()) {
            // reset unchanged uniform flag
            clearUniformsSetByCurrent(technique.getShader());
            rm.updateUniformBindings(technique.getWorldBindUniforms());
        }
@david.bernard.31 said: What is the use case when techDef.isUsingShaders() == false ? Material can be rendered ?
the use case was fixed pipeline (opengl1 had no shaders) but it has been removed recently from the core.

techDef.isUsingShaders() == true means your material def actually has shader files for both vertex and fragment shader.

techDef.isUsingShaderNodes() == true means that the Material def has no shader but has shader nodes definition, and the shaders will be generated by the engine.

So if !isUsingShaders && !isUsingShaderNodes the material should not be rendered. Then the Material.render should escape, isn’t it ?

For some of my Material with empty default technique (no shaderà, I’ve got isUsingShaders == true, I had to also test technique.getShader().getId() < 1 to escape. Is it a bug ?

Idk if it’s a bug or if it has never been intended to work like this.