Jump to content
The Dark Mod Forums

[2.10] X-Rays


Dragofer
 Share

Recommended Posts

Can this also been used with a mirror, so that you can show things in a mirror behind the player that is not visible when the player turns around (for example a ghost)?

Edit: I tried getting this to work by placing a mirror behind the X-ray screen. This does not seem to work properly, or I am doing something wrong.

A possible alternative way might be placing a camera pointed toward the players front side through an x-ray screen and then put a monitor on the other side. Just thinking out loud..

Edited by datiswous
  • Like 1
Link to comment
Share on other sites

14 hours ago, datiswous said:

Can this also been used with a mirror, so that you can show things in a mirror behind the player that is not visible when the player turns around (for example a ghost)?

Edit: I tried getting this to work by placing a mirror behind the X-ray screen. This does not seem to work properly, or I am doing something wrong.

A possible alternative way might be placing a camera pointed toward the players front side through an x-ray screen and then put a monitor on the other side. Just thinking out loud..

Xrays + mirrors don't seem to work well together yet, though experimentation may yield interesting results and maybe support could be added if it's considered an interesting combination by mappers.

From a performance perspective it seems unsensible to attempt this though, since the xray system adds a 2nd model and the mirror doubles everything, ending up at 4 models. But it depends on what you do with the system: if all you do is change some decorative models you probably wouldn't notice a difference, but you would notice it if you converted your entire city map into an undead necropolis through xray vision and threw in a mirror with realtime reflections.

  • Like 2
  • Thanks 1
Link to comment
Share on other sites

Quote

Can this also been used with a mirror, so that you can show things in a mirror behind the player that is not visible when the player turns around (for example a ghost)?

Using Xray system imo seems overkill for something like that, i think there are simple tricks for that. 

If you have Doom 3, you can always go look how idSoftware team made the famous bathroom scare scene, where everything reflected in the mirror changes to a hellish look, including the player. I bet most of it is script, not hardcoded c++ but I'm not sure, unlike latter idtech 4 games, many stuff in Doom 3 is script based so perhaps that is as well.

Spoiler

But like I said, IMO something like that should be simple to do, you can always do vector math to check what is in front or back of the player but perhaps TDM scripting already has functions exactly for that.

For example, Doom3 idActor class has the following function bellow, obviously this is TDM, so things maybe different but if the TDM player, works in the same basic principles/code as the Doom 3 player then perhaps that function still exist, then is just a matter of, if TDM team exposed it to script, if it did, imo it is exactly what you want to use, to check what the player can and cannot see.

But if they didn't exposed it and you know how to scrip, I don't think it would be hard to create your own script function inspired on the c++ code bellow, with what TDM team already has exposed to script.

//////////

bool idActor::CanSee( idEntity *ent, bool useFov ) const {
    trace_t        tr;
    idVec3        eye;
    idVec3        toPos;

    if ( ent->IsHidden() ) {
        return false;
    }

    if ( ent->IsType( idActor::Type ) ) {
        toPos = ( ( idActor * )ent )->GetEyePosition();
    } else {
        toPos = ent->GetPhysics()->GetOrigin();
    }

    if ( useFov && !CheckFOV( toPos ) ) {
        return false;
    }

    eye = GetEyePosition();

    gameLocal.clip.TracePoint( tr, eye, toPos, MASK_OPAQUE, this );
    if ( tr.fraction >= 1.0f || ( gameLocal.GetTraceEntity( tr ) == ent ) ) {
        return true;
    }

    return false;
}

  • Like 1
Link to comment
Share on other sites

1 hour ago, Wellingtoncrab said:

but I can't find how to simply flag an object as hidden unless viewed through the xray. Is this info in the wiki somewhere?

The current method mentioned in the wiki in the spawnargs section is just to set "skin" "invisible" and "skin_xray" "visible".

We thought about using the "xray" spawnarg for this so that "0" = invisible in xray, "1" = invisible in normal vision and i.e. no value = visible in both, but the skin method just seemed more intuitive.

  • Like 1
Link to comment
Share on other sites

Beta2 features a new spawnarg: "suppressInSubview". Specific to lights, setting this to "1" makes the light visible only in normal vision while "2" makes it visible only in xray vision. Note that this affects other subviews like mirrors and camera screens, too.

The below screenshot was achieved by setting the spawnarg on the regular ceiling lamp to "1" and on the blue flame light to "2".

xray_2021-12-19_20_02_44.thumb.jpg.c233fa827daecb36b6dfd06bafe5ac18.jpg

  • Like 3
Link to comment
Share on other sites

This is a really awesome mechanic - I really like the default mixed material which blends the two realities together in a very eerie way. I was wondering looking at the material def if one of the parameters influenced the sort of mixing amount between the two vision modes - say if for example you wanted the xray vision to be a little more prevalent in the scene? 

