- Home /
Drawing semi-transparent objects with GL.Begin(GL.QUADS)
I am drawing some semi-transparent spots with GL.Begin(GL.QUADS). They appear as I expect except for the fact that I have some semi-transparent objects in my scene. The spots are being obscured by Opaque objects as they should be but they are showing on top of the semi-transparent objects.
I am using the following script on my camera: (the actual code that does the drawing using GL is in another script - functions get called on a bunch of different objects to get their trajMark positions)
var drawLines = true; private var lineMaterial : Material; private var stateLink : StateController;
function Awake () { lineMaterial = new Material( "Shader \"Lines/Colored Blended\" {" + "SubShader { Tags { \"Queue\" = \"Geometry+1\" \"RenderType\"=\"Transparent\"}" + "Pass {" + " BindChannels { Bind \"Color\",color }" + " Blend SrcAlpha OneMinusSrcAlpha" + " ZWrite Off Cull Off Fog { Mode Off }" + "} } }"); lineMaterial.hideFlags = HideFlags.HideAndDontSave; lineMaterial.shader.hideFlags = HideFlags.HideAndDontSave; stateLink = GameObject.FindWithTag ("Engine").GetComponent(StateController); }
function OnPostRender () { if(drawLines) { lineMaterial.SetPass(0); stateLink.drawTrajMarks(); } }
function OnApplicationQuit () { DestroyImmediate(lineMaterial); }
@script RequireComponent(Camera)
It is adapted from the wiki example for drawing lines.
I have added Tags to the shader:
Tags { "Queue" = "Geometry+1" "RenderType"="Transparent"}"
However they don't appear to be having an effect. I also tried Queue = Transparent-1 (which is basically the same).
Does anyone know how to get the alpha blend to work correctly when using OnPostRender()? Can it actually work in this situation (i'm suspecting possibly not)? Am I missing something simple?
Thanks in advance
Answer by Slin · Jul 07, 2010 at 12:59 PM
I think that the GL class draws in the same moment you call one of its draw functions. As the Queue tag would define when an object is rendered, it is just ignored. I am not exactly sure if I understand your problem correctly, but as you already draw after everything else, by doing it within that OnPostRender event, I guess that it has to do with depth testing. Transparent objects usually dont write into the depth buffer and you also disable writing into it for your custom drawing. This means that if you want it to be behind transparent objects, you have to draw it before drawing anything transparent, or if you want it to be drawn in front of solid objects, you have to set the vertex position correctly or disable the depth test.
I hope this makes sense...
Hi Slin thanks for that. I thought that would be the case. The problem is that the spots map out the trajactory that the objects have travelled so they should always be underneath things and not show over the top. This is fine for opaque objects as the spots are not rendered over the top as the depth of the objects from the camera is observed. However like you say with transparent objects the depth info is not written and so the spots just render over the top. I have tried a few things. I have ztest turned off because the documentation says to for transparent objects - It would have no effect.
The thing is I need to render these in OnPostRender() because that is the only place GL calls will show up and it is the only way I can get decent performance with the large number of calls. I had used graphics.draw$$anonymous$$esh in a slightly different way but there are issues with that as well if you want every spot to have a fading transparency.
Answer by Yanger_xy · Mar 30, 2011 at 03:53 PM
Hi, I am not very familiar with custom shader. And maybe this is what you want.The code below draws a semi-transparent QUAD. Make sure that you have assign a transparent type material and attach this script to a camera.
using UnityEngine;
using System.Collections;
public class GLUtility : MonoBehaviour { public Material _glMaterial;
void Update() { _mousePos = Input.mousePosition; if (Input.GetKeyDown(KeyCode.Space)) { _startVertex = new Vector3(_mousePos.x, _mousePos.y, 0); } } //Note that the OpenGL's coordinate system in Unity is right-hand rule.And the left-bottom is (0,0), and right-top is (1,1) when you use GL.LoadOrtho() void OnPostRender() { if (_glMaterial == null) { print("Please assign a material on the inspector"); return; } GL.PushMatrix(); _glMaterial.SetPass(0);
GL.LoadPixelMatrix();
GL.Viewport(new Rect(0, 0, Screen.width, Screen.height));
GL.Color(new Color(0.5f, 0.0f, 0.0f, 0.5f));
GL.Begin(GL.QUADS);
GL.Vertex3(0, 0, 0);
GL.Vertex3(0, Screen.height / 3, 0);
GL.Vertex3(Screen.width / 3, Screen.height / 3, 0);
GL.Vertex3(Screen.width / 3, 0, 0);
GL.End();
GL.PopMatrix();
}
}
GOOD LUCK !
Answer by Jonathan Marin · Oct 03, 2013 at 03:25 PM
Hi, I found the solution for your problem today. You have to put a second camera in your scene, which will render the GL in the OnPostRender(). To render behind transparent object the camera will have to render before (using the depth of the GL camera to be rendered before the main camera. the GL and main camera will have to be at the exact same position to superpose the two images) see the information about renderPath and depth here if you have to: Camera Component DOC
here is a custom class to create the camera and display the lines:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Camera2DRender : MonoBehaviour {
static Camera m_camera;
//Make a singleton so that you can access it easily
private static Camera2D m_instance;
public static Camera2D Instance
{
get
{
return m_instance;
}
set
{
if (m_instance == null)
{
m_instance = value;
}
}
}
//use this getter to initialize the camera
public static Camera camera2D
{
get
{
if (m_camera == null)
{
//Here create the camera copying mainCamera transform infos
Instance.gameObject.AddComponent<Camera>();
Instance.gameObject.transform.position = Camera.main.transform.position;
Instance.gameObject.transform.rotation = Camera.main.transform.rotation;
Instance.gameObject.camera.orthographicSize = Camera.main.orthographicSize;
Camera.main.renderingPath = RenderingPath.Forward;
Camera.main.clearFlags = CameraClearFlags.Depth;
/*We have to render this camera before the main Cam (if you want objects to be dispayed between 2 objects you will have to render 3 cams, one for the objects behind line(depth -1), one for the GL lines (depth), and the last for the objects in front of the lines (depth + 1).*/
Instance.gameObject.camera.depth = Camera.main.depth - 1;
m_camera = Instance.GetComponent<Camera>();
m_camera.orthographic = true;
m_camera.cullingMask = 0;
}
return m_camera;
}
set
{
if (m_camera == null)
{
m_camera = value;
}
}
}
public Material m_material;
void Awake () {
Instance = this;
transform.position = camera2D.transform.position;
}
//Here render your GL you want to be drawn behind objects
void OnPostRender()
{
GL.PushMatrix();
GL.LoadOrtho();
m_material.SetPass(0);
GL.Begin(GL.QUADS);
GL.TexCoord2(0, 1);
GL.Vertex3(0, 1, 1);
GL.TexCoord2(1, 1);
GL.Vertex3(1, 1, 1);
GL.TexCoord2(1, 0);
GL.Vertex3(1, 0, 1);
GL.TexCoord2(0, 0);
GL.Vertex3(0, 0, 1);
GL.End();
GL.PopMatrix();
}
}
Your answer
Follow this Question
Related Questions
Camera OnPostRenderer on iPhone/iPad sometimes paints all the GL.Lines Black. 1 Answer
Sprite behind semi transparent mesh 0 Answers
Is it possible to restrict which subshader pass to use with Cameras 0 Answers
How to draw GL Lines over GameObjects/Images? 1 Answer
How to permanently set the renderQueue variable for a material? 2 Answers