- Home /
Finding an appropriate alternative to textures
Hello everyone,
first of all, I want you to know what I'm trying to do and what I got so far:
In Unity, I set up an object on which I am trying to display websites, being able to interact with them. The surface of the object is not flat, it looks more like a curved wall:
In addition to the website itself, I want to display a simple mouse cursor (by now a simple black rectangle, maybe a crosshair in the future), indicating the current mouse position. The way I'm achieving this right now is to use a mesh renderer component attached to the gameObject, containing two materials and two scripts, manipulating the material's textures. To get an overview of the scripts and materials I attached to the gameObject in question, see the following screen capture of the inspector panel:
The first material uses a diffuse shader and its texture is manipulated (overwritten) by the script providing the webView ("WebTexture"). I believe this likely to be non-optional since I'm using a Unity plugin called "uWebKit" to provide this kind of functionality.
The second material instead uses a transparent/diffuse shader and its texture is overwritten by a script i wrote on my own ("mousePointerTexture"). My script creates a texture having the same dimensions than the texture of the website. Almost every pixel of my texture is transparent except for a few pixels which are black, representing the mouse cursor. To get an idea how I do this, please see the following script:
using UnityEngine;
using System.Collections;
public class mousePointerTexture : MonoBehaviour {
// dimensions of texture
int dimX = 1920;
int dimY = 1200;
// background color, transparent
Color bgColor = Color.clear;
// color representing the mouse cursor
Color crsrColor = Color.black;
// resolution of application window
int resX = 1280;
int resY = 800;
// texture on which the mouse cursor appears
Texture2D texture;
// scaling factors for the mouse position
float scaleX, scaleY;
// mouse position relative to the app window
Vector3 mp;
// calculated mouse position on the texture/website
int mx;
int my;
// list of materials the renderer contains
public Material[] materials;
// colors being used by setpixels()
Color[] colorsCRSR;
Color[] colorsBG;
// Use this for initialization
void Start () {
// calculating scaling factors
scaleX = (float)dimX / (float)resX;
scaleY = (float)dimY / (float)resY;
// initializing texture for mouse cursor
texture = new Texture2D (dimX, dimY, TextureFormat.ARGB32, false);
for (int i = 0; i < dimX; i++) {
for (int j = 0; j < dimY; j++) {
texture.SetPixel(i, j, bgColor);
}
}
texture.Apply ();
// get renderer's materials
materials = renderer.materials;
// setting texture as 2nd material's mainTexture
(renderer.materials.GetValue (1) as Material).mainTexture = texture;
// initializing colors
colorsCRSR = new Color[4 * 8];
for(int i = 0; i < (4*8); i++) {
colorsCRSR[i] = crsrColor;
}
colorsBG = new Color[4 * 8];
for(int i = 0; i < (4*8); i++) {
colorsBG[i] = bgColor;
}
}
// Update is called once per frame
void Update () {
if (materials.Length == 0) {
return;
}
// get new mouse position
mp = Input.mousePosition;
// calculate corresponding position on webSite
mx = (int)(mp.x * scaleX);
my = (int)(mp.y * scaleY);
// set pixels representing the mouse cursor black
texture.SetPixels(mx, my, 4, 8, colorsCRSR);
// push to GFX card
texture.Apply ();
// set pixels transparent again
texture.SetPixels(mx, my, 4, 8, colorsBG);
}
}
As you can see, I use the known to be slow texture.SetPixels()/texture.Apply() combination. And this is exactly where my problem is: As you probably could imagine, the single line of
texture.Apply ();
causes the framerate to decrease from 60fps by 20 to 40fps. I'm aware of my method not being adequate in this case, but other solutions i read about, like using faces of triangles, looking not that simple in my case, considering the object I'm working on being non-planar.
So here is my question: Is there an appropriate alternative to textures to fulfill my needs?
Any answers, suggestions and even the tiniest hints will be much appreciated.
Thanks for your patience.
"$$anonymous$$y script creates a texture having the same dimensions than the texture of the website. Almost every pixel of my texture is transparent except for a few pixels which are black, representing the mouse cursor."
Why would you need to do this? Any per-frame texture manipulation is expensive, let alone a gigantic texture. Why not have a separate object acting as the cursor, then do some wizardry (ray projection maybe) to know the position of the Unity mouse input on the curved wall. That's your cursor object position. Easy.
Getting the position of the cursor in web-page-space is likewise fairly straightforward.
If the cursor object can't be billboarded (it must have the curvature of the wall) then you can produce a procedural mesh which shares the curvature of the wall directly behind it. This is a bit trickier, but still do-able.
Why would I need to use ray projection in order to know the position of the Unity mouse input on the curved wall? Achieving this has already been accomplished. $$anonymous$$y problem refers more to develop an alternative of displaying the cursor on the webtexture. What do you mean exactly by "having a seperate object acting as the cursor"? Creating a new gameObject, maybe a black plane and move it around in front of the webtexture? What do you mean by a procedural mesh? I could only find some references about procedural materials which can be assigned to ordinary meshes. And how can I make the procedural mesh share the curvature of the wall directly behind it? I am sorry if I partially misunderstood you.
Yes, a new gameobject. Not only is it going to be massively more efficient, it's also going to be a much more flexible system. The simplest thing to start with would be to make it a sphere.
Even though it does not match exactly what I wanted to get, using a sphere as a cursor is a great idea since it handles the problem with the webtTexture's curvedness! Considering this, there is one thing I struggle with. In order to be able to move the sphere to the current cursor position, I would need to calculate the world coordinates of a given pixel on my webTexture, right? So how can this be done?
I guess, like @AlwaysSunny says, that would be ray projection wizardry. The only thing I was adding was the idea that making it a sphere means you can ignore the curvature of the wall.
Answer by Owen-Reynolds · Feb 07, 2015 at 04:03 PM
I'm pretty sure, no, there is no other way to display an image on a model besides using a texture. The graphics card, which displays the model, has textures built-in to the pipeline, scads of optimized texture sampling hardware bits... . You're not going to do any better than that.
For live texture manipulation, you can often use a shader (like the sort of thing Unity Projections do.)
The use of a shader for the purpose of texture manipulation sounds interesting. But how can I configure a shader to simply black out some pixels of a texture? Since I am new to the topic the information is a bit overwhel$$anonymous$$g. Can you point me to some appropriate ressources which fit my needs?
Answer by toddisarockstar · Feb 07, 2015 at 04:13 PM
if (Input.GetMouseButtonDown(0)) {
var hit: RaycastHit;
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, hit)) {
mx=hit.point.x;
my=hit.point.y;}}
Hi there, thanks for your reply. As I stated in another comment, getting the position of the mouse cursor is not an issue. This is already done directly by scaling Input.mousePosition up to the dimension of the webTexture.
Your answer
Follow this Question
Related Questions
Assigning UV Map to model at runtime 0 Answers
Made a HUD with planes and need it to ignore lights. 2 Answers
How to apply a material/Texture on a irregular shape? 1 Answer
Getting None or Missing Texture from AssetPreview.GetAssetPreview 4 Answers
Making Unity textures/materials look as good as they did in Blender 2 Answers