Link to comment
Share on other sites

@WellingtoncrabMixing models is probably my favourite mode, too. For adjusting their relative contributions I found it useful to add a line with "alpha" followed by a number to the xray material stage. Note that if you go for alpha values over 1 the rendering may become... weird and overly bright, depending on your colour precision setting.

  • Thanks 1
Link to comment
Share on other sites

Thanks@Dragofer! If I could trouble you for one more bit of guidance the wiki mentions using additional scripting to do things like manipulate the solid property objects. I see the default behavior for brushwork with xray skins is to make them non solid.

I want to make certain objects solid when not wearing the xray glasses and I am admittedly not sure where to start. I see there is a global parameter to track the state of whether or not the glasses are on - does that mean it can be referenced by the map script? 

Link to comment
Share on other sites

4 hours ago, Wellingtoncrab said:

I want to make certain objects solid when not wearing the xray glasses and I am admittedly not sure where to start.

My approach was to add another function to the scriptobject, "update_xray_entities", which is called by the scriptobject's init function at map start and whenever the player puts on or takes off the xray glasses. See the customised scriptobject below (it also contains a proper cooldown to limit how rapidly the player can toggle the glasses to minimise visual glitches).

Spoiler
#ifndef __XRAY_GLASSES__
#define __XRAY_GLASSES__

float wearing_xray_glasses;		//this is global for the benefit of the spyglass_overridable scriptobject

object playertools_xray_glasses : player_tools
{
	void init();
	void inventoryUse(entity userEntity, entity frobbedEntity, float buttonState);
	void update_xray_entities();	//updates frobability and solidity of xray entities on the map

	float overlayHandle;
	float xrayGlassesCooldown;
};

void playertools_xray_glasses::init()
{
	sys.waitFrame();
	update_xray_entities();
}

void playertools_xray_glasses::inventoryUse(entity userEntity, entity frobbedEntity, float buttonState)
{
	if( sys.getTime() < xrayGlassesCooldown )
	{
		return;
	}

	if ( !wearing_xray_glasses )
	{
		wearing_xray_glasses = true;
		overlayHandle = $player1.createOverlay(getKey("gui"), ZOOM_GUI_LAYER);
		$player1.setSpyglassOverlayBackground();	// display the correct background based on aspect ratio
	}

	else
	{
		wearing_xray_glasses = false;
		$player1.destroyOverlay(overlayHandle);
	}

	update_xray_entities();
	sys.fadeIn('0 0 0', 1);
	xrayGlassesCooldown = sys.getTime() + 1.5;
}

void playertools_xray_glasses::update_xray_entities()
{
	// find entities whose solidity should toggle when xray glasses are toggled.
	entity e;
	do
	{
		e = sys.getNextEntity("solid_xray","",e);
		if( e )
		{
			if ( e.getFloatKey("solid_xray") == 0 )
			{
				if ( wearing_xray_glasses )	e.setSolid(0);
				else				e.setSolid(1);
			}
			
			else
			{
				if ( wearing_xray_glasses )	e.setSolid(1);
				else				e.setSolid(0);
			}
		}
	} while (e);

	// find entities whose frobability should toggle when xray glasses are toggled.
	do
	{
		e = sys.getNextEntity("frobable_xray","",e);
		if( e )
		{
			if ( e.getFloatKey("frobable_xray") == 0 )
			{
				if ( wearing_xray_glasses )	e.setFrobable(0);
				else				e.setFrobable(1);
			}
			
			else
			{
				if ( wearing_xray_glasses )	e.setFrobable(1);
				else				e.setFrobable(0);
			}
		}
	} while (e);
}

#endif //__XRAY_GLASSES__

 

4 hours ago, Wellingtoncrab said:

I see there is a global parameter to track the state of whether or not the glasses are on - does that mean it can be referenced by the map script?

Yes, making that variable accessible to other scripts was the reason behind making it global. Personally I've used this for a custom version of the spyglass scriptobject that can't be used while the player has xray glasses on (see the beginning of the inventoryUse function in the below scriptobject).

Note that the custom spyglass scriptobject has to be #included later than the xray glasses in tdm_custom_scripts.script so that the variable already exists by the time the spyglass scriptobject tries to read it.

Spoiler
#ifndef __SPYGLASS_OVERRIDABLE__
#define __SPYGLASS_OVERRIDABLE__

//difference to normal spyglass: can't be used if already wearing xray_glasses (wearing_xray_glasses = true)

object playertools_spyglass_overridable : player_tools {
	void init();
	void inventoryUse(entity userEntity, entity frobbedEntity, float buttonState);
	void zoomOut();

