Skip to main content

Vertex color support?

2 replies [Last post]
garyritchie
Offline
Joined: 2009-08-27
Points: 0

I'm using Blender 2.49b+ (latest svn) and I'd like to know if there's vertex color support in WL and how I might go about hacking the collada file to mix vertex colors with the model's texture.

I'm willing to examine a collada file from another application that has this working in WL.

Using vertex colors is a resource-friendly way to add visual interest to an otherwise dull, repeating texture.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
dougfinn
Offline
Joined: 2008-10-28
Points: 0

WL, through JME and mtgame, supports shaders.

There are a few shader demos in the mtgame test folder.

I tried writing the bare minimum shader code (with reference to mtgame's ShaderTest.java), which I've copied below (apologies for so much code!). You'll have to make changes to your package names/filepaths, etc. This is a simple standalone mtgame program, since I was curious about using mtgame as-is (to get a better understanding before looking in depth at how it fits in with WL). You should be able to use similar shader code in the rendering part of your WL module.

Not sure if this is what you're looking for, but hope it helps. It's just test code, so some of it will be wrong or redundant. All it does is create a primitive and apply the shader. Vertex colours and texture blending should be straightforward.

Though any questions you have about the graphics side of WL should be double-checked with Paul (paulby).

[code]
package mtgame_01;

import com.jme.image.Texture;
import com.jme.light.LightNode;
import com.jme.light.PointLight;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.scene.CameraNode;
import com.jme.scene.Geometry;
import com.jme.scene.Node;
import com.jme.scene.shape.Box;
import com.jme.scene.state.GLSLShaderObjectsState;
import com.jme.scene.state.RenderState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.util.TextureManager;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.jdesktop.mtgame.AWTInputComponent;
import org.jdesktop.mtgame.CameraComponent;
import org.jdesktop.mtgame.Entity;
import org.jdesktop.mtgame.InputManager;
import org.jdesktop.mtgame.OnscreenRenderBuffer;
import org.jdesktop.mtgame.ProcessorCollectionComponent;
import org.jdesktop.mtgame.RenderBuffer;
import org.jdesktop.mtgame.RenderComponent;
import org.jdesktop.mtgame.RenderUpdater;
import org.jdesktop.mtgame.WorldManager;
import org.jdesktop.mtgame.processor.JBSelectionProcessor;
import org.jdesktop.mtgame.processor.OrbitCameraProcessor;

/**
*
* @author douglas
*/
public class MTGame_01 implements RenderUpdater {
private Canvas canvas = null;
private RenderBuffer rb = null;
int desiredFrameRate = 500;
int width = 800;
int height = 600;
private float aspect = 800.0f/600.0f;
WorldManager wm;
Node primNode;
Entity primEntity;
private CameraNode cameraNode = null;

private URL vert = null;
private URL frag = null;

public MTGame_01(){
wm = new WorldManager("Test");

// Loading urls from files is deprecated, I think, but it works ...
try {
File fv = new File("C:/_MTGAME/MTGAME_01/src/shaders/SampleVertShader.vert");
File ff = new File("C:/_MTGAME/MTGAME_01/src/shaders/SampleFragShader.frag");
vert = fv.toURI().toURL();
frag = ff.toURI().toURL();
} catch (MalformedURLException e) {
System.out.println(e);
}

wm.getRenderManager().setDesiredFrameRate(desiredFrameRate);
createUI(wm);
createCameraEntity(wm);
createPrimitive();
createGlobalLight();
}

public void createUI(WorldManager wm){
SwingFrame frame = new SwingFrame(wm);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}

private void createPrimitive(){
RenderComponent sc = null;
primNode = createModel(0, 0, 0);
primEntity = new Entity("Prim ");
sc = wm.getRenderManager().createRenderComponent(primNode);
primEntity.addComponent(RenderComponent.class, sc);
wm.addEntity(primEntity);
}

private Node createModel(float x, float y, float z) {
Node node = new Node("PrimNode ");
Box prim = new Box("Box ", new Vector3f(0.0f,0.0f,0.0f), 12.0f, 12.0f, 12.0f);
node.attachChild(prim);

ZBufferState buf = (ZBufferState) wm.getRenderManager().createRendererState(RenderState.StateType.ZBuffer);
buf.setEnabled(true);
buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);

ColorRGBA color = new ColorRGBA(1.0f, 1.0f, 0.0f, 1.0f);

// The shader object code
GLSLShaderObjectsState shader = (GLSLShaderObjectsState) wm.getRenderManager().createRendererState(RenderState.StateType.GLSLShaderObjects);
shader.setUniform("color", color);

try {
File texFile = new File("C:/_MTGAME/MTGAME_01/data/textures/brick.jpg");
URL texURL = texFile.toURI().toURL();
Texture tex2d = TextureManager.loadTexture(texURL,
Texture.MinificationFilter.BilinearNearestMipMap,
Texture.MagnificationFilter.Bilinear);
TextureState ts = (TextureState) wm.getRenderManager().createRendererState
(RenderState.StateType.Texture);
ts.setEnabled(true);
ts.setTexture(tex2d, 0);
Geometry g = (Geometry)prim;
g.setRenderState(ts);
} catch (MalformedURLException ex) {
Logger.getLogger(MTGame_01.class.getName()).log(Level.SEVERE, null, ex);
}

wm.addRenderUpdater(this, shader);
node.setRenderState(shader);

node.setRenderState(buf);
node.setLocalTranslation(x, y, z);

return node;
}

private void createGlobalLight() {
PointLight light1 = new PointLight();
light1.setDiffuse(new ColorRGBA(0.55f, 0.55f, 0.55f, 0.55f));
light1.setAmbient(new ColorRGBA(0.25f, 0.25f, 0.25f, 1.0f));
light1.setEnabled(true);
LightNode ln1 = new LightNode();
ln1.setLight(light1);
ln1.setLocalTranslation(new Vector3f(100, 100, 100));

PointLight light2 = new PointLight();
light2.setDiffuse(new ColorRGBA(0.45f, 0.45f, 0.45f, 0.45f));
light2.setAmbient(new ColorRGBA(0.45f, 0.45f, 0.45f, 1.0f));
light2.setEnabled(true);
LightNode ln2 = new LightNode();
ln2.setLight(light2);
ln2.setLocalTranslation(new Vector3f(-100, 0, -100));

wm.getRenderManager().addLight(ln2);
wm.getRenderManager().addLight(ln1);
}

private void createCameraEntity(WorldManager wm) {
Node cameraSG = createCameraGraph(wm);

// Add the camera
Entity camera = new Entity("DefaultCamera");
CameraComponent cc = wm.getRenderManager().createCameraComponent(cameraSG, cameraNode,
width, height, 45.0f, aspect, 1.0f, 1000.0f, true);
rb.setCameraComponent(cc);
camera.addComponent(CameraComponent.class, cc);

// Create the input listener and process for the camera
int eventMask = InputManager.KEY_EVENTS | InputManager.MOUSE_EVENTS;
AWTInputComponent cameraListener = (AWTInputComponent)wm.getInputManager().createInputComponent(canvas, eventMask);
//FPSCameraProcessor eventProcessor = new FPSCameraProcessor(eventListener, cameraNode, wm, camera);
OrbitCameraProcessor eventProcessor = new OrbitCameraProcessor(cameraListener, cameraNode, wm, camera);
eventProcessor.setRunInRenderer(true);

AWTInputComponent selectionListener = (AWTInputComponent)wm.getInputManager().createInputComponent(canvas, eventMask);
JBSelectionProcessor selector = new JBSelectionProcessor(selectionListener, wm, camera, camera, width, height, eventProcessor);
selector.setRunInRenderer(true);

ProcessorCollectionComponent pcc = new ProcessorCollectionComponent();
pcc.addProcessor(eventProcessor);
pcc.addProcessor(selector);
camera.addComponent(ProcessorCollectionComponent.class, pcc);

wm.addEntity(camera);
}

private Node createCameraGraph(WorldManager wm) {
Node cameraSG = new Node("MyCamera SG");
cameraNode = new CameraNode("MyCamera", null);
cameraSG.attachChild(cameraNode);

return (cameraSG);
}

public void update(Object obj) {
GLSLShaderObjectsState shader = (GLSLShaderObjectsState)obj;
shader.load(vert, frag);
}

public static void main(String[] args) {
MTGame_01 mt = new MTGame_01();
}

class SwingFrame extends JFrame implements ActionListener {
JPanel contentPane;
JPanel canvasPanel = new JPanel();

public SwingFrame(WorldManager wm){
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.out.println("exit");
dispose();
System.exit(0);
}
});

contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(new BorderLayout());
rb = wm.getRenderManager().createRenderBuffer(RenderBuffer.Target.ONSCREEN, width, height);
wm.getRenderManager().addRenderBuffer(rb);
canvas = ((OnscreenRenderBuffer)rb).getCanvas();
canvas.setVisible(true);
canvas.setBounds(0, 0, width, height);
canvasPanel.setLayout(new GridBagLayout());
canvasPanel.add(canvas);
contentPane.add(canvasPanel, BorderLayout.CENTER);
pack();
}

public void actionPerformed(ActionEvent e) {

}
}

}
[/code]

The vert shader:

[code]
varying vec4 diffuse;

void main()
{
gl_Position = ftransform();
gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;

vec3 normal = gl_Normal;
vec3 lightVector = gl_LightSource[0].position.xyz - gl_Vertex.xyz;
float dist = length(lightVector);

float attenuation = 1.0/(gl_LightSource[0].constantAttenuation +
gl_LightSource[0].linearAttenuation * dist +
gl_LightSource[0].quadraticAttenuation * dist * dist);

lightVector = normalize(lightVector);

float nxDir = max(0.0, dot(normal, lightVector));
diffuse = gl_LightSource[0].diffuse * nxDir * attenuation;
}
[/code]

The frag shader:

[code]
uniform sampler2D texture;
varying vec4 diffuse;

void main()
{
vec4 texColor = texture2D(texture, gl_TexCoord[0].st);
gl_FragColor = (gl_LightSource[0].ambient + diffuse) * texColor;
}

[/code]

garyritchie
Offline
Joined: 2009-08-27
Points: 0

Thanks Doug. While what you sent is a bit outside of my expertise but it forced me to do proper experimentation.

What seems to work best, as a compromise, is to disable lighting (in Object Properties) for those items where you want to mix vertex colors and diffuse (color or texture). The result seems to work well so far but eventually I would like to figure out how to mix both vertex and diffuse yet use the world lighting.