	float zoomedIn;
	float zoomMutex;
	float overlayHandle;
};

void playertools_spyglass_overridable::init()
{
	zoomedIn = false;
	zoomMutex = false;
}

void playertools_spyglass_overridable::zoomOut()
{
	zoomedIn = false;
	$player1.endZoom(ZOOM_OUT_DURATION);

	zoomMutex = true; // disable commands during the zoom out transition

	sys.wait(ZOOM_OUT_DURATION/1000);
	$player1.destroyOverlay(overlayHandle);
	overlayHandle = 0;

	zoomMutex = false;

	$player1.setImmobilization(SPYGLASS, 0);
}

void playertools_spyglass_overridable::inventoryUse(entity userEntity, entity frobbedEntity, float buttonState)
{
	if (wearing_xray_glasses)
	{
		return;
	}

	// This is to avoid zoomIn events during zoomOut transitions, which look bad
	if (zoomMutex) {
		return;
	}

	if (!zoomedIn)
	{
		// Start zooming in
		zoomedIn = true;
		$player1.startZoom(ZOOM_IN_DURATION, ZOOM_STARTFOV, ZOOM_ENDFOV);

		// Create the GUI
		overlayHandle = $player1.createOverlay(getKey("gui"), ZOOM_GUI_LAYER);

		// Disable some player actions while zoomed in
		$player1.setImmobilization(SPYGLASS, SPYGLASS_IMMOBILIZATION);

		$player1.setGuiFloat(overlayHandle, STATE_ZOOM_IN_REQUEST, 0);
		$player1.setGuiFloat(overlayHandle, STATE_ZOOM_OUT_REQUEST, 0);

		// grayman #3807 - display the correct background based on aspect ratio
		$player1.setSpyglassOverlayBackground();

		eachFrame {
			// Check if the zoom has been ended >> break the loop
			if (!zoomedIn) {
				break;
			}

			float closeRequest = $player1.getGuiFloat(overlayHandle, STATE_CLOSE_REQUEST);
			if (closeRequest)
			{
				// Perform the zoomOut transition and break the loop
				zoomOut();
				break;
			}

			float zoomInRequest = $player1.getGuiFloat(overlayHandle, STATE_ZOOM_IN_REQUEST);
			float zoomOutRequest = $player1.getGuiFloat(overlayHandle, STATE_ZOOM_OUT_REQUEST);

			float curFov = $player1.getFov();
			float newFov = curFov;

			if (zoomInRequest)
			{
				newFov -= ZOOM_STEP;

				// Reset the GUI variable
				$player1.setGuiFloat(overlayHandle, STATE_ZOOM_IN_REQUEST, 0);
			}
			else if (zoomOutRequest)
			{
				// Zoom further out, if applicable
				newFov += ZOOM_STEP;

				// Reset the GUI variable
				$player1.setGuiFloat(overlayHandle, STATE_ZOOM_OUT_REQUEST, 0);
			}

			if (zoomInRequest || zoomOutRequest)
			{
				// Clamp the zoom value
				if (newFov < ZOOM_ENDFOV)
				{
					newFov = ZOOM_ENDFOV;
				}
				else if (newFov > ZOOM_STARTFOV) 
				{
					newFov = ZOOM_STARTFOV;
				}

				// Start the zoom transition from the current value to the the new one
				$player1.startZoom(ZOOM_STEP_DURATION, curFov, newFov);
			}
		}
	}
	else
	{
		// We're already zoomed in, so zoom out now.
		zoomOut();
	}
}

#endif //__SPYGLASS_OVERRIDABLE__
4 hours ago, Wellingtoncrab said:

I see the default behavior for brushwork with xray skins is to make them non solid.

The xray system itself should not have any effect on the solidity of entities, only the regular "skin". That said, I can't exclude 100% from my memory that setting a nonsolid "skin_xray" on i.e. a brush entity may affect its solidity in unforeseen ways.

  • Like 1
Link to comment
Share on other sites

Thank you for the expanded scripts - those additional spawnargs work great! Didn't even think about the spyglass!

3 hours ago, Dragofer said:

The xray system itself should not have any effect on the solidity of entities, only the regular "skin". That said, I can't exclude 100% from my memory that setting a nonsolid "skin_xray" on i.e. a brush entity may affect its solidity in unforeseen ways.

Yeah, reading your point above I realized the issue on the brush work I was putting both "skin" "visible" and "skin_xray" "invisible" on them and it was that inclusion of "skin" "visible" which was making them nonsolid when the glasses weren't on - obviously a bit redundant to specify you should be able to see the brush with the glasses off, so just removed that spawn arg and now it works exactly like I would expect - thanks again!

  • Like 1
